ir_to_mesa: Implement ir_unop_any using DP4 w/saturate or DP4 w/SLT
[mesa.git] / src / mesa / program / ir_to_mesa.cpp
index cb310231704632816f750f18ee1270de34623d10..1bd9a2eee1b73a8a2a469a6e9f318e75b79dbf34 100644 (file)
@@ -56,16 +56,20 @@ extern "C" {
 #include "program/sampler.h"
 }
 
+class src_reg;
+class dst_reg;
+
 static int swizzle_for_size(int size);
 
 /**
  * This struct is a corresponding struct to Mesa prog_src_register, with
  * wider fields.
  */
-typedef struct ir_to_mesa_src_reg {
-   ir_to_mesa_src_reg(int file, int index, const glsl_type *type)
+class src_reg {
+public:
+   src_reg(gl_register_file file, int index, const glsl_type *type)
    {
-      this->file = (gl_register_file) file;
+      this->file = file;
       this->index = index;
       if (type && (type->is_scalar() || type->is_vector() || type->is_matrix()))
         this->swizzle = swizzle_for_size(type->vector_elements);
@@ -75,7 +79,7 @@ typedef struct ir_to_mesa_src_reg {
       this->reladdr = NULL;
    }
 
-   ir_to_mesa_src_reg()
+   src_reg()
    {
       this->file = PROGRAM_UNDEFINED;
       this->index = 0;
@@ -84,42 +88,81 @@ typedef struct ir_to_mesa_src_reg {
       this->reladdr = NULL;
    }
 
+   explicit src_reg(dst_reg reg);
+
    gl_register_file file; /**< PROGRAM_* from Mesa */
    int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
    GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
    int negate; /**< NEGATE_XYZW mask from mesa */
    /** Register index should be offset by the integer in this reg. */
-   ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_src_reg;
+   src_reg *reladdr;
+};
+
+class dst_reg {
+public:
+   dst_reg(gl_register_file file, int writemask)
+   {
+      this->file = file;
+      this->index = 0;
+      this->writemask = writemask;
+      this->cond_mask = COND_TR;
+      this->reladdr = NULL;
+   }
+
+   dst_reg()
+   {
+      this->file = PROGRAM_UNDEFINED;
+      this->index = 0;
+      this->writemask = 0;
+      this->cond_mask = COND_TR;
+      this->reladdr = NULL;
+   }
+
+   explicit dst_reg(src_reg reg);
 
-typedef struct ir_to_mesa_dst_reg {
-   int file; /**< PROGRAM_* from Mesa */
+   gl_register_file file; /**< PROGRAM_* from Mesa */
    int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
    int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
    GLuint cond_mask:4;
    /** Register index should be offset by the integer in this reg. */
-   ir_to_mesa_src_reg *reladdr;
-} ir_to_mesa_dst_reg;
+   src_reg *reladdr;
+};
 
-extern ir_to_mesa_src_reg ir_to_mesa_undef;
+src_reg::src_reg(dst_reg reg)
+{
+   this->file = reg.file;
+   this->index = reg.index;
+   this->swizzle = SWIZZLE_XYZW;
+   this->negate = 0;
+   this->reladdr = reg.reladdr;
+}
+
+dst_reg::dst_reg(src_reg reg)
+{
+   this->file = reg.file;
+   this->index = reg.index;
+   this->writemask = WRITEMASK_XYZW;
+   this->cond_mask = COND_TR;
+   this->reladdr = reg.reladdr;
+}
 
 class ir_to_mesa_instruction : public exec_node {
 public:
-   /* Callers of this talloc-based new need not call delete. It's
-    * easier to just talloc_free 'ctx' (or any of its ancestors). */
+   /* Callers of this ralloc-based new need not call delete. It's
+    * easier to just ralloc_free 'ctx' (or any of its ancestors). */
    static void* operator new(size_t size, void *ctx)
    {
       void *node;
 
-      node = talloc_zero_size(ctx, size);
+      node = rzalloc_size(ctx, size);
       assert(node != NULL);
 
       return node;
    }
 
    enum prog_opcode op;
-   ir_to_mesa_dst_reg dst_reg;
-   ir_to_mesa_src_reg src_reg[3];
+   dst_reg dst;
+   src_reg src[3];
    /** Pointer to the ir source this tree came from for debugging */
    ir_instruction *ir;
    GLboolean cond_update;
@@ -174,7 +217,7 @@ public:
    int inst;
 
    /** Storage for the return value. */
-   ir_to_mesa_src_reg return_reg;
+   src_reg return_reg;
 };
 
 class ir_to_mesa_visitor : public ir_visitor {
@@ -195,11 +238,10 @@ public:
 
    function_entry *get_function_signature(ir_function_signature *sig);
 
-   ir_to_mesa_src_reg get_temp(const glsl_type *type);
-   void reladdr_to_temp(ir_instruction *ir,
-                       ir_to_mesa_src_reg *reg, int *num_reladdr);
+   src_reg get_temp(const glsl_type *type);
+   void reladdr_to_temp(ir_instruction *ir, src_reg *reg, int *num_reladdr);
 
-   struct ir_to_mesa_src_reg src_reg_for_float(float val);
+   src_reg src_reg_for_float(float val);
 
    /**
     * \name Visit methods
@@ -228,7 +270,7 @@ public:
    virtual void visit(ir_if *);
    /*@}*/
 
-   struct ir_to_mesa_src_reg result;
+   src_reg result;
 
    /** List of variable_storage */
    exec_list variables;
@@ -240,52 +282,35 @@ public:
    /** List of ir_to_mesa_instruction */
    exec_list instructions;
 
-   ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
-                                              enum prog_opcode op);
+   ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op);
 
-   ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
-                                              enum prog_opcode op,
-                                              ir_to_mesa_dst_reg dst,
-                                              ir_to_mesa_src_reg src0);
+   ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op,
+                               dst_reg dst, src_reg src0);
 
-   ir_to_mesa_instruction *ir_to_mesa_emit_op2(ir_instruction *ir,
-                                              enum prog_opcode op,
-                                              ir_to_mesa_dst_reg dst,
-                                              ir_to_mesa_src_reg src0,
-                                              ir_to_mesa_src_reg src1);
+   ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op,
+                               dst_reg dst, src_reg src0, src_reg src1);
 
-   ir_to_mesa_instruction *ir_to_mesa_emit_op3(ir_instruction *ir,
-                                              enum prog_opcode op,
-                                              ir_to_mesa_dst_reg dst,
-                                              ir_to_mesa_src_reg src0,
-                                              ir_to_mesa_src_reg src1,
-                                              ir_to_mesa_src_reg src2);
+   ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op,
+                               dst_reg dst,
+                               src_reg src0, src_reg src1, src_reg src2);
 
    /**
     * Emit the correct dot-product instruction for the type of arguments
-    *
-    * \sa ir_to_mesa_emit_op2
     */
-   void ir_to_mesa_emit_dp(ir_instruction *ir,
-                          ir_to_mesa_dst_reg dst,
-                          ir_to_mesa_src_reg src0,
-                          ir_to_mesa_src_reg src1,
-                          unsigned elements);
-
-   void ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
-                                  enum prog_opcode op,
-                                  ir_to_mesa_dst_reg dst,
-                                  ir_to_mesa_src_reg src0);
-
-   void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
-                                  enum prog_opcode op,
-                                  ir_to_mesa_dst_reg dst,
-                                  ir_to_mesa_src_reg src0,
-                                  ir_to_mesa_src_reg src1);
+   ir_to_mesa_instruction * emit_dp(ir_instruction *ir,
+                                   dst_reg dst,
+                                   src_reg src0,
+                                   src_reg src1,
+                                   unsigned elements);
+
+   void emit_scalar(ir_instruction *ir, enum prog_opcode op,
+                   dst_reg dst, src_reg src0);
+
+   void emit_scalar(ir_instruction *ir, enum prog_opcode op,
+                   dst_reg dst, src_reg src0, src_reg src1);
 
    void emit_scs(ir_instruction *ir, enum prog_opcode op,
-                ir_to_mesa_dst_reg dst,
-                const ir_to_mesa_src_reg &src);
+                dst_reg dst, const src_reg &src);
 
    GLboolean try_emit_mad(ir_expression *ir,
                          int mul_operand);
@@ -300,29 +325,11 @@ public:
    void *mem_ctx;
 };
 
-ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL);
+src_reg undef_src = src_reg(PROGRAM_UNDEFINED, 0, NULL);
 
-ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
-   PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
-};
+dst_reg undef_dst = dst_reg(PROGRAM_UNDEFINED, SWIZZLE_NOOP);
 
-ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
-   PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
-};
-
-static void
-fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3);
-
-static void
-fail_link(struct gl_shader_program *prog, const char *fmt, ...)
-{
-   va_list args;
-   va_start(args, fmt);
-   prog->InfoLog = talloc_vasprintf_append(prog->InfoLog, fmt, args);
-   va_end(args);
-
-   prog->LinkStatus = GL_FALSE;
-}
+dst_reg address_reg = dst_reg(PROGRAM_ADDRESS, WRITEMASK_X);
 
 static int
 swizzle_for_size(int size)
@@ -339,12 +346,9 @@ swizzle_for_size(int size)
 }
 
 ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
-                                       enum prog_opcode op,
-                                       ir_to_mesa_dst_reg dst,
-                                       ir_to_mesa_src_reg src0,
-                                       ir_to_mesa_src_reg src1,
-                                       ir_to_mesa_src_reg src2)
+ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op,
+                        dst_reg dst,
+                        src_reg src0, src_reg src1, src_reg src2)
 {
    ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
    int num_reladdr = 0;
@@ -363,18 +367,16 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
    reladdr_to_temp(ir, &src0, &num_reladdr);
 
    if (dst.reladdr) {
-      ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
-                          *dst.reladdr);
-
+      emit(ir, OPCODE_ARL, address_reg, *dst.reladdr);
       num_reladdr--;
    }
    assert(num_reladdr == 0);
 
    inst->op = op;
-   inst->dst_reg = dst;
-   inst->src_reg[0] = src0;
-   inst->src_reg[1] = src1;
-   inst->src_reg[2] = src2;
+   inst->dst = dst;
+   inst->src[0] = src0;
+   inst->src[1] = src1;
+   inst->src[2] = src2;
    inst->ir = ir;
 
    inst->function = NULL;
@@ -386,69 +388,36 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
 
 
 ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op2(ir_instruction *ir,
-                                       enum prog_opcode op,
-                                       ir_to_mesa_dst_reg dst,
-                                       ir_to_mesa_src_reg src0,
-                                       ir_to_mesa_src_reg src1)
+ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op,
+                        dst_reg dst, src_reg src0, src_reg src1)
 {
-   return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
+   return emit(ir, op, dst, src0, src1, undef_src);
 }
 
 ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir,
