r300g: Remove is_r3xx
[mesa.git] / src / gallium / drivers / nv50 / nv50_tgsi_to_nc.c
index e1c6ed87bfe2049decd9453d259ed1c553c6b55a..15aa40cddd10ecb8dacac450b64a6f4ce783ef1e 100644 (file)
  * SOFTWARE.
  */
 
-/* #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"
@@ -33,7 +29,6 @@
 #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
@@ -41,7 +36,7 @@
 #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
 
@@ -72,14 +67,14 @@ bld_vals_del_val(struct bld_value_stack *stk, struct nv_value *val)
 {
    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;
@@ -127,7 +122,7 @@ struct bld_context {
    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];
@@ -216,6 +211,7 @@ static INLINE void
 bld_warn_uninitialized(struct bld_context *bld, int kind,
                        struct bld_value_stack *stk, struct nv_basic_block *b)
 {
+#if NV50_DEBUG & NV50_DEBUG_PROG_IR
    long i = (stk - &bld->tvs[0][0]) / 4;
    long c = (stk - &bld->tvs[0][0]) & 3;
 
@@ -224,6 +220,7 @@ bld_warn_uninitialized(struct bld_context *bld, int kind,
 
    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 *
@@ -274,6 +271,12 @@ fetch_by_bb(struct bld_value_stack *stack,
          fetch_by_bb(stack, vals, n, b->in[i]);
 }
 
+static INLINE boolean
+nvbb_is_terminated(struct nv_basic_block *bb)
+{
+   return bb->exit && bb->exit->is_terminator;
+}
+
 static INLINE struct nv_value *
 bld_load_imm_u32(struct bld_context *bld, uint32_t u);
 
@@ -290,7 +293,8 @@ bld_phi(struct bld_context *bld, struct nv_basic_block *b,
         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;
 
@@ -476,6 +480,7 @@ bld_loop_end(struct bld_context *bld, struct nv_basic_block *bb)
       stk = (struct bld_value_stack *)phi->target;
       phi->target = NULL;
 
+      /* start with s == 1, src[0] is from outside the loop */
       for (s = 1, n = 0; n < bb->num_in; ++n) {
          if (bb->in_kind[n] != CFG_EDGE_BACK)
             continue;
@@ -487,8 +492,11 @@ bld_loop_end(struct bld_context *bld, struct nv_basic_block *bb)
          for (i = 0; i < 4; ++i)
             if (phi->src[i] && phi->src[i]->value == val)
                break;
-         if (i == 4)
+         if (i == 4) {
+            /* skip values we do not want to replace */
+            for (; phi->src[s] && phi->src[s]->value != phi->def[0]; ++s);
             nv_reference(bld->pc, &phi->src[s++], val);
+         }
       }
       bld->pc->current_block = save;
 
@@ -519,17 +527,16 @@ bld_imm_f32(struct bld_context *bld, float f)
    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 *
@@ -541,7 +548,7 @@ bld_insn_2(struct bld_context *bld, uint opcode,
    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 *
@@ -555,20 +562,80 @@ bld_insn_3(struct bld_context *bld, uint opcode,
    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)
@@ -589,7 +656,10 @@ bld_pow(struct bld_context *bld, struct nv_value *x, struct nv_value *e)
 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 *
@@ -603,6 +673,7 @@ bld_get_address(struct bld_context *bld, int id, struct nv_value *indirect)
 {
    int i;
    struct nv_instruction *nvi;
+   struct nv_value *val;
 
    for (i = 0; i < 4; ++i) {
       if (!bld->saved_addr[i][0])
@@ -615,8 +686,15 @@ bld_get_address(struct bld_context *bld, int id, struct nv_value *indirect)
    }
    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];
 }
@@ -637,19 +715,15 @@ bld_predicate(struct bld_context *bld, struct nv_value *src, boolean bool_only)
       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);
    }
@@ -854,10 +928,18 @@ infer_dst_type(unsigned opcode)
 
 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(&reg->Indirect, 0));
+   } else {
+      ptr = NULL;
+   }
+
    assert(chan < 4);
 
    if (inst->Instruction.Opcode != TGSI_OPCODE_MOV)
