gallivm: silence uninitialized var warning
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_tgsi_soa.c
index 2896c522fcfdbb462daf5be58497f55f88edc138..aaf3360aa245b4b974496e986420036388f9f215 100644 (file)
 #include "util/u_debug.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
+#include "tgsi/tgsi_dump.h"
 #include "tgsi/tgsi_info.h"
 #include "tgsi/tgsi_parse.h"
 #include "tgsi/tgsi_util.h"
 #include "tgsi/tgsi_exec.h"
+#include "tgsi/tgsi_scan.h"
 #include "lp_bld_type.h"
 #include "lp_bld_const.h"
 #include "lp_bld_arit.h"
 #include "lp_bld_swizzle.h"
 #include "lp_bld_flow.h"
 #include "lp_bld_tgsi.h"
-
-
-#define LP_MAX_TEMPS 256
-#define LP_MAX_IMMEDIATES 256
+#include "lp_bld_limits.h"
+#include "lp_bld_debug.h"
 
 
 #define FOR_EACH_CHANNEL( CHAN )\
 #define QUAD_BOTTOM_RIGHT 3
 
 
+struct lp_exec_mask {
+   struct lp_build_context *bld;
+
+   boolean has_mask;
+
+   LLVMTypeRef int_vec_type;
+
+   LLVMValueRef cond_stack[LP_MAX_TGSI_NESTING];
+   int cond_stack_size;
+   LLVMValueRef cond_mask;
+
+   LLVMBasicBlockRef loop_block;
+   LLVMValueRef cont_mask;
+   LLVMValueRef break_mask;
+   LLVMValueRef break_var;
+   struct {
+      LLVMBasicBlockRef loop_block;
+      LLVMValueRef cont_mask;
+      LLVMValueRef break_mask;
+      LLVMValueRef break_var;
+   } loop_stack[LP_MAX_TGSI_NESTING];
+   int loop_stack_size;
+
+   LLVMValueRef exec_mask;
+};
+
 struct lp_build_tgsi_soa_context
 {
    struct lp_build_context base;
 
+   /* Builder for integer masks and indices */
+   struct lp_build_context int_bld;
+
    LLVMValueRef consts_ptr;
    const LLVMValueRef *pos;
    const LLVMValueRef (*inputs)[NUM_CHANNELS];
    LLVMValueRef (*outputs)[NUM_CHANNELS];
 
-   struct lp_build_sampler_soa *sampler;
+   const struct lp_build_sampler_soa *sampler;
+
+   LLVMValueRef immediates[LP_MAX_TGSI_IMMEDIATES][NUM_CHANNELS];
+   LLVMValueRef temps[LP_MAX_TGSI_TEMPS][NUM_CHANNELS];
+   LLVMValueRef addr[LP_MAX_TGSI_ADDRS][NUM_CHANNELS];
+   LLVMValueRef preds[LP_MAX_TGSI_PREDS][NUM_CHANNELS];
 
-   LLVMValueRef immediates[LP_MAX_IMMEDIATES][NUM_CHANNELS];
-   LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
+   /* we allocate an array of temps if we have indirect
+    * addressing and then the temps above is unused */
+   LLVMValueRef temps_array;
+   boolean has_indirect_addressing;
 
    struct lp_build_mask_context *mask;
+   struct lp_exec_mask exec_mask;
 };
 