-                                       enum prog_opcode op,
-                                       ir_to_mesa_dst_reg dst,
-                                       ir_to_mesa_src_reg src0)
+ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op,
+                        dst_reg dst, src_reg src0)
 {
    assert(dst.writemask != 0);
-   return ir_to_mesa_emit_op3(ir, op, dst,
-                             src0, ir_to_mesa_undef, ir_to_mesa_undef);
+   return emit(ir, op, dst, src0, undef_src, undef_src);
 }
 
 ir_to_mesa_instruction *
-ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
-                                       enum prog_opcode op)
+ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op)
 {
-   return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
-                             ir_to_mesa_undef,
-                             ir_to_mesa_undef,
-                             ir_to_mesa_undef);
+   return emit(ir, op, undef_dst, undef_src, undef_src, undef_src);
 }
 
-void
-ir_to_mesa_visitor::ir_to_mesa_emit_dp(ir_instruction *ir,
-                                      ir_to_mesa_dst_reg dst,
-                                      ir_to_mesa_src_reg src0,
-                                      ir_to_mesa_src_reg src1,
-                                      unsigned elements)
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::emit_dp(ir_instruction *ir,
+                           dst_reg dst, src_reg src0, src_reg src1,
+                           unsigned elements)
 {
    static const gl_inst_opcode dot_opcodes[] = {
       OPCODE_DP2, OPCODE_DP3, OPCODE_DP4
    };
 
-   ir_to_mesa_emit_op3(ir, dot_opcodes[elements - 2],
-                      dst, src0, src1, ir_to_mesa_undef);
-}
-
-inline ir_to_mesa_dst_reg
-ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
-{
-   ir_to_mesa_dst_reg dst_reg;
-
-   dst_reg.file = reg.file;
-   dst_reg.index = reg.index;
-   dst_reg.writemask = WRITEMASK_XYZW;
-   dst_reg.cond_mask = COND_TR;
-   dst_reg.reladdr = reg.reladdr;
-
-   return dst_reg;
-}
-
-inline ir_to_mesa_src_reg
-ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
-{
-   return ir_to_mesa_src_reg(reg.file, reg.index, NULL);
+   return emit(ir, dot_opcodes[elements - 2], dst, src0, src1);
 }
 
 /**
@@ -460,11 +429,9 @@ ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
  * to produce dest channels.
  */
 void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
-                                              enum prog_opcode op,
-                                              ir_to_mesa_dst_reg dst,
-                                              ir_to_mesa_src_reg orig_src0,
-                                              ir_to_mesa_src_reg orig_src1)
+ir_to_mesa_visitor::emit_scalar(ir_instruction *ir, enum prog_opcode op,
+                               dst_reg dst,
+                               src_reg orig_src0, src_reg orig_src1)
 {
    int i, j;
    int done_mask = ~dst.writemask;
@@ -476,8 +443,8 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
    for (i = 0; i < 4; i++) {
       GLuint this_mask = (1 << i);
       ir_to_mesa_instruction *inst;
-      ir_to_mesa_src_reg src0 = orig_src0;
-      ir_to_mesa_src_reg src1 = orig_src1;
+      src_reg src0 = orig_src0;
+      src_reg src1 = orig_src1;
 
       if (done_mask & this_mask)
         continue;
@@ -500,26 +467,21 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
       src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
                                  src1_swiz, src1_swiz);
 
-      inst = ir_to_mesa_emit_op2(ir, op,
-                                dst,
-                                src0,
-                                src1);
-      inst->dst_reg.writemask = this_mask;
+      inst = emit(ir, op, dst, src0, src1);
+      inst->dst.writemask = this_mask;
       done_mask |= this_mask;
    }
 }
 
 void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
-                                              enum prog_opcode op,
-                                              ir_to_mesa_dst_reg dst,
-                                              ir_to_mesa_src_reg src0)
+ir_to_mesa_visitor::emit_scalar(ir_instruction *ir, enum prog_opcode op,
+                               dst_reg dst, src_reg src0)
 {
-   ir_to_mesa_src_reg undef = ir_to_mesa_undef;
+   src_reg undef = undef_src;
 
    undef.swizzle = SWIZZLE_XXXX;
 
-   ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
+   emit_scalar(ir, op, dst, src0, undef);
 }
 
 /**
@@ -538,20 +500,20 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
  */
 void
 ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
-                            ir_to_mesa_dst_reg dst,
-                            const ir_to_mesa_src_reg &src)
+                            dst_reg dst,
+                            const src_reg &src)
 {
    /* Vertex programs cannot use the SCS opcode.
     */
    if (this->prog->Target == GL_VERTEX_PROGRAM_ARB) {
-      ir_to_mesa_emit_scalar_op1(ir, op, dst, src);
+      emit_scalar(ir, op, dst, src);
       return;
    }
 
    const unsigned component = (op == OPCODE_SIN) ? 0 : 1;
    const unsigned scs_mask = (1U << component);
    int done_mask = ~dst.writemask;
-   ir_to_mesa_src_reg tmp;
+   src_reg tmp;
 
    assert(op == OPCODE_SIN || op == OPCODE_COS);
 
@@ -564,7 +526,7 @@ ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
 
    for (unsigned i = 0; i < 4; i++) {
       unsigned this_mask = (1U << i);
-      ir_to_mesa_src_reg src0 = src;
+      src_reg src0 = src;
 
       if ((done_mask & this_mask) != 0)
         continue;
@@ -592,41 +554,40 @@ ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op,
 
       if (this_mask != scs_mask) {
         ir_to_mesa_instruction *inst;
-        ir_to_mesa_dst_reg tmp_dst = ir_to_mesa_dst_reg_from_src(tmp);
+        dst_reg tmp_dst = dst_reg(tmp);
 
         /* Emit the SCS instruction.
          */
-        inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, tmp_dst, src0);
-        inst->dst_reg.writemask = scs_mask;
+        inst = emit(ir, OPCODE_SCS, tmp_dst, src0);
+        inst->dst.writemask = scs_mask;
 
         /* Move the result of the SCS instruction to the desired location in
          * the destination.
          */
         tmp.swizzle = MAKE_SWIZZLE4(component, component,
                                     component, component);
-        inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, tmp);
-        inst->dst_reg.writemask = this_mask;
+        inst = emit(ir, OPCODE_SCS, dst, tmp);
+        inst->dst.writemask = this_mask;
       } else {
         /* Emit the SCS instruction to write directly to the destination.
          */
-        ir_to_mesa_instruction *inst =
-           ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, src0);
-        inst->dst_reg.writemask = scs_mask;
+        ir_to_mesa_instruction *inst = emit(ir, OPCODE_SCS, dst, src0);
+        inst->dst.writemask = scs_mask;
       }
 
       done_mask |= this_mask;
    }
 }
 
-struct ir_to_mesa_src_reg
+struct src_reg
 ir_to_mesa_visitor::src_reg_for_float(float val)
 {
-   ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL);
+   src_reg src(PROGRAM_CONSTANT, -1, NULL);
 
-   src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
-                                             &val, 1, &src_reg.swizzle);
+   src.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+                                         (const gl_constant_value *)&val, 1, &src.swizzle);
 
-   return src_reg;
+   return src;
 }
 
 static int
@@ -651,6 +612,7 @@ type_size(const struct glsl_type *type)
         return 1;
       }
    case GLSL_TYPE_ARRAY:
+      assert(type->length > 0);
       return type_size(type->fields.array) * type->length;
    case GLSL_TYPE_STRUCT:
       size = 0;
@@ -675,31 +637,24 @@ type_size(const struct glsl_type *type)
  * storage).  Actual register allocation for the Mesa VM occurs in a
  * pass over the Mesa IR later.
  */
-ir_to_mesa_src_reg
+src_reg
 ir_to_mesa_visitor::get_temp(const glsl_type *type)
 {
-   ir_to_mesa_src_reg src_reg;
-   int swizzle[4];
-   int i;
+   src_reg src;
 
-   src_reg.file = PROGRAM_TEMPORARY;
-   src_reg.index = next_temp;
-   src_reg.reladdr = NULL;
+   src.file = PROGRAM_TEMPORARY;
+   src.index = next_temp;
+   src.reladdr = NULL;
    next_temp += type_size(type);
 
    if (type->is_array() || type->is_record()) {
-      src_reg.swizzle = SWIZZLE_NOOP;
+      src.swizzle = SWIZZLE_NOOP;
    } else {
-      for (i = 0; i < type->vector_elements; i++)
-        swizzle[i] = i;
-      for (; i < 4; i++)
-        swizzle[i] = type->vector_elements - 1;
-      src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
-                                     swizzle[2], swizzle[3]);
+      src.swizzle = swizzle_for_size(type->vector_elements);
    }
-   src_reg.negate = 0;
+   src.negate = 0;
 
-   return src_reg;
+   return src;
 }
 
 variable_storage *
@@ -726,31 +681,35 @@ ir_to_mesa_visitor::visit(ir_variable *ir)
 
       fp->OriginUpperLeft = ir->origin_upper_left;
       fp->PixelCenterInteger = ir->pixel_center_integer;
+
+   } else if (strcmp(ir->name, "gl_FragDepth") == 0) {
+      struct gl_fragment_program *fp = (struct gl_fragment_program *)this->prog;
+      switch (ir->depth_layout) {
+      case ir_depth_layout_none:
+        fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_NONE;
+        break;
+      case ir_depth_layout_any:
+        fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_ANY;
+        break;
+      case ir_depth_layout_greater:
+        fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_GREATER;
+        break;
+      case ir_depth_layout_less:
+        fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_LESS;
+        break;
+      case ir_depth_layout_unchanged:
+        fp->FragDepthLayout = FRAG_DEPTH_LAYOUT_UNCHANGED;
+        break;
+      default:
+        assert(0);
+        break;
+      }
    }
 
    if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) {
       unsigned int i;
-      const struct gl_builtin_uniform_desc *statevar;
-
-      for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) {
-        if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0)
-           break;
-      }
-
-      if (!_mesa_builtin_uniform_desc[i].name) {
-        fail_link(this->shader_program,
-                  "Failed to find builtin uniform `%s'\n", ir->name);
-        return;
-      }
-
-      statevar = &_mesa_builtin_uniform_desc[i];
-
-      int array_count;
-      if (ir->type->is_array()) {
-        array_count = ir->type->length;
-      } else {
-        array_count = 1;
-      }
+      const ir_state_slot *const slots = ir->state_slots;
+      assert(ir->state_slots != NULL);
 
       /* Check if this statevar's setup in the STATE file exactly
        * matches how we'll want to reference it as a
@@ -758,67 +717,62 @@ ir_to_mesa_visitor::visit(ir_variable *ir)
        * temporary storage and hope that it'll get copy-propagated
        * out.
        */
-      for (i = 0; i < statevar->num_elements; i++) {
-        if (statevar->elements[i].swizzle != SWIZZLE_XYZW) {
+      for (i = 0; i < ir->num_state_slots; i++) {
+        if (slots[i].swizzle != SWIZZLE_XYZW) {
            break;
         }
       }
 
       struct variable_storage *storage;
-      ir_to_mesa_dst_reg dst;
-      if (i == statevar->num_elements) {
+      dst_reg dst;
+      if (i == ir->num_state_slots) {
         /* We'll set the index later. */
         storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1);
         this->variables.push_tail(storage);
 
-        dst = ir_to_mesa_undef_dst;
+        dst = undef_dst;
       } else {
+        /* The variable_storage constructor allocates slots based on the size
+         * of the type.  However, this had better match the number of state
+         * elements that we're going to copy into the new temporary.
+         */
+        assert((int) ir->num_state_slots == type_size(ir->type));
+
         storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY,
                                                 this->next_temp);
         this->variables.push_tail(storage);
         this->next_temp += type_size(ir->type);
 
-        dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY,
-                                                             storage->index,
-                                                             NULL));
+        dst = dst_reg(src_reg(PROGRAM_TEMPORARY, storage->index, NULL));
       }
 
 
-      for (int a = 0; a < array_count; a++) {
-        for (unsigned int i = 0; i < statevar->num_elements; i++) {
-           struct gl_builtin_uniform_element *element = &statevar->elements[i];
-           int tokens[STATE_LENGTH];
+      for (unsigned int i = 0; i < ir->num_state_slots; i++) {
+        int index = _mesa_add_state_reference(this->prog->Parameters,
+                                              (gl_state_index *)slots[i].tokens);
 
-           memcpy(tokens, element->tokens, sizeof(element->tokens));
-           if (ir->type->is_array()) {
-              tokens[1] = a;
-           }
-
-           int index = _mesa_add_state_reference(this->prog->Parameters,
-                                                 (gl_state_index *)tokens);
-
-           if (storage->file == PROGRAM_STATE_VAR) {
-              if (storage->index == -1) {
-                 storage->index = index;
-              } else {
-                 assert(index ==
-                         (int)(storage->index + a * statevar->num_elements + i));
-              }
+        if (storage->file == PROGRAM_STATE_VAR) {
+           if (storage->index == -1) {
+              storage->index = index;
            } else {
-              ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL);
-              src.swizzle = element->swizzle;
-              ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src);
-              /* even a float takes up a whole vec4 reg in a struct/array. */
-              dst.index++;
+              assert(index == storage->index + (int)i);
            }
+        } else {
+           src_reg src(PROGRAM_STATE_VAR, index, NULL);
+           src.swizzle = slots[i].swizzle;
+           emit(ir, OPCODE_MOV, dst, src);
+           /* even a float takes up a whole vec4 reg in a struct/array. */
+           dst.index++;
         }
       }
+
       if (storage->file == PROGRAM_TEMPORARY &&
-         dst.index != storage->index + type_size(ir->type)) {
-        fail_link(this->shader_program,
-                  "failed to load builtin uniform `%s'  (%d/%d regs loaded)\n",
-                  ir->name, dst.index - storage->index,
-                  type_size(ir->type));
+         dst.index != storage->index + (int) ir->num_state_slots) {
+        linker_error(this->shader_program,
+                     "failed to load builtin uniform `%s' "
+                     "(%d/%d regs loaded)\n",
+                     ir->name, dst.index - storage->index,
+                     type_size(ir->type));
       }
    }
 }
@@ -829,51 +783,47 @@ ir_to_mesa_visitor::visit(ir_loop *ir)
    ir_dereference_variable *counter = NULL;
 
    if (ir->counter != NULL)
-      counter = new(ir) ir_dereference_variable(ir->counter);
+      counter = new(mem_ctx) ir_dereference_variable(ir->counter);
 
    if (ir->from != NULL) {
       assert(ir->counter != NULL);
 
-      ir_assignment *a = new(ir) ir_assignment(counter, ir->from, NULL);
+      ir_assignment *a =
+       new(mem_ctx) ir_assignment(counter, ir->from, NULL);
 
       a->accept(this);
-      delete a;
    }
 
-   ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
+   emit(NULL, OPCODE_BGNLOOP);
 
    if (ir->to) {
       ir_expression *e =
-        new(ir) ir_expression(ir->cmp, glsl_type::bool_type,
-                              counter, ir->to);
-      ir_if *if_stmt =  new(ir) ir_if(e);
+        new(mem_ctx) ir_expression(ir->cmp, glsl_type::bool_type,
+                                         counter, ir->to);
+      ir_if *if_stmt =  new(mem_ctx) ir_if(e);
 
-      ir_loop_jump *brk = new(ir) ir_loop_jump(ir_loop_jump::jump_break);
+      ir_loop_jump *brk =
+       new(mem_ctx) ir_loop_jump(ir_loop_jump::jump_break);
 
       if_stmt->then_instructions.push_tail(brk);
 
       if_stmt->accept(this);
-
-      delete if_stmt;
-      delete e;
-      delete brk;
    }
 
    visit_exec_list(&ir->body_instructions, this);
 
    if (ir->increment) {
       ir_expression *e =
-        new(ir) ir_expression(ir_binop_add, counter->type,
-                              counter, ir->increment);
+        new(mem_ctx) ir_expression(ir_binop_add, counter->type,
+                                         counter, ir->increment);
 
-      ir_assignment *a = new(ir) ir_assignment(counter, e, NULL);
+      ir_assignment *a =
+       new(mem_ctx) ir_assignment(counter, e, NULL);
 
       a->accept(this);
-      delete a;
-      delete e;
    }
 
-   ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
+   emit(NULL, OPCODE_ENDLOOP);
 }
 
 void
@@ -881,10 +831,10 @@ ir_to_mesa_visitor::visit(ir_loop_jump *ir)
 {
    switch (ir->mode) {
    case ir_loop_jump::jump_break:
-      ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
+      emit(NULL, OPCODE_BRK);
       break;
    case ir_loop_jump::jump_continue:
-      ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
+      emit(NULL, OPCODE_CONT);
       break;
    }
 }
@@ -923,7 +873,7 @@ GLboolean
 ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
 {
    int nonmul_operand = 1 - mul_operand;
-   ir_to_mesa_src_reg a, b, c;
+   src_reg a, b, c;
 
    ir_expression *expr = ir->operands[mul_operand]->as_expression();
    if (!expr || expr->operation != ir_binop_mul)
@@ -937,8 +887,7 @@ ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
    c = this->result;
 
    this->result = get_temp(ir->type);
-   ir_to_mesa_emit_op3(ir, OPCODE_MAD,
-                      ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
+   emit(ir, OPCODE_MAD, dst_reg(this->result), a, b, c);
 
    return true;
 }
@@ -957,32 +906,49 @@ ir_to_mesa_visitor::try_emit_sat(ir_expression *ir)
       return false;
 
    sat_src->accept(this);
-   ir_to_mesa_src_reg src = this->result;
+   src_reg src = this->result;
 
-   this->result = get_temp(ir->type);
-   ir_to_mesa_instruction *inst;
-   inst = ir_to_mesa_emit_op1(ir, OPCODE_MOV,
-                             ir_to_mesa_dst_reg_from_src(this->result),
-                             src);
-   inst->saturate = true;
+   /* If we generated an expression instruction into a temporary in
+    * processing the saturate's operand, apply the saturate to that
+    * instruction.  Otherwise, generate a MOV to do the saturate.
+    *
+    * Note that we have to be careful to only do this optimization if
+    * the instruction in question was what generated src->result.  For
+    * example, ir_dereference_array might generate a MUL instruction
+    * to create the reladdr, and return us a src reg using that
+    * reladdr.  That MUL result is not the value we're trying to
+    * saturate.
+    */
+   ir_expression *sat_src_expr = sat_src->as_expression();
+   ir_to_mesa_instruction *new_inst;
+   new_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+   if (sat_src_expr && (sat_src_expr->operation == ir_binop_mul ||
+                       sat_src_expr->operation == ir_binop_add ||
+                       sat_src_expr->operation == ir_binop_dot)) {
+      new_inst->saturate = true;
+   } else {
+      this->result = get_temp(ir->type);
+      ir_to_mesa_instruction *inst;
+      inst = emit(ir, OPCODE_MOV, dst_reg(this->result), src);
+      inst->saturate = true;
+   }
 
    return true;
 }
 
 void
 ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
-                                   ir_to_mesa_src_reg *reg, int *num_reladdr)
+                                   src_reg *reg, int *num_reladdr)
 {
    if (!reg->reladdr)
       return;
 
-   ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
+   emit(ir, OPCODE_ARL, address_reg, *reg->reladdr);
 
    if (*num_reladdr != 1) {
-      ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+      src_reg temp = get_temp(glsl_type::vec4_type);
 
-      ir_to_mesa_emit_op1(ir, OPCODE_MOV,
-                         ir_to_mesa_dst_reg_from_src(temp), *reg);
+      emit(ir, OPCODE_MOV, dst_reg(temp), *reg);
       *reg = temp;
    }
 
@@ -1078,7 +1044,7 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir)
       exit(1);
    }
 
-   ir_to_mesa_src_reg src;
+   src_reg src;
 
    src = this->result;
    src.swizzle = MAKE_SWIZZLE4(components[0],
@@ -1093,8 +1059,8 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir)
    /* Storage for our result.  Ideally for an assignment we'd be using the
     * actual storage for the result here, instead.
     */
-   const ir_to_mesa_src_reg result_src = get_temp(ir->type);
-   ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+   const src_reg result_src = get_temp(ir->type);
+   dst_reg result_dst = dst_reg(result_src);
 
    /* Limit writes to the channels that will be used by result_src later.
     * This does limit this temp's use as a temporary for multi-instruction
@@ -1102,7 +1068,7 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir)
     */
    result_dst.writemask = (1 << ir->type->vector_elements) - 1;
 
-   ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src);
+   emit(ir, OPCODE_SWZ, result_dst, src);
    this->result = result_src;
 }
 
@@ -1110,9 +1076,9 @@ void
 ir_to_mesa_visitor::visit(ir_expression *ir)
 {
    unsigned int operand;
-   struct ir_to_mesa_src_reg op[Elements(ir->operands)];
-   struct ir_to_mesa_src_reg result_src;
-   struct ir_to_mesa_dst_reg result_dst;
+   src_reg op[Elements(ir->operands)];
+   src_reg result_src;
+   dst_reg result_dst;
 
    /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
     */
@@ -1160,7 +1126,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
     */
    result_src = get_temp(ir->type);
    /* convenience for the emit functions below. */
-   result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+   result_dst = dst_reg(result_src);
    /* Limit writes to the channels that will be used by result_src later.
     * This does limit this temp's use as a temporary for multi-instruction
     * sequences.
@@ -1169,38 +1135,43 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
 
    switch (ir->operation) {
    case ir_unop_logic_not:
-      ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst,
-                         op[0], src_reg_for_float(0.0));
+      /* Previously 'SEQ dst, src, 0.0' was used for this.  However, many
+       * older GPUs implement SEQ using multiple instructions (i915 uses two
+       * SGE instructions and a MUL instruction).  Since our logic values are
+       * 0.0 and 1.0, 1-x also implements !x.
+       */
+      op[0].negate = ~op[0].negate;
+      emit(ir, OPCODE_ADD, result_dst, op[0], src_reg_for_float(1.0));
       break;
    case ir_unop_neg:
       op[0].negate = ~op[0].negate;
       result_src = op[0];
       break;
    case ir_unop_abs:
-      ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
+      emit(ir, OPCODE_ABS, result_dst, op[0]);
       break;
    case ir_unop_sign:
-      ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
+      emit(ir, OPCODE_SSG, result_dst, op[0]);
       break;
    case ir_unop_rcp:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_RCP, result_dst, op[0]);
       break;
 
    case ir_unop_exp2:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_EX2, result_dst, op[0]);
       break;
    case ir_unop_exp:
    case ir_unop_log:
       assert(!"not reached: should be handled by ir_explog_to_explog2");
       break;
    case ir_unop_log2:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_LG2, result_dst, op[0]);
       break;
    case ir_unop_sin:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_SIN, result_dst, op[0]);
       break;
    case ir_unop_cos:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_COS, result_dst, op[0]);
       break;
    case ir_unop_sin_reduced:
       emit_scs(ir, OPCODE_SIN, result_dst, op[0]);
@@ -1210,10 +1181,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
       break;
 
    case ir_unop_dFdx:
-      ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
+      emit(ir, OPCODE_DDX, result_dst, op[0]);
       break;
    case ir_unop_dFdy:
-      ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
+      emit(ir, OPCODE_DDY, result_dst, op[0]);
       break;
 
    case ir_unop_noise: {
@@ -1222,19 +1193,19 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
                     + (ir->operands[0]->type->vector_elements) - 1);
       assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4));
 
-      ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]);
+      emit(ir, opcode, result_dst, op[0]);
       break;
    }
 
    case ir_binop_add:
-      ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_ADD, result_dst, op[0], op[1]);
       break;
    case ir_binop_sub:
-      ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SUB, result_dst, op[0], op[1]);
       break;
 
    case ir_binop_mul:
-      ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_MUL, result_dst, op[0], op[1]);
       break;
    case ir_binop_div:
       assert(!"not reached: should be handled by ir_div_to_mul_rcp");
@@ -1243,142 +1214,168 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
       break;
 
    case ir_binop_less:
-      ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SLT, result_dst, op[0], op[1]);
       break;
    case ir_binop_greater:
-      ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SGT, result_dst, op[0], op[1]);
       break;
    case ir_binop_lequal:
-      ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SLE, result_dst, op[0], op[1]);
       break;
    case ir_binop_gequal:
-      ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SGE, result_dst, op[0], op[1]);
       break;
    case ir_binop_equal:
-      ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
       break;
    case ir_binop_nequal:
-      ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
       break;
    case ir_binop_all_equal:
       /* "==" operator producing a scalar boolean. */
       if (ir->operands[0]->type->is_vector() ||
          ir->operands[1]->type->is_vector()) {
-        ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
-        ir_to_mesa_emit_op2(ir, OPCODE_SNE,
-                            ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
-        ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
-        ir_to_mesa_emit_op2(ir, OPCODE_SEQ,
-                            result_dst, result_src, src_reg_for_float(0.0));
+        src_reg temp = get_temp(glsl_type::vec4_type);
+        emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]);
+        emit_dp(ir, result_dst, temp, temp, vector_elements);
+        emit(ir, OPCODE_SEQ, result_dst, result_src, src_reg_for_float(0.0));
       } else {
-        ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+        emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
       }
       break;
    case ir_binop_any_nequal:
       /* "!=" operator producing a scalar boolean. */
       if (ir->operands[0]->type->is_vector() ||
          ir->operands[1]->type->is_vector()) {
-        ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
-        ir_to_mesa_emit_op2(ir, OPCODE_SNE,
-                            ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]);
-        ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements);
-        ir_to_mesa_emit_op2(ir, OPCODE_SNE,
-                            result_dst, result_src, src_reg_for_float(0.0));
+        src_reg temp = get_temp(glsl_type::vec4_type);
+        emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]);
+        emit_dp(ir, result_dst, temp, temp, vector_elements);
+        emit(ir, OPCODE_SNE, result_dst, result_src, src_reg_for_float(0.0));
       } else {
-        ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+        emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
       }
       break;
 
-   case ir_unop_any:
+   case ir_unop_any: {
       assert(ir->operands[0]->type->is_vector());
-      ir_to_mesa_emit_dp(ir, result_dst, op[0], op[0],
-                        ir->operands[0]->type->vector_elements);
-      ir_to_mesa_emit_op2(ir, OPCODE_SNE,
-                         result_dst, result_src, src_reg_for_float(0.0));
+
+      /* After the dot-product, the value will be an integer on the
+       * range [0,4].  Zero stays zero, and positive values become 1.0.
+       */
+      ir_to_mesa_instruction *const dp =
+        emit_dp(ir, result_dst, op[0], op[0],
+                ir->operands[0]->type->vector_elements);
+      if (this->prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
+        /* The clamping to [0,1] can be done for free in the fragment
+         * shader with a saturate.
+         */
+        dp->saturate = true;
+      } else {
+        /* Negating the result of the dot-product gives values on the range
+         * [-4, 0].  Zero stays zero, and negative values become 1.0.  This
+         * is achieved using SLT.
+         */
+        src_reg slt_src = result_src;
+        slt_src.negate = ~slt_src.negate;
+        emit(ir, OPCODE_SLT, result_dst, slt_src, src_reg_for_float(0.0));
+      }
       break;
+   }
 
    case ir_binop_logic_xor:
-      ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
       break;
 
-   case ir_binop_logic_or:
-      /* This could be a saturated add and skip the SNE. */
-      ir_to_mesa_emit_op2(ir, OPCODE_ADD,
-                         result_dst,
-                         op[0], op[1]);
-
-      ir_to_mesa_emit_op2(ir, OPCODE_SNE,
-                         result_dst,
-                         result_src, src_reg_for_float(0.0));
+   case ir_binop_logic_or: {
+      /* After the addition, the value will be an integer on the
+       * range [0,2].  Zero stays zero, and positive values become 1.0.
+       */
+      ir_to_mesa_instruction *add =
+        emit(ir, OPCODE_ADD, result_dst, op[0], op[1]);
+      if (this->prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
+        /* The clamping to [0,1] can be done for free in the fragment
+         * shader with a saturate.
+         */
+        add->saturate = true;
+      } else {
+        /* Negating the result of the addition gives values on the range
+         * [-2, 0].  Zero stays zero, and negative values become 1.0.  This
+         * is achieved using SLT.
+         */
+        src_reg slt_src = result_src;
+        slt_src.negate = ~slt_src.negate;
+        emit(ir, OPCODE_SLT, result_dst, slt_src, src_reg_for_float(0.0));
+      }
       break;
+   }
 
    case ir_binop_logic_and:
       /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */
-      ir_to_mesa_emit_op2(ir, OPCODE_MUL,
-                         result_dst,
-                         op[0], op[1]);
+      emit(ir, OPCODE_MUL, result_dst, op[0], op[1]);
       break;
 
    case ir_binop_dot:
       assert(ir->operands[0]->type->is_vector());
       assert(ir->operands[0]->type == ir->operands[1]->type);
-      ir_to_mesa_emit_dp(ir, result_dst, op[0], op[1],
-                        ir->operands[0]->type->vector_elements);
+      emit_dp(ir, result_dst, op[0], op[1],
+             ir->operands[0]->type->vector_elements);
       break;
 
    case ir_unop_sqrt:
       /* sqrt(x) = x * rsq(x). */
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
-      ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]);
+      emit_scalar(ir, OPCODE_RSQ, result_dst, op[0]);
+      emit(ir, OPCODE_MUL, result_dst, result_src, op[0]);
       /* For incoming channels <= 0, set the result to 0. */
       op[0].negate = ~op[0].negate;
-      ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
+      emit(ir, OPCODE_CMP, result_dst,
                          op[0], result_src, src_reg_for_float(0.0));
       break;
    case ir_unop_rsq:
-      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+      emit_scalar(ir, OPCODE_RSQ, result_dst, op[0]);
       break;
    case ir_unop_i2f:
+   case ir_unop_u2f:
    case ir_unop_b2f:
    case ir_unop_b2i:
+   case ir_unop_i2u:
+   case ir_unop_u2i:
       /* Mesa IR lacks types, ints are stored as truncated floats. */
       result_src = op[0];
       break;
    case ir_unop_f2i:
-      ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+      emit(ir, OPCODE_TRUNC, result_dst, op[0]);
       break;
    case ir_unop_f2b:
    case ir_unop_i2b:
-      ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
+      emit(ir, OPCODE_SNE, result_dst,
                          op[0], src_reg_for_float(0.0));
       break;
    case ir_unop_trunc:
-      ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
+      emit(ir, OPCODE_TRUNC, result_dst, op[0]);
       break;
    case ir_unop_ceil:
       op[0].negate = ~op[0].negate;
-      ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+      emit(ir, OPCODE_FLR, result_dst, op[0]);
       result_src.negate = ~result_src.negate;
       break;
    case ir_unop_floor:
-      ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+      emit(ir, OPCODE_FLR, result_dst, op[0]);
       break;
    case ir_unop_fract:
-      ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
+      emit(ir, OPCODE_FRC, result_dst, op[0]);
       break;
 
    case ir_binop_min:
-      ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_MIN, result_dst, op[0], op[1]);
       break;
    case ir_binop_max:
-      ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
+      emit(ir, OPCODE_MAX, result_dst, op[0], op[1]);
       break;
    case ir_binop_pow:
-      ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
+      emit_scalar(ir, OPCODE_POW, result_dst, op[0], op[1]);
       break;
 
    case ir_unop_bit_not:
-   case ir_unop_u2f:
    case ir_binop_lshift:
    case ir_binop_rshift:
    case ir_binop_bit_and:
@@ -1402,7 +1399,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir)
 void
 ir_to_mesa_visitor::visit(ir_swizzle *ir)
 {
-   ir_to_mesa_src_reg src_reg;
+   src_reg src;
    int i;
    int swizzle[4];
 
@@ -1412,23 +1409,23 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir)
     */
 
    ir->val->accept(this);
-   src_reg = this->result;
-   assert(src_reg.file != PROGRAM_UNDEFINED);
+   src = this->result;
+   assert(src.file != PROGRAM_UNDEFINED);
 
    for (i = 0; i < 4; i++) {
       if (i < ir->type->vector_elements) {
         switch (i) {
         case 0:
-           swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
+           swizzle[i] = GET_SWZ(src.swizzle, ir->mask.x);
            break;
         case 1:
-           swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
+           swizzle[i] = GET_SWZ(src.swizzle, ir->mask.y);
            break;
         case 2:
-           swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
+           swizzle[i] = GET_SWZ(src.swizzle, ir->mask.z);
            break;
         case 3:
-           swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
+           swizzle[i] = GET_SWZ(src.swizzle, ir->mask.w);
            break;
         }
       } else {
@@ -1439,122 +1436,131 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir)
       }
    }
 
-   src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
-                                  swizzle[1],
-                                  swizzle[2],
-                                  swizzle[3]);
+   src.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
 
-   this->result = src_reg;
+   this->result = src;
 }
 
 void
 ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
 {
    variable_storage *entry = find_variable_storage(ir->var);
+   ir_variable *var = ir->var;
 
    if (!entry) {
-      switch (ir->var->mode) {
+      switch (var->mode) {
       case ir_var_uniform:
-        entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_UNIFORM,
-                                              ir->var->location);
+        entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM,
+                                              var->location);
         this->variables.push_tail(entry);
         break;
       case ir_var_in:
-      case ir_var_out:
       case ir_var_inout:
         /* The linker assigns locations for varyings and attributes,
-         * including deprecated builtins (like gl_Color), user-assign
-         * generic attributes (glBindVertexLocation), and
-         * user-defined varyings.
+         * including deprecated builtins (like gl_Color),
+         * user-assigned generic attributes (glBindVertexLocation),
+         * and user-defined varyings.
          *
          * FINISHME: We would hit this path for function arguments.  Fix!
          */
-        assert(ir->var->location != -1);
-        if (ir->var->mode == ir_var_in ||
-            ir->var->mode == ir_var_inout) {
-           entry = new(mem_ctx) variable_storage(ir->var,
-                                                 PROGRAM_INPUT,
-                                                 ir->var->location);
-
-           if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
-               ir->var->location >= VERT_ATTRIB_GENERIC0) {
-              _mesa_add_attribute(prog->Attributes,
-                                  ir->var->name,
-                                  _mesa_sizeof_glsl_type(ir->var->type->gl_type),
-                                  ir->var->type->gl_type,
-                                  ir->var->location - VERT_ATTRIB_GENERIC0);
-           }
-        } else {
-           entry = new(mem_ctx) variable_storage(ir->var,
-                                                 PROGRAM_OUTPUT,
-                                                 ir->var->location);
-        }
-
+        assert(var->location != -1);
+         entry = new(mem_ctx) variable_storage(var,
+                                               PROGRAM_INPUT,
+                                               var->location);
+         if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
+             var->location >= VERT_ATTRIB_GENERIC0) {
+            _mesa_add_attribute(this->prog->Attributes,
+                                var->name,
+                                _mesa_sizeof_glsl_type(var->type->gl_type),
+                                var->type->gl_type,
+                                var->location - VERT_ATTRIB_GENERIC0);
+         }
+         break;
+      case ir_var_out:
+        assert(var->location != -1);
+         entry = new(mem_ctx) variable_storage(var,
+                                               PROGRAM_OUTPUT,
+                                               var->location);
         break;
+      case ir_var_system_value:
+         entry = new(mem_ctx) variable_storage(var,
+                                               PROGRAM_SYSTEM_VALUE,
+                                               var->location);
+         break;
       case ir_var_auto:
       case ir_var_temporary:
-        entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY,
+        entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY,
                                               this->next_temp);
         this->variables.push_tail(entry);
 
-        next_temp += type_size(ir->var->type);
+        next_temp += type_size(var->type);
         break;
       }
 
       if (!entry) {
-        printf("Failed to make storage for %s\n", ir->var->name);
+        printf("Failed to make storage for %s\n", var->name);
         exit(1);
       }
    }
 
-   this->result = ir_to_mesa_src_reg(entry->file, entry->index, ir->var->type);
+   this->result = src_reg(entry->file, entry->index, var->type);
 }
 
 void
 ir_to_mesa_visitor::visit(ir_dereference_array *ir)
 {
    ir_constant *index;
-   ir_to_mesa_src_reg src_reg;
+   src_reg src;
    int element_size = type_size(ir->type);
 
    index = ir->array_index->constant_expression_value();
 
    ir->array->accept(this);
-   src_reg = this->result;
+   src = this->result;
 
    if (index) {
-      src_reg.index += index->value.i[0] * element_size;
+      src.index += index->value.i[0] * element_size;
    } else {
-      ir_to_mesa_src_reg array_base = this->result;
       /* Variable index array dereference.  It eats the "vec4" of the
        * base of the array and an index that offsets the Mesa register
        * index.
        */
       ir->array_index->accept(this);
 
-      ir_to_mesa_src_reg index_reg;
+      src_reg index_reg;
 
       if (element_size == 1) {
         index_reg = this->result;
       } else {
         index_reg = get_temp(glsl_type::float_type);
 
-        ir_to_mesa_emit_op2(ir, OPCODE_MUL,
-                            ir_to_mesa_dst_reg_from_src(index_reg),
-                            this->result, src_reg_for_float(element_size));
+        emit(ir, OPCODE_MUL, dst_reg(index_reg),
+             this->result, src_reg_for_float(element_size));
+      }
+
+      /* If there was already a relative address register involved, add the
+       * new and the old together to get the new offset.
+       */
+      if (src.reladdr != NULL)  {
+        src_reg accum_reg = get_temp(glsl_type::float_type);
+
+        emit(ir, OPCODE_ADD, dst_reg(accum_reg),
+             index_reg, *src.reladdr);
+
+        index_reg = accum_reg;
       }
 
-      src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
-      memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
+      src.reladdr = ralloc(mem_ctx, src_reg);
+      memcpy(src.reladdr, &index_reg, sizeof(index_reg));
    }
 
    /* If the type is smaller than a vec4, replicate the last channel out. */
    if (ir->type->is_scalar() || ir->type->is_vector())
-      src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
+      src.swizzle = swizzle_for_size(ir->type->vector_elements);
    else
-      src_reg.swizzle = SWIZZLE_NOOP;
+      src.swizzle = SWIZZLE_NOOP;
 
-   this->result = src_reg;
+   this->result = src;
 }
 
 void
@@ -1586,7 +1592,7 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir)
  * instead of potentially using a temporary like we might with the
  * ir_dereference handler.
  */
-static struct ir_to_mesa_dst_reg
+static dst_reg
 get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
 {
    /* The LHS must be a dereference.  If the LHS is a variable indexed array
@@ -1603,7 +1609,7 @@ get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v)
     * swizzles in it and write swizzles using writemask, though.
     */
    ir->accept(v);
-   return ir_to_mesa_dst_reg_from_src(v->result);
+   return dst_reg(v->result);
 }
 
 /**
@@ -1696,8 +1702,8 @@ ir_to_mesa_visitor::process_move_condition(ir_rvalue *ir)
 void
 ir_to_mesa_visitor::visit(ir_assignment *ir)
 {
-   struct ir_to_mesa_dst_reg l;
-   struct ir_to_mesa_src_reg r;
+   dst_reg l;
+   src_reg r;
    int i;
 
    ir->rhs->accept(this);
@@ -1753,15 +1759,13 @@ ir_to_mesa_visitor::visit(ir_assignment *ir)
 
    if (ir->condition) {
       const bool switch_order = this->process_move_condition(ir->condition);
-      ir_to_mesa_src_reg condition = this->result;
+      src_reg condition = this->result;
 
       for (i = 0; i < type_size(ir->lhs->type); i++) {
         if (switch_order) {
-           ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
-                               condition, ir_to_mesa_src_reg_from_dst(l), r);
+           emit(ir, OPCODE_CMP, l, condition, src_reg(l), r);
         } else {
-           ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
-                               condition, r, ir_to_mesa_src_reg_from_dst(l));
+           emit(ir, OPCODE_CMP, l, condition, r, src_reg(l));
         }
 
         l.index++;
@@ -1769,7 +1773,7 @@ ir_to_mesa_visitor::visit(ir_assignment *ir)
       }
    } else {
       for (i = 0; i < type_size(ir->lhs->type); i++) {
-        ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+        emit(ir, OPCODE_MOV, l, r);
         l.index++;
         r.index++;
       }
@@ -1780,7 +1784,7 @@ ir_to_mesa_visitor::visit(ir_assignment *ir)
 void
 ir_to_mesa_visitor::visit(ir_constant *ir)
 {
-   ir_to_mesa_src_reg src_reg;
+   src_reg src;
    GLfloat stack_vals[4] = { 0 };
    GLfloat *values = stack_vals;
    unsigned int i;
@@ -1792,8 +1796,8 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
     */
 
    if (ir->type->base_type == GLSL_TYPE_STRUCT) {
-      ir_to_mesa_src_reg temp_base = get_temp(ir->type);
-      ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+      src_reg temp_base = get_temp(ir->type);
+      dst_reg temp = dst_reg(temp_base);
 
       foreach_iter(exec_list_iterator, iter, ir->components) {
         ir_constant *field_value = (ir_constant *)iter.get();
@@ -1802,12 +1806,12 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
         assert(size > 0);
 
         field_value->accept(this);
-        src_reg = this->result;
+        src = this->result;
 
         for (i = 0; i < (unsigned int)size; i++) {
-           ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+           emit(ir, OPCODE_MOV, temp, src);
 
-           src_reg.index++;
+           src.index++;
            temp.index++;
         }
       }
@@ -1816,19 +1820,19 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
    }
 
    if (ir->type->is_array()) {
-      ir_to_mesa_src_reg temp_base = get_temp(ir->type);
-      ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base);
+      src_reg temp_base = get_temp(ir->type);
+      dst_reg temp = dst_reg(temp_base);
       int size = type_size(ir->type->fields.array);
 
       assert(size > 0);
 
       for (i = 0; i < ir->type->length; i++) {
         ir->array_elements[i]->accept(this);
-        src_reg = this->result;
+        src = this->result;
         for (int j = 0; j < size; j++) {
-           ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg);
+           emit(ir, OPCODE_MOV, temp, src);
 
-           src_reg.index++;
+           src.index++;
            temp.index++;
         }
       }
@@ -1837,19 +1841,19 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
    }
 
    if (ir->type->is_matrix()) {
-      ir_to_mesa_src_reg mat = get_temp(ir->type);
-      ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
+      src_reg mat = get_temp(ir->type);
+      dst_reg mat_column = dst_reg(mat);
 
       for (i = 0; i < ir->type->matrix_columns; i++) {
         assert(ir->type->base_type == GLSL_TYPE_FLOAT);
         values = &ir->value.f[i * ir->type->vector_elements];
 
-        src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL);
-        src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
-                                               values,
+        src = src_reg(PROGRAM_CONSTANT, -1, NULL);
+        src.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+                                               (gl_constant_value *) values,
                                                ir->type->vector_elements,
-                                               &src_reg.swizzle);
-        ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
+                                               &src.swizzle);
+        emit(ir, OPCODE_MOV, mat_column, src);
 
         mat_column.index++;
       }
@@ -1858,7 +1862,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
       return;
    }
 
-   src_reg.file = PROGRAM_CONSTANT;
+   src.file = PROGRAM_CONSTANT;
    switch (ir->type->base_type) {
    case GLSL_TYPE_FLOAT:
       values = &ir->value.f[0];
@@ -1882,9 +1886,9 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
       assert(!"Non-float/uint/int/bool constant");
    }
 
-   this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type);
+   this->result = src_reg(PROGRAM_CONSTANT, -1, ir->type);
    this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters,
-                                                  values,
+                                                  (gl_constant_value *) values,
                                                   ir->type->vector_elements,
                                                   &this->result.swizzle);
 }
@@ -1901,7 +1905,7 @@ ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
         return entry;
    }
 
-   entry = talloc(mem_ctx, function_entry);
+   entry = ralloc(mem_ctx, function_entry);
    entry->sig = sig;
    entry->sig_id = this->next_signature_id++;
    entry->bgn_inst = NULL;
@@ -1924,7 +1928,7 @@ ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
    if (!sig->return_type->is_void()) {
       entry->return_reg = get_temp(sig->return_type);
    } else {
-      entry->return_reg = ir_to_mesa_undef;
+      entry->return_reg = undef_src;
    }
 
    this->function_signatures.push_tail(entry);
@@ -1951,9 +1955,9 @@ ir_to_mesa_visitor::visit(ir_call *ir)
         assert(storage);
 
         param_rval->accept(this);
-        ir_to_mesa_src_reg r = this->result;
+        src_reg r = this->result;
 
-        ir_to_mesa_dst_reg l;
+        dst_reg l;
         l.file = storage->file;
         l.index = storage->index;
         l.reladdr = NULL;
@@ -1961,7 +1965,7 @@ ir_to_mesa_visitor::visit(ir_call *ir)
         l.cond_mask = COND_TR;
 
         for (i = 0; i < type_size(param->type); i++) {
-           ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+           emit(ir, OPCODE_MOV, l, r);
            l.index++;
            r.index++;
         }
@@ -1972,8 +1976,7 @@ ir_to_mesa_visitor::visit(ir_call *ir)
    assert(!sig_iter.has_next());
 
    /* Emit call instruction */
-   call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
-                                  ir_to_mesa_undef_dst, ir_to_mesa_undef);
+   call_inst = emit(ir, OPCODE_CAL);
    call_inst->function = entry;
 
    /* Process out parameters. */
@@ -1987,7 +1990,7 @@ ir_to_mesa_visitor::visit(ir_call *ir)
         variable_storage *storage = find_variable_storage(param);
         assert(storage);
 
-        ir_to_mesa_src_reg r;
+        src_reg r;
         r.file = storage->file;
         r.index = storage->index;
         r.reladdr = NULL;
@@ -1995,10 +1998,10 @@ ir_to_mesa_visitor::visit(ir_call *ir)
         r.negate = 0;
 
         param_rval->accept(this);
-        ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
+        dst_reg l = dst_reg(this->result);
 
         for (i = 0; i < type_size(param->type); i++) {
-           ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+           emit(ir, OPCODE_MOV, l, r);
            l.index++;
            r.index++;
         }
@@ -2015,8 +2018,8 @@ ir_to_mesa_visitor::visit(ir_call *ir)
 void
 ir_to_mesa_visitor::visit(ir_texture *ir)
 {
-   ir_to_mesa_src_reg result_src, coord, lod_info, projector;
-   ir_to_mesa_dst_reg result_dst, coord_dst;
+   src_reg result_src, coord, lod_info, projector, dx, dy;
+   dst_reg result_dst, coord_dst;
    ir_to_mesa_instruction *inst = NULL;
    prog_opcode opcode = OPCODE_NOP;
 
@@ -2028,9 +2031,8 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
     * handle cleaning up our mess in that case.
     */
    coord = get_temp(glsl_type::vec4_type);
-   coord_dst = ir_to_mesa_dst_reg_from_src(coord);
-   ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
-                      this->result);
+   coord_dst = dst_reg(coord);
+   emit(ir, OPCODE_MOV, coord_dst, this->result);
 
    if (ir->projector) {
       ir->projector->accept(this);
@@ -2041,7 +2043,7 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
     * the actual storage for the result here, instead.
     */
    result_src = get_temp(glsl_type::vec4_type);
-   result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+   result_dst = dst_reg(result_src);
 
    switch (ir->op) {
    case ir_tex:
@@ -2058,6 +2060,12 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
       lod_info = this->result;
       break;
    case ir_txd:
+      opcode = OPCODE_TXD;
+      ir->lod_info.grad.dPdx->accept(this);
+      dx = this->result;
+      ir->lod_info.grad.dPdy->accept(this);
+      dy = this->result;
+      break;
    case ir_txf:
       assert(!"GLSL 1.30 features unsupported");
       break;
@@ -2067,11 +2075,11 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
       if (opcode == OPCODE_TEX) {
         /* Slot the projector in as the last component of the coord. */
         coord_dst.writemask = WRITEMASK_W;
-        ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
+        emit(ir, OPCODE_MOV, coord_dst, projector);
         coord_dst.writemask = WRITEMASK_XYZW;
         opcode = OPCODE_TXP;
       } else {
-        ir_to_mesa_src_reg coord_w = coord;
+        src_reg coord_w = coord;
         coord_w.swizzle = SWIZZLE_WWWW;
 
         /* For the other TEX opcodes there's no projective version
@@ -2079,34 +2087,61 @@ ir_to_mesa_visitor::visit(ir_texture *ir)
          * projective divide now.
          */
         coord_dst.writemask = WRITEMASK_W;
-        ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
+        emit(ir, OPCODE_RCP, coord_dst, projector);
+
+        /* In the case where we have to project the coordinates "by hand,"
+         * the shadow comparitor value must also be projected.
+         */
+        src_reg tmp_src = coord;
+        if (ir->shadow_comparitor) {
+           /* Slot the shadow value in as the second to last component of the
+            * coord.
+            */
+           ir->shadow_comparitor->accept(this);
+
+           tmp_src = get_temp(glsl_type::vec4_type);
+           dst_reg tmp_dst = dst_reg(tmp_src);
+
+           tmp_dst.writemask = WRITEMASK_Z;
+           emit(ir, OPCODE_MOV, tmp_dst, this->result);
+
+           tmp_dst.writemask = WRITEMASK_XY;
+           emit(ir, OPCODE_MOV, tmp_dst, coord);
+        }
 
         coord_dst.writemask = WRITEMASK_XYZ;
-        ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
+        emit(ir, OPCODE_MUL, coord_dst, tmp_src, coord_w);
 
         coord_dst.writemask = WRITEMASK_XYZW;
         coord.swizzle = SWIZZLE_XYZW;
       }
    }
 
-   if (ir->shadow_comparitor) {
+   /* If projection is done and the opcode is not OPCODE_TXP, then the shadow
+    * comparitor was put in the correct place (and projected) by the code,
+    * above, that handles by-hand projection.
+    */
+   if (ir->shadow_comparitor && (!ir->projector || opcode == OPCODE_TXP)) {
       /* Slot the shadow value in as the second to last component of the
        * coord.
        */
       ir->shadow_comparitor->accept(this);
       coord_dst.writemask = WRITEMASK_Z;
-      ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
+      emit(ir, OPCODE_MOV, coord_dst, this->result);
       coord_dst.writemask = WRITEMASK_XYZW;
    }
 
    if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
       /* Mesa IR stores lod or lod bias in the last channel of the coords. */
       coord_dst.writemask = WRITEMASK_W;
-      ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
+      emit(ir, OPCODE_MOV, coord_dst, lod_info);
       coord_dst.writemask = WRITEMASK_XYZW;
    }
 
-   inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
+   if (opcode == OPCODE_TXD)
+      inst = emit(ir, opcode, result_dst, coord, dx, dy);
+   else
+      inst = emit(ir, opcode, result_dst, coord);
 
    if (ir->shadow_comparitor)
       inst->tex_shadow = GL_TRUE;
@@ -2149,24 +2184,24 @@ void
 ir_to_mesa_visitor::visit(ir_return *ir)
 {
    if (ir->get_value()) {
-      ir_to_mesa_dst_reg l;
+      dst_reg l;
       int i;
 
       assert(current_function);
 
       ir->get_value()->accept(this);
-      ir_to_mesa_src_reg r = this->result;
+      src_reg r = this->result;
 
-      l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
+      l = dst_reg(current_function->return_reg);
 
       for (i = 0; i < type_size(current_function->sig->return_type); i++) {
-        ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+        emit(ir, OPCODE_MOV, l, r);
         l.index++;
         r.index++;
       }
    }
 
-   ir_to_mesa_emit_op0(ir, OPCODE_RET);
+   emit(ir, OPCODE_RET);
 }
 
 void
@@ -2177,9 +2212,9 @@ ir_to_mesa_visitor::visit(ir_discard *ir)
    if (ir->condition) {
       ir->condition->accept(this);
       this->result.negate = ~this->result.negate;
-      ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result);
+      emit(ir, OPCODE_KIL, undef_dst, this->result);
    } else {
-      ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
+      emit(ir, OPCODE_KIL_NV);
    }
 
    fp->UsesKill = GL_TRUE;
@@ -2188,7 +2223,7 @@ ir_to_mesa_visitor::visit(ir_discard *ir)
 void
 ir_to_mesa_visitor::visit(ir_if *ir)
 {
-   ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
+   ir_to_mesa_instruction *cond_inst, *if_inst;
    ir_to_mesa_instruction *prev_inst;
 
    prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
@@ -2204,19 +2239,15 @@ ir_to_mesa_visitor::visit(ir_if *ir)
        * have something to set cond_update on.
        */
       if (cond_inst == prev_inst) {
-        ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
-        cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
-                                        ir_to_mesa_dst_reg_from_src(temp),
-                                        result);
+        src_reg temp = get_temp(glsl_type::bool_type);
+        cond_inst = emit(ir->condition, OPCODE_MOV, dst_reg(temp), result);
       }
       cond_inst->cond_update = GL_TRUE;
 
-      if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
-      if_inst->dst_reg.cond_mask = COND_NE;
+      if_inst = emit(ir->condition, OPCODE_IF);
+      if_inst->dst.cond_mask = COND_NE;
    } else {
-      if_inst = ir_to_mesa_emit_op1(ir->condition,
-                                   OPCODE_IF, ir_to_mesa_undef_dst,
-                                   this->result);
+      if_inst = emit(ir->condition, OPCODE_IF, undef_dst, this->result);
    }
 
    this->instructions.push_tail(if_inst);
@@ -2224,12 +2255,11 @@ ir_to_mesa_visitor::visit(ir_if *ir)
    visit_exec_list(&ir->then_instructions, this);
 
    if (!ir->else_instructions.is_empty()) {
-      else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
+      emit(ir->condition, OPCODE_ELSE);
       visit_exec_list(&ir->else_instructions, this);
    }
 
-   if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
-                                ir_to_mesa_undef_dst, ir_to_mesa_undef);
+   if_inst = emit(ir->condition, OPCODE_ENDIF);
 }
 
 ir_to_mesa_visitor::ir_to_mesa_visitor()
@@ -2238,16 +2268,16 @@ ir_to_mesa_visitor::ir_to_mesa_visitor()
    next_temp = 1;
    next_signature_id = 1;
    current_function = NULL;
-   mem_ctx = talloc_new(NULL);
+   mem_ctx = ralloc_context(NULL);
 }
 
 ir_to_mesa_visitor::~ir_to_mesa_visitor()
 {
-   talloc_free(mem_ctx);
+   ralloc_free(mem_ctx);
 }
 
 static struct prog_src_register
-mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
+mesa_src_reg_from_ir_src_reg(src_reg reg)
 {
    struct prog_src_register mesa_reg;
 
@@ -2292,8 +2322,8 @@ set_branchtargets(ir_to_mesa_visitor *v,
       }
    }
 