@@ -870,14 +952,16 @@ emit_store(struct bld_context *bld, const struct tgsi_full_instruction *inst,
       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;
 
@@ -890,14 +974,19 @@ emit_store(struct bld_context *bld, const struct tgsi_full_instruction *inst,
       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;
    }
@@ -1000,7 +1089,8 @@ emit_fetch(struct bld_context *bld, const struct tgsi_full_instruction *insn,
 {
    const struct tgsi_full_src_register *src = &insn->Src[s];
    struct nv_value *res;
-   unsigned idx, swz, dim_idx, ind_idx, ind_swz;
+   struct nv_value *ptr = NULL;
+   unsigned idx, swz, dim_idx, ind_idx, ind_swz, sgn;
    ubyte type = infer_src_type(insn->Instruction.Opcode);
 
    idx = src->Register.Index;
@@ -1012,42 +1102,42 @@ emit_fetch(struct bld_context *bld, const struct tgsi_full_instruction *insn,
    if (src->Register.Indirect) {
       ind_idx = src->Indirect.Index;
       ind_swz = tgsi_util_get_src_register_swizzle(&src->Indirect, 0);
+
+      ptr = FETCH_ADDR(ind_idx, ind_swz);
    }
+   if (idx >= (128 / 4) && src->Register.File == TGSI_FILE_CONSTANT)
+      ptr = bld_get_address(bld, (idx * 16) & ~0x1ff, ptr);
 
    switch (src->Register.File) {
    case TGSI_FILE_CONSTANT:
-      dim_idx = src->Dimension.Index ? src->Dimension.Index + 2 : 1;
-      assert(dim_idx < 14);
-      assert(dim_idx == 1); /* for now */
+      dim_idx = src->Dimension.Index;
+      assert(dim_idx < 15);
 
       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);
 
-      if (src->Register.Indirect)
-         res->insn->src[4] = new_ref(bld->pc, FETCH_ADDR(ind_idx, ind_swz));
-      if (idx >= (128 / 4))
-         res->insn->src[4] =
-            new_ref(bld->pc, bld_get_address(bld, (idx * 16) & ~0x1ff, NULL));
+      if (ptr)
+         res->insn->src[4] = new_ref(bld->pc, ptr);
       break;
    case TGSI_FILE_IMMEDIATE:
       assert(idx < bld->ti->immd32_nr);
       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;
    case TGSI_FILE_INPUT:
       res = bld_saved_input(bld, idx, swz);
       if (res && (insn->Instruction.Opcode != TGSI_OPCODE_TXP))
-         return res;
+         break;
 
       res = new_value(bld->pc, bld->ti->input_file, type);
       res->reg.id = bld->ti->input_map[idx][swz];
@@ -1062,8 +1152,10 @@ emit_fetch(struct bld_context *bld, const struct tgsi_full_instruction *insn,
       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]);
@@ -1071,6 +1163,13 @@ emit_fetch(struct bld_context *bld, const struct tgsi_full_instruction *insn,
    case TGSI_FILE_PREDICATE:
       res = bld_fetch_global(bld, &bld->pvs[idx][swz]);
       break;
+   case TGSI_FILE_SYSTEM_VALUE:
+      res = new_value(bld->pc, bld->ti->input_file, NV_TYPE_U32);
+      res->reg.id = bld->ti->sysval_map[idx];
+      res = bld_insn_1(bld, NV_OP_LDA, res);
+      res = bld_insn_1(bld, NV_OP_CVT, res);
+      res->reg.type = NV_TYPE_F32;
+      break;
    default:
       NOUVEAU_ERR("illegal/unhandled src reg file: %d\n", src->Register.File);
       abort();
@@ -1079,7 +1178,15 @@ emit_fetch(struct bld_context *bld, const struct tgsi_full_instruction *insn,
    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:
@@ -1105,7 +1212,8 @@ static void
 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)))
@@ -1176,29 +1284,38 @@ get_tex_dim(const struct tgsi_full_instruction *insn, int *dim, int *arg)
 
 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) {
@@ -1257,7 +1374,7 @@ emit_tex(struct bld_context *bld, uint opcode,
    /* 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;
    }
 
@@ -1315,7 +1432,7 @@ bld_texbias_sequence(struct bld_context *bld,
       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);
@@ -1365,16 +1482,19 @@ bld_tex(struct bld_context *bld, struct nv_value *dst0[4],
    uint opcode = translate_opcode(insn->Instruction.Opcode);
    int arg, dim, c;
    const int tic = insn->Src[1].Register.Index;
-   const int tsc = 0;
+   const int tsc = tic;
    const int cube = (insn->Texture.Texture  == TGSI_TEXTURE_CUBE) ? 1 : 0;
 
    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);
@@ -1389,9 +1509,6 @@ bld_tex(struct bld_context *bld, struct nv_value *dst0[4],
          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);
 
@@ -1435,15 +1552,17 @@ static void
 bld_instruction(struct bld_context *bld,
                 const struct tgsi_full_instruction *insn)
 {
+   struct nv50_program *prog = bld->ti->p;
+   const struct tgsi_full_dst_register *dreg = &insn->Dst[0];
    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);
 
-#ifdef NV50_TGSI2NC_DEBUG
+#if NV50_DEBUG & NV50_DEBUG_PROG_IR
    debug_printf("bld_instruction:"); tgsi_dump_instruction(insn, 1);
 #endif
        
@@ -1462,7 +1581,8 @@ bld_instruction(struct bld_context *bld,
       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;
@@ -1534,6 +1654,23 @@ bld_instruction(struct bld_context *bld,
       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);
@@ -1561,6 +1698,8 @@ bld_instruction(struct bld_context *bld,
    {
       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;
@@ -1594,6 +1733,9 @@ bld_instruction(struct bld_context *bld,
    {
       struct nv_basic_block *b = new_basic_block(bld->pc);
 
+      if (!nvbb_is_terminated(bld->pc->current_block))
+         bld_flow(bld, NV_OP_BRA, NV_CC_TR, NULL, b, FALSE);
+
       --bld->cond_lvl;
       nvbb_attach_block(bld->pc->current_block, b, bld->out_kind);
       nvbb_attach_block(bld->cond_bb[bld->cond_lvl], b, CFG_EDGE_FORWARD);
@@ -1613,6 +1755,8 @@ bld_instruction(struct bld_context *bld,
       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;
 
@@ -1661,7 +1805,8 @@ bld_instruction(struct bld_context *bld,
    {
       struct nv_basic_block *bb = bld->loop_bb[bld->loop_lvl - 1];
 
-      bld_flow(bld, NV_OP_BRA, NV_CC_TR, NULL, bb, FALSE);
+      if (!nvbb_is_terminated(bld->pc->current_block))
+         bld_flow(bld, NV_OP_BRA, NV_CC_TR, NULL, bb, FALSE);
 
       nvbb_attach_block(bld->pc->current_block, bb, CFG_EDGE_BACK);
 
@@ -1712,6 +1857,24 @@ bld_instruction(struct bld_context *bld,
       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);
@@ -1743,7 +1906,7 @@ bld_instruction(struct bld_context *bld,
          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 =
@@ -1751,11 +1914,10 @@ bld_instruction(struct bld_context *bld,
 
          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:
@@ -1781,6 +1943,7 @@ bld_instruction(struct bld_context *bld,
          dst0[c] = bld_insn_2(bld, NV_OP_XOR, temp, temp);
          dst0[c]->insn->cc = NV_CC_EQ;
          nv_reference(bld->pc, &dst0[c]->insn->flags_src, src1);
+         dst0[c] = bld_insn_2(bld, NV_OP_SELECT, dst0[c], temp);
       }
       break;
    case TGSI_OPCODE_SUB:
@@ -1829,6 +1992,31 @@ bld_instruction(struct bld_context *bld,
 
    FOR_EACH_DST0_ENABLED_CHANNEL(c, insn)
       emit_store(bld, insn, c, dst0[c]);
+
+   if (prog->type == PIPE_SHADER_VERTEX && prog->vp.clpd_nr &&
+       dreg->Register.File == TGSI_FILE_OUTPUT && !dreg->Register.Indirect &&
+       prog->out[dreg->Register.Index].sn == TGSI_SEMANTIC_POSITION) {
+
+      int p;
+      for (p = 0; p < prog->vp.clpd_nr; p++) {
+         struct nv_value *clipd = NULL;
+
+         for (c = 0; c < 4; c++) {
+            temp = new_value(bld->pc, NV_FILE_MEM_C(15), NV_TYPE_F32);
+            temp->reg.id = p * 4 + c;
+            temp = bld_insn_1(bld, NV_OP_LDA, temp);
+
+            clipd = clipd ?
+                        bld_insn_3(bld, NV_OP_MAD, dst0[c], temp, clipd) :
+                        bld_insn_2(bld, NV_OP_MUL, dst0[c], temp);
+         }
+
+         temp = bld_insn_1(bld, NV_OP_MOV, clipd);
+         temp->reg.file = NV_FILE_OUT;
+         temp->reg.id = bld->ti->p->vp.clpd + p;
+         temp->insn->fixed = 1;
+      }
+   }
 }
 
 static INLINE void
@@ -1847,8 +2035,9 @@ nv50_tgsi_to_nc(struct nv_pc *pc, struct nv50_translation_info *ti)
 {
    struct bld_context *bld = CALLOC_STRUCT(bld_context);
    int c;
+   unsigned ip;
 
-   pc->root = pc->current_block = new_basic_block(pc);
+   pc->root[0] = pc->current_block = new_basic_block(pc);
 
    bld->pc = pc;
    bld->ti = ti;
@@ -1863,21 +2052,8 @@ nv50_tgsi_to_nc(struct nv_pc *pc, struct nv50_translation_info *ti)
       bld->frgcrd[3] = bld_insn_1(bld, NV_OP_RCP, bld->frgcrd[3]);
    }
 
-   tgsi_parse_init(&bld->parse[0], ti->p->pipe.tokens);
-
-   while (!tgsi_parse_end_of_tokens(&bld->parse[bld->call_lvl])) {
-      const union tgsi_full_token *tok = &bld->parse[bld->call_lvl].FullToken;
-
-      tgsi_parse_token(&bld->parse[bld->call_lvl]);
-
-      switch (tok->Token.Type) {
-      case TGSI_TOKEN_TYPE_INSTRUCTION:
-         bld_instruction(bld, &tok->FullInstruction);
-         break;
-      default:
-         break;
-      }
-   }
+   for (ip = 0; ip < ti->inst_nr; ++ip)
+      bld_instruction(bld, &ti->insns[ip]);
 
    bld_free_value_trackers(&bld->tvs[0][0], BLD_MAX_TEMPS);
    bld_free_value_trackers(&bld->avs[0][0], BLD_MAX_ADDRS);