Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / drivers / llvmpipe / lp_bld_tgsi_soa.c
index 7ef01c045149920d3eae125bd6f355242a7bef7a..3eb0e0c57cb5d5b272521cfcf244c062991e38bf 100644 (file)
  * 
  **************************************************************************/
 
+/**
+ * @file
+ * TGSI to LLVM IR translation -- SoA.
+ *
+ * @author Jose Fonseca <jfonseca@vmware.com>
+ *
+ * Based on tgsi_sse2.c code written by Michal Krol, Keith Whitwell,
+ * Brian Paul, and others.
+ */
+
 #include "pipe/p_config.h"
 #include "pipe/p_shader_tokens.h"
 #include "util/u_debug.h"
@@ -41,7 +51,9 @@
 #include "lp_bld_arit.h"
 #include "lp_bld_logic.h"
 #include "lp_bld_swizzle.h"
+#include "lp_bld_flow.h"
 #include "lp_bld_tgsi.h"
+#include "lp_bld_debug.h"
 
 
 #define LP_MAX_TEMPS 256
@@ -52,7 +64,7 @@
    for (CHAN = 0; CHAN < NUM_CHANNELS; CHAN++)
 
 #define IS_DST0_CHANNEL_ENABLED( INST, CHAN )\
-   ((INST).FullDstRegisters[0].DstRegister.WriteMask & (1 << (CHAN)))
+   ((INST)->Dst[0].Register.WriteMask & (1 << (CHAN)))
 
 #define IF_IS_DST0_CHANNEL_ENABLED( INST, CHAN )\
    if (IS_DST0_CHANNEL_ENABLED( INST, CHAN ))
 #define CHAN_Z 2
 #define CHAN_W 3
 
+#define QUAD_TOP_LEFT     0
+#define QUAD_TOP_RIGHT    1
+#define QUAD_BOTTOM_LEFT  2
+#define QUAD_BOTTOM_RIGHT 3
+
 
 struct lp_build_tgsi_soa_context
 {
    struct lp_build_context base;
 
-   LLVMValueRef x, y, w;
-   LLVMValueRef a0_ptr;
-   LLVMValueRef dadx_ptr;
-   LLVMValueRef dady_ptr;
-
    LLVMValueRef consts_ptr;
+   const LLVMValueRef *pos;
+   const LLVMValueRef (*inputs)[NUM_CHANNELS];
    LLVMValueRef (*outputs)[NUM_CHANNELS];
-   LLVMValueRef samplers_ptr;
 
-   LLVMValueRef oow;
-
-   LLVMValueRef inputs[PIPE_MAX_SHADER_INPUTS][NUM_CHANNELS];
+   struct lp_build_sampler_soa *sampler;
 
    LLVMValueRef immediates[LP_MAX_IMMEDIATES][NUM_CHANNELS];
    LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
 
-   LLVMValueRef mask;
+   struct lp_build_mask_context *mask;
+};
+
+
+static const unsigned char
+swizzle_left[4] = {
+   QUAD_TOP_LEFT,     QUAD_TOP_LEFT,
+   QUAD_BOTTOM_LEFT,  QUAD_BOTTOM_LEFT
+};
 
-   /** Coords/texels store */
-   LLVMValueRef store_ptr;
+static const unsigned char
+swizzle_right[4] = {
+   QUAD_TOP_RIGHT,    QUAD_TOP_RIGHT,
+   QUAD_BOTTOM_RIGHT, QUAD_BOTTOM_RIGHT
 };
 
+static const unsigned char
+swizzle_top[4] = {
+   QUAD_TOP_LEFT,     QUAD_TOP_RIGHT,
+   QUAD_TOP_LEFT,     QUAD_TOP_RIGHT
+};
+
+static const unsigned char
+swizzle_bottom[4] = {
+   QUAD_BOTTOM_LEFT,  QUAD_BOTTOM_RIGHT,
+   QUAD_BOTTOM_LEFT,  QUAD_BOTTOM_RIGHT
+};
+
+
+static LLVMValueRef
+emit_ddx(struct lp_build_tgsi_soa_context *bld,
+         LLVMValueRef src)
+{
+   LLVMValueRef src_left  = lp_build_swizzle1_aos(&bld->base, src, swizzle_left);
+   LLVMValueRef src_right = lp_build_swizzle1_aos(&bld->base, src, swizzle_right);
+   return lp_build_sub(&bld->base, src_right, src_left);
+}
+
+
+static LLVMValueRef
+emit_ddy(struct lp_build_tgsi_soa_context *bld,
+         LLVMValueRef src)
+{
+   LLVMValueRef src_top    = lp_build_swizzle1_aos(&bld->base, src, swizzle_top);
+   LLVMValueRef src_bottom = lp_build_swizzle1_aos(&bld->base, src, swizzle_bottom);
+   return lp_build_sub(&bld->base, src_top, src_bottom);
+}
+
 
 /**
  * Register fetch.
  */
-
 static LLVMValueRef
 emit_fetch(
    struct lp_build_tgsi_soa_context *bld,
-   const struct tgsi_full_src_register *reg,
+   const struct tgsi_full_instruction *inst,
+   unsigned index,
    const unsigned chan_index )
 {
-   unsigned swizzle = tgsi_util_get_full_src_register_extswizzle( reg, chan_index );
+   const struct tgsi_full_src_register *reg = &inst->Src[index];
+   unsigned swizzle = tgsi_util_get_full_src_register_swizzle( reg, chan_index );
    LLVMValueRef res;
 
    switch (swizzle) {
-   case TGSI_EXTSWIZZLE_X:
-   case TGSI_EXTSWIZZLE_Y:
-   case TGSI_EXTSWIZZLE_Z:
-   case TGSI_EXTSWIZZLE_W:
+   case TGSI_SWIZZLE_X:
+   case TGSI_SWIZZLE_Y:
+   case TGSI_SWIZZLE_Z:
+   case TGSI_SWIZZLE_W:
 
-      switch (reg->SrcRegister.File) {
+      switch (reg->Register.File) {
       case TGSI_FILE_CONSTANT: {
-         LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), reg->SrcRegister.Index*4 + swizzle, 0);
+         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, "");
          res = lp_build_broadcast_scalar(&bld->base, scalar);
@@ -123,17 +177,17 @@ emit_fetch(
       }
 
       case TGSI_FILE_IMMEDIATE:
-         res = bld->immediates[reg->SrcRegister.Index][swizzle];
+         res = bld->immediates[reg->Register.Index][swizzle];
          assert(res);
          break;
 
       case TGSI_FILE_INPUT:
-         res = bld->inputs[reg->SrcRegister.Index][swizzle];
+         res = bld->inputs[reg->Register.Index][swizzle];
          assert(res);
          break;
 
       case TGSI_FILE_TEMPORARY:
-         res = bld->temps[reg->SrcRegister.Index][swizzle];
+         res = bld->temps[reg->Register.Index][swizzle];
          if(!res)
             return bld->base.undef;
          break;
@@ -144,14 +198,6 @@ emit_fetch(
       }
       break;
 
-   case TGSI_EXTSWIZZLE_ZERO:
-      res = bld->base.zero;
-      break;
-
-   case TGSI_EXTSWIZZLE_ONE:
-      res = bld->base.one;
-      break;
-
    default:
       assert( 0 );
       return bld->base.undef;
@@ -163,6 +209,7 @@ emit_fetch(
       break;
 
    case TGSI_UTIL_SIGN_SET:
+      /* TODO: Use bitwese OR for floating point */
       res = lp_build_abs( &bld->base, res );
       res = LLVMBuildNeg( bld->base.builder, res, "" );
       break;
@@ -178,41 +225,75 @@ emit_fetch(
    return res;
 }
 
-#define FETCH( FUNC, INST, INDEX, CHAN )\
-   emit_fetch( FUNC, &(INST).FullSrcRegisters[INDEX], CHAN )
 
 /**
- * Register store.
+ * Register fetch with derivatives.
  */
+static void
+emit_fetch_deriv(
+   struct lp_build_tgsi_soa_context *bld,
+   const struct tgsi_full_instruction *inst,
+   unsigned index,
+   const unsigned chan_index,
+   LLVMValueRef *res,
+   LLVMValueRef *ddx,
+   LLVMValueRef *ddy)
+{
+   LLVMValueRef src;
+
+   src = emit_fetch(bld, inst, index, chan_index);
+
+   if(res)
+      *res = src;
 
+   /* TODO: use interpolation coeffs for inputs */
+
+   if(ddx)
+      *ddx = emit_ddx(bld, src);
+
+   if(ddy)
+      *ddy = emit_ddy(bld, src);
+}
+
+
+/**
+ * Register store.
+ */
 static void
 emit_store(
    struct lp_build_tgsi_soa_context *bld,
-   const struct tgsi_full_dst_register *reg,
    const struct tgsi_full_instruction *inst,
+   unsigned index,
    unsigned chan_index,
    LLVMValueRef value)
 {
+   const struct tgsi_full_dst_register *reg = &inst->Dst[index];
+
    switch( inst->Instruction.Saturate ) {
    case TGSI_SAT_NONE:
       break;
 
    case TGSI_SAT_ZERO_ONE:
-      /* assert( 0 ); */
+      value = lp_build_max(&bld->base, value, bld->base.zero);
+      value = lp_build_min(&bld->base, value, bld->base.one);
       break;
 
    case TGSI_SAT_MINUS_PLUS_ONE:
-      assert( 0 );
+      value = lp_build_max(&bld->base, value, lp_build_const_scalar(bld->base.type, -1.0));
+      value = lp_build_min(&bld->base, value, bld->base.one);
       break;
+
+   default:
+      assert(0);
    }
 
-   switch( reg->DstRegister.File ) {
+   switch( reg->Register.File ) {
    case TGSI_FILE_OUTPUT:
-      bld->outputs[reg->DstRegister.Index][chan_index] = value;
+      bld->outputs[reg->Register.Index][chan_index] = value;
       break;
 
    case TGSI_FILE_TEMPORARY:
-      bld->temps[reg->DstRegister.Index][chan_index] = value;
+      bld->temps[reg->Register.Index][chan_index] = value;
       break;
 
    case TGSI_FILE_ADDRESS:
@@ -225,88 +306,40 @@ emit_store(
    }
 }
 
-#define STORE( FUNC, INST, INDEX, CHAN, VAL )\
-   emit_store( FUNC, &(INST).FullDstRegisters[INDEX], &(INST), CHAN, VAL )
-
-
-void PIPE_CDECL
-lp_build_tgsi_fetch_texel_soa( struct tgsi_sampler **samplers,
-                               uint32_t unit,
-                               float *store )
-{
-   struct tgsi_sampler *sampler = samplers[unit];
-
-#if 0
-   uint j;
-
-   debug_printf("%s sampler: %p (%p) store: %p\n", 
-                __FUNCTION__,
-                sampler, *sampler,
-                store );
-
-   debug_printf("lodbias %f\n", store[12]);
-
-   for (j = 0; j < 4; j++)
-      debug_printf("sample %d texcoord %f %f\n", 
-                   j, 
-                   store[0+j],
-                   store[4+j]);
-#endif
-
-   {
-      float rgba[NUM_CHANNELS][QUAD_SIZE];
-      sampler->get_samples(sampler,
-                           &store[0],
-                           &store[4],
-                           &store[8],
-                           0.0f, /*store[12],  lodbias */
-                           rgba);
-      memcpy(store, rgba, sizeof rgba);
-   }
-
-#if 0
-   for (j = 0; j < 4; j++)
-      debug_printf("sample %d result %f %f %f %f\n", 
-                   j, 
-                   store[0+j],
-                   store[4+j],
-                   store[8+j],
-                   store[12+j]);
-#endif
-}
 
 /**
  * High-level instruction translators.
  */
 
+
 static void
 emit_tex( struct lp_build_tgsi_soa_context *bld,
           const struct tgsi_full_instruction *inst,
           boolean apply_lodbias,
-          boolean projected)
+          boolean projected,
+          LLVMValueRef *texel)
 {
-   LLVMTypeRef vec_type = lp_build_vec_type(bld->base.type);
-   const uint unit = inst->FullSrcRegisters[1].SrcRegister.Index;
+   const uint unit = inst->Src[1].Register.Index;
    LLVMValueRef lodbias;
    LLVMValueRef oow;
-   LLVMValueRef args[3];
-   unsigned count;
+   LLVMValueRef coords[3];
+   unsigned num_coords;
    unsigned i;
 
-   switch (inst->InstructionExtTexture.Texture) {
+   switch (inst->Texture.Texture) {
    case TGSI_TEXTURE_1D:
-   case TGSI_TEXTURE_SHADOW1D:
-      count = 1;
+      num_coords = 1;
       break;
    case TGSI_TEXTURE_2D:
    case TGSI_TEXTURE_RECT:
+      num_coords = 2;
+      break;
+   case TGSI_TEXTURE_SHADOW1D:
    case TGSI_TEXTURE_SHADOW2D:
    case TGSI_TEXTURE_SHADOWRECT:
-      count = 2;
-      break;
    case TGSI_TEXTURE_3D:
    case TGSI_TEXTURE_CUBE:
-      count = 3;
+      num_coords = 3;
       break;
    default:
       assert(0);
@@ -314,55 +347,37 @@ emit_tex( struct lp_build_tgsi_soa_context *bld,
    }
 
    if(apply_lodbias)
-      lodbias = FETCH( bld, *inst, 0, 3 );
+      lodbias = emit_fetch( bld, inst, 0, 3 );
    else
       lodbias = bld->base.zero;
 
-   if(!bld->store_ptr)
-      bld->store_ptr = LLVMBuildArrayAlloca(bld->base.builder,
-                                            vec_type,
-                                            LLVMConstInt(LLVMInt32Type(), 4, 0),
-                                            "store");
-
    if (projected) {
-      oow = FETCH( bld, *inst, 0, 3 );
+      oow = emit_fetch( bld, inst, 0, 3 );
       oow = lp_build_rcp(&bld->base, oow);
    }
 
-   for (i = 0; i < count; i++) {
-      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
-      LLVMValueRef coord_ptr = LLVMBuildGEP(bld->base.builder, bld->store_ptr, &index, 1, "");
-      LLVMValueRef coord;
-
-      coord = FETCH( bld, *inst, 0, i );
-
+   for (i = 0; i < num_coords; i++) {
+      coords[i] = emit_fetch( bld, inst, 0, i );
       if (projected)
-         coord = lp_build_mul(&bld->base, coord, oow);
-
-      LLVMBuildStore(bld->base.builder, coord, coord_ptr);
+         coords[i] = lp_build_mul(&bld->base, coords[i], oow);
    }
 
-   args[0] = bld->samplers_ptr;
-   args[1] = LLVMConstInt(LLVMInt32Type(), unit, 0);
-   args[2] = bld->store_ptr;
-
-   lp_build_intrinsic(bld->base.builder, "fetch_texel", LLVMVoidType(), args, 3);
-
-   FOR_EACH_DST0_ENABLED_CHANNEL( *inst, i ) {
-      LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0);
-      LLVMValueRef res_ptr = LLVMBuildGEP(bld->base.builder, bld->store_ptr, &index, 1, "");
-      LLVMValueRef res = LLVMBuildLoad(bld->base.builder, res_ptr, "");
-      STORE( bld, *inst, 0, i, res );
-   }
+   bld->sampler->emit_fetch_texel(bld->sampler,
+                                  bld->base.builder,
+                                  bld->base.type,
+                                  unit, num_coords, coords, lodbias,
+                                  texel);
 }
 
 
 static void
 emit_kil(
    struct lp_build_tgsi_soa_context *bld,
-   const struct tgsi_full_src_register *reg )
+   const struct tgsi_full_instruction *inst )
 {
+   const struct tgsi_full_src_register *reg = &inst->Src[0];
    LLVMValueRef terms[NUM_CHANNELS];
+   LLVMValueRef mask;
    unsigned chan_index;
 
    memset(&terms, 0, sizeof terms);
@@ -371,40 +386,31 @@ emit_kil(
       unsigned swizzle;
 
       /* Unswizzle channel */
-      swizzle = tgsi_util_get_full_src_register_extswizzle( reg, chan_index );
-
-      /* Note that we test if the value is less than zero, so 1.0 and 0.0 need
-       * not to be tested. */
-      if(swizzle == TGSI_EXTSWIZZLE_ZERO || swizzle == TGSI_EXTSWIZZLE_ONE)
-         continue;
+      swizzle = tgsi_util_get_full_src_register_swizzle( reg, chan_index );
 
       /* Check if the component has not been already tested. */
       assert(swizzle < NUM_CHANNELS);
       if( !terms[swizzle] )
          /* TODO: change the comparison operator instead of setting the sign */
-         terms[swizzle] =  emit_fetch(bld, reg, chan_index );
+         terms[swizzle] =  emit_fetch(bld, inst, 0, chan_index );
    }
 
+   mask = NULL;
    FOR_EACH_CHANNEL( chan_index ) {
       if(terms[chan_index]) {
-         LLVMValueRef mask;
+         LLVMValueRef chan_mask;
 
-         mask = lp_build_cmp(&bld->base, PIPE_FUNC_GEQUAL, terms[chan_index], bld->base.zero);
+         chan_mask = lp_build_cmp(&bld->base, PIPE_FUNC_GEQUAL, terms[chan_index], bld->base.zero);
 
-         if(bld->mask)
-            bld->mask = LLVMBuildAnd(bld->base.builder, bld->mask, mask, "");
+         if(mask)
+            mask = LLVMBuildAnd(bld->base.builder, mask, chan_mask, "");
          else
-            bld->mask = mask;
+            mask = chan_mask;
       }
    }
-}
-
 
-static void
-emit_kilp(
-   struct lp_build_tgsi_soa_context *bld )
-{
-   /* XXX todo / fix me */
+   if(mask)
+      lp_build_mask_update(bld->mask, mask);
 }
 
 
@@ -417,15 +423,15 @@ indirect_temp_reference(const struct tgsi_full_instruction *inst)
 {
    uint i;
    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
-      const struct tgsi_full_src_register *reg = &inst->FullSrcRegisters[i];
-      if (reg->SrcRegister.File == TGSI_FILE_TEMPORARY &&
-          reg->SrcRegister.Indirect)
+      const struct tgsi_full_src_register *reg = &inst->Src[i];
+      if (reg->Register.File == TGSI_FILE_TEMPORARY &&
+          reg->Register.Indirect)
          return TRUE;
    }
    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
-      const struct tgsi_full_dst_register *reg = &inst->FullDstRegisters[i];
-      if (reg->DstRegister.File == TGSI_FILE_TEMPORARY &&
-          reg->DstRegister.Indirect)
+      const struct tgsi_full_dst_register *reg = &inst->Dst[i];
+      if (reg->Register.File == TGSI_FILE_TEMPORARY &&
+          reg->Register.Indirect)
          return TRUE;
    }
    return FALSE;
@@ -435,488 +441,485 @@ indirect_temp_reference(const struct tgsi_full_instruction *inst)
 static int
 emit_instruction(
    struct lp_build_tgsi_soa_context *bld,
-   struct tgsi_full_instruction *inst )
+   const struct tgsi_full_instruction *inst,
+   const struct tgsi_opcode_info *info)
 {
    unsigned chan_index;
    LLVMValueRef src0, src1, src2;
    LLVMValueRef tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
-   LLVMValueRef dst0;
+   LLVMValueRef res;
+   LLVMValueRef dst0[NUM_CHANNELS];
 
    /* we can't handle indirect addressing into temp register file yet */
    if (indirect_temp_reference(inst))
       return FALSE;
 
+   assert(info->num_dst <= 1);
+   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:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
+      /* 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 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+         dst0[chan_index] = tmp0;
       }
       break;
 #endif
 
    case TGSI_OPCODE_MOV:
-   case TGSI_OPCODE_SWZ:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = emit_fetch( bld, inst, 0, chan_index );
       }
       break;
 
    case TGSI_OPCODE_LIT:
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) ) {
-         STORE( bld, *inst, 0, CHAN_X, bld->base.one);
-      }
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W ) ) {
-         STORE( bld, *inst, 0, CHAN_W, bld->base.one);
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) ) {
+         dst0[CHAN_X] = bld->base.one;
       }
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-         tmp0 = lp_build_max( &bld->base, tmp0, bld->base.one);
-         STORE( bld, *inst, 0, CHAN_Y, tmp0);
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) ) {
+         src0 = emit_fetch( bld, inst, 0, CHAN_X );
+         dst0[CHAN_Y] = lp_build_max( &bld->base, src0, bld->base.zero);
       }
-#if 0
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) ) {
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) ) {
          /* XMM[1] = SrcReg[0].yyyy */
-         tmp1 = FETCH( bld, *inst, 0, CHAN_Y );
+         tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );
          /* XMM[1] = max(XMM[1], 0) */
          tmp1 = lp_build_max( &bld->base, tmp1, bld->base.zero);
          /* XMM[2] = SrcReg[0].wwww */
-         tmp2 = FETCH( bld, *inst, 0, CHAN_W );
+         tmp2 = emit_fetch( bld, inst, 0, CHAN_W );
          tmp1 = lp_build_pow( &bld->base, tmp1, tmp2);
-         tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-         tmp2 = bld->base.zero;
-         sse_cmpps(
-            bld,
-            make_xmm( 2 ),
-            make_xmm( 0 ),
-            cc_LessThan );
-         sse_andps(
-            bld,
-            make_xmm( 2 ),
-            make_xmm( 1 ) );
-         STORE( bld, *inst, 0, CHAN_Z, tmp2);
-      }
-      break;
-#else
-      return 0;
-#endif
+         tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+         tmp2 = lp_build_cmp(&bld->base, PIPE_FUNC_GREATER, tmp0, bld->base.zero);
+         dst0[CHAN_Z] = lp_build_select(&bld->base, tmp2, tmp1, bld->base.zero);
+      }
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_W ) ) {
+         dst0[CHAN_W] = bld->base.one;
+      }
+      break;
 
    case TGSI_OPCODE_RCP:
    /* TGSI_OPCODE_RECIP */
-      src0 = FETCH( bld, *inst, 0, CHAN_X );
-      dst0 = lp_build_rcp(&bld->base, src0);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, dst0 );
+      src0 = emit_fetch( bld, inst, 0, CHAN_X );
+      res = lp_build_rcp(&bld->base, src0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = res;
       }
       break;
 
    case TGSI_OPCODE_RSQ:
    /* TGSI_OPCODE_RECIPSQRT */
-      src0 = FETCH( bld, *inst, 0, CHAN_X );
+      src0 = emit_fetch( bld, inst, 0, CHAN_X );
       src0 = lp_build_abs(&bld->base, src0);
-      dst0 = lp_build_rsqrt(&bld->base, src0);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, dst0 );
+      res = lp_build_rsqrt(&bld->base, src0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = res;
       }
       break;
 
    case TGSI_OPCODE_EXP:
-      if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z )) {
+      if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z )) {
          LLVMValueRef *p_exp2_int_part = NULL;
          LLVMValueRef *p_frac_part = NULL;
          LLVMValueRef *p_exp2 = NULL;
 
-         src0 = FETCH( bld, *inst, 0, CHAN_X );
+         src0 = emit_fetch( bld, inst, 0, CHAN_X );
 
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ))
             p_exp2_int_part = &tmp0;
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ))
             p_frac_part = &tmp1;
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ))
             p_exp2 = &tmp2;
 
          lp_build_exp2_approx(&bld->base, src0, p_exp2_int_part, p_frac_part, p_exp2);
 
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ))
-            STORE( bld, *inst, 0, CHAN_X, tmp0);
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ))
-            STORE( bld, *inst, 0, CHAN_Y, tmp1);
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ))
-            STORE( bld, *inst, 0, CHAN_Z, tmp2);
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ))
+            dst0[CHAN_X] = tmp0;
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ))
+            dst0[CHAN_Y] = tmp1;
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ))
+            dst0[CHAN_Z] = tmp2;
       }
       /* dst.w = 1.0 */
-      if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W )) {
-         tmp0 = bld->base.one;
-         STORE( bld, *inst, 0, CHAN_W, tmp0);
+      if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_W )) {
+         dst0[CHAN_W] = bld->base.one;
       }
       break;
 
    case TGSI_OPCODE_LOG:
-      if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z )) {
-         LLVMValueRef *p_floor_log2;
-         LLVMValueRef *p_exp;
-         LLVMValueRef *p_log2;
-
-         src0 = FETCH( bld, *inst, 0, CHAN_X );
+      if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z )) {
+         LLVMValueRef *p_floor_log2 = NULL;
+         LLVMValueRef *p_exp = NULL;
+         LLVMValueRef *p_log2 = NULL;
+
+         src0 = emit_fetch( bld, inst, 0, CHAN_X );
          src0 = lp_build_abs( &bld->base, src0 );
 
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ))
             p_floor_log2 = &tmp0;
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ))
             p_exp = &tmp1;
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ))
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ))
             p_log2 = &tmp2;
 
          lp_build_log2_approx(&bld->base, src0, p_exp, p_floor_log2, p_log2);
 
          /* dst.x = floor(lg2(abs(src.x))) */
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ))
-            STORE( bld, *inst, 0, CHAN_X, tmp0);
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ))
+            dst0[CHAN_X] = tmp0;
          /* dst.y = abs(src)/ex2(floor(lg2(abs(src.x)))) */
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y )) {
-            tmp1 = lp_build_div( &bld->base, src0, tmp1);
-            STORE( bld, *inst, 0, CHAN_Y, tmp1);
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y )) {
+            dst0[CHAN_Y] = lp_build_div( &bld->base, src0, tmp1);
          }
          /* dst.z = lg2(abs(src.x)) */
-         if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ))
-            STORE( bld, *inst, 0, CHAN_Z, tmp2);
+         if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ))
+            dst0[CHAN_Z] = tmp2;
       }
       /* dst.w = 1.0 */
-      if (IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W )) {
-         tmp0 = bld->base.one;
-         STORE( bld, *inst, 0, CHAN_W, tmp0);
+      if (IS_DST0_CHANNEL_ENABLED( inst, CHAN_W )) {
+         dst0[CHAN_W] = bld->base.one;
       }
       break;
 
    case TGSI_OPCODE_MUL:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         src0 = FETCH( bld, *inst, 0, chan_index );
-         src1 = FETCH( bld, *inst, 1, chan_index );
-         dst0 = lp_build_mul(&bld->base, src0, src1);
-         STORE( bld, *inst, 0, chan_index, dst0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         dst0[chan_index] = lp_build_mul(&bld->base, src0, src1);
       }
       break;
 
    case TGSI_OPCODE_ADD:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         src0 = FETCH( bld, *inst, 0, chan_index );
-         src1 = FETCH( bld, *inst, 1, chan_index );
-         dst0 = lp_build_add(&bld->base, src0, src1);
-         STORE( bld, *inst, 0, chan_index, dst0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         dst0[chan_index] = lp_build_add(&bld->base, src0, src1);
       }
       break;
 
    case TGSI_OPCODE_DP3:
    /* TGSI_OPCODE_DOT3 */
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-      tmp1 = FETCH( bld, *inst, 1, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_X );
       tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Y );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Y );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Y );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Z );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Z );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Z );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Z );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_DP4:
    /* TGSI_OPCODE_DOT4 */
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-      tmp1 = FETCH( bld, *inst, 1, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_X );
       tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Y );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Y );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Y );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Z );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Z );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Z );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Z );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_W );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_W );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_W );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_W );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_DST:
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) {
-         tmp0 = bld->base.one;
-         STORE( bld, *inst, 0, CHAN_X, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) {
+         dst0[CHAN_X] = bld->base.one;
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_Y );
-         tmp1 = FETCH( bld, *inst, 1, CHAN_Y );
-         tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);
-         STORE( bld, *inst, 0, CHAN_Y, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) {
+         tmp0 = emit_fetch( bld, inst, 0, CHAN_Y );
+         tmp1 = emit_fetch( bld, inst, 1, CHAN_Y );
+         dst0[CHAN_Y] = lp_build_mul( &bld->base, tmp0, tmp1);
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_Z );
-         STORE( bld, *inst, 0, CHAN_Z, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) {
+         dst0[CHAN_Z] = emit_fetch( bld, inst, 0, CHAN_Z );
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W ) {
-         tmp0 = FETCH( bld, *inst, 1, CHAN_W );
-         STORE( bld, *inst, 0, CHAN_W, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_W ) {
+         dst0[CHAN_W] = emit_fetch( bld, inst, 1, CHAN_W );
       }
       break;
 
    case TGSI_OPCODE_MIN:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         src0 = FETCH( bld, *inst, 0, chan_index );
-         src1 = FETCH( bld, *inst, 1, chan_index );
-         dst0 = lp_build_min( &bld->base, src0, src1 );
-         STORE( bld, *inst, 0, chan_index, dst0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         dst0[chan_index] = lp_build_min( &bld->base, src0, src1 );
       }
       break;
 
    case TGSI_OPCODE_MAX:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         src0 = FETCH( bld, *inst, 0, chan_index );
-         src1 = FETCH( bld, *inst, 1, chan_index );
-         dst0 = lp_build_max( &bld->base, src0, src1 );
-         STORE( bld, *inst, 0, chan_index, dst0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         dst0[chan_index] = lp_build_max( &bld->base, src0, src1 );
       }
       break;
 
-#if 0
    case TGSI_OPCODE_SLT:
    /* TGSI_OPCODE_SETLT */
-      emit_setcc( bld, inst, cc_LessThan );
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_LESS, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
 
    case TGSI_OPCODE_SGE:
    /* TGSI_OPCODE_SETGE */
-      emit_setcc( bld, inst, cc_NotLessThan );
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_GEQUAL, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
-#endif
 
    case TGSI_OPCODE_MAD:
    /* TGSI_OPCODE_MADD */
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         tmp1 = FETCH( bld, *inst, 1, chan_index );
-         tmp2 = FETCH( bld, *inst, 2, chan_index );
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         tmp1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp2 = emit_fetch( bld, inst, 2, chan_index );
          tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);
          tmp0 = lp_build_add( &bld->base, tmp0, tmp2);
-         STORE( bld, *inst, 0, chan_index, tmp0);
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_SUB:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         tmp1 = FETCH( bld, *inst, 1, chan_index );
-         tmp0 = lp_build_sub( &bld->base, tmp0, tmp1);
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         tmp1 = emit_fetch( bld, inst, 1, chan_index );
+         dst0[chan_index] = lp_build_sub( &bld->base, tmp0, tmp1);
       }
       break;
 
    case TGSI_OPCODE_LRP:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         src0 = FETCH( bld, *inst, 0, chan_index );
-         src1 = FETCH( bld, *inst, 1, chan_index );
-         src2 = FETCH( bld, *inst, 2, chan_index );
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         src2 = emit_fetch( bld, inst, 2, chan_index );
          tmp0 = lp_build_sub( &bld->base, src1, src2 );
          tmp0 = lp_build_mul( &bld->base, src0, tmp0 );
-         dst0 = lp_build_add( &bld->base, tmp0, src2 );
-         STORE( bld, *inst, 0, chan_index, dst0 );
+         dst0[chan_index] = lp_build_add( &bld->base, tmp0, src2 );
       }
       break;
 
    case TGSI_OPCODE_CND:
-      return 0;
-      break;
-
-   case TGSI_OPCODE_CND0:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         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);
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_GREATER, src2, tmp1);
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, src0, src1 );
+      }
       break;
 
    case TGSI_OPCODE_DP2A:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );  /* xmm0 = src[0].x */
-      tmp1 = FETCH( bld, *inst, 1, CHAN_X );  /* xmm1 = src[1].x */
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );  /* xmm0 = src[0].x */
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_X );  /* xmm1 = src[1].x */
       tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);              /* xmm0 = xmm0 * xmm1 */
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Y );  /* xmm1 = src[0].y */
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Y );  /* xmm2 = src[1].y */
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );  /* xmm1 = src[0].y */
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Y );  /* xmm2 = src[1].y */
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);              /* xmm1 = xmm1 * xmm2 */
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);              /* xmm0 = xmm0 + xmm1 */
-      tmp1 = FETCH( bld, *inst, 2, CHAN_X );  /* xmm1 = src[2].x */
+      tmp1 = emit_fetch( bld, inst, 2, CHAN_X );  /* xmm1 = src[2].x */
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);              /* xmm0 = xmm0 + xmm1 */
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);  /* dest[ch] = xmm0 */
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;  /* dest[ch] = xmm0 */
       }
       break;
 
-#if 0
    case TGSI_OPCODE_FRC:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         emit_frc( bld, 0, 0 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         tmp0 = lp_build_floor(&bld->base, src0);
+         tmp0 = lp_build_sub(&bld->base, tmp0, src0);
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_CLAMP:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         src2 = emit_fetch( bld, inst, 2, chan_index );
+         tmp0 = lp_build_max(&bld->base, tmp0, src1);
+         tmp0 = lp_build_min(&bld->base, tmp0, src2);
+         dst0[chan_index] = tmp0;
+      }
       break;
 
    case TGSI_OPCODE_FLR:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         emit_flr( bld, 0, 0 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_floor(&bld->base, tmp0);
       }
       break;
 
    case TGSI_OPCODE_ROUND:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         emit_rnd( bld, 0, 0 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_round(&bld->base, tmp0);
       }
       break;
-#endif
 
    case TGSI_OPCODE_EX2: {
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
       tmp0 = lp_build_exp2( &bld->base, tmp0);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
    }
 
    case TGSI_OPCODE_LG2:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
       tmp0 = lp_build_log2( &bld->base, tmp0);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_POW:
-      src0 = FETCH( bld, *inst, 0, CHAN_X );
-      src1 = FETCH( bld, *inst, 1, CHAN_X );
-      dst0 = lp_build_pow( &bld->base, src0, src1 );
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, dst0 );
+      src0 = emit_fetch( bld, inst, 0, CHAN_X );
+      src1 = emit_fetch( bld, inst, 1, CHAN_X );
+      res = lp_build_pow( &bld->base, src0, src1 );
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = res;
       }
       break;
 
    case TGSI_OPCODE_XPD:
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) ) {
-         tmp1 = FETCH( bld, *inst, 1, CHAN_Z );
-         tmp3 = FETCH( bld, *inst, 0, CHAN_Z );
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) ) {
+         tmp1 = emit_fetch( bld, inst, 1, CHAN_Z );
+         tmp3 = emit_fetch( bld, inst, 0, CHAN_Z );
       }
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_Y );
-         tmp4 = FETCH( bld, *inst, 1, CHAN_Y );
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) ) {
+         tmp0 = emit_fetch( bld, inst, 0, CHAN_Y );
+         tmp4 = emit_fetch( bld, inst, 1, CHAN_Y );
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) {
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) {
          tmp2 = tmp0;
          tmp2 = lp_build_mul( &bld->base, tmp2, tmp1);
          tmp5 = tmp3;
          tmp5 = lp_build_mul( &bld->base, tmp5, tmp4);
          tmp2 = lp_build_sub( &bld->base, tmp2, tmp5);
-         STORE( bld, *inst, 0, CHAN_X, tmp2);
+         dst0[CHAN_X] = tmp2;
       }
-      if( IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) ||
-          IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) ) {
-         tmp2 = FETCH( bld, *inst, 1, CHAN_X );
-         tmp5 = FETCH( bld, *inst, 0, CHAN_X );
+      if( IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) ||
+          IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) ) {
+         tmp2 = emit_fetch( bld, inst, 1, CHAN_X );
+         tmp5 = emit_fetch( bld, inst, 0, CHAN_X );
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) {
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) {
          tmp3 = lp_build_mul( &bld->base, tmp3, tmp2);
          tmp1 = lp_build_mul( &bld->base, tmp1, tmp5);
          tmp3 = lp_build_sub( &bld->base, tmp3, tmp1);
-         STORE( bld, *inst, 0, CHAN_Y, tmp3);
+         dst0[CHAN_Y] = tmp3;
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) {
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) {
          tmp5 = lp_build_mul( &bld->base, tmp5, tmp4);
          tmp0 = lp_build_mul( &bld->base, tmp0, tmp2);
          tmp5 = lp_build_sub( &bld->base, tmp5, tmp0);
-         STORE( bld, *inst, 0, CHAN_Z, tmp5);
+         dst0[CHAN_Z] = tmp5;
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W ) {
-         tmp0 = bld->base.one;
-         STORE( bld, *inst, 0, CHAN_W, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_W ) {
+         dst0[CHAN_W] = bld->base.one;
       }
       break;
 
    case TGSI_OPCODE_ABS:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         tmp0 = lp_build_abs( &bld->base, tmp0 ) ;
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_abs( &bld->base, tmp0 );
       }
       break;
 
    case TGSI_OPCODE_RCC:
+      /* deprecated? */
+      assert(0);
       return 0;
-      break;
 
    case TGSI_OPCODE_DPH:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-      tmp1 = FETCH( bld, *inst, 1, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_X );
       tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Y );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Y );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Y );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Z );
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Z );
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Z );
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Z );
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      tmp1 = FETCH( bld, *inst, 1, CHAN_W );
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_W );
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_COS:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
       tmp0 = lp_build_cos( &bld->base, tmp0 );
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_DDX:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         emit_fetch_deriv( bld, inst, 0, chan_index, NULL, &dst0[chan_index], NULL);
+      }
       break;
 
    case TGSI_OPCODE_DDY:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         emit_fetch_deriv( bld, inst, 0, chan_index, NULL, NULL, &dst0[chan_index]);
+      }
       break;
 
-#if 0
    case TGSI_OPCODE_KILP:
       /* predicated kill */
-      emit_kilp( bld );
-      return 0; /* XXX fix me */
+      /* FIXME */
+      return 0;
       break;
-#endif
 
    case TGSI_OPCODE_KIL:
       /* conditional kill */
-      emit_kil( bld, &inst->FullSrcRegisters[0] );
+      emit_kil( bld, inst );
       break;
 
    case TGSI_OPCODE_PK2H:
@@ -940,135 +943,174 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_SEQ:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_EQUAL, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
 
    case TGSI_OPCODE_SFL:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = bld->base.zero;
+      }
       break;
 
    case TGSI_OPCODE_SGT:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_GREATER, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
 
    case TGSI_OPCODE_SIN:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
       tmp0 = lp_build_sin( &bld->base, tmp0 );
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;
       }
       break;
 
    case TGSI_OPCODE_SLE:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_LEQUAL, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
 
    case TGSI_OPCODE_SNE:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_NOTEQUAL, src0, src1 );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, bld->base.one, bld->base.zero );
+      }
       break;
 
    case TGSI_OPCODE_STR:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = bld->base.one;
+      }
       break;
 
    case TGSI_OPCODE_TEX:
-      emit_tex( bld, inst, FALSE, FALSE );
+      emit_tex( bld, inst, FALSE, FALSE, dst0 );
       break;
 
    case TGSI_OPCODE_TXD:
+      /* FIXME */
       return 0;
       break;
 
    case TGSI_OPCODE_UP2H:
+      /* deprecated */
+      assert (0);
       return 0;
       break;
 
    case TGSI_OPCODE_UP2US:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_UP4B:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_UP4UB:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_X2D:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_ARA:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
 #if 0
    case TGSI_OPCODE_ARR:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
+      /* 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 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+         dst0[chan_index] = tmp0;
       }
       break;
 #endif
 
    case TGSI_OPCODE_BRA:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_CAL:
+      /* FIXME */
       return 0;
       break;
 
-#if 0
    case TGSI_OPCODE_RET:
-      emit_ret( bld );
+      /* FIXME */
+      return 0;
       break;
-#endif
 
    case TGSI_OPCODE_END:
       break;
 
-#if 0
    case TGSI_OPCODE_SSG:
    /* TGSI_OPCODE_SGN */
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         emit_sgn( bld, 0, 0 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_sgn( &bld->base, tmp0 );
       }
       break;
 
    case TGSI_OPCODE_CMP:
-      emit_cmp (bld, inst);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         src0 = emit_fetch( bld, inst, 0, chan_index );
+         src1 = emit_fetch( bld, inst, 1, chan_index );
+         src2 = emit_fetch( bld, inst, 2, chan_index );
+         tmp0 = lp_build_cmp( &bld->base, PIPE_FUNC_LESS, src0, bld->base.zero );
+         dst0[chan_index] = lp_build_select( &bld->base, tmp0, src1, src2);
+      }
       break;
-#endif
 
    case TGSI_OPCODE_SCS:
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_X ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-         tmp0 = lp_build_cos( &bld->base, tmp0 );
-         STORE( bld, *inst, 0, CHAN_X, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_X ) {
+         tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+         dst0[CHAN_X] = lp_build_cos( &bld->base, tmp0 );
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Y ) {
-         tmp0 = FETCH( bld, *inst, 0, CHAN_X );
-         tmp0 = lp_build_sin( &bld->base, tmp0 );
-         STORE( bld, *inst, 0, CHAN_Y, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Y ) {
+         tmp0 = emit_fetch( bld, inst, 0, CHAN_X );
+         dst0[CHAN_Y] = lp_build_sin( &bld->base, tmp0 );
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_Z ) {
-         tmp0 = bld->base.zero;
-         STORE( bld, *inst, 0, CHAN_Z, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_Z ) {
+         dst0[CHAN_Z] = bld->base.zero;
       }
-      IF_IS_DST0_CHANNEL_ENABLED( *inst, CHAN_W ) {
-         tmp0 = bld->base.one;
-         STORE( bld, *inst, 0, CHAN_W, tmp0);
+      IF_IS_DST0_CHANNEL_ENABLED( inst, CHAN_W ) {
+         dst0[CHAN_W] = bld->base.one;
       }
       break;
 
    case TGSI_OPCODE_TXB:
-      emit_tex( bld, inst, TRUE, FALSE );
+      emit_tex( bld, inst, TRUE, FALSE, dst0 );
       break;
 
    case TGSI_OPCODE_NRM:
@@ -1078,25 +1120,25 @@ emit_instruction(
       {
          uint dims = (inst->Instruction.Opcode == TGSI_OPCODE_NRM) ? 3 : 4;
 
-         if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_X) ||
-             IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Y) ||
-             IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Z) ||
-             (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_W) && dims == 4)) {
+         if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_X) ||
+             IS_DST0_CHANNEL_ENABLED(inst, CHAN_Y) ||
+             IS_DST0_CHANNEL_ENABLED(inst, CHAN_Z) ||
+             (IS_DST0_CHANNEL_ENABLED(inst, CHAN_W) && dims == 4)) {
 
             /* NOTE: Cannot use xmm regs 2/3 here (see emit_rsqrt() above). */
 
             /* xmm4 = src.x */
             /* xmm0 = src.x * src.x */
-            tmp0 = FETCH(bld, *inst, 0, CHAN_X);
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_X)) {
+            tmp0 = emit_fetch(bld, inst, 0, CHAN_X);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_X)) {
                tmp4 = tmp0;
             }
             tmp0 = lp_build_mul( &bld->base, tmp0, tmp0);
 
             /* xmm5 = src.y */
             /* xmm0 = xmm0 + src.y * src.y */
-            tmp1 = FETCH(bld, *inst, 0, CHAN_Y);
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Y)) {
+            tmp1 = emit_fetch(bld, inst, 0, CHAN_Y);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_Y)) {
                tmp5 = tmp1;
             }
             tmp1 = lp_build_mul( &bld->base, tmp1, tmp1);
@@ -1104,8 +1146,8 @@ emit_instruction(
 
             /* xmm6 = src.z */
             /* xmm0 = xmm0 + src.z * src.z */
-            tmp1 = FETCH(bld, *inst, 0, CHAN_Z);
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Z)) {
+            tmp1 = emit_fetch(bld, inst, 0, CHAN_Z);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_Z)) {
                tmp6 = tmp1;
             }
             tmp1 = lp_build_mul( &bld->base, tmp1, tmp1);
@@ -1114,8 +1156,8 @@ emit_instruction(
             if (dims == 4) {
                /* xmm7 = src.w */
                /* xmm0 = xmm0 + src.w * src.w */
-               tmp1 = FETCH(bld, *inst, 0, CHAN_W);
-               if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_W)) {
+               tmp1 = emit_fetch(bld, inst, 0, CHAN_W);
+               if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_W)) {
                   tmp7 = tmp1;
                }
                tmp1 = lp_build_mul( &bld->base, tmp1, tmp1);
@@ -1126,163 +1168,199 @@ emit_instruction(
             tmp1 = lp_build_rsqrt( &bld->base, tmp0);
 
             /* dst.x = xmm1 * src.x */
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_X)) {
-               tmp4 = lp_build_mul( &bld->base, tmp4, tmp1);
-               STORE(bld, *inst, 0, CHAN_X, tmp4);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_X)) {
+               dst0[CHAN_X] = lp_build_mul( &bld->base, tmp4, tmp1);
             }
 
             /* dst.y = xmm1 * src.y */
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Y)) {
-               tmp5 = lp_build_mul( &bld->base, tmp5, tmp1);
-               STORE(bld, *inst, 0, CHAN_Y, tmp5);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_Y)) {
+               dst0[CHAN_Y] = lp_build_mul( &bld->base, tmp5, tmp1);
             }
 
             /* dst.z = xmm1 * src.z */
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_Z)) {
-               tmp6 = lp_build_mul( &bld->base, tmp6, tmp1);
-               STORE(bld, *inst, 0, CHAN_Z, tmp6);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_Z)) {
+               dst0[CHAN_Z] = lp_build_mul( &bld->base, tmp6, tmp1);
             }
 
             /* dst.w = xmm1 * src.w */
-            if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_X) && dims == 4) {
-               tmp7 = lp_build_mul( &bld->base, tmp7, tmp1);
-               STORE(bld, *inst, 0, CHAN_W, tmp7);
+            if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_X) && dims == 4) {
+               dst0[CHAN_W] = lp_build_mul( &bld->base, tmp7, tmp1);
             }
          }
 
-         /* dst0.w = 1.0 */
-         if (IS_DST0_CHANNEL_ENABLED(*inst, CHAN_W) && dims == 3) {
-            tmp0 = bld->base.one;
-            STORE(bld, *inst, 0, CHAN_W, tmp0);
+         /* dst.w = 1.0 */
+         if (IS_DST0_CHANNEL_ENABLED(inst, CHAN_W) && dims == 3) {
+            dst0[CHAN_W] = bld->base.one;
          }
       }
       break;
 
    case TGSI_OPCODE_DIV:
+      /* deprecated */
+      assert( 0 );
       return 0;
       break;
 
    case TGSI_OPCODE_DP2:
-      tmp0 = FETCH( bld, *inst, 0, CHAN_X );  /* xmm0 = src[0].x */
-      tmp1 = FETCH( bld, *inst, 1, CHAN_X );  /* xmm1 = src[1].x */
+      tmp0 = emit_fetch( bld, inst, 0, CHAN_X );  /* xmm0 = src[0].x */
+      tmp1 = emit_fetch( bld, inst, 1, CHAN_X );  /* xmm1 = src[1].x */
       tmp0 = lp_build_mul( &bld->base, tmp0, tmp1);              /* xmm0 = xmm0 * xmm1 */
-      tmp1 = FETCH( bld, *inst, 0, CHAN_Y );  /* xmm1 = src[0].y */
-      tmp2 = FETCH( bld, *inst, 1, CHAN_Y );  /* xmm2 = src[1].y */
+      tmp1 = emit_fetch( bld, inst, 0, CHAN_Y );  /* xmm1 = src[0].y */
+      tmp2 = emit_fetch( bld, inst, 1, CHAN_Y );  /* xmm2 = src[1].y */
       tmp1 = lp_build_mul( &bld->base, tmp1, tmp2);              /* xmm1 = xmm1 * xmm2 */
       tmp0 = lp_build_add( &bld->base, tmp0, tmp1);              /* xmm0 = xmm0 + xmm1 */
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         STORE( bld, *inst, 0, chan_index, tmp0);  /* dest[ch] = xmm0 */
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         dst0[chan_index] = tmp0;  /* dest[ch] = xmm0 */
       }
       break;
 
    case TGSI_OPCODE_TXL:
-      emit_tex( bld, inst, TRUE, FALSE );
+      emit_tex( bld, inst, TRUE, FALSE, dst0 );
       break;
 
    case TGSI_OPCODE_TXP:
-      emit_tex( bld, inst, FALSE, TRUE );
+      emit_tex( bld, inst, FALSE, TRUE, dst0 );
       break;
       
    case TGSI_OPCODE_BRK:
+      /* FIXME */
       return 0;
       break;
 
    case TGSI_OPCODE_IF:
+      /* FIXME */
       return 0;
       break;
 
-   case TGSI_OPCODE_LOOP:
+   case TGSI_OPCODE_BGNFOR:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_REP:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_ELSE:
+      /* FIXME */
       return 0;
       break;
 
    case TGSI_OPCODE_ENDIF:
+      /* FIXME */
       return 0;
       break;
 
-   case TGSI_OPCODE_ENDLOOP:
+   case TGSI_OPCODE_ENDFOR:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_ENDREP:
+      /* deprecated */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_PUSHA:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_POPA:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_CEIL:
-      return 0;
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_ceil(&bld->base, tmp0);
+      }
       break;
 
    case TGSI_OPCODE_I2F:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_NOT:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
-#if 0
    case TGSI_OPCODE_TRUNC:
-      FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
-         tmp0 = FETCH( bld, *inst, 0, chan_index );
-         emit_f2it( bld, 0 );
-         emit_i2f( bld, 0 );
-         STORE( bld, *inst, 0, chan_index, tmp0);
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         tmp0 = emit_fetch( bld, inst, 0, chan_index );
+         dst0[chan_index] = lp_build_trunc(&bld->base, tmp0);
       }
       break;
-#endif
 
    case TGSI_OPCODE_SHL:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_SHR:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_AND:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_OR:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_MOD:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_XOR:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_SAD:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_TXF:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_TXQ:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
    case TGSI_OPCODE_CONT:
+      /* deprecated? */
+      assert(0);
       return 0;
       break;
 
@@ -1294,110 +1372,33 @@ emit_instruction(
       return 0;
       break;
 
+   case TGSI_OPCODE_NOP:
+      break;
+
    default:
       return 0;
    }
    
-   return 1;
-}
-
-static void
-emit_declaration(
-   struct lp_build_tgsi_soa_context *bld,
-   struct tgsi_full_declaration *decl )
-{
-   if( decl->Declaration.File == TGSI_FILE_INPUT ) {
-      LLVMBuilderRef builder = bld->base.builder;
-      unsigned first, last, mask;
-      unsigned attrib, chan;
-
-      first = decl->DeclarationRange.First;
-      last = decl->DeclarationRange.Last;
-      mask = decl->Declaration.UsageMask;
-
-      for( attrib = first; attrib <= last; attrib++ ) {
-         for( chan = 0; chan < NUM_CHANNELS; chan++ ) {
-            LLVMValueRef input = bld->base.undef;
-
-            if( mask & (1 << chan) ) {
-               LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), attrib*NUM_CHANNELS + chan, 0);
-               LLVMValueRef a0;
-               LLVMValueRef dadx;
-               LLVMValueRef dady;
-               char name[32];
-
-               switch( decl->Declaration.Interpolate ) {
-               case TGSI_INTERPOLATE_PERSPECTIVE:
-               case TGSI_INTERPOLATE_LINEAR: {
-                  LLVMValueRef dadx_ptr = LLVMBuildGEP(builder, bld->dadx_ptr, &index, 1, "");
-                  LLVMValueRef dady_ptr = LLVMBuildGEP(builder, bld->dady_ptr, &index, 1, "");
-                  dadx = LLVMBuildLoad(builder, dadx_ptr, "");
-                  dady = LLVMBuildLoad(builder, dady_ptr, "");
-                  dadx = lp_build_broadcast_scalar(&bld->base, dadx);
-                  dady = lp_build_broadcast_scalar(&bld->base, dady);
-                  util_snprintf(name, sizeof name, "dadx_%u.%c", attrib, "xyzw"[chan]);
-                  LLVMSetValueName(dadx, name);
-                  util_snprintf(name, sizeof name, "dady_%u.%c", attrib, "xyzw"[chan]);
-                  LLVMSetValueName(dady, name);
-               }
-
-               case TGSI_INTERPOLATE_CONSTANT: {
-                  LLVMValueRef a0_ptr = LLVMBuildGEP(builder, bld->a0_ptr, &index, 1, "");
-                  a0 = LLVMBuildLoad(builder, a0_ptr, "");
-                  a0 = lp_build_broadcast_scalar(&bld->base, a0);
-                  util_snprintf(name, sizeof name, "a0_%u.%c", attrib, "xyzw"[chan]);
-                  LLVMSetValueName(a0, name);
-                  break;
-               }
-
-               default:
-                  assert(0);
-                  break;
-               }
-
-               input = a0;
-
-               if (decl->Declaration.Interpolate != TGSI_INTERPOLATE_CONSTANT) {
-                  input = lp_build_add(&bld->base, input, lp_build_mul(&bld->base, bld->x, dadx));
-                  input = lp_build_add(&bld->base, input, lp_build_mul(&bld->base, bld->y, dady));
-               }
-
-               if (decl->Declaration.Interpolate == TGSI_INTERPOLATE_PERSPECTIVE) {
-                  if(!bld->oow)
-                     bld->oow = lp_build_rcp(&bld->base, bld->w);
-                  input = lp_build_mul(&bld->base, input, bld->oow);
-               }
-
-               util_snprintf(name, sizeof name, "input%u.%c", attrib, "xyzw"[chan]);
-               LLVMSetValueName(input, name);
-            }
-
-            bld->inputs[attrib][chan] = input;
-         }
+   if(info->num_dst) {
+      FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
+         emit_store( bld, inst, 0, chan_index, dst0[chan_index]);
       }
    }
+
+   return 1;
 }
 
-/**
- * Translate a TGSI vertex/fragment shader to SSE2 code.
- * Slightly different things are done for vertex vs. fragment shaders.
- *
- * \param tokens  the TGSI input shader
- * \param bld  the output SSE code/function
- * \param immediates  buffer to place immediates, later passed to SSE bld
- * \param return  1 for success, 0 if translation failed
- */
-LLVMValueRef
+
+void
 lp_build_tgsi_soa(LLVMBuilderRef builder,
                   const struct tgsi_token *tokens,
-                  union lp_type type,
-                  LLVMValueRef *pos,
-                  LLVMValueRef a0_ptr,
-                  LLVMValueRef dadx_ptr,
-                  LLVMValueRef dady_ptr,
+                  struct lp_type type,
+                  struct lp_build_mask_context *mask,
                   LLVMValueRef consts_ptr,
-                  LLVMValueRef (*outputs)[4],
-                  LLVMValueRef samplers_ptr)
+                  const LLVMValueRef *pos,
+                  const LLVMValueRef (*inputs)[NUM_CHANNELS],
+                  LLVMValueRef (*outputs)[NUM_CHANNELS],
+                  struct lp_build_sampler_soa *sampler)
 {
    struct lp_build_tgsi_soa_context bld;
    struct tgsi_parse_context parse;
@@ -1407,15 +1408,12 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
    /* Setup build context */
    memset(&bld, 0, sizeof bld);
    lp_build_context_init(&bld.base, builder, type);
-   bld.x = pos[0];
-   bld.y = pos[1];
-   bld.w = pos[3];
-   bld.a0_ptr = a0_ptr;
-   bld.dadx_ptr = dadx_ptr;
-   bld.dady_ptr = dady_ptr;
+   bld.mask = mask;
+   bld.pos = pos;
+   bld.inputs = inputs;
    bld.outputs = outputs;
    bld.consts_ptr = consts_ptr;
-   bld.samplers_ptr = samplers_ptr;
+   bld.sampler = sampler;
 
    tgsi_parse_init( &parse, tokens );
 
@@ -1424,18 +1422,18 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
 
       switch( parse.FullToken.Token.Type ) {
       case TGSI_TOKEN_TYPE_DECLARATION:
-         if (parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
-            emit_declaration( &bld, &parse.FullToken.FullDeclaration );
-         }
+         /* Inputs already interpolated */
          break;
 
       case TGSI_TOKEN_TYPE_INSTRUCTION:
-         if (!emit_instruction( &bld, &parse.FullToken.FullInstruction )) {
+         {
             unsigned opcode = parse.FullToken.FullInstruction.Instruction.Opcode;
             const struct tgsi_opcode_info *info = tgsi_get_opcode_info(opcode);
-           _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
-                         info ? info->mnemonic : "<invalid>");
-        }
+            if (!emit_instruction( &bld, &parse.FullToken.FullInstruction, info ))
+               _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
+                             info ? info->mnemonic : "<invalid>");
+         }
+
          break;
 
       case TGSI_TOKEN_TYPE_IMMEDIATE:
@@ -1446,7 +1444,7 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
             assert(num_immediates < LP_MAX_IMMEDIATES);
             for( i = 0; i < size; ++i )
                bld.immediates[num_immediates][i] =
-                  lp_build_const_uni(type, parse.FullToken.FullImmediate.u[i].Float);
+                  lp_build_const_scalar(type, parse.FullToken.FullImmediate.u[i].Float);
             for( i = size; i < 4; ++i )
                bld.immediates[num_immediates][i] = bld.base.undef;
             num_immediates++;
@@ -1459,7 +1457,5 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
    }
 
    tgsi_parse_free( &parse );
-
-   return bld.mask;
 }