/* #define NV50_TGSI2NC_DEBUG */
-/* XXX: need to clean this up so we get the typecasting right more naturally */
-
#include <unistd.h>
#include "nv50_context.h"
#include "tgsi/tgsi_parse.h"
#include "tgsi/tgsi_util.h"
-#include "util/u_simple_list.h"
#include "tgsi/tgsi_dump.h"
#define BLD_MAX_TEMPS 64
#define BLD_MAX_PREDS 4
#define BLD_MAX_IMMDS 128
-#define BLD_MAX_COND_NESTING 4
+#define BLD_MAX_COND_NESTING 8
#define BLD_MAX_LOOP_NESTING 4
#define BLD_MAX_CALL_NESTING 2
{
unsigned i;
- for (i = stk->size - 1; i >= 0; --i)
- if (stk->body[i] == val)
+ for (i = stk->size; i > 0; --i)
+ if (stk->body[i - 1] == val)
break;
- if (i < 0)
+ if (!i)
return FALSE;
- if (i != stk->size - 1)
- stk->body[i] = stk->body[stk->size - 1];
+ if (i != stk->size)
+ stk->body[i - 1] = stk->body[stk->size - 1];
--stk->size; /* XXX: old size in REALLOC */
return TRUE;
struct bld_value_stack pvs[BLD_MAX_PREDS][4]; /* TGSI_FILE_PREDICATE */
struct bld_value_stack ovs[PIPE_MAX_SHADER_OUTPUTS][4];
- uint32_t outputs_written[(PIPE_MAX_SHADER_OUTPUTS + 31) / 32];
+ uint32_t outputs_written[(PIPE_MAX_SHADER_OUTPUTS + 7) / 8];
struct nv_value *frgcrd[4];
struct nv_value *sysval[4];
bld_warn_uninitialized(struct bld_context *bld, int kind,
struct bld_value_stack *stk, struct nv_basic_block *b)
{
+#ifdef NV50_TGSI2NC_DEBUG
long i = (stk - &bld->tvs[0][0]) / 4;
long c = (stk - &bld->tvs[0][0]) & 3;
debug_printf("WARNING: TEMP[%li].%c %s used uninitialized in BB:%i\n",
i, (int)('x' + c), kind ? "may be" : "is", b->id);
+#endif
}
static INLINE struct nv_value *
struct bld_value_stack *stack)
{
struct nv_basic_block *in;
- struct nv_value *vals[16], *val;
+ struct nv_value *vals[16] = { 0 };
+ struct nv_value *val;
struct nv_instruction *phi;
int i, j, n;
return bld_imm_u32(bld, fui(f));
}
-#define SET_TYPE(v, t) ((v)->reg.type = NV_TYPE_##t)
+#define SET_TYPE(v, t) ((v)->reg.type = (v)->reg.as_type = (t))
static struct nv_value *
bld_insn_1(struct bld_context *bld, uint opcode, struct nv_value *src0)
{
struct nv_instruction *insn = new_instruction(bld->pc, opcode);
- assert(insn);
- nv_reference(bld->pc, &insn->src[0], src0); /* NOTE: new_ref would suffice */
+ nv_reference(bld->pc, &insn->src[0], src0);
- return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.type));
+ return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.as_type));
}
static struct nv_value *
nv_reference(bld->pc, &insn->src[0], src0);
nv_reference(bld->pc, &insn->src[1], src1);
- return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.type));
+ return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.as_type));
}
static struct nv_value *
nv_reference(bld->pc, &insn->src[1], src1);
nv_reference(bld->pc, &insn->src[2], src2);
- return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.type));
+ return bld_def(insn, 0, new_value(bld->pc, NV_FILE_GPR, src0->reg.as_type));
+}
+
+static struct nv_value *
+bld_duplicate_insn(struct bld_context *bld, struct nv_instruction *nvi)
+{
+ struct nv_instruction *dupi = new_instruction(bld->pc, nvi->opcode);
+ int c;
+
+ if (nvi->def[0])
+ bld_def(dupi, 0, new_value_like(bld->pc, nvi->def[0]));
+
+ if (nvi->flags_def) {
+ dupi->flags_def = new_value_like(bld->pc, nvi->flags_def);
+ dupi->flags_def->insn = dupi;
+ }
+
+ for (c = 0; c < 5; ++c)
+ if (nvi->src[c])
+ nv_reference(bld->pc, &dupi->src[c], nvi->src[c]->value);
+ if (nvi->flags_src)
+ nv_reference(bld->pc, &dupi->flags_src, nvi->flags_src->value);
+
+ dupi->cc = nvi->cc;
+ dupi->saturate = nvi->saturate;
+ dupi->centroid = nvi->centroid;
+ dupi->flat = nvi->flat;
+
+ return dupi->def[0];
+}
+
+static void
+bld_lmem_store(struct bld_context *bld, struct nv_value *ptr, int ofst,
+ struct nv_value *val)
+{
+ struct nv_instruction *insn = new_instruction(bld->pc, NV_OP_STA);
+ struct nv_value *loc;
+
+ loc = new_value(bld->pc, NV_FILE_MEM_L, NV_TYPE_U32);
+
+ loc->reg.id = ofst * 4;
+
+ nv_reference(bld->pc, &insn->src[0], loc);
+ nv_reference(bld->pc, &insn->src[1], val);
+ nv_reference(bld->pc, &insn->src[4], ptr);
+}
+
+static struct nv_value *
+bld_lmem_load(struct bld_context *bld, struct nv_value *ptr, int ofst)
+{
+ struct nv_value *loc, *val;
+
+ loc = new_value(bld->pc, NV_FILE_MEM_L, NV_TYPE_U32);
+
+ loc->reg.id = ofst * 4;
+
+ val = bld_insn_1(bld, NV_OP_LDA, loc);
+
+ nv_reference(bld->pc, &val->insn->src[4], ptr);
+
+ return val;
}
#define BLD_INSN_1_EX(d, op, dt, s0, s0t) \
do { \
(d) = bld_insn_1(bld, (NV_OP_##op), (s0)); \
- (d)->reg.type = NV_TYPE_##dt; \
+ SET_TYPE(d, NV_TYPE_##dt); \
(d)->insn->src[0]->typecast = NV_TYPE_##s0t; \
} while(0)
#define BLD_INSN_2_EX(d, op, dt, s0, s0t, s1, s1t) \
do { \
(d) = bld_insn_2(bld, (NV_OP_##op), (s0), (s1)); \
- (d)->reg.type = NV_TYPE_##dt; \
+ SET_TYPE(d, NV_TYPE_##dt); \
(d)->insn->src[0]->typecast = NV_TYPE_##s0t; \
(d)->insn->src[1]->typecast = NV_TYPE_##s1t; \
} while(0)
static INLINE struct nv_value *
bld_load_imm_f32(struct bld_context *bld, float f)
{
- return bld_insn_1(bld, NV_OP_MOV, bld_imm_f32(bld, f));
+ struct nv_value *imm = bld_insn_1(bld, NV_OP_MOV, bld_imm_f32(bld, f));
+
+ SET_TYPE(imm, NV_TYPE_F32);
+ return imm;
}
static INLINE struct nv_value *
{
int i;
struct nv_instruction *nvi;
+ struct nv_value *val;
for (i = 0; i < 4; ++i) {
if (!bld->saved_addr[i][0])
}
i &= 3;
- bld->saved_addr[i][0] = bld_load_imm_u32(bld, id);
+ val = bld_imm_u32(bld, id);
+ if (indirect)
+ val = bld_insn_2(bld, NV_OP_ADD, indirect, val);
+ else
+ val = bld_insn_1(bld, NV_OP_MOV, val);
+
+ bld->saved_addr[i][0] = val;
bld->saved_addr[i][0]->reg.file = NV_FILE_ADDR;
+ bld->saved_addr[i][0]->reg.type = NV_TYPE_U16;
bld->saved_addr[i][1] = indirect;
return bld->saved_addr[i][0];
}
while (nvi->opcode == NV_OP_ABS || nvi->opcode == NV_OP_NEG ||
nvi->opcode == NV_OP_CVT) {
s0i = nvi->src[0]->value->insn;
- if (!s0i ||
- s0i->opcode == NV_OP_LDA ||
- s0i->opcode == NV_OP_MOV ||
- s0i->opcode == NV_OP_PHI)
+ if (!s0i || !nv50_op_can_write_flags(s0i->opcode))
break;
nvi = s0i;
assert(!nvi->flags_src);
}
}
- if (nvi->opcode == NV_OP_LDA ||
- nvi->opcode == NV_OP_MOV ||
- nvi->opcode == NV_OP_PHI || nvi->bb != bld->pc->current_block) {
+ if (!nv50_op_can_write_flags(nvi->opcode) ||
+ nvi->bb != bld->pc->current_block) {
nvi = new_instruction(bld->pc, NV_OP_CVT);
nv_reference(bld->pc, &nvi->src[0], src);
}
static void
emit_store(struct bld_context *bld, const struct tgsi_full_instruction *inst,
- unsigned chan, struct nv_value *value)
+ unsigned chan, struct nv_value *value)
{
+ struct nv_value *ptr;
const struct tgsi_full_dst_register *reg = &inst->Dst[0];
+ if (reg->Register.Indirect) {
+ ptr = FETCH_ADDR(reg->Indirect.Index,
+ tgsi_util_get_src_register_swizzle(®->Indirect, 0));
+ } else {
+ ptr = NULL;
+ }
+
assert(chan < 4);
if (inst->Instruction.Opcode != TGSI_OPCODE_MOV)
BLD_INSN_1_EX(value, SAT, F32, value, F32);
break;
case TGSI_SAT_MINUS_PLUS_ONE:
+ value->reg.as_type = NV_TYPE_F32;
value = bld_insn_2(bld, NV_OP_MAX, value, bld_load_imm_f32(bld, -1.0f));
value = bld_insn_2(bld, NV_OP_MIN, value, bld_load_imm_f32(bld, 1.0f));
- value->reg.type = NV_TYPE_F32;
break;
}
switch (reg->Register.File) {
case TGSI_FILE_OUTPUT:
+ if (!value->insn && (bld->ti->output_file == NV_FILE_OUT))
+ value = bld_insn_1(bld, NV_OP_MOV, value);
value = bld_insn_1(bld, NV_OP_MOV, value);
value->reg.file = bld->ti->output_file;
break;
case TGSI_FILE_TEMPORARY:
assert(reg->Register.Index < BLD_MAX_TEMPS);
- value->reg.file = NV_FILE_GPR;
- if (value->insn->bb != bld->pc->current_block)
+ if (!value->insn || (value->insn->bb != bld->pc->current_block))
value = bld_insn_1(bld, NV_OP_MOV, value);
- STORE_TEMP(reg->Register.Index, chan, value);
+ value->reg.file = NV_FILE_GPR;
+
+ if (bld->ti->store_to_memory)
+ bld_lmem_store(bld, ptr, reg->Register.Index * 4 + chan, value);
+ else
+ STORE_TEMP(reg->Register.Index, chan, value);
break;
case TGSI_FILE_ADDRESS:
assert(reg->Register.Index < BLD_MAX_ADDRS);
value->reg.file = NV_FILE_ADDR;
+ value->reg.type = NV_TYPE_U16;
STORE_ADDR(reg->Register.Index, chan, value);
break;
}
const struct tgsi_full_src_register *src = &insn->Src[s];
struct nv_value *res;
struct nv_value *ptr = NULL;
- unsigned idx, swz, dim_idx, ind_idx, ind_swz;
+ unsigned idx, swz, dim_idx, ind_idx, ind_swz, sgn;
ubyte type = infer_src_type(insn->Instruction.Opcode);
idx = src->Register.Index;
assert(dim_idx == 1); /* for now */
res = new_value(bld->pc, NV_FILE_MEM_C(dim_idx), type);
- res->reg.type = type;
+ SET_TYPE(res, type);
res->reg.id = (idx * 4 + swz) & 127;
res = bld_insn_1(bld, NV_OP_LDA, res);
res = bld_load_imm_u32(bld, bld->ti->immd32[idx * 4 + swz]);
switch (bld->ti->immd32_ty[idx]) {
- case TGSI_IMM_FLOAT32: res->reg.type = NV_TYPE_F32; break;
- case TGSI_IMM_UINT32: res->reg.type = NV_TYPE_U32; break;
- case TGSI_IMM_INT32: res->reg.type = NV_TYPE_S32; break;
+ case TGSI_IMM_FLOAT32: SET_TYPE(res, NV_TYPE_F32); break;
+ case TGSI_IMM_UINT32: SET_TYPE(res, NV_TYPE_U32); break;
+ case TGSI_IMM_INT32: SET_TYPE(res, NV_TYPE_S32); break;
default:
- res->reg.type = type;
+ SET_TYPE(res, type);
break;
}
break;
bld->saved_inputs[bld->ti->input_map[idx][swz]] = res;
break;
case TGSI_FILE_TEMPORARY:
- /* this should be load from l[], with reload elimination later on */
- res = bld_fetch_global(bld, &bld->tvs[idx][swz]);
+ if (bld->ti->store_to_memory)
+ res = bld_lmem_load(bld, ptr, idx * 4 + swz);
+ else
+ res = bld_fetch_global(bld, &bld->tvs[idx][swz]);
break;
case TGSI_FILE_ADDRESS:
res = bld_fetch_global(bld, &bld->avs[idx][swz]);
if (!res)
return bld_undef(bld, NV_FILE_GPR);
- switch (tgsi_util_get_full_src_register_sign_mode(src, chan)) {
+ sgn = tgsi_util_get_full_src_register_sign_mode(src, chan);
+
+ if (insn->Instruction.Opcode != TGSI_OPCODE_MOV)
+ res->reg.as_type = type;
+ else
+ if (sgn != TGSI_UTIL_SIGN_KEEP) /* apparently "MOV A, -B" assumes float */
+ res->reg.as_type = NV_TYPE_F32;
+
+ switch (sgn) {
case TGSI_UTIL_SIGN_KEEP:
break;
case TGSI_UTIL_SIGN_CLEAR:
bld_lit(struct bld_context *bld, struct nv_value *dst0[4],
const struct tgsi_full_instruction *insn)
{
- struct nv_value *val0, *zero;
+ struct nv_value *val0 = NULL;
+ struct nv_value *zero = NULL;
unsigned mask = insn->Dst[0].Register.WriteMask;
if (mask & ((1 << 0) | (1 << 3)))
static void
load_proj_tex_coords(struct bld_context *bld,
- struct nv_value *t[4], int dim,
+ struct nv_value *t[4], int dim, int arg,
const struct tgsi_full_instruction *insn)
{
- int c, mask = 0;
+ int c, mask;
+
+ mask = (1 << dim) - 1;
+ if (arg != dim)
+ mask |= 4; /* depth comparison value */
t[3] = emit_fetch(bld, insn, 0, 3);
if (t[3]->insn->opcode == NV_OP_PINTERP) {
+ t[3] = bld_duplicate_insn(bld, t[3]->insn);
t[3]->insn->opcode = NV_OP_LINTERP;
nv_reference(bld->pc, &t[3]->insn->src[1], NULL);
}
t[3] = bld_insn_1(bld, NV_OP_RCP, t[3]);
- for (c = 0; c < dim; ++c) {
+ for (c = 0; c < 4; ++c) {
+ if (!(mask & (1 << c)))
+ continue;
t[c] = emit_fetch(bld, insn, 0, c);
- if (t[c]->insn->opcode == NV_OP_LINTERP)
- t[c]->insn->opcode = NV_OP_PINTERP;
- if (t[c]->insn->opcode == NV_OP_PINTERP)
- nv_reference(bld->pc, &t[c]->insn->src[1], t[3]);
- else
- mask |= 1 << c;
+ if (t[c]->insn->opcode != NV_OP_LINTERP &&
+ t[c]->insn->opcode != NV_OP_PINTERP)
+ continue;
+ t[c] = bld_duplicate_insn(bld, t[c]->insn);
+ t[c]->insn->opcode = NV_OP_PINTERP;
+ nv_reference(bld->pc, &t[c]->insn->src[1], t[3]);
+
+ mask &= ~(1 << c);
}
for (c = 0; mask; ++c, mask >>= 1) {
/* the inputs to a tex instruction must be separate values */
for (c = 0; c < argc; ++c) {
t[c] = bld_insn_1(bld, NV_OP_MOV, t_in[c]);
- t[c]->reg.type = NV_TYPE_F32;
+ SET_TYPE(t[c], NV_TYPE_F32);
t[c]->insn->fixed = 1;
}
cr[l] = bld_cmov(bld, bit[l], NV_CC_EQ, val->insn->flags_def);
cr[l]->reg.file = NV_FILE_FLAGS;
- cr[l]->reg.type = NV_TYPE_U16;
+ SET_TYPE(cr[l], NV_TYPE_U16);
}
sel = new_instruction(bld->pc, NV_OP_SELECT);
get_tex_dim(insn, &dim, &arg);
if (!cube && insn->Instruction.Opcode == TGSI_OPCODE_TXP)
- load_proj_tex_coords(bld, t, dim, insn);
- else
+ load_proj_tex_coords(bld, t, dim, arg, insn);
+ else {
for (c = 0; c < dim; ++c)
t[c] = emit_fetch(bld, insn, 0, c);
+ if (arg != dim)
+ t[dim] = emit_fetch(bld, insn, 0, 2);
+ }
if (cube) {
assert(dim >= 3);
t[c] = bld_insn_2(bld, NV_OP_MUL, t[c], s[0]);
}
- if (arg != dim)
- t[dim] = emit_fetch(bld, insn, 0, 2);
-
if (opcode == NV_OP_TXB || opcode == NV_OP_TXL) {
t[arg++] = emit_fetch(bld, insn, 0, 3);
struct nv_value *src0;
struct nv_value *src1;
struct nv_value *src2;
- struct nv_value *dst0[4];
+ struct nv_value *dst0[4] = { 0 };
struct nv_value *temp;
int c;
uint opcode = translate_opcode(insn->Instruction.Opcode);
src1 = bld_imm_u32(bld, 4);
FOR_EACH_DST0_ENABLED_CHANNEL(c, insn) {
src0 = emit_fetch(bld, insn, 0, c);
- (temp = bld_insn_1(bld, NV_OP_FLOOR, src0))->reg.type = NV_TYPE_S32;
+ temp = bld_insn_1(bld, NV_OP_FLOOR, src0);
+ SET_TYPE(temp, NV_TYPE_S32);
dst0[c] = bld_insn_2(bld, NV_OP_SHL, temp, src1);
}
break;
if (insn->Dst[0].Register.WriteMask & 8)
dst0[3] = emit_fetch(bld, insn, 1, 3);
break;
+ case TGSI_OPCODE_EXP:
+ src0 = emit_fetch(bld, insn, 0, 0);
+ temp = bld_insn_1(bld, NV_OP_FLOOR, src0);
+
+ if (insn->Dst[0].Register.WriteMask & 2)
+ dst0[1] = bld_insn_2(bld, NV_OP_SUB, src0, temp);
+ if (insn->Dst[0].Register.WriteMask & 1) {
+ temp = bld_insn_1(bld, NV_OP_PREEX2, temp);
+ dst0[0] = bld_insn_1(bld, NV_OP_EX2, temp);
+ }
+ if (insn->Dst[0].Register.WriteMask & 4) {
+ temp = bld_insn_1(bld, NV_OP_PREEX2, src0);
+ dst0[2] = bld_insn_1(bld, NV_OP_EX2, temp);
+ }
+ if (insn->Dst[0].Register.WriteMask & 8)
+ dst0[3] = bld_imm_f32(bld, 1.0f);
+ break;
case TGSI_OPCODE_EX2:
src0 = emit_fetch(bld, insn, 0, 0);
temp = bld_insn_1(bld, NV_OP_PREEX2, src0);
{
struct nv_basic_block *b = new_basic_block(bld->pc);
+ assert(bld->cond_lvl < BLD_MAX_COND_NESTING);
+
nvbb_attach_block(bld->pc->current_block, b, CFG_EDGE_FORWARD);
bld->join_bb[bld->cond_lvl] = bld->pc->current_block;
struct nv_basic_block *bl = new_basic_block(bld->pc);
struct nv_basic_block *bb = new_basic_block(bld->pc);
+ assert(bld->loop_lvl < BLD_MAX_LOOP_NESTING);
+
bld->loop_bb[bld->loop_lvl] = bl;
bld->brkt_bb[bld->loop_lvl] = bb;
FOR_EACH_DST0_ENABLED_CHANNEL(c, insn)
dst0[c] = temp;
break;
+ case TGSI_OPCODE_LOG:
+ src0 = emit_fetch(bld, insn, 0, 0);
+ src0 = bld_insn_1(bld, NV_OP_ABS, src0);
+ temp = bld_insn_1(bld, NV_OP_LG2, src0);
+ dst0[2] = temp;
+ if (insn->Dst[0].Register.WriteMask & 3) {
+ temp = bld_insn_1(bld, NV_OP_FLOOR, temp);
+ dst0[0] = temp;
+ }
+ if (insn->Dst[0].Register.WriteMask & 2) {
+ temp = bld_insn_1(bld, NV_OP_PREEX2, temp);
+ temp = bld_insn_1(bld, NV_OP_EX2, temp);
+ temp = bld_insn_1(bld, NV_OP_RCP, temp);
+ dst0[1] = bld_insn_2(bld, NV_OP_MUL, src0, temp);
+ }
+ if (insn->Dst[0].Register.WriteMask & 8)
+ dst0[3] = bld_imm_f32(bld, 1.0f);
+ break;
case TGSI_OPCODE_RCP:
case TGSI_OPCODE_LG2:
src0 = emit_fetch(bld, insn, 0, 0);
src1 = emit_fetch(bld, insn, 1, c);
dst0[c] = bld_insn_2(bld, NV_OP_SET, src0, src1);
dst0[c]->insn->set_cond = translate_setcc(insn->Instruction.Opcode);
- dst0[c]->reg.type = infer_dst_type(insn->Instruction.Opcode);
+ SET_TYPE(dst0[c], infer_dst_type(insn->Instruction.Opcode));
dst0[c]->insn->src[0]->typecast =
dst0[c]->insn->src[1]->typecast =
if (dst0[c]->reg.type != NV_TYPE_F32)
break;
+ dst0[c]->reg.as_type = NV_TYPE_S32;
dst0[c] = bld_insn_1(bld, NV_OP_ABS, dst0[c]);
- dst0[c]->insn->src[0]->typecast = NV_TYPE_S32;
- dst0[c]->reg.type = NV_TYPE_S32;
dst0[c] = bld_insn_1(bld, NV_OP_CVT, dst0[c]);
- dst0[c]->reg.type = NV_TYPE_F32;
+ SET_TYPE(dst0[c], NV_TYPE_F32);
}
break;
case TGSI_OPCODE_SCS: