i965/fs: Implement texelFetch() on Ivybridge.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_visitor.cpp
index 2704f06ceb3c3c3552026909ee6f5de099ce70f7..2c8d16035863d61dc105da445a53a7a6bb58048e 100644 (file)
@@ -46,9 +46,9 @@ extern "C" {
 }
 #include "brw_shader.h"
 #include "brw_fs.h"
-#include "../glsl/glsl_types.h"
-#include "../glsl/ir_optimization.h"
-#include "../glsl/ir_print_visitor.h"
+#include "glsl/glsl_types.h"
+#include "glsl/ir_optimization.h"
+#include "glsl/ir_print_visitor.h"
 
 void
 fs_visitor::visit(ir_variable *ir)
@@ -142,9 +142,7 @@ fs_visitor::visit(ir_dereference_array *ir)
    this->result.type = brw_type_for_base_type(ir->type);
 
    if (index) {
-      assert(this->result.file == UNIFORM ||
-            (this->result.file == GRF &&
-             this->result.reg != 0));
+      assert(this->result.file == UNIFORM || this->result.file == GRF);
       this->result.reg_offset += index->value.i[0] * element_size;
    } else {
       assert(!"FINISHME: non-constant array element");
@@ -162,7 +160,6 @@ fs_visitor::try_emit_saturate(ir_expression *ir)
    if (!sat_val)
       return false;
 
-   this->result = reg_undef;
    sat_val->accept(this);
    fs_reg src = this->result;
 
@@ -185,11 +182,7 @@ fs_visitor::visit(ir_expression *ir)
    if (try_emit_saturate(ir))
       return;
 
-   /* This is where our caller would like us to put the result, if possible. */
-   fs_reg saved_result_storage = this->result;
-
    for (operand = 0; operand < ir->get_num_operands(); operand++) {
-      this->result = reg_undef;
       ir->operands[operand]->accept(this);
       if (this->result.file == BAD_FILE) {
         ir_print_visitor v;
@@ -207,14 +200,10 @@ fs_visitor::visit(ir_expression *ir)
       assert(!ir->operands[operand]->type->is_vector());
    }
 
-   /* Inherit storage from our parent if possible, and otherwise we
-    * alloc a temporary.
+   /* Storage for our result.  If our result goes into an assignment, it will
+    * just get copy-propagated out, so no worries.
     */
-   if (saved_result_storage.file == BAD_FILE) {
-      this->result = fs_reg(this, ir->type);
-   } else {
-      this->result = saved_result_storage;
-   }
+   this->result = fs_reg(this, ir->type);
 
    switch (ir->operation) {
    case ir_unop_logic_not:
@@ -235,9 +224,6 @@ fs_visitor::visit(ir_expression *ir)
    case ir_unop_sign:
       temp = fs_reg(this, ir->type);
 
-      /* Unalias the destination.  (imagine a = sign(a)) */
-      this->result = fs_reg(this, ir->type);
-
       emit(BRW_OPCODE_MOV, this->result, fs_reg(0.0f));
 
       inst = emit(BRW_OPCODE_CMP, reg_null_f, op[0], fs_reg(0.0f));
@@ -252,14 +238,14 @@ fs_visitor::visit(ir_expression *ir)
 
       break;
    case ir_unop_rcp:
-      emit_math(FS_OPCODE_RCP, this->result, op[0]);
+      emit_math(SHADER_OPCODE_RCP, this->result, op[0]);
       break;
 
    case ir_unop_exp2:
-      emit_math(FS_OPCODE_EXP2, this->result, op[0]);
+      emit_math(SHADER_OPCODE_EXP2, this->result, op[0]);
       break;
    case ir_unop_log2:
-      emit_math(FS_OPCODE_LOG2, this->result, op[0]);
+      emit_math(SHADER_OPCODE_LOG2, this->result, op[0]);
       break;
    case ir_unop_exp:
    case ir_unop_log:
@@ -267,11 +253,11 @@ fs_visitor::visit(ir_expression *ir)
       break;
    case ir_unop_sin:
    case ir_unop_sin_reduced:
-      emit_math(FS_OPCODE_SIN, this->result, op[0]);
+      emit_math(SHADER_OPCODE_SIN, this->result, op[0]);
       break;
    case ir_unop_cos:
    case ir_unop_cos_reduced:
-      emit_math(FS_OPCODE_COS, this->result, op[0]);
+      emit_math(SHADER_OPCODE_COS, this->result, op[0]);
       break;
 
    case ir_unop_dFdx:
@@ -289,7 +275,23 @@ fs_visitor::visit(ir_expression *ir)
       break;
 
    case ir_binop_mul:
-      emit(BRW_OPCODE_MUL, this->result, op[0], op[1]);
+      if (ir->type->is_integer()) {
+        /* For integer multiplication, the MUL uses the low 16 bits
+         * of one of the operands (src0 on gen6, src1 on gen7).  The
+         * MACH accumulates in the contribution of the upper 16 bits
+         * of that operand.
+         *
+         * FINISHME: Emit just the MUL if we know an operand is small
+         * enough.
+         */
+        struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_D);
+
+        emit(BRW_OPCODE_MUL, acc, op[0], op[1]);
+        emit(BRW_OPCODE_MACH, reg_null_d, op[0], op[1]);
+        emit(BRW_OPCODE_MOV, this->result, fs_reg(acc));
+      } else {
+        emit(BRW_OPCODE_MUL, this->result, op[0], op[1]);
+      }
       break;
    case ir_binop_div:
       assert(!"not reached: should be handled by ir_div_to_mul_rcp");
@@ -342,14 +344,23 @@ fs_visitor::visit(ir_expression *ir)
       break;
 
    case ir_unop_sqrt:
-      emit_math(FS_OPCODE_SQRT, this->result, op[0]);
+      emit_math(SHADER_OPCODE_SQRT, this->result, op[0]);
       break;
 
    case ir_unop_rsq:
-      emit_math(FS_OPCODE_RSQ, this->result, op[0]);
+      emit_math(SHADER_OPCODE_RSQ, this->result, op[0]);
       break;
 
+   case ir_unop_i2u:
+      op[0].type = BRW_REGISTER_TYPE_UD;
+      this->result = op[0];
+      break;
+   case ir_unop_u2i:
+      op[0].type = BRW_REGISTER_TYPE_D;
+      this->result = op[0];
+      break;
    case ir_unop_i2f:
+   case ir_unop_u2f:
    case ir_unop_b2f:
    case ir_unop_b2i:
    case ir_unop_f2i:
@@ -417,7 +428,7 @@ fs_visitor::visit(ir_expression *ir)
       break;
 
    case ir_binop_pow:
-      emit_math(FS_OPCODE_POW, this->result, op[0], op[1]);
+      emit_math(SHADER_OPCODE_POW, this->result, op[0], op[1]);
       break;
 
    case ir_unop_bit_not:
@@ -433,7 +444,6 @@ fs_visitor::visit(ir_expression *ir)
       inst = emit(BRW_OPCODE_OR, this->result, op[0], op[1]);
       break;
 
-   case ir_unop_u2f:
    case ir_binop_lshift:
    case ir_binop_rshift:
       assert(!"GLSL 1.30 features unsupported");
@@ -485,34 +495,65 @@ fs_visitor::emit_assignment_writes(fs_reg &l, fs_reg &r,
    }
 }
 
+/* If the RHS processing resulted in an instruction generating a
+ * temporary value, and it would be easy to rewrite the instruction to
+ * generate its result right into the LHS instead, do so.  This ends
+ * up reliably removing instructions where it can be tricky to do so
+ * later without real UD chain information.
+ */
+bool
+fs_visitor::try_rewrite_rhs_to_dst(ir_assignment *ir,
+                                   fs_reg dst,
+                                   fs_reg src,
+                                   fs_inst *pre_rhs_inst,
+                                   fs_inst *last_rhs_inst)
+{
+   if (pre_rhs_inst == last_rhs_inst)
+      return false; /* No instructions generated to work with. */
+
+   /* Only attempt if we're doing a direct assignment. */
+   if (ir->condition ||
+       !(ir->lhs->type->is_scalar() ||
+        (ir->lhs->type->is_vector() &&
+         ir->write_mask == (1 << ir->lhs->type->vector_elements) - 1)))
+      return false;
+
+   /* Make sure the last instruction generated our source reg. */
+   if (last_rhs_inst->predicated ||
+       last_rhs_inst->force_uncompressed ||
+       last_rhs_inst->force_sechalf ||
+       !src.equals(&last_rhs_inst->dst))
+      return false;
+
+   /* Success!  Rewrite the instruction. */
+   last_rhs_inst->dst = dst;
+
+   return true;
+}
+
 void
 fs_visitor::visit(ir_assignment *ir)
 {
-   struct fs_reg l, r;
+   fs_reg l, r;
    fs_inst *inst;
 
    /* FINISHME: arrays on the lhs */
-   this->result = reg_undef;
    ir->lhs->accept(this);
    l = this->result;
 
-   /* If we're doing a direct assignment, an RHS expression could
-    * drop its result right into our destination.  Otherwise, tell it
-    * not to.
-    */
-   if (ir->condition ||
-       !(ir->lhs->type->is_scalar() ||
-        (ir->lhs->type->is_vector() &&
-         ir->write_mask == (1 << ir->lhs->type->vector_elements) - 1))) {
-      this->result = reg_undef;
-   }
+   fs_inst *pre_rhs_inst = (fs_inst *) this->instructions.get_tail();
 
    ir->rhs->accept(this);
    r = this->result;
 
+   fs_inst *last_rhs_inst = (fs_inst *) this->instructions.get_tail();
+
    assert(l.file != BAD_FILE);
    assert(r.file != BAD_FILE);
 
+   if (try_rewrite_rhs_to_dst(ir, l, r, pre_rhs_inst, last_rhs_inst))
+      return;
+
    if (ir->condition) {
       emit_bool_to_cond_code(ir->condition);
    }
@@ -521,13 +562,9 @@ fs_visitor::visit(ir_assignment *ir)
        ir->lhs->type->is_vector()) {
       for (int i = 0; i < ir->lhs->type->vector_elements; i++) {
         if (ir->write_mask & (1 << i)) {
-           if (ir->condition) {
-              inst = emit(BRW_OPCODE_MOV, l, r);
+           inst = emit(BRW_OPCODE_MOV, l, r);
+           if (ir->condition)
               inst->predicated = true;
-           } else if (!l.equals(&r)) {
-              inst = emit(BRW_OPCODE_MOV, l, r);
-           }
-
            r.reg_offset++;
         }
         l.reg_offset++;
@@ -568,19 +605,16 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), fs_reg(0.0f));
         mlen++;
       } else if (ir->op == ir_txb) {
-        this->result = reg_undef;
         ir->lod_info.bias->accept(this);
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
         mlen++;
       } else {
         assert(ir->op == ir_txl);
-        this->result = reg_undef;
         ir->lod_info.lod->accept(this);
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
         mlen++;
       }
 
-      this->result = reg_undef;
       ir->shadow_comparitor->accept(this);
       emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
       mlen++;
@@ -612,6 +646,8 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
        * dPdx = dudx, dvdx, drdx
        * dPdy = dudy, dvdy, drdy
        *
+       * 1-arg: Does not exist.
+       *
        * 2-arg: dudx   dvdx   dudy   dvdy
        *        dPdx.x dPdx.y dPdy.x dPdy.y
        *        m4     m5     m6     m7
@@ -623,18 +659,25 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       for (int i = 0; i < ir->lod_info.grad.dPdx->type->vector_elements; i++) {
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), dPdx);
         dPdx.reg_offset++;
-        mlen++;
       }
+      mlen += MAX2(ir->lod_info.grad.dPdx->type->vector_elements, 2);
 
       for (int i = 0; i < ir->lod_info.grad.dPdy->type->vector_elements; i++) {
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), dPdy);
         dPdy.reg_offset++;
-        mlen++;
       }
+      mlen += MAX2(ir->lod_info.grad.dPdy->type->vector_elements, 2);
+   } else if (ir->op == ir_txs) {
+      /* There's no SIMD8 resinfo message on Gen4.  Use SIMD16 instead. */
+      simd16 = true;
+      ir->lod_info.lod->accept(this);
+      emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_UD), this->result);
+      mlen += 2;
    } else {
       /* Oh joy.  gen4 doesn't have SIMD8 non-shadow-compare bias/lod
        * instructions.  We'll need to do SIMD16 here.
        */
+      simd16 = true;
       assert(ir->op == ir_txb || ir->op == ir_txl);
 
       for (int i = 0; i < ir->coordinate->type->vector_elements; i++) {
@@ -650,12 +693,10 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       mlen += 6;
 
       if (ir->op == ir_txb) {
-        this->result = reg_undef;
         ir->lod_info.bias->accept(this);
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
         mlen++;
       } else {
-        this->result = reg_undef;
         ir->lod_info.lod->accept(this);
         emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
         mlen++;
@@ -663,16 +704,19 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
 
       /* The unused upper half. */
       mlen++;
+   }
 
+   if (simd16) {
       /* Now, since we're doing simd16, the return is 2 interleaved
        * vec4s where the odd-indexed ones are junk. We'll need to move
        * this weirdness around to the expected layout.
        */
-      simd16 = true;
       orig_dst = dst;
-      dst = fs_reg(this, glsl_type::get_array_instance(glsl_type::vec4_type,
-                                                      2));
-      dst.type = BRW_REGISTER_TYPE_F;
+      const glsl_type *vec_type =
+        glsl_type::get_instance(ir->type->base_type, 4, 1);
+      dst = fs_reg(this, glsl_type::get_array_instance(vec_type, 2));
+      dst.type = intel->is_g4x ? brw_type_for_base_type(ir->type)
+                              : BRW_REGISTER_TYPE_F;
    }
 
    fs_inst *inst = NULL;
@@ -689,6 +733,9 @@ fs_visitor::emit_texture_gen4(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    case ir_txd:
       inst = emit(FS_OPCODE_TXD, dst);
       break;
+   case ir_txs:
+      inst = emit(FS_OPCODE_TXS, dst);
+      break;
    case ir_txf:
       assert(!"GLSL 1.30 features unsupported");
       break;
@@ -724,6 +771,8 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    int base_mrf = 2;
    int reg_width = c->dispatch_width / 8;
    bool header_present = false;
+   const int vector_elements =
+      ir->coordinate ? ir->coordinate->type->vector_elements : 0;
 
    if (ir->offset) {
       /* The offsets set up by the ir_texture visitor are in the
@@ -734,20 +783,20 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       base_mrf--;
    }
 
-   for (int i = 0; i < ir->coordinate->type->vector_elements; i++) {
+   for (int i = 0; i < vector_elements; i++) {
       fs_inst *inst = emit(BRW_OPCODE_MOV,
-                          fs_reg(MRF, base_mrf + mlen + i * reg_width),
+                          fs_reg(MRF, base_mrf + mlen + i * reg_width,
+                                 coordinate.type),
                           coordinate);
       if (i < 3 && c->key.gl_clamp_mask[i] & (1 << sampler))
         inst->saturate = true;
       coordinate.reg_offset++;
    }
-   mlen += ir->coordinate->type->vector_elements * reg_width;
+   mlen += vector_elements * reg_width;
 
    if (ir->shadow_comparitor && ir->op != ir_txd) {
       mlen = MAX2(mlen, header_present + 4 * reg_width);
 
-      this->result = reg_undef;
       ir->shadow_comparitor->accept(this);
       emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
       mlen += reg_width;
@@ -759,7 +808,6 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       inst = emit(FS_OPCODE_TEX, dst);
       break;
    case ir_txb:
-      this->result = reg_undef;
       ir->lod_info.bias->accept(this);
       mlen = MAX2(mlen, header_present + 4 * reg_width);
       emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
@@ -769,7 +817,6 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
 
       break;
    case ir_txl:
-      this->result = reg_undef;
       ir->lod_info.lod->accept(this);
       mlen = MAX2(mlen, header_present + 4 * reg_width);
       emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result);
@@ -808,8 +855,20 @@ fs_visitor::emit_texture_gen5(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       inst = emit(FS_OPCODE_TXD, dst);
       break;
    }
+   case ir_txs:
+      ir->lod_info.lod->accept(this);
+      emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_UD), this->result);
+      mlen += reg_width;
+      inst = emit(FS_OPCODE_TXS, dst);
+      break;
    case ir_txf:
-      assert(!"GLSL 1.30 features unsupported");
+      mlen = header_present + 4 * reg_width;
+
+      ir->lod_info.lod->accept(this);
+      emit(BRW_OPCODE_MOV,
+          fs_reg(MRF, base_mrf + mlen - reg_width, BRW_REGISTER_TYPE_UD),
+          this->result);
+      inst = emit(FS_OPCODE_TXF, dst);
       break;
    }
    inst->base_mrf = base_mrf;
@@ -892,13 +951,35 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       }
       break;
    }
+   case ir_txs:
+      ir->lod_info.lod->accept(this);
+      emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_UD), this->result);
+      mlen += reg_width;
+      break;
    case ir_txf:
-      assert(!"GLSL 1.30 features unsupported");
+      /* Unfortunately, the parameters for LD are intermixed: u, lod, v, r. */
+      fs_inst *inst = emit(BRW_OPCODE_MOV,
+                          fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D),
+                          coordinate);
+      coordinate.reg_offset++;
+      mlen += reg_width;
+
+      ir->lod_info.lod->accept(this);
+      emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D), this->result);
+      mlen += reg_width;
+
+      for (int i = 1; i < ir->coordinate->type->vector_elements; i++) {
+        fs_inst *inst = emit(BRW_OPCODE_MOV,
+                             fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D),
+                             coordinate);
+        coordinate.reg_offset++;
+        mlen += reg_width;
+      }
       break;
    }
 
-   /* Set up the coordinate (except for TXD where it was done earlier) */
-   if (ir->op != ir_txd) {
+   /* Set up the coordinate (except for cases where it was done above) */
+   if (ir->op != ir_txd && ir->op != ir_txs && ir->op != ir_txf) {
       for (int i = 0; i < ir->coordinate->type->vector_elements; i++) {
         fs_inst *inst = emit(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen),
                              coordinate);
@@ -916,7 +997,8 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    case ir_txb: inst = emit(FS_OPCODE_TXB, dst); break;
    case ir_txl: inst = emit(FS_OPCODE_TXL, dst); break;
    case ir_txd: inst = emit(FS_OPCODE_TXD, dst); break;
-   case ir_txf: assert(!"TXF unsupported.");
+   case ir_txf: inst = emit(FS_OPCODE_TXF, dst); break;
+   case ir_txs: inst = emit(FS_OPCODE_TXS, dst); break;
    }
    inst->base_mrf = base_mrf;
    inst->mlen = mlen;
@@ -950,8 +1032,8 @@ fs_visitor::visit(ir_texture *ir)
         return swizzle_result(ir, fs_reg(0.0f), sampler);
    }
 
-   this->result = reg_undef;
-   ir->coordinate->accept(this);
+   if (ir->coordinate)
+      ir->coordinate->accept(this);
    fs_reg coordinate = this->result;
 
    if (ir->offset != NULL) {
@@ -992,7 +1074,8 @@ fs_visitor::visit(ir_texture *ir)
     * texture coordinates.  We use the program parameter state
     * tracking to get the scaling factor.
     */
-   if (ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_RECT) {
+   if (intel->gen < 6 &&
+       ir->sampler->type->sampler_dimensionality == GLSL_SAMPLER_DIM_RECT) {
       struct gl_program_parameter_list *params = c->fp->program.Base.Parameters;
       int tokens[STATE_LENGTH] = {
         STATE_INTERNAL,
@@ -1038,7 +1121,7 @@ fs_visitor::visit(ir_texture *ir)
    /* Writemasking doesn't eliminate channels on SIMD8 texture
     * samples, so don't worry about them.
     */
-   fs_reg dst = fs_reg(this, glsl_type::vec4_type);
+   fs_reg dst = fs_reg(this, glsl_type::get_instance(ir->type->base_type, 4, 1));
 
    if (intel->gen >= 7) {
       inst = emit_texture_gen7(ir, dst, coordinate, sampler);
@@ -1140,7 +1223,6 @@ fs_visitor::swizzle_result(ir_texture *ir, fs_reg orig_val, int sampler)
 void
 fs_visitor::visit(ir_swizzle *ir)
 {
-   this->result = reg_undef;
    ir->val->accept(this);
    fs_reg val = this->result;
 
@@ -1203,7 +1285,6 @@ fs_visitor::visit(ir_constant *ir)
       const unsigned size = type_size(ir->type->fields.array);
 
       for (unsigned i = 0; i < ir->type->length; i++) {
-        this->result = reg_undef;
         ir->array_elements[i]->accept(this);
         fs_reg src_reg = this->result;
 
@@ -1219,7 +1300,6 @@ fs_visitor::visit(ir_constant *ir)
         ir_instruction *const field = (ir_instruction *) node;
         const unsigned size = type_size(field->type);
 
-        this->result = reg_undef;
         field->accept(this);
         fs_reg src_reg = this->result;
 
@@ -1270,7 +1350,6 @@ fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
       for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
         assert(expr->operands[i]->type->is_scalar());
 
-        this->result = reg_undef;
         expr->operands[i]->accept(this);
         op[i] = this->result;
       }
@@ -1335,7 +1414,6 @@ fs_visitor::emit_bool_to_cond_code(ir_rvalue *ir)
       return;
    }
 
-   this->result = reg_undef;
    ir->accept(this);
 
    if (intel->gen >= 6) {
@@ -1365,7 +1443,6 @@ fs_visitor::emit_if_gen6(ir_if *ir)
       for (unsigned int i = 0; i < expr->get_num_operands(); i++) {
         assert(expr->operands[i]->type->is_scalar());
 
-        this->result = reg_undef;
         expr->operands[i]->accept(this);
         op[i] = this->result;
       }
@@ -1427,7 +1504,6 @@ fs_visitor::emit_if_gen6(ir_if *ir)
       return;
    }
 
-   this->result = reg_undef;
    ir->condition->accept(this);
 
    fs_inst *inst = emit(BRW_OPCODE_IF, reg_null_d, this->result, fs_reg(0));
@@ -1457,20 +1533,20 @@ fs_visitor::visit(ir_if *ir)
       inst->predicated = true;
    }
 
-   foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
+   foreach_list(node, &ir->then_instructions) {
+      ir_instruction *ir = (ir_instruction *)node;
       this->base_ir = ir;
-      this->result = reg_undef;
+
       ir->accept(this);
    }
 
    if (!ir->else_instructions.is_empty()) {
       emit(BRW_OPCODE_ELSE);
 
-      foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
-        ir_instruction *ir = (ir_instruction *)iter.get();
+      foreach_list(node, &ir->else_instructions) {
+        ir_instruction *ir = (ir_instruction *)node;
         this->base_ir = ir;
-        this->result = reg_undef;
+
         ir->accept(this);
       }
    }
@@ -1493,14 +1569,10 @@ fs_visitor::visit(ir_loop *ir)
       counter = *(variable_storage(ir->counter));
 
       if (ir->from) {
-        this->result = counter;
-
         this->base_ir = ir->from;
-        this->result = counter;
         ir->from->accept(this);
 
-        if (!this->result.equals(&counter))
-           emit(BRW_OPCODE_MOV, counter, this->result);
+        emit(BRW_OPCODE_MOV, counter, this->result);
       }
    }
 
@@ -1508,7 +1580,6 @@ fs_visitor::visit(ir_loop *ir)
 
    if (ir->to) {
       this->base_ir = ir->to;
-      this->result = reg_undef;
       ir->to->accept(this);
 
       fs_inst *inst = emit(BRW_OPCODE_CMP, reg_null_cmp, counter, this->result);
@@ -1518,17 +1589,15 @@ fs_visitor::visit(ir_loop *ir)
       inst->predicated = true;
    }
 
-   foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
-      ir_instruction *ir = (ir_instruction *)iter.get();
+   foreach_list(node, &ir->body_instructions) {
+      ir_instruction *ir = (ir_instruction *)node;
 
       this->base_ir = ir;
-      this->result = reg_undef;
       ir->accept(this);
    }
 
    if (ir->increment) {
       this->base_ir = ir->increment;
-      this->result = reg_undef;
       ir->increment->accept(this);
       emit(BRW_OPCODE_ADD, counter, counter, this->result);
    }
@@ -1575,10 +1644,10 @@ fs_visitor::visit(ir_function *ir)
 
       assert(sig);
 
-      foreach_iter(exec_list_iterator, iter, sig->body) {
-        ir_instruction *ir = (ir_instruction *)iter.get();
+      foreach_list(node, &sig->body) {
+        ir_instruction *ir = (ir_instruction *)node;
         this->base_ir = ir;
-        this->result = reg_undef;
+
         ir->accept(this);
       }
    }
@@ -1676,7 +1745,7 @@ fs_visitor::emit_interpolation_setup_gen4()
        interp_reg(FRAG_ATTRIB_WPOS, 3));
    /* Compute the pixel 1/W value from wpos.w. */
    this->pixel_w = fs_reg(this, glsl_type::float_type);
-   emit_math(FS_OPCODE_RCP, this->pixel_w, wpos_w);
+   emit_math(SHADER_OPCODE_RCP, this->pixel_w, wpos_w);
    this->current_annotation = NULL;
 }
 
@@ -1713,7 +1782,7 @@ fs_visitor::emit_interpolation_setup_gen6()
    this->current_annotation = "compute pos.w";
    this->pixel_w = fs_reg(brw_vec8_grf(c->source_w_reg, 0));
    this->wpos_w = fs_reg(this, glsl_type::float_type);
-   emit_math(FS_OPCODE_RCP, this->wpos_w, this->pixel_w);
+   emit_math(SHADER_OPCODE_RCP, this->wpos_w, this->pixel_w);
 
    this->delta_x = fs_reg(brw_vec8_grf(2, 0));
    this->delta_y = fs_reg(brw_vec8_grf(3, 0));
@@ -1725,6 +1794,7 @@ void
 fs_visitor::emit_color_write(int index, int first_color_mrf, fs_reg color)
 {
    int reg_width = c->dispatch_width / 8;
+   fs_inst *inst;
 
    if (c->dispatch_width == 8 || intel->gen == 6) {
       /* SIMD8 write looks like:
@@ -1743,8 +1813,10 @@ fs_visitor::emit_color_write(int index, int first_color_mrf, fs_reg color)
        * m + 6: a0
        * m + 7: a1
        */
-      emit(BRW_OPCODE_MOV, fs_reg(MRF, first_color_mrf + index * reg_width),
-          color);
+      inst = emit(BRW_OPCODE_MOV,
+                 fs_reg(MRF, first_color_mrf + index * reg_width),
+                 color);
+      inst->saturate = c->key.clamp_fragment_color;
    } else {
       /* pre-gen6 SIMD16 single source DP write looks like:
        * m + 0: r0
@@ -1762,16 +1834,22 @@ fs_visitor::emit_color_write(int index, int first_color_mrf, fs_reg color)
          * usual destination + 1 for the second half we get
          * destination + 4.
          */
-        emit(BRW_OPCODE_MOV,
-             fs_reg(MRF, BRW_MRF_COMPR4 + first_color_mrf + index), color);
+        inst = emit(BRW_OPCODE_MOV,
+                    fs_reg(MRF, BRW_MRF_COMPR4 + first_color_mrf + index),
+                    color);
+        inst->saturate = c->key.clamp_fragment_color;
       } else {
         push_force_uncompressed();
-        emit(BRW_OPCODE_MOV, fs_reg(MRF, first_color_mrf + index), color);
+        inst = emit(BRW_OPCODE_MOV, fs_reg(MRF, first_color_mrf + index),
+                    color);
+        inst->saturate = c->key.clamp_fragment_color;
         pop_force_uncompressed();
 
         push_force_sechalf();
         color.sechalf = true;
-        emit(BRW_OPCODE_MOV, fs_reg(MRF, first_color_mrf + index + 4), color);
+        inst = emit(BRW_OPCODE_MOV, fs_reg(MRF, first_color_mrf + index + 4),
+                    color);
+        inst->saturate = c->key.clamp_fragment_color;
         pop_force_sechalf();
         color.sechalf = false;
       }
@@ -1783,7 +1861,8 @@ fs_visitor::emit_fb_writes()
 {
    this->current_annotation = "FB write header";
    GLboolean header_present = GL_TRUE;
-   int nr = 2;
+   int base_mrf = 2;
+   int nr = base_mrf;
    int reg_width = c->dispatch_width / 8;
 
    if (intel->gen >= 6 &&
@@ -1862,8 +1941,8 @@ fs_visitor::emit_fb_writes()
 
       fs_inst *inst = emit(FS_OPCODE_FB_WRITE);
       inst->target = target;
-      inst->base_mrf = 2;
-      inst->mlen = nr;
+      inst->base_mrf = base_mrf;
+      inst->mlen = nr - base_mrf;
       if (target == c->key.nr_color_regions - 1)
         inst->eot = true;
       inst->header_present = header_present;
@@ -1880,8 +1959,8 @@ fs_visitor::emit_fb_writes()
       }
 
       fs_inst *inst = emit(FS_OPCODE_FB_WRITE);
-      inst->base_mrf = 2;
-      inst->mlen = nr;
+      inst->base_mrf = base_mrf;
+      inst->mlen = nr - base_mrf;
       inst->eot = true;
       inst->header_present = header_present;
    }