-
 static const unsigned char
 swizzle_left[4] = {
    QUAD_TOP_LEFT,     QUAD_TOP_LEFT,
@@ -124,6 +160,214 @@ swizzle_bottom[4] = {
    QUAD_BOTTOM_LEFT,  QUAD_BOTTOM_RIGHT
 };
 
+static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
+{
+   mask->bld = bld;
+   mask->has_mask = FALSE;
+   mask->cond_stack_size = 0;
+   mask->loop_stack_size = 0;
+
+   mask->int_vec_type = lp_build_int_vec_type(mask->bld->type);
+   mask->break_mask = mask->cont_mask = mask->cond_mask =
+         LLVMConstAllOnes(mask->int_vec_type);
+}
+
+static void lp_exec_mask_update(struct lp_exec_mask *mask)
+{
+   if (mask->loop_stack_size) {
+      /*for loops we need to update the entire mask at runtime */
+      LLVMValueRef tmp;
+      assert(mask->break_mask);
+      tmp = LLVMBuildAnd(mask->bld->builder,
+                         mask->cont_mask,
+                         mask->break_mask,
+                         "maskcb");
+      mask->exec_mask = LLVMBuildAnd(mask->bld->builder,
+                                     mask->cond_mask,
+                                     tmp,
+                                     "maskfull");
+   } else
+      mask->exec_mask = mask->cond_mask;
+
+
+   mask->has_mask = (mask->cond_stack_size > 0 ||
+                     mask->loop_stack_size > 0);
+}
+
+static void lp_exec_mask_cond_push(struct lp_exec_mask *mask,
+                                   LLVMValueRef val)
+{
+   assert(mask->cond_stack_size < LP_MAX_TGSI_NESTING);
+   if (mask->cond_stack_size == 0) {
+      assert(mask->cond_mask == LLVMConstAllOnes(mask->int_vec_type));
+   }
+   mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask;
+   assert(LLVMTypeOf(val) == mask->int_vec_type);
+   mask->cond_mask = val;
+
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_mask_cond_invert(struct lp_exec_mask *mask)
+{
+   LLVMValueRef prev_mask;
+   LLVMValueRef inv_mask;
+
+   assert(mask->cond_stack_size);
+   prev_mask = mask->cond_stack[mask->cond_stack_size - 1];
+   if (mask->cond_stack_size == 1) {
+      assert(prev_mask == LLVMConstAllOnes(mask->int_vec_type));
+   }
+
+   inv_mask = LLVMBuildNot(mask->bld->builder, mask->cond_mask, "");
+
+   mask->cond_mask = LLVMBuildAnd(mask->bld->builder,
+                                  inv_mask,
+                                  prev_mask, "");
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask)
+{
+   assert(mask->cond_stack_size);
+   mask->cond_mask = mask->cond_stack[--mask->cond_stack_size];
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_bgnloop(struct lp_exec_mask *mask)
+{
+   if (mask->loop_stack_size == 0) {
+      assert(mask->loop_block == NULL);
+      assert(mask->cont_mask == LLVMConstAllOnes(mask->int_vec_type));
+      assert(mask->break_mask == LLVMConstAllOnes(mask->int_vec_type));
+      assert(mask->break_var == NULL);
+   }
+
+   assert(mask->loop_stack_size < LP_MAX_TGSI_NESTING);
+
+   mask->loop_stack[mask->loop_stack_size].loop_block = mask->loop_block;
+   mask->loop_stack[mask->loop_stack_size].cont_mask = mask->cont_mask;
+   mask->loop_stack[mask->loop_stack_size].break_mask = mask->break_mask;
+   mask->loop_stack[mask->loop_stack_size].break_var = mask->break_var;
+   ++mask->loop_stack_size;
+
+   mask->break_var = lp_build_alloca(mask->bld->builder, mask->int_vec_type, "");
+   LLVMBuildStore(mask->bld->builder, mask->break_mask, mask->break_var);
+
+   mask->loop_block = lp_build_insert_new_block(mask->bld->builder, "bgnloop");
+   LLVMBuildBr(mask->bld->builder, mask->loop_block);
+   LLVMPositionBuilderAtEnd(mask->bld->builder, mask->loop_block);
+
+   mask->break_mask = LLVMBuildLoad(mask->bld->builder, mask->break_var, "");
+
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_break(struct lp_exec_mask *mask)
+{
+   LLVMValueRef exec_mask = LLVMBuildNot(mask->bld->builder,
+                                         mask->exec_mask,
+                                         "break");
+
+   mask->break_mask = LLVMBuildAnd(mask->bld->builder,
+                                   mask->break_mask,
+                                   exec_mask, "break_full");
+
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_continue(struct lp_exec_mask *mask)
+{
+   LLVMValueRef exec_mask = LLVMBuildNot(mask->bld->builder,
+                                         mask->exec_mask,
+                                         "");
+
+   mask->cont_mask = LLVMBuildAnd(mask->bld->builder,
+                                  mask->cont_mask,
+                                  exec_mask, "");
+
+   lp_exec_mask_update(mask);
+}
+
+
+static void lp_exec_endloop(struct lp_exec_mask *mask)
+{
+   LLVMBasicBlockRef endloop;
+   LLVMTypeRef reg_type = LLVMIntType(mask->bld->type.width*
+                                      mask->bld->type.length);
+   LLVMValueRef i1cond;
+
+   assert(mask->break_mask);
+
+   /*
+    * Restore the cont_mask, but don't pop
+    */
+   assert(mask->loop_stack_size);
+   mask->cont_mask = mask->loop_stack[mask->loop_stack_size - 1].cont_mask;
+   lp_exec_mask_update(mask);
+
+   /*
+    * Unlike the continue mask, the break_mask must be preserved across loop
+    * iterations
+    */
+   LLVMBuildStore(mask->bld->builder, mask->break_mask, mask->break_var);
+
+   /* i1cond = (mask == 0) */
+   i1cond = LLVMBuildICmp(
+      mask->bld->builder,
+      LLVMIntNE,
+      LLVMBuildBitCast(mask->bld->builder, mask->exec_mask, reg_type, ""),
+      LLVMConstNull(reg_type), "");
+
+   endloop = lp_build_insert_new_block(mask->bld->builder, "endloop");
+
+   LLVMBuildCondBr(mask->bld->builder,
+                   i1cond, mask->loop_block, endloop);
+
+   LLVMPositionBuilderAtEnd(mask->bld->builder, endloop);
+
+   assert(mask->loop_stack_size);
+   --mask->loop_stack_size;
+   mask->loop_block = mask->loop_stack[mask->loop_stack_size].loop_block;
+   mask->cont_mask = mask->loop_stack[mask->loop_stack_size].cont_mask;
+   mask->break_mask = mask->loop_stack[mask->loop_stack_size].break_mask;
+   mask->break_var = mask->loop_stack[mask->loop_stack_size].break_var;
+
+   lp_exec_mask_update(mask);
+}
+
+/* stores val into an address pointed to by dst.
+ * mask->exec_mask is used to figure out which bits of val
+ * should be stored into the address
+ * (0 means don't store this bit, 1 means do store).
+ */
+static void lp_exec_mask_store(struct lp_exec_mask *mask,
+                               LLVMValueRef pred,
+                               LLVMValueRef val,
+                               LLVMValueRef dst)
+{
+   /* Mix the predicate and execution mask */
+   if (mask->has_mask) {
+      if (pred) {
+         pred = LLVMBuildAnd(mask->bld->builder, pred, mask->exec_mask, "");
+      } else {
+         pred = mask->exec_mask;
+      }
+   }
+
+   if (pred) {
+      LLVMValueRef real_val, dst_val;
+
+      dst_val = LLVMBuildLoad(mask->bld->builder, dst, "");
+      real_val = lp_build_select(mask->bld,
+                                 pred,
+                                 val, dst_val);
+
+      LLVMBuildStore(mask->bld->builder, real_val, dst);
+   } else
+      LLVMBuildStore(mask->bld->builder, val, dst);
+}
+
 
 static LLVMValueRef
 emit_ddx(struct lp_build_tgsi_soa_context *bld,
@@ -144,6 +388,24 @@ emit_ddy(struct lp_build_tgsi_soa_context *bld,
    return lp_build_sub(&bld->base, src_top, src_bottom);
 }
 
+static LLVMValueRef
+get_temp_ptr(struct lp_build_tgsi_soa_context *bld,
+             unsigned index,
+             unsigned chan,
+             boolean is_indirect,
+             LLVMValueRef addr)
+{
+   assert(chan < 4);
+   if (!bld->has_indirect_addressing) {
+      return bld->temps[index][chan];
+   } else {
+      LLVMValueRef lindex =
+         LLVMConstInt(LLVMInt32Type(), index * 4 + chan, 0);
+      if (is_indirect)
+         lindex = lp_build_add(&bld->base, lindex, addr);
+      return LLVMBuildGEP(bld->base.builder, bld->temps_array, &lindex, 1, "");
+   }
+}
 
 /**
  * Register fetch.
@@ -158,6 +420,7 @@ emit_fetch(
    const struct tgsi_full_src_register *reg = &inst->Src[index];
    unsigned swizzle = tgsi_util_get_full_src_register_swizzle( reg, chan_index );
    LLVMValueRef res;
+   LLVMValueRef addr = NULL;
 
    switch (swizzle) {
    case TGSI_SWIZZLE_X:
@@ -165,11 +428,34 @@ emit_fetch(
    case TGSI_SWIZZLE_Z:
    case TGSI_SWIZZLE_W:
 
+      if (reg->Register.Indirect) {
+         LLVMTypeRef int_vec_type = lp_build_int_vec_type(bld->base.type);
+         unsigned swizzle = tgsi_util_get_src_register_swizzle( &reg->Indirect, chan_index );
+         addr = LLVMBuildLoad(bld->base.builder,
+                              bld->addr[reg->Indirect.Index][swizzle],
+                              "");
+         /* for indexing we want integers */
+         addr = LLVMBuildFPToSI(bld->base.builder, addr,
+                                int_vec_type, "");
+         addr = LLVMBuildExtractElement(bld->base.builder,
+                                        addr, LLVMConstInt(LLVMInt32Type(), 0, 0),
+                                        "");
+         addr = lp_build_mul(&bld->base, addr, LLVMConstInt(LLVMInt32Type(), 4, 0));
+      }
+
       switch (reg->Register.File) {
       case TGSI_FILE_CONSTANT: {
          LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), reg->Register.Index*4 + swizzle, 0);
-         LLVMValueRef scalar_ptr = LLVMBuildGEP(bld->base.builder, bld->consts_ptr, &index, 1, "");
-         LLVMValueRef scalar = LLVMBuildLoad(bld->base.builder, scalar_ptr, "");
+         LLVMValueRef scalar, scalar_ptr;
+
+         if (reg->Register.Indirect) {
+            /*lp_build_printf(bld->base.builder,
+              "\taddr = %d\n", addr);*/
+            index = lp_build_add(&bld->base, index, addr);
+         }
+         scalar_ptr = LLVMBuildGEP(bld->base.builder, bld->consts_ptr, &index, 1, "");
+         scalar = LLVMBuildLoad(bld->base.builder, scalar_ptr, "");
+
          res = lp_build_broadcast_scalar(&bld->base, scalar);
          break;
       }
@@ -184,11 +470,16 @@ emit_fetch(
          assert(res);
          break;
 
-      case TGSI_FILE_TEMPORARY:
-         res = LLVMBuildLoad(bld->base.builder, bld->temps[reg->Register.Index][swizzle], "");
+      case TGSI_FILE_TEMPORARY: {
+         LLVMValueRef temp_ptr = get_temp_ptr(bld, reg->Register.Index,
+                                              swizzle,
+                                              reg->Register.Indirect,
+                                              addr);
+         res = LLVMBuildLoad(bld->base.builder, temp_ptr, "");
          if(!res)
             return bld->base.undef;
          break;
+      }
 
       default:
          assert( 0 );
@@ -254,6 +545,73 @@ emit_fetch_deriv(
 }
 
 
+/**
+ * Predicate.
+ */
+static void
+emit_fetch_predicate(
+   struct lp_build_tgsi_soa_context *bld,
+   const struct tgsi_full_instruction *inst,
+   LLVMValueRef *pred)
+{
+   unsigned index;
+   unsigned char swizzles[4];
+   LLVMValueRef unswizzled[4] = {NULL, NULL, NULL, NULL};
+   LLVMValueRef value;
+   unsigned chan;
+
+   if (!inst->Instruction.Predicate) {
+      FOR_EACH_CHANNEL( chan ) {
+         pred[chan] = NULL;
+      }
+      return;
+   }
+
+   swizzles[0] = inst->Predicate.SwizzleX;
+   swizzles[1] = inst->Predicate.SwizzleY;
+   swizzles[2] = inst->Predicate.SwizzleZ;
+   swizzles[3] = inst->Predicate.SwizzleW;
+
+   index = inst->Predicate.Index;
+   assert(index < LP_MAX_TGSI_PREDS);
+
+   FOR_EACH_CHANNEL( chan ) {
+      unsigned swizzle = swizzles[chan];
+
+      /*
+       * Only fetch the predicate register channels that are actually listed
+       * in the swizzles
+       */
+      if (!unswizzled[swizzle]) {
+         value = LLVMBuildLoad(bld->base.builder,
+                               bld->preds[index][swizzle], "");
+
+         /*
+          * Convert the value to an integer mask.
+          *
+          * TODO: Short-circuit this comparison -- a D3D setp_xx instructions
+          * is needlessly causing two comparisons due to storing the intermediate
+          * result as float vector instead of an integer mask vector.
+          */
+         value = lp_build_compare(bld->base.builder,
+                                  bld->base.type,
+                                  PIPE_FUNC_NOTEQUAL,
+                                  value,
+                                  bld->base.zero);
+         if (inst->Predicate.Negate) {
+            value = LLVMBuildNot(bld->base.builder, value, "");
+         }
+
+         unswizzled[swizzle] = value;
+      } else {
+         value = unswizzled[swizzle];
+      }
+
+      pred[chan] = value;
+   }
+}
+
+
 /**
  * Register store.
  */
@@ -263,9 +621,11 @@ emit_store(
    const struct tgsi_full_instruction *inst,
    unsigned index,
    unsigned chan_index,
+   LLVMValueRef pred,
    LLVMValueRef value)
 {
    const struct tgsi_full_dst_register *reg = &inst->Dst[index];
+   LLVMValueRef addr = NULL;
 
    switch( inst->Instruction.Saturate ) {
    case TGSI_SAT_NONE:
@@ -277,7 +637,7 @@ emit_store(
       break;
 
    case TGSI_SAT_MINUS_PLUS_ONE:
-      value = lp_build_max(&bld->base, value, lp_build_const_scalar(bld->base.type, -1.0));
+      value = lp_build_max(&bld->base, value, lp_build_const_vec(bld->base.type, -1.0));
       value = lp_build_min(&bld->base, value, bld->base.one);
       break;
 
@@ -285,20 +645,44 @@ emit_store(
       assert(0);
    }
 
+   if (reg->Register.Indirect) {
+      LLVMTypeRef int_vec_type = lp_build_int_vec_type(bld->base.type);
+      unsigned swizzle = tgsi_util_get_src_register_swizzle( &reg->Indirect, chan_index );
+      addr = LLVMBuildLoad(bld->base.builder,
+                           bld->addr[reg->Indirect.Index][swizzle],
+                           "");
+      /* for indexing we want integers */
+      addr = LLVMBuildFPToSI(bld->base.builder, addr,
+                             int_vec_type, "");
+      addr = LLVMBuildExtractElement(bld->base.builder,
+                                     addr, LLVMConstInt(LLVMInt32Type(), 0, 0),
+                                     "");
+      addr = lp_build_mul(&bld->base, addr, LLVMConstInt(LLVMInt32Type(), 4, 0));
+   }
+
    switch( reg->Register.File ) {
    case TGSI_FILE_OUTPUT:
-      LLVMBuildStore(bld->base.builder, value,
-                     bld->outputs[reg->Register.Index][chan_index]);
+      lp_exec_mask_store(&bld->exec_mask, pred, value,
+                         bld->outputs[reg->Register.Index][chan_index]);
       break;
 
-   case TGSI_FILE_TEMPORARY:
-      LLVMBuildStore(bld->base.builder, value,
-                     bld->temps[reg->Register.Index][chan_index]);
+   case TGSI_FILE_TEMPORARY: {
+      LLVMValueRef temp_ptr = get_temp_ptr(bld, reg->Register.Index,
+                                           chan_index,
+                                           reg->Register.Indirect,
+                                           addr);
+      lp_exec_mask_store(&bld->exec_mask, pred, value, temp_ptr);
       break;
+   }
 
    case TGSI_FILE_ADDRESS:
-      /* FIXME */
-      assert(0);
+      lp_exec_mask_store(&bld->exec_mask, pred, value,
+                         bld->addr[reg->Indirect.Index][chan_index]);
+      break;
+
+   case TGSI_FILE_PREDICATE:
+      lp_exec_mask_store(&bld->exec_mask, pred, value,
+                         bld->preds[index][chan_index]);
       break;
 
    default:
@@ -311,21 +695,37 @@ emit_store(
  * High-level instruction translators.
  */
 
+enum tex_modifier {
+   TEX_MODIFIER_NONE = 0,
+   TEX_MODIFIER_PROJECTED,
+   TEX_MODIFIER_LOD_BIAS,
+   TEX_MODIFIER_EXPLICIT_LOD,
+   TEX_MODIFIER_EXPLICIT_DERIV
+};
 
 static void
 emit_tex( struct lp_build_tgsi_soa_context *bld,
           const struct tgsi_full_instruction *inst,
-          boolean apply_lodbias,
-          boolean projected,
+          enum tex_modifier modifier,
           LLVMValueRef *texel)
 {
-   const uint unit = inst->Src[1].Register.Index;
-   LLVMValueRef lodbias;
+   unsigned unit;
+   LLVMValueRef lod_bias, explicit_lod;
    LLVMValueRef oow = NULL;
    LLVMValueRef coords[3];
+   LLVMValueRef ddx[3];
+   LLVMValueRef ddy[3];
    unsigned num_coords;
    unsigned i;
 
+   if (!bld->sampler) {
+      _debug_printf("warning: found texture instruction but no sampler generator supplied\n");
+      for (i = 0; i < 4; i++) {
+         texel[i] = bld->base.undef;
+      }
+      return;
+   }
+
    switch (inst->Texture.Texture) {
    case TGSI_TEXTURE_1D:
       num_coords = 1;
@@ -346,33 +746,64 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
       return;
    }
 
-   if(apply_lodbias)
-      lodbias = emit_fetch( bld, inst, 0, 3 );
-   else
-      lodbias = bld->base.zero;
+   if (modifier == TEX_MODIFIER_LOD_BIAS) {
+      lod_bias = emit_fetch( bld, inst, 0, 3 );
+      explicit_lod = NULL;
+   }
+   else if (modifier == TEX_MODIFIER_EXPLICIT_LOD) {
+      lod_bias = NULL;
+      explicit_lod = emit_fetch( bld, inst, 0, 3 );
+   }
+   else {
+      lod_bias = NULL;
+      explicit_lod = NULL;
+   }
 
-   if (projected) {
+   if (modifier == TEX_MODIFIER_PROJECTED) {
       oow = emit_fetch( bld, inst, 0, 3 );
       oow = lp_build_rcp(&bld->base, oow);
    }
 
    for (i = 0; i < num_coords; i++) {
       coords[i] = emit_fetch( bld, inst, 0, i );
-      if (projected)
+      if (modifier == TEX_MODIFIER_PROJECTED)
          coords[i] = lp_build_mul(&bld->base, coords[i], oow);
    }
    for (i = num_coords; i < 3; i++) {
       coords[i] = bld->base.undef;
    }
 
+   if (modifier == TEX_MODIFIER_EXPLICIT_DERIV) {
+      for (i = 0; i < num_coords; i++) {
+         ddx[i] = emit_fetch( bld, inst, 1, i );
+         ddy[i] = emit_fetch( bld, inst, 2, i );
+      }
+      unit = inst->Src[3].Register.Index;
+   }  else {
+      for (i = 0; i < num_coords; i++) {
+         ddx[i] = emit_ddx( bld, coords[i] );
+         ddy[i] = emit_ddy( bld, coords[i] );
+      }
+      unit = inst->Src[1].Register.Index;
+   }
+   for (i = num_coords; i < 3; i++) {
+      ddx[i] = bld->base.undef;
+      ddy[i] = bld->base.undef;
+   }
+
    bld->sampler->emit_fetch_texel(bld->sampler,
                                   bld->base.builder,
                                   bld->base.type,
-                                  unit, num_coords, coords, lodbias,
+                                  unit, num_coords, coords,
+                                  ddx, ddy,
+                                  lod_bias, explicit_lod,
                                   texel);
 }
 
 
+/**
+ * Kill fragment if any of the src register values are negative.
+ */
 static void
 emit_kil(
    struct lp_build_tgsi_soa_context *bld,
@@ -403,6 +834,9 @@ emit_kil(
       if(terms[chan_index]) {
          LLVMValueRef chan_mask;
 
+         /*
+          * If term < 0 then mask = 0 else mask = ~0.
+          */
          chan_mask = lp_build_cmp(&bld->base, PIPE_FUNC_GEQUAL, terms[chan_index], bld->base.zero);
 
          if(mask)
@@ -418,66 +852,90 @@ emit_kil(
 
 
 /**
- * Check if inst src/dest regs use indirect addressing into temporary
- * register file.
+ * Predicated fragment kill.
+ * XXX Actually, we do an unconditional kill (as in tgsi_exec.c).
+ * The only predication is the execution mask which will apply if
+ * we're inside a loop or conditional.
  */
-static boolean
-indirect_temp_reference(const struct tgsi_full_instruction *inst)
+static void
+emit_kilp(struct lp_build_tgsi_soa_context *bld,
+          const struct tgsi_full_instruction *inst)
 {
-   uint i;
-   for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
-      const struct tgsi_full_src_register *reg = &inst->Src[i];
-      if (reg->Register.File == TGSI_FILE_TEMPORARY &&
-          reg->Register.Indirect)
-         return TRUE;
+   LLVMValueRef mask;
+
+   /* For those channels which are "alive", disable fragment shader
+    * execution.
+    */
+   if (bld->exec_mask.has_mask) {
+      mask = LLVMBuildNot(bld->base.builder, bld->exec_mask.exec_mask, "kilp");
    }
-   for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
-      const struct tgsi_full_dst_register *reg = &inst->Dst[i];
-      if (reg->Register.File == TGSI_FILE_TEMPORARY &&
-          reg->Register.Indirect)
-         return TRUE;
+   else {
+      mask = bld->base.zero;
    }
-   return FALSE;
+
+   lp_build_mask_update(bld->mask, mask);
 }
 
-static int
+static void
 emit_declaration(
    struct lp_build_tgsi_soa_context *bld,
    const struct tgsi_full_declaration *decl)
 {
+   LLVMTypeRef vec_type = lp_build_vec_type(bld->base.type);
+
    unsigned first = decl->Range.First;
    unsigned last = decl->Range.Last;
    unsigned idx, i;
 
    for (idx = first; idx <= last; ++idx) {
-      boolean ok;
-
       switch (decl->Declaration.File) {
       case TGSI_FILE_TEMPORARY:
-         for (i = 0; i < NUM_CHANNELS; i++)
-            bld->temps[idx][i] = lp_build_alloca(&bld->base);
-         ok = TRUE;
+         assert(idx < LP_MAX_TGSI_TEMPS);
+         if (bld->has_indirect_addressing) {
+            LLVMValueRef val = LLVMConstInt(LLVMInt32Type(),
+                                            last*4 + 4, 0);
+            bld->temps_array = lp_build_array_alloca(bld->base.builder,
+                                                     vec_type, val, "");
+         } else {
+            for (i = 0; i < NUM_CHANNELS; i++)
+               bld->temps[idx][i] = lp_build_alloca(bld->base.builder,
+                                                    vec_type, "");
+         }
          break;
 
       case TGSI_FILE_OUTPUT:
          for (i = 0; i < NUM_CHANNELS; i++)
-            bld->outputs[idx][i] = lp_build_alloca(&bld->base);
-         ok = TRUE;
+            bld->outputs[idx][i] = lp_build_alloca(bld->base.builder,
+                                                   vec_type, "");
+         break;
+
+      case TGSI_FILE_ADDRESS:
+         assert(idx < LP_MAX_TGSI_ADDRS);
+         for (i = 0; i < NUM_CHANNELS; i++)
+            bld->addr[idx][i] = lp_build_alloca(bld->base.builder,
+                                                vec_type, "");
+         break;
+
+      case TGSI_FILE_PREDICATE:
+         assert(idx < LP_MAX_TGSI_PREDS);
+         for (i = 0; i < NUM_CHANNELS; i++)
+            bld->preds[idx][i] = lp_build_alloca(bld->base.builder,
+                                                 vec_type, "");
          break;
 
       default:
          /* don't need to declare other vars */
-         ok = TRUE;
+         break;
       }
-
-      if (!ok)
-         return FALSE;
    }
-
-   return TRUE;
 }
 
-static int
+
+/**
+ * Emit LLVM for one TGSI instruction.
+ * \param return TRUE for success, FALSE otherwise
+ */
+static boolean
 emit_instruction(
    struct lp_build_tgsi_soa_context *bld,
    const struct tgsi_full_instruction *inst,
@@ -494,29 +952,32 @@ emit_instruction(
    LLVMValueRef res;
    LLVMValueRef dst0[NUM_CHANNELS];
 
-   /* we can't handle indirect addressing into temp register file yet */
-   if (indirect_temp_reference(inst))
-      return FALSE;
+   /*
+    * Stores and write masks are handled in a general fashion after the long
+    * instruction opcode switch statement.
+    *
+    * Although not stricitly necessary, we avoid generating instructions for
+    * channels which won't be stored, in cases where's that easy. For some
+    * complex instructions, like texture sampling, it is more convenient to
+    * assume a full writemask and then let LLVM optimization passes eliminate
+    * redundant code.
+    */
 
    assert(info->num_dst <= 1);
-   if(info->num_dst) {
+   if (info->num_dst) {
       FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
          dst0[chan_index] = bld->base.undef;
       }
    }
 
    switch (inst->Instruction.Opcode) {
-#if 0
    case TGSI_OPCODE_ARL:
-      /* FIXME */
       FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
          tmp0 = emit_fetch( bld, inst, 0, chan_index );
-         emit_flr(bld, 0, 0);
-         emit_f2it( bld, 0 );
+         tmp0 = lp_build_floor(&bld->base, tmp0);
          dst0[chan_index] = tmp0;
       }
       break;
-#endif
 
    case TGSI_OPCODE_MOV:
       FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
@@ -782,7 +1243,7 @@ emit_instruction(
          src0 = emit_fetch( bld, inst, 0, chan_index );
          src1 = emit_fetch( bld, inst, 1, chan_index );
          src2 = emit_fetch( bld, inst, 2, chan_index );
-         tmp1 = lp_build_const_scalar(bld->base.type, 0.5);
+         tmp1 = lp_build_const_vec(bld->base.type, 0.5);
          tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_GREATER, src2, tmp1);
          dst0[chan_index] = lp_build_select( &bld->base, tmp0, src0, src1 );
       }
@@ -914,7 +1375,7 @@ emit_instruction(
    case TGSI_OPCODE_RCC:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
 
    case TGSI_OPCODE_DPH:
       tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
@@ -957,8 +1418,7 @@ emit_instruction(
 
    case TGSI_OPCODE_KILP:
       /* predicated kill */
-      /* FIXME */
-      return 0;
+      emit_kilp( bld, inst );
       break;
 
    case TGSI_OPCODE_KIL:
@@ -967,23 +1427,23 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_PK2H:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_PK2US:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_PK4B:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_PK4UB:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_RFL:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_SEQ:
@@ -1043,76 +1503,71 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_TEX:
-      emit_tex( bld, inst, FALSE, FALSE, dst0 );
+      emit_tex( bld, inst, TEX_MODIFIER_NONE, dst0 );
       break;
 
    case TGSI_OPCODE_TXD:
-      /* FIXME */
-      return 0;
+      emit_tex( bld, inst, TEX_MODIFIER_EXPLICIT_DERIV, dst0 );
       break;
 
    case TGSI_OPCODE_UP2H:
       /* deprecated */
       assert (0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_UP2US:
       /* deprecated */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_UP4B:
       /* deprecated */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_UP4UB:
       /* deprecated */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_X2D:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_ARA:
       /* deprecated */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
-#if 0
    case TGSI_OPCODE_ARR:
-      /* FIXME */
       FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
          tmp0 = emit_fetch( bld, inst, 0, chan_index );
-         emit_rnd( bld, 0, 0 );
-         emit_f2it( bld, 0 );
+         tmp0 = lp_build_round(&bld->base, tmp0);
          dst0[chan_index] = tmp0;
       }
       break;
-#endif
 
    case TGSI_OPCODE_BRA:
       /* deprecated */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_CAL:
       /* FIXME */
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_RET:
       /* FIXME */
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_END:
@@ -1154,7 +1609,7 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_TXB:
-      emit_tex( bld, inst, TRUE, FALSE, dst0 );
+      emit_tex( bld, inst, TEX_MODIFIER_LOD_BIAS, dst0 );
       break;
 
    case TGSI_OPCODE_NRM:
@@ -1242,7 +1697,7 @@ emit_instruction(
    case TGSI_OPCODE_DIV:
       /* deprecated */
       assert( 0 );
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_DP2:
@@ -1259,67 +1714,50 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_TXL:
-      emit_tex( bld, inst, TRUE, FALSE, dst0 );
+      emit_tex( bld, inst, TEX_MODIFIER_EXPLICIT_LOD, dst0 );
       break;
 
    case TGSI_OPCODE_TXP:
-      emit_tex( bld, inst, FALSE, TRUE, dst0 );
+      emit_tex( bld, inst, TEX_MODIFIER_PROJECTED, dst0 );
       break;
-      
+
    case TGSI_OPCODE_BRK:
-      /* FIXME */
-      return 0;
+      lp_exec_break(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_IF:
-      /* FIXME */
-      return 0;
-      break;
-
-   case TGSI_OPCODE_BGNFOR:
-      /* deprecated */
-      assert(0);
-      return 0;
+      tmp0 = emit_fetch(bld, inst, 0, CHAN_X);
+      tmp0 = lp_build_cmp(&bld->base, PIPE_FUNC_NOTEQUAL,
+                          tmp0, bld->base.zero);
+      lp_exec_mask_cond_push(&bld->exec_mask, tmp0);
       break;
 
-   case TGSI_OPCODE_REP:
-      /* deprecated */
-      assert(0);
-      return 0;
+   case TGSI_OPCODE_BGNLOOP:
+      lp_exec_bgnloop(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_ELSE:
-      /* FIXME */
-      return 0;
+      lp_exec_mask_cond_invert(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_ENDIF:
-      /* FIXME */
-      return 0;
+      lp_exec_mask_cond_pop(&bld->exec_mask);
       break;
 
-   case TGSI_OPCODE_ENDFOR:
-      /* deprecated */
-      assert(0);
-      return 0;
-      break;
-
-   case TGSI_OPCODE_ENDREP:
-      /* deprecated */
-      assert(0);
-      return 0;
+   case TGSI_OPCODE_ENDLOOP:
+      lp_exec_endloop(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_PUSHA:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_POPA:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_CEIL:
@@ -1332,13 +1770,13 @@ emit_instruction(
    case TGSI_OPCODE_I2F:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_NOT:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_TRUNC:
@@ -1351,84 +1789,87 @@ emit_instruction(
    case TGSI_OPCODE_SHL:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_ISHR:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_AND:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_OR:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_MOD:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_XOR:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_SAD:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_TXF:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_TXQ:
       /* deprecated? */
       assert(0);
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_CONT:
-      /* FIXME */
-      return 0;
+      lp_exec_continue(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_EMIT:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_ENDPRIM:
-      return 0;
+      return FALSE;
       break;
 
    case TGSI_OPCODE_NOP:
       break;
 
    default:
-      return 0;
+      return FALSE;
    }
    
    if(info->num_dst) {
+      LLVMValueRef pred[NUM_CHANNELS];
+
+      emit_fetch_predicate( bld, inst, pred );
+
       FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
-         emit_store( bld, inst, 0, chan_index, dst0[chan_index]);
+         emit_store( bld, inst, 0, chan_index, pred[chan_index], dst0[chan_index]);
       }
    }
 
-   return 1;
+   return TRUE;
 }
 
 
@@ -1441,7 +1882,8 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
                   const LLVMValueRef *pos,
                   const LLVMValueRef (*inputs)[NUM_CHANNELS],
                   LLVMValueRef (*outputs)[NUM_CHANNELS],
-                  struct lp_build_sampler_soa *sampler)
+                  struct lp_build_sampler_soa *sampler,
+                  const struct tgsi_shader_info *info)
 {
    struct lp_build_tgsi_soa_context bld;
    struct tgsi_parse_context parse;
@@ -1451,12 +1893,17 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
    /* Setup build context */
    memset(&bld, 0, sizeof bld);
    lp_build_context_init(&bld.base, builder, type);
+   lp_build_context_init(&bld.int_bld, builder, lp_int_type(type));
    bld.mask = mask;
    bld.pos = pos;
    bld.inputs = inputs;
    bld.outputs = outputs;
    bld.consts_ptr = consts_ptr;
    bld.sampler = sampler;
+   bld.has_indirect_addressing = info->opcode_count[TGSI_OPCODE_ARR] > 0 ||
+                                 info->opcode_count[TGSI_OPCODE_ARL] > 0;
+
+   lp_exec_mask_init(&bld.exec_mask, &bld.base);
 
    tgsi_parse_init( &parse, tokens );
 
@@ -1466,19 +1913,16 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
       switch( parse.FullToken.Token.Type ) {
       case TGSI_TOKEN_TYPE_DECLARATION:
          /* Inputs already interpolated */
-         {
-            if (!emit_declaration( &bld, &parse.FullToken.FullDeclaration ))
-               _debug_printf("warning: failed to define LLVM variable\n");
-         }
+         emit_declaration( &bld, &parse.FullToken.FullDeclaration );
          break;
 
       case TGSI_TOKEN_TYPE_INSTRUCTION:
          {
             unsigned opcode = parse.FullToken.FullInstruction.Instruction.Opcode;
-            const struct tgsi_opcode_info *info = tgsi_get_opcode_info(opcode);
-            if (!emit_instruction( &bld, &parse.FullToken.FullInstruction, info ))
+            const struct tgsi_opcode_info *opcode_info = tgsi_get_opcode_info(opcode);
+            if (!emit_instruction( &bld, &parse.FullToken.FullInstruction, opcode_info ))
                _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
-                             info ? info->mnemonic : "<invalid>");
+                             opcode_info->mnemonic);
          }
 
          break;
@@ -1488,21 +1932,31 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
          {
             const uint size = parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
             assert(size <= 4);
-            assert(num_immediates < LP_MAX_IMMEDIATES);
+            assert(num_immediates < LP_MAX_TGSI_IMMEDIATES);
             for( i = 0; i < size; ++i )
                bld.immediates[num_immediates][i] =
-                  lp_build_const_scalar(type, parse.FullToken.FullImmediate.u[i].Float);
+                  lp_build_const_vec(type, parse.FullToken.FullImmediate.u[i].Float);
             for( i = size; i < 4; ++i )
                bld.immediates[num_immediates][i] = bld.base.undef;
             num_immediates++;
          }
          break;
 
+      case TGSI_TOKEN_TYPE_PROPERTY:
+         break;
+
       default:
          assert( 0 );
       }
    }
-
+   if (0) {
+      LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
+      LLVMValueRef function = LLVMGetBasicBlockParent(block);
+      debug_printf("11111111111111111111111111111 \n");
+      tgsi_dump(tokens, 0);
+      lp_debug_dump_value(function);
+      debug_printf("2222222222222222222222222222 \n");
+   }
    tgsi_parse_free( &parse );
 }