-   if_stack = talloc_zero_array(v->mem_ctx, int, if_count);
-   loop_stack = talloc_zero_array(v->mem_ctx, int, loop_count);
+   if_stack = rzalloc_array(v->mem_ctx, int, if_count);
+   loop_stack = rzalloc_array(v->mem_ctx, int, loop_count);
 
    for (i = 0; i < num_instructions; i++) {
       switch (mesa_instructions[i].Opcode) {
@@ -2380,6 +2410,11 @@ print_program(struct prog_instruction *mesa_instructions,
    }
 }
 
+
+/**
+ * Count resources used by the given gpu program (number of texture
+ * samplers, etc).
+ */
 static void
 count_resources(struct gl_program *prog)
 {
@@ -2403,6 +2438,58 @@ count_resources(struct gl_program *prog)
    _mesa_update_shader_textures_used(prog);
 }
 
+
+/**
+ * Check if the given vertex/fragment/shader program is within the
+ * resource limits of the context (number of texture units, etc).
+ * If any of those checks fail, record a linker error.
+ *
+ * XXX more checks are needed...
+ */
+static void
+check_resources(const struct gl_context *ctx,
+                struct gl_shader_program *shader_program,
+                struct gl_program *prog)
+{
+   switch (prog->Target) {
+   case GL_VERTEX_PROGRAM_ARB:
+      if (_mesa_bitcount(prog->SamplersUsed) >
+          ctx->Const.MaxVertexTextureImageUnits) {
+         linker_error(shader_program,
+                     "Too many vertex shader texture samplers");
+      }
+      if (prog->Parameters->NumParameters > MAX_UNIFORMS) {
+         linker_error(shader_program, "Too many vertex shader constants");
+      }
+      break;
+   case MESA_GEOMETRY_PROGRAM:
+      if (_mesa_bitcount(prog->SamplersUsed) >
+          ctx->Const.MaxGeometryTextureImageUnits) {
+         linker_error(shader_program,
+                     "Too many geometry shader texture samplers");
+      }
+      if (prog->Parameters->NumParameters >
+          MAX_GEOMETRY_UNIFORM_COMPONENTS / 4) {
+         linker_error(shader_program, "Too many geometry shader constants");
+      }
+      break;
+   case GL_FRAGMENT_PROGRAM_ARB:
+      if (_mesa_bitcount(prog->SamplersUsed) >
+          ctx->Const.MaxTextureImageUnits) {
+         linker_error(shader_program,
+                     "Too many fragment shader texture samplers");
+      }
+      if (prog->Parameters->NumParameters > MAX_UNIFORMS) {
+         linker_error(shader_program, "Too many fragment shader constants");
+      }
+      break;
+   default:
+      _mesa_problem(ctx, "unexpected program type in check_resources()");
+   }
+}
+
+
+
 struct uniform_sort {
    struct gl_uniform *u;
    int pos;
@@ -2436,7 +2523,7 @@ add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
    unsigned int next_sampler = 0, num_uniforms = 0;
    struct uniform_sort *sorted_uniforms;
 
-   sorted_uniforms = talloc_array(NULL, struct uniform_sort,
+   sorted_uniforms = ralloc_array(NULL, struct uniform_sort,
                                  shader_program->Uniforms->NumUniforms);
 
    for (i = 0; i < shader_program->Uniforms->NumUniforms; i++) {
@@ -2501,21 +2588,22 @@ add_uniforms_to_parameters_list(struct gl_shader_program *shader_program,
          */
         if (file == PROGRAM_SAMPLER) {
            for (unsigned int j = 0; j < size / 4; j++)
-              prog->Parameters->ParameterValues[index + j][0] = next_sampler++;
+              prog->Parameters->ParameterValues[index + j][0].f = next_sampler++;
         }
 
         /* The location chosen in the Parameters list here (returned
          * from _mesa_add_uniform) has to match what the linker chose.
          */
         if (index != parameter_index) {
-           fail_link(shader_program, "Allocation of uniform `%s' to target "
-                     "failed (%d vs %d)\n",
-                     uniform->Name, index, parameter_index);
+           linker_error(shader_program,
+                        "Allocation of uniform `%s' to target failed "
+                        "(%d vs %d)\n",
+                        uniform->Name, index, parameter_index);
         }
       }
    }
 
-   talloc_free(sorted_uniforms);
+   ralloc_free(sorted_uniforms);
 }
 
 static void
@@ -2531,7 +2619,7 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
 
       for (unsigned int i = 0; i < type->length; i++) {
         const glsl_type *field_type = type->fields.structure[i].type;
-        const char *field_name = talloc_asprintf(mem_ctx, "%s.%s", name,
+        const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
                                            type->fields.structure[i].name);
         set_uniform_initializer(ctx, mem_ctx, shader_program, field_name,
                                 field_type, field_constant);
@@ -2543,8 +2631,8 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
    int loc = _mesa_get_uniform_location(ctx, shader_program, name);
 
    if (loc == -1) {
-      fail_link(shader_program,
-               "Couldn't find uniform for initializer %s\n", name);
+      linker_error(shader_program,
+                  "Couldn't find uniform for initializer %s\n", name);
       return;
    }
 
@@ -2562,7 +2650,7 @@ set_uniform_initializer(struct gl_context *ctx, void *mem_ctx,
       void *values;
 
       if (element_type->base_type == GLSL_TYPE_BOOL) {
-        int *conv = talloc_array(mem_ctx, int, element_type->components());
+        int *conv = ralloc_array(mem_ctx, int, element_type->components());
         for (unsigned int j = 0; j < element_type->components(); j++) {
            conv[j] = element->value.b[j];
         }
@@ -2608,14 +2696,14 @@ set_uniform_initializers(struct gl_context *ctx,
            continue;
 
         if (!mem_ctx)
-           mem_ctx = talloc_new(NULL);
+           mem_ctx = ralloc_context(NULL);
 
         set_uniform_initializer(ctx, mem_ctx, shader_program, var->name,
                                 var->type, var->constant_value);
       }
    }
 
-   talloc_free(mem_ctx);
+   ralloc_free(mem_ctx);
 }
 
 /*
@@ -2641,21 +2729,26 @@ set_uniform_initializers(struct gl_context *ctx,
 void
 ir_to_mesa_visitor::copy_propagate(void)
 {
-   ir_to_mesa_instruction **acp = new ir_to_mesa_instruction *[this->next_temp * 4];
-
-   memset(acp, 0, sizeof(acp) * this->next_temp * 4);
+   ir_to_mesa_instruction **acp = rzalloc_array(mem_ctx,
+                                                   ir_to_mesa_instruction *,
+                                                   this->next_temp * 4);
+   int *acp_level = rzalloc_array(mem_ctx, int, this->next_temp * 4);
+   int level = 0;
 
    foreach_iter(exec_list_iterator, iter, this->instructions) {
       ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
 
+      assert(inst->dst.file != PROGRAM_TEMPORARY
+            || inst->dst.index < this->next_temp);
+
       /* First, do any copy propagation possible into the src regs. */
       for (int r = 0; r < 3; r++) {
         ir_to_mesa_instruction *first = NULL;
         bool good = true;
-        int acp_base = inst->src_reg[r].index * 4;
+        int acp_base = inst->src[r].index * 4;
 
-        if (inst->src_reg[r].file != PROGRAM_TEMPORARY ||
-            inst->src_reg[r].reladdr)
+        if (inst->src[r].file != PROGRAM_TEMPORARY ||
+            inst->src[r].reladdr)
            continue;
 
         /* See if we can find entries in the ACP consisting of MOVs
@@ -2663,7 +2756,7 @@ ir_to_mesa_visitor::copy_propagate(void)
          * of this src register reference.
          */
         for (int i = 0; i < 4; i++) {
-           int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
+           int src_chan = GET_SWZ(inst->src[r].swizzle, i);
            ir_to_mesa_instruction *copy_chan = acp[acp_base + src_chan];
 
            if (!copy_chan) {
@@ -2671,11 +2764,13 @@ ir_to_mesa_visitor::copy_propagate(void)
               break;
            }
 
+           assert(acp_level[acp_base + src_chan] <= level);
+
            if (!first) {
               first = copy_chan;
            } else {
-              if (first->src_reg[0].file != copy_chan->src_reg[0].file ||
-                  first->src_reg[0].index != copy_chan->src_reg[0].index) {
+              if (first->src[0].file != copy_chan->src[0].file ||
+                  first->src[0].index != copy_chan->src[0].index) {
                  good = false;
                  break;
               }
@@ -2686,40 +2781,96 @@ ir_to_mesa_visitor::copy_propagate(void)
            /* We've now validated that we can copy-propagate to
             * replace this src register reference.  Do it.
             */
-           inst->src_reg[r].file = first->src_reg[0].file;
-           inst->src_reg[r].index = first->src_reg[0].index;
+           inst->src[r].file = first->src[0].file;
+           inst->src[r].index = first->src[0].index;
 
            int swizzle = 0;
            for (int i = 0; i < 4; i++) {
-              int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i);
+              int src_chan = GET_SWZ(inst->src[r].swizzle, i);
               ir_to_mesa_instruction *copy_inst = acp[acp_base + src_chan];
-              swizzle |= (GET_SWZ(copy_inst->src_reg[0].swizzle, src_chan) <<
+              swizzle |= (GET_SWZ(copy_inst->src[0].swizzle, src_chan) <<
                           (3 * i));
            }
-           inst->src_reg[r].swizzle = swizzle;
+           inst->src[r].swizzle = swizzle;
         }
       }
 
       switch (inst->op) {
       case OPCODE_BGNLOOP:
       case OPCODE_ENDLOOP:
-      case OPCODE_ELSE:
-      case OPCODE_ENDIF:
         /* End of a basic block, clear the ACP entirely. */
-        memset(&acp, 0, sizeof(acp));
+        memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
+        break;
+
+      case OPCODE_IF:
+        ++level;
+        break;
+
+      case OPCODE_ENDIF:
+      case OPCODE_ELSE:
+        /* Clear all channels written inside the block from the ACP, but
+         * leaving those that were not touched.
+         */
+        for (int r = 0; r < this->next_temp; r++) {
+           for (int c = 0; c < 4; c++) {
+              if (!acp[4 * r + c])
+                 continue;
+
+              if (acp_level[4 * r + c] >= level)
+                 acp[4 * r + c] = NULL;
+           }
+        }
+        if (inst->op == OPCODE_ENDIF)
+           --level;
         break;
 
       default:
         /* Continuing the block, clear any written channels from
          * the ACP.
          */
-        if (inst->dst_reg.file == PROGRAM_TEMPORARY) {
-           if (inst->dst_reg.reladdr) {
-              memset(&acp, 0, sizeof(acp));
-           } else {
-              for (int i = 0; i < 4; i++) {
-                 if (inst->dst_reg.writemask & (1 << i)) {
-                    acp[4 * inst->dst_reg.index + i] = NULL;
+        if (inst->dst.file == PROGRAM_TEMPORARY && inst->dst.reladdr) {
+           /* Any temporary might be written, so no copy propagation
+            * across this instruction.
+            */
+           memset(acp, 0, sizeof(*acp) * this->next_temp * 4);
+        } else if (inst->dst.file == PROGRAM_OUTPUT &&
+                   inst->dst.reladdr) {
+           /* Any output might be written, so no copy propagation
+            * from outputs across this instruction.
+            */
+           for (int r = 0; r < this->next_temp; r++) {
+              for (int c = 0; c < 4; c++) {
+                 if (!acp[4 * r + c])
+                    continue;
+
+                 if (acp[4 * r + c]->src[0].file == PROGRAM_OUTPUT)
+                    acp[4 * r + c] = NULL;
+              }
+           }
+        } else if (inst->dst.file == PROGRAM_TEMPORARY ||
+                   inst->dst.file == PROGRAM_OUTPUT) {
+           /* Clear where it's used as dst. */
+           if (inst->dst.file == PROGRAM_TEMPORARY) {
+              for (int c = 0; c < 4; c++) {
+                 if (inst->dst.writemask & (1 << c)) {
+                    acp[4 * inst->dst.index + c] = NULL;
+                 }
+              }
+           }
+
+           /* Clear where it's used as src. */
+           for (int r = 0; r < this->next_temp; r++) {
+              for (int c = 0; c < 4; c++) {
+                 if (!acp[4 * r + c])
+                    continue;
+
+                 int src_chan = GET_SWZ(acp[4 * r + c]->src[0].swizzle, c);
+
+                 if (acp[4 * r + c]->src[0].file == inst->dst.file &&
+                     acp[4 * r + c]->src[0].index == inst->dst.index &&
+                     inst->dst.writemask & (1 << src_chan))
+                 {
+                    acp[4 * r + c] = NULL;
                  }
               }
            }
@@ -2729,20 +2880,22 @@ ir_to_mesa_visitor::copy_propagate(void)
 
       /* If this is a copy, add it to the ACP. */
       if (inst->op == OPCODE_MOV &&
-         inst->dst_reg.file == PROGRAM_TEMPORARY &&
-         !inst->dst_reg.reladdr &&
+         inst->dst.file == PROGRAM_TEMPORARY &&
+         !inst->dst.reladdr &&
          !inst->saturate &&
-         !inst->src_reg[0].reladdr &&
-         !inst->src_reg[0].negate) {
+         !inst->src[0].reladdr &&
+         !inst->src[0].negate) {
         for (int i = 0; i < 4; i++) {
-           if (inst->dst_reg.writemask & (1 << i)) {
-              acp[4 * inst->dst_reg.index + i] = inst;
+           if (inst->dst.writemask & (1 << i)) {
+              acp[4 * inst->dst.index + i] = inst;
+              acp_level[4 * inst->dst.index + i] = level;
            }
         }
       }
    }
 
-   delete [] acp;
+   ralloc_free(acp_level);
+   ralloc_free(acp);
 }
 
 
@@ -2800,7 +2953,7 @@ get_mesa_program(struct gl_context *ctx,
 
    /* Emit Mesa IR for main(). */
    visit_exec_list(shader->ir, &v);
-   v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
+   v.emit(NULL, OPCODE_END);
 
    /* Now emit bodies for any functions that were used. */
    do {
@@ -2812,7 +2965,7 @@ get_mesa_program(struct gl_context *ctx,
         if (!entry->bgn_inst) {
            v.current_function = entry;
 
-           entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
+           entry->bgn_inst = v.emit(NULL, OPCODE_BGNSUB);
            entry->bgn_inst->function = entry;
 
            visit_exec_list(&entry->sig->body, &v);
@@ -2820,10 +2973,10 @@ get_mesa_program(struct gl_context *ctx,
            ir_to_mesa_instruction *last;
            last = (ir_to_mesa_instruction *)v.instructions.get_tail();
            if (last->op != OPCODE_RET)
-              v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
+              v.emit(NULL, OPCODE_RET);
 
            ir_to_mesa_instruction *end;
-           end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
+           end = v.emit(NULL, OPCODE_ENDSUB);
            end->function = entry;
 
            progress = GL_TRUE;
@@ -2841,7 +2994,7 @@ get_mesa_program(struct gl_context *ctx,
    mesa_instructions =
       (struct prog_instruction *)calloc(num_instructions,
                                        sizeof(*mesa_instructions));
-   mesa_instruction_annotation = talloc_array(v.mem_ctx, ir_instruction *,
+   mesa_instruction_annotation = ralloc_array(v.mem_ctx, ir_instruction *,
                                              num_instructions);
 
    v.copy_propagate();
@@ -2857,14 +3010,14 @@ get_mesa_program(struct gl_context *ctx,
       mesa_inst->CondUpdate = inst->cond_update;
       if (inst->saturate)
         mesa_inst->SaturateMode = SATURATE_ZERO_ONE;
-      mesa_inst->DstReg.File = inst->dst_reg.file;
-      mesa_inst->DstReg.Index = inst->dst_reg.index;
-      mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
-      mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
-      mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
-      mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
-      mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
-      mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
+      mesa_inst->DstReg.File = inst->dst.file;
+      mesa_inst->DstReg.Index = inst->dst.index;
+      mesa_inst->DstReg.CondMask = inst->dst.cond_mask;
+      mesa_inst->DstReg.WriteMask = inst->dst.writemask;
+      mesa_inst->DstReg.RelAddr = inst->dst.reladdr != NULL;
+      mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src[0]);
+      mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src[1]);
+      mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src[2]);
       mesa_inst->TexSrcUnit = inst->sampler;
       mesa_inst->TexSrcTarget = inst->tex_target;
       mesa_inst->TexShadow = inst->tex_shadow;
@@ -2879,11 +3032,31 @@ get_mesa_program(struct gl_context *ctx,
          if (mesa_inst->SrcReg[src].RelAddr)
             prog->IndirectRegisterFiles |= 1 << mesa_inst->SrcReg[src].File;
 
-      if (options->EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
-        fail_link(shader_program, "Couldn't flatten if statement\n");
-      }
-
       switch (mesa_inst->Opcode) {
+      case OPCODE_IF:
+        if (options->EmitNoIfs) {
+           linker_warning(shader_program,
+                          "Couldn't flatten if-statement.  "
+                          "This will likely result in software "
+                          "rasterization.\n");
+        }
+        break;
+      case OPCODE_BGNLOOP:
+        if (options->EmitNoLoops) {
+           linker_warning(shader_program,
+                          "Couldn't unroll loop.  "
+                          "This will likely result in software "
+                          "rasterization.\n");
+        }
+        break;
+      case OPCODE_CONT:
+        if (options->EmitNoCont) {
+           linker_warning(shader_program,
+                          "Couldn't lower continue-statement.  "
+                          "This will likely result in software "
+                          "rasterization.\n");
+        }
+        break;
       case OPCODE_BGNSUB:
         inst->function->inst = i;
         mesa_inst->Comment = strdup(inst->function->sig->function_name());
@@ -2935,6 +3108,8 @@ get_mesa_program(struct gl_context *ctx,
    do_set_program_inouts(shader->ir, prog);
    count_resources(prog);
 
+   check_resources(ctx, shader_program, prog);
+
    _mesa_reference_program(ctx, &shader->Program, prog);
 
    if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
@@ -2946,21 +3121,6 @@ get_mesa_program(struct gl_context *ctx,
 
 extern "C" {
 
-/**
- * Called via ctx->Driver.CompilerShader().
- * This is a no-op.
- * XXX can we remove the ctx->Driver.CompileShader() hook?
- */
-GLboolean
-_mesa_ir_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
-{
-   assert(shader->CompileStatus);
-   (void) ctx;
-
-   return GL_TRUE;
-}
-
-
 /**
  * Link a shader.
  * Called via ctx->Driver.LinkShader()
@@ -3088,7 +3248,8 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
                             &ctx->Extensions, ctx->API);
 
    if (ctx->Shader.Flags & GLSL_DUMP) {
-      printf("GLSL source for shader %d:\n", shader->Name);
+      printf("GLSL source for %s shader %d:\n",
+            _mesa_glsl_shader_target_name(state->target), shader->Name);
       printf("%s\n", shader->Source);
    }
 
@@ -3098,7 +3259,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
      _mesa_glsl_lexer_dtor(state);
    }
 
-   talloc_free(shader->ir);
+   ralloc_free(shader->ir);
    shader->ir = new(shader) exec_list;
    if (!state->error && !state->translation_unit.is_empty())
       _mesa_ast_to_hir(shader->ir, state);
@@ -3145,12 +3306,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader)
    /* Retain any live IR, but trash the rest. */
    reparent_ir(shader->ir, shader->ir);
 
-   talloc_free(state);
-
-   if (shader->CompileStatus) {
-      if (!ctx->Driver.CompileShader(ctx, shader))
-        shader->CompileStatus = GL_FALSE;
-   }
+   ralloc_free(state);
 }
 
 
@@ -3168,7 +3324,7 @@ _mesa_glsl_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
 
    for (i = 0; i < prog->NumShaders; i++) {
       if (!prog->Shaders[i]->CompileStatus) {
-        fail_link(prog, "linking with uncompiled shader");
+        linker_error(prog, "linking with uncompiled shader");
         prog->LinkStatus = GL_FALSE;
       }
    }