OSDN Git Service

Merge branch 'mesa'
authorEric Anholt <eric@anholt.net>
Thu, 24 Jun 2010 22:21:51 +0000 (15:21 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 24 Jun 2010 22:27:10 +0000 (15:27 -0700)
This brings in the ir_to_mesa.cpp code I've been developing to codegen
to the Mesa IR.  It does not actually generate a complete Mesa
fragment/vertex program yet.

.gitignore
Makefile.am
glsl_parser_extras.h
ir.h
ir_to_mesa.cpp [new file with mode: 0644]
main/mtypes.h
mesa/shader/prog_instruction.c [new file with mode: 0644]
mesa/shader/prog_instruction.h [new file with mode: 0644]
mesa/shader/prog_print.c [new file with mode: 0644]
mesa/shader/prog_print.h [new file with mode: 0644]
program.h

index b3ce5e7..376aaed 100644 (file)
@@ -21,3 +21,5 @@ glsl_parser.output
 glsl_parser.cpp
 glsl_parser.h
 glsl
+mesa_codegen.cpp
+mesa_codegen.h
index a88bf00..c34f7d8 100644 (file)
@@ -21,6 +21,7 @@
 # USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 AUTOMAKE_OPTIONS = foreign
+AM_CPPFLAGS = -I mesa
 
 SUBDIRS = glcpp
 
@@ -57,9 +58,15 @@ glsl_SOURCES = \
        ir_hierarchical_visitor.h \
        ir_hierarchical_visitor.cpp \
        ir_swizzle_swizzle.cpp \
+       ir_to_mesa.cpp \
+       ir_to_mesa.h \
        ir_validate.cpp \
        ir_vec_index_to_swizzle.cpp \
-       linker.cpp
+       linker.cpp \
+       mesa/shader/prog_instruction.c \
+       mesa/shader/prog_instruction.h \
+       mesa/shader/prog_print.c \
+       mesa/shader/prog_print.h
 
 BUILT_SOURCES = glsl_parser.h glsl_parser.cpp glsl_lexer.cpp
 CLEANFILES = $(BUILT_SOURCES)
index 87de908..cfe02e3 100644 (file)
@@ -134,4 +134,6 @@ extern bool _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
 extern const char *
 _mesa_glsl_shader_target_name(enum _mesa_glsl_parser_targets target);
 
+void do_ir_to_mesa(exec_list *instructions);
+
 #endif /* GLSL_PARSER_EXTRAS_H */
diff --git a/ir.h b/ir.h
index 1c95512..3d2c7ff 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -37,6 +37,10 @@ extern "C" {
 #include "ir_visitor.h"
 #include "ir_hierarchical_visitor.h"
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#endif
+
 struct ir_program {
    void *bong_hits;
 };
@@ -758,9 +762,9 @@ public:
    };
 
    ir_loop_jump(jump_mode mode)
-      : mode(mode)
    {
-      /* empty */
+      this->mode = mode;
+      this->loop = loop;
    }
 
    virtual ir_instruction *clone(struct hash_table *) const;
@@ -782,9 +786,11 @@ public:
       return mode == jump_continue;
    }
 
-private:
    /** Mode selector for the jump instruction. */
    enum jump_mode mode;
+private:
+   /** Loop containing this break instruction. */
+   ir_loop *loop;
 };
 /*@}*/
 
diff --git a/ir_to_mesa.cpp b/ir_to_mesa.cpp
new file mode 100644 (file)
index 0000000..26449c5
--- /dev/null
@@ -0,0 +1,1211 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ir_to_mesa.cpp
+ *
+ * Translates the IR to ARB_fragment_program text if possible,
+ * printing the result
+ */
+
+#include <stdio.h>
+#include "ir.h"
+#include "ir_visitor.h"
+#include "ir_print_visitor.h"
+#include "ir_expression_flattening.h"
+#include "glsl_types.h"
+
+extern "C" {
+#include "shader/prog_instruction.h"
+#include "shader/prog_print.h"
+}
+
+/**
+ * This struct is a corresponding struct to Mesa prog_src_register, with
+ * wider fields.
+ */
+typedef struct ir_to_mesa_src_reg {
+   int file; /**< PROGRAM_* from Mesa */
+   int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+   int swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
+   int negate; /**< NEGATE_XYZW mask from mesa */
+   bool reladdr; /**< Register index should be offset by address reg. */
+} ir_to_mesa_src_reg;
+
+typedef struct ir_to_mesa_dst_reg {
+   int file; /**< PROGRAM_* from Mesa */
+   int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+   int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
+} ir_to_mesa_dst_reg;
+
+extern ir_to_mesa_src_reg ir_to_mesa_undef;
+
+class ir_to_mesa_instruction : public exec_node {
+public:
+   enum prog_opcode op;
+   ir_to_mesa_dst_reg dst_reg;
+   ir_to_mesa_src_reg src_reg[3];
+   /** Pointer to the ir source this tree came from for debugging */
+   ir_instruction *ir;
+};
+
+class temp_entry : public exec_node {
+public:
+   temp_entry(ir_variable *var, int file, int index)
+      : file(file), index(index), var(var)
+   {
+      /* empty */
+   }
+
+   int file;
+   int index;
+   ir_variable *var; /* variable that maps to this, if any */
+};
+
+class ir_to_mesa_visitor : public ir_visitor {
+public:
+   ir_to_mesa_visitor();
+
+   int next_temp;
+   int next_constant;
+   int next_uniform;
+
+   temp_entry *find_variable_storage(ir_variable *var);
+
+   ir_to_mesa_src_reg get_temp(const glsl_type *type);
+
+   struct ir_to_mesa_src_reg src_reg_for_float(float val);
+
+   /**
+    * \name Visit methods
+    *
+    * As typical for the visitor pattern, there must be one \c visit method for
+    * each concrete subclass of \c ir_instruction.  Virtual base classes within
+    * the hierarchy should not have \c visit methods.
+    */
+   /*@{*/
+   virtual void visit(ir_variable *);
+   virtual void visit(ir_loop *);
+   virtual void visit(ir_loop_jump *);
+   virtual void visit(ir_function_signature *);
+   virtual void visit(ir_function *);
+   virtual void visit(ir_expression *);
+   virtual void visit(ir_swizzle *);
+   virtual void visit(ir_dereference_variable  *);
+   virtual void visit(ir_dereference_array *);
+   virtual void visit(ir_dereference_record *);
+   virtual void visit(ir_assignment *);
+   virtual void visit(ir_constant *);
+   virtual void visit(ir_call *);
+   virtual void visit(ir_return *);
+   virtual void visit(ir_texture *);
+   virtual void visit(ir_if *);
+   /*@}*/
+
+   struct ir_to_mesa_src_reg result;
+
+   /** List of temp_entry */
+   exec_list variable_storage;
+
+   /** List of ir_to_mesa_instruction */
+   exec_list instructions;
+
+   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 *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 *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);
+
+   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);
+
+   /* talloc context (the ) */
+   void *ctx;
+};
+
+ir_to_mesa_src_reg ir_to_mesa_undef = {
+   PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false,
+};
+
+ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
+   PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP
+};
+
+ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
+   PROGRAM_ADDRESS, 0, WRITEMASK_X
+};
+
+static int swizzle_for_size(int size)
+{
+   int size_swizzles[4] = {
+      MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
+      MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y),
+      MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z),
+      MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
+   };
+
+   return size_swizzles[size - 1];
+}
+
+/* This list should match up with builtin_variables.h */
+static const struct {
+   const char *name;
+   int file;
+   int index;
+} builtin_var_to_mesa_reg[] = {
+   /* core_vs */
+   {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS},
+   {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ},
+
+   /* core_fs */
+   {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS},
+   {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE},
+   {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0},
+   {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */
+
+   /* 110_deprecated_fs */
+   {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0},
+   {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1},
+   {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC},
+   {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */
+
+   /* 110_deprecated_vs */
+   {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS},
+   {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL},
+   {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0},
+   {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1},
+   {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0},
+   {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1},
+   {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2},
+   {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3},
+   {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4},
+   {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5},
+   {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6},
+   {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7},
+   {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */
+   {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC},
+   /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
+   {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0},
+   {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0},
+   {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1},
+   {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1},
+   {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC},
+
+   /* 130_vs */
+   /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
+
+   {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */
+};
+
+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_instruction *inst = new(ctx) ir_to_mesa_instruction();
+
+   inst->op = op;
+   inst->dst_reg = dst;
+   inst->src_reg[0] = src0;
+   inst->src_reg[1] = src1;
+   inst->src_reg[2] = src2;
+   inst->ir = ir;
+
+   this->instructions.push_tail(inst);
+
+   return inst;
+}
+
+
+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)
+{
+   return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef);
+}
+
+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)
+{
+   return ir_to_mesa_emit_op3(ir, op, dst,
+                             src0, ir_to_mesa_undef, 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;
+
+   return dst_reg;
+}
+
+/**
+ * Emits Mesa scalar opcodes to produce unique answers across channels.
+ *
+ * Some Mesa opcodes are scalar-only, like ARB_fp/vp.  The src X
+ * channel determines the result across all channels.  So to do a vec4
+ * of this operation, we want to emit a scalar per source channel used
+ * to produce dest channels.
+ */
+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)
+{
+   int i, j;
+   int done_mask = ~dst.writemask;
+
+   /* Mesa RCP is a scalar operation splatting results to all channels,
+    * like ARB_fp/vp.  So emit as many RCPs as necessary to cover our
+    * dst channels.
+    */
+   for (i = 0; i < 4; i++) {
+      int this_mask = (1 << i);
+      ir_to_mesa_instruction *inst;
+      ir_to_mesa_src_reg src = src0;
+
+      if (done_mask & this_mask)
+        continue;
+
+      int src_swiz = GET_SWZ(src.swizzle, i);
+      for (j = i + 1; j < 4; j++) {
+        if (!(done_mask & (1 << j)) && GET_SWZ(src.swizzle, j) == src_swiz) {
+           this_mask |= (1 << j);
+        }
+      }
+      src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz,
+                                 src_swiz, src_swiz);
+
+      inst = ir_to_mesa_emit_op1(ir, op,
+                                dst,
+                                src);
+      inst->dst_reg.writemask = this_mask;
+      done_mask |= this_mask;
+   }
+}
+
+struct ir_to_mesa_src_reg
+ir_to_mesa_visitor::src_reg_for_float(float val)
+{
+   ir_to_mesa_src_reg src_reg;
+
+   /* FINISHME: This will end up being _mesa_add_unnamed_constant,
+    * which handles sharing values and sharing channels of vec4
+    * constants for small values.
+    */
+   /* FINISHME: Do something with the constant values for now.
+    */
+   (void)val;
+   src_reg.file = PROGRAM_CONSTANT;
+   src_reg.index = this->next_constant++;
+   src_reg.swizzle = SWIZZLE_NOOP;
+
+   return src_reg;
+}
+
+/**
+ * In the initial pass of codegen, we assign temporary numbers to
+ * intermediate results.  (not SSA -- variable assignments will reuse
+ * storage).  Actual register allocation for the Mesa VM occurs in a
+ * pass over the Mesa IR later.
+ */
+ir_to_mesa_src_reg
+ir_to_mesa_visitor::get_temp(const glsl_type *type)
+{
+   ir_to_mesa_src_reg src_reg;
+   int swizzle[4];
+   int i;
+
+   assert(!type->is_array());
+
+   src_reg.file = PROGRAM_TEMPORARY;
+   src_reg.index = type->matrix_columns;
+   src_reg.reladdr = false;
+
+   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]);
+
+   return src_reg;
+}
+
+static int
+type_size(const struct glsl_type *type)
+{
+   unsigned int i;
+   int size;
+
+   switch (type->base_type) {
+   case GLSL_TYPE_UINT:
+   case GLSL_TYPE_INT:
+   case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_BOOL:
+      if (type->is_matrix()) {
+        return 4; /* FINISHME: Not all matrices are 4x4. */
+      } else {
+        /* Regardless of size of vector, it gets a vec4. This is bad
+         * packing for things like floats, but otherwise arrays become a
+         * mess.  Hopefully a later pass over the code can pack scalars
+         * down if appropriate.
+         */
+        return 1;
+      }
+   case GLSL_TYPE_ARRAY:
+      return type_size(type->fields.array) * type->length;
+   case GLSL_TYPE_STRUCT:
+      size = 0;
+      for (i = 0; i < type->length; i++) {
+        size += type_size(type->fields.structure[i].type);
+      }
+      return size;
+   default:
+      assert(0);
+   }
+}
+
+temp_entry *
+ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
+{
+   
+   temp_entry *entry;
+
+   foreach_iter(exec_list_iterator, iter, this->variable_storage) {
+      entry = (temp_entry *)iter.get();
+
+      if (entry->var == var)
+        return entry;
+   }
+
+   return NULL;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_variable *ir)
+{
+   (void)ir;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop *ir)
+{
+   assert(!ir->from);
+   assert(!ir->to);
+   assert(!ir->increment);
+   assert(!ir->counter);
+
+   ir_to_mesa_emit_op1(NULL, OPCODE_BGNLOOP,
+                      ir_to_mesa_undef_dst, ir_to_mesa_undef);
+
+   visit_exec_list(&ir->body_instructions, this);
+
+   ir_to_mesa_emit_op1(NULL, OPCODE_ENDLOOP,
+                      ir_to_mesa_undef_dst, ir_to_mesa_undef);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_loop_jump *ir)
+{
+   switch (ir->mode) {
+   case ir_loop_jump::jump_break:
+      ir_to_mesa_emit_op1(NULL, OPCODE_BRK,
+                         ir_to_mesa_undef_dst, ir_to_mesa_undef);
+      break;
+   case ir_loop_jump::jump_continue:
+      ir_to_mesa_emit_op1(NULL, OPCODE_CONT,
+                         ir_to_mesa_undef_dst, ir_to_mesa_undef);
+      break;
+   }
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_function_signature *ir)
+{
+   assert(0);
+   (void)ir;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_function *ir)
+{
+   /* Ignore function bodies other than main() -- we shouldn't see calls to
+    * them since they should all be inlined before we get to ir_to_mesa.
+    */
+   if (strcmp(ir->name, "main") == 0) {
+      const ir_function_signature *sig;
+      exec_list empty;
+
+      sig = ir->matching_signature(&empty);
+
+      assert(sig);
+
+      foreach_iter(exec_list_iterator, iter, sig->body) {
+        ir_instruction *ir = (ir_instruction *)iter.get();
+
+        ir->accept(this);
+      }
+   }
+}
+
+void
+ir_to_mesa_visitor::visit(ir_expression *ir)
+{
+   unsigned int operand;
+   struct ir_to_mesa_src_reg op[2];
+   struct ir_to_mesa_src_reg result_src;
+   struct ir_to_mesa_dst_reg result_dst;
+   const glsl_type *vec4_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 4, 1);
+   const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1);
+   const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1);
+
+   for (operand = 0; operand < ir->get_num_operands(); operand++) {
+      this->result.file = PROGRAM_UNDEFINED;
+      ir->operands[operand]->accept(this);
+      if (this->result.file == PROGRAM_UNDEFINED) {
+        ir_print_visitor v;
+        printf("Failed to get tree for expression operand:\n");
+        ir->operands[operand]->accept(&v);
+        exit(1);
+      }
+      op[operand] = this->result;
+
+      /* Only expression implemented for matrices yet */
+      assert(!ir->operands[operand]->type->is_matrix() ||
+            ir->operation == ir_binop_mul);
+   }
+
+   this->result.file = PROGRAM_UNDEFINED;
+
+   /* Storage for our result.  Ideally for an assignment we'd be using
+    * the actual storage for the result here, instead.
+    */
+   result_src = get_temp(ir->type);
+   /* convenience for the emit functions below. */
+   result_dst = ir_to_mesa_dst_reg_from_src(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.
+    */
+   result_dst.writemask = (1 << ir->type->vector_elements) - 1;
+
+   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));
+      break;
+   case ir_unop_neg:
+      op[0].negate = ~op[0].negate;
+      result_src = op[0];
+      break;
+   case ir_unop_exp:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_EXP, result_dst, op[0]);
+      break;
+   case ir_unop_exp2:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
+      break;
+   case ir_unop_log:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_LOG, result_dst, op[0]);
+      break;
+   case ir_unop_log2:
+      ir_to_mesa_emit_scalar_op1(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]);
+      break;
+   case ir_unop_cos:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
+      break;
+   case ir_binop_add:
+      ir_to_mesa_emit_op2(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]);
+      break;
+   case ir_binop_mul:
+      if (ir->operands[0]->type->is_matrix() &&
+         !ir->operands[1]->type->is_matrix()) {
+        if (ir->operands[0]->type->is_scalar()) {
+           ir_to_mesa_dst_reg dst_column = result_dst;
+           ir_to_mesa_src_reg src_column = op[0];
+           for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
+              ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+                                  dst_column, src_column, op[1]);
+              dst_column.index++;
+              src_column.index++;
+           }
+        } else {
+           ir_to_mesa_dst_reg dst_chan = result_dst;
+           ir_to_mesa_src_reg src_column = op[0];
+           ir_to_mesa_src_reg src_chan = op[1];
+           for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
+              dst_chan.writemask = (1 << i);
+              src_chan.swizzle = MAKE_SWIZZLE4(i, i, i, i);
+              ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+                                  dst_chan, src_column, src_chan);
+              src_column.index++;
+           }
+        }
+      } else {
+        assert(!ir->operands[0]->type->is_matrix());
+        assert(!ir->operands[1]->type->is_matrix());
+        ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
+      }
+      break;
+   case ir_binop_div:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]);
+      ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], result_src);
+      break;
+
+   case ir_binop_less:
+      ir_to_mesa_emit_op2(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]);
+      break;
+   case ir_binop_lequal:
+      ir_to_mesa_emit_op2(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]);
+      break;
+   case ir_binop_equal:
+      ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+      break;
+   case ir_binop_logic_xor:
+   case ir_binop_nequal:
+      ir_to_mesa_emit_op2(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));
+      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]);
+      break;
+
+   case ir_binop_dot:
+      if (ir->operands[0]->type == vec4_type) {
+        assert(ir->operands[1]->type == vec4_type);
+        ir_to_mesa_emit_op2(ir, OPCODE_DP4,
+                            result_dst,
+                            op[0], op[1]);
+      } else if (ir->operands[0]->type == vec3_type) {
+        assert(ir->operands[1]->type == vec3_type);
+        ir_to_mesa_emit_op2(ir, OPCODE_DP3,
+                            result_dst,
+                            op[0], op[1]);
+      } else if (ir->operands[0]->type == vec2_type) {
+        assert(ir->operands[1]->type == vec2_type);
+        ir_to_mesa_emit_op2(ir, OPCODE_DP2,
+                            result_dst,
+                            op[0], op[1]);
+      }
+      break;
+   case ir_unop_sqrt:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+      ir_to_mesa_emit_op1(ir, OPCODE_RCP, result_dst, result_src);
+      break;
+   case ir_unop_rsq:
+      ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
+      break;
+   case ir_unop_i2f:
+      /* 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]);
+      break;
+   case ir_unop_f2b:
+      ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
+                         result_src, src_reg_for_float(0.0));
+      break;
+   case ir_unop_trunc:
+      ir_to_mesa_emit_op1(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]);
+      result_src.negate = ~result_src.negate;
+      break;
+   case ir_unop_floor:
+      ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
+      break;
+   case ir_binop_min:
+      ir_to_mesa_emit_op2(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]);
+      break;
+   default:
+      ir_print_visitor v;
+      printf("Failed to get tree for expression:\n");
+      ir->accept(&v);
+      exit(1);
+      break;
+   }
+
+   this->result = result_src;
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_swizzle *ir)
+{
+   ir_to_mesa_src_reg src_reg;
+   int i;
+   int swizzle[4];
+
+   /* Note that this is only swizzles in expressions, not those on the left
+    * hand side of an assignment, which do write masking.  See ir_assignment
+    * for that.
+    */
+
+   ir->val->accept(this);
+   src_reg = this->result;
+   assert(src_reg.file != PROGRAM_UNDEFINED);
+
+   for (i = 0; i < 4; i++) {
+      if (i < ir->type->vector_elements) {
+        switch (i) {
+        case 0:
+           swizzle[i] = ir->mask.x;
+           break;
+        case 1:
+           swizzle[i] = ir->mask.y;
+           break;
+        case 2:
+           swizzle[i] = ir->mask.z;
+           break;
+        case 3:
+           swizzle[i] = ir->mask.w;
+           break;
+        }
+      } else {
+        /* If the type is smaller than a vec4, replicate the last
+         * channel out.
+         */
+        swizzle[i] = ir->type->vector_elements - 1;
+      }
+   }
+
+   src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0],
+                                  swizzle[1],
+                                  swizzle[2],
+                                  swizzle[3]);
+
+   this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
+{
+   ir_to_mesa_src_reg src_reg;
+   temp_entry *entry = find_variable_storage(ir->var);
+   unsigned int i;
+   bool var_in;
+
+   if (!entry) {
+      switch (ir->var->mode) {
+      case ir_var_uniform:
+        entry = new(ctx)  temp_entry(ir->var, PROGRAM_UNIFORM,
+                                     this->next_uniform);
+        this->variable_storage.push_tail(entry);
+
+        this->next_uniform += type_size(ir->var->type);
+        break;
+      case ir_var_in:
+      case ir_var_out:
+      case ir_var_inout:
+        var_in = (ir->var->mode == ir_var_in ||
+                  ir->var->mode == ir_var_inout);
+
+        for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) {
+           bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT;
+
+           if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 &&
+               !(var_in ^ in))
+              break;
+        }
+        if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) {
+           printf("Failed to find builtin for %s variable %s\n",
+                  var_in ? "in" : "out",
+                  ir->var->name);
+           abort();
+        }
+        entry = new(ctx)  temp_entry(ir->var,
+                                     builtin_var_to_mesa_reg[i].file,
+                                     builtin_var_to_mesa_reg[i].index);
+        break;
+      case ir_var_auto:
+        entry = new(ctx) temp_entry(ir->var, PROGRAM_TEMPORARY,
+                                    this->next_temp);
+        this->variable_storage.push_tail(entry);
+
+        next_temp += type_size(ir->var->type);
+        break;
+      }
+
+      if (!entry) {
+        printf("Failed to make storage for %s\n", ir->var->name);
+        exit(1);
+      }
+   }
+
+   src_reg.file = entry->file;
+   src_reg.index = entry->index;
+   /* If the type is smaller than a vec4, replicate the last channel out. */
+   src_reg.swizzle = swizzle_for_size(ir->var->type->vector_elements);
+   src_reg.reladdr = false;
+   src_reg.negate = 0;
+
+   this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_array *ir)
+{
+   ir_constant *index;
+   ir_to_mesa_src_reg src_reg;
+
+   index = ir->array_index->constant_expression_value();
+
+   /* By the time we make it to this stage, matrices should be broken down
+    * to vectors.
+    */
+   assert(!ir->type->is_matrix());
+
+   ir->array->accept(this);
+   src_reg = this->result;
+
+   if (src_reg.file == PROGRAM_INPUT ||
+       src_reg.file == PROGRAM_OUTPUT) {
+      assert(index); /* FINISHME: Handle variable indexing of builtins. */
+
+      src_reg.index += index->value.i[0];
+   } else {
+      if (index) {
+        src_reg.index += index->value.i[0];
+      } 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);
+
+        /* FINISHME: This doesn't work when we're trying to do the LHS
+         * of an assignment.
+         */
+        src_reg.reladdr = true;
+        ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
+                            this->result);
+
+        this->result = get_temp(ir->type);
+        ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+                            ir_to_mesa_dst_reg_from_src(this->result),
+                            src_reg);
+      }
+   }
+
+   /* If the type is smaller than a vec4, replicate the last channel out. */
+   src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
+
+   this->result = src_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_dereference_record *ir)
+{
+   unsigned int i;
+   const glsl_type *struct_type = ir->record->type;
+   int offset = 0;
+
+   ir->record->accept(this);
+
+   for (i = 0; i < struct_type->length; i++) {
+      if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+        break;
+      offset += type_size(struct_type->fields.structure[i].type);
+   }
+   this->result.index += offset;
+}
+
+/**
+ * We want to be careful in assignment setup to hit the actual storage
+ * instead of potentially using a temporary like we might with the
+ * ir_dereference handler.
+ *
+ * Thanks to ir_swizzle_swizzle, and ir_vec_index_to_swizzle, we
+ * should only see potentially one variable array index of a vector,
+ * and one swizzle, before getting to actual vec4 storage.  So handle
+ * those, then go use ir_dereference to handle the rest.
+ */
+static struct ir_to_mesa_dst_reg
+get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v)
+{
+   struct ir_to_mesa_dst_reg dst_reg;
+   ir_dereference *deref;
+   ir_swizzle *swiz;
+
+   /* Use the rvalue deref handler for the most part.  We'll ignore
+    * swizzles in it and write swizzles using writemask, though.
+    */
+   ir->accept(v);
+   dst_reg = ir_to_mesa_dst_reg_from_src(v->result);
+
+   if ((deref = ir->as_dereference())) {
+      ir_dereference_array *deref_array = ir->as_dereference_array();
+      assert(!deref_array || deref_array->array->type->is_array());
+
+      ir->accept(v);
+   } else if ((swiz = ir->as_swizzle())) {
+      dst_reg.writemask = 0;
+      if (swiz->mask.num_components >= 1)
+        dst_reg.writemask |= (1 << swiz->mask.x);
+      if (swiz->mask.num_components >= 2)
+        dst_reg.writemask |= (1 << swiz->mask.y);
+      if (swiz->mask.num_components >= 3)
+        dst_reg.writemask |= (1 << swiz->mask.z);
+      if (swiz->mask.num_components >= 4)
+        dst_reg.writemask |= (1 << swiz->mask.w);
+   }
+
+   return dst_reg;
+}
+
+void
+ir_to_mesa_visitor::visit(ir_assignment *ir)
+{
+   struct ir_to_mesa_dst_reg l;
+   struct ir_to_mesa_src_reg r;
+
+   assert(!ir->lhs->type->is_matrix());
+   assert(!ir->lhs->type->is_array());
+   assert(ir->lhs->type->base_type != GLSL_TYPE_STRUCT);
+
+   l = get_assignment_lhs(ir->lhs, this);
+
+   ir->rhs->accept(this);
+   r = this->result;
+   assert(l.file != PROGRAM_UNDEFINED);
+   assert(r.file != PROGRAM_UNDEFINED);
+
+   if (ir->condition) {
+        ir_constant *condition_constant;
+
+        condition_constant = ir->condition->constant_expression_value();
+
+        assert(condition_constant && condition_constant->value.b[0]);
+   }
+
+   ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_constant *ir)
+{
+   ir_to_mesa_src_reg src_reg;
+
+   assert(ir->type->base_type == GLSL_TYPE_FLOAT ||
+         ir->type->base_type == GLSL_TYPE_UINT ||
+         ir->type->base_type == GLSL_TYPE_INT ||
+         ir->type->base_type == GLSL_TYPE_BOOL);
+
+   /* FINISHME: This will end up being _mesa_add_unnamed_constant,
+    * which handles sharing values and sharing channels of vec4
+    * constants for small values.
+    */
+   /* FINISHME: Do something with the constant values for now.
+    */
+   src_reg.file = PROGRAM_CONSTANT;
+   src_reg.index = this->next_constant;
+   src_reg.swizzle = SWIZZLE_NOOP;
+   src_reg.reladdr = false;
+   src_reg.negate = 0;
+
+   this->next_constant += type_size(ir->type);
+
+   this->result = src_reg;
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_call *ir)
+{
+   printf("Can't support call to %s\n", ir->callee_name());
+   exit(1);
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_texture *ir)
+{
+   assert(0);
+
+   ir->coordinate->accept(this);
+}
+
+void
+ir_to_mesa_visitor::visit(ir_return *ir)
+{
+   assert(0);
+
+   ir->get_value()->accept(this);
+}
+
+
+void
+ir_to_mesa_visitor::visit(ir_if *ir)
+{
+   ir_to_mesa_instruction *if_inst, *else_inst = NULL;
+
+   ir->condition->accept(this);
+   assert(this->result.file != PROGRAM_UNDEFINED);
+
+   if_inst = ir_to_mesa_emit_op1(ir->condition,
+                                OPCODE_IF, ir_to_mesa_undef_dst,
+                                this->result);
+
+   this->instructions.push_tail(if_inst);
+
+   visit_exec_list(&ir->then_instructions, this);
+
+   if (!ir->else_instructions.is_empty()) {
+      else_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ELSE,
+                                     ir_to_mesa_undef_dst,
+                                     ir_to_mesa_undef);
+      visit_exec_list(&ir->then_instructions, this);
+   }
+
+   if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
+                                ir_to_mesa_undef_dst, ir_to_mesa_undef);
+}
+
+ir_to_mesa_visitor::ir_to_mesa_visitor()
+{
+   result.file = PROGRAM_UNDEFINED;
+   next_temp = 1;
+   next_constant = 0;
+   next_uniform = 0;
+}
+
+static struct prog_src_register
+mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
+{
+   struct prog_src_register mesa_reg;
+
+   mesa_reg.File = reg.file;
+   assert(reg.index < (1 << INST_INDEX_BITS) - 1);
+   mesa_reg.Index = reg.index;
+   mesa_reg.Swizzle = reg.swizzle;
+   mesa_reg.RelAddr = reg.reladdr;
+
+   return mesa_reg;
+}
+
+static void
+set_branchtargets(struct prog_instruction *mesa_instructions,
+                 int num_instructions)
+{
+   int if_count = 0, loop_count;
+   int *if_stack, *loop_stack;
+   int if_stack_pos = 0, loop_stack_pos = 0;
+   int i, j;
+
+   for (i = 0; i < num_instructions; i++) {
+      switch (mesa_instructions[i].Opcode) {
+      case OPCODE_IF:
+        if_count++;
+        break;
+      case OPCODE_BGNLOOP:
+        loop_count++;
+        break;
+      case OPCODE_BRK:
+      case OPCODE_CONT:
+        mesa_instructions[i].BranchTarget = -1;
+        break;
+      default:
+        break;
+      }
+   }
+
+   if_stack = (int *)calloc(if_count, sizeof(*if_stack));
+   loop_stack = (int *)calloc(loop_count, sizeof(*loop_stack));
+
+   for (i = 0; i < num_instructions; i++) {
+      switch (mesa_instructions[i].Opcode) {
+      case OPCODE_IF:
+        if_stack[if_stack_pos] = i;
+        if_stack_pos++;
+        break;
+      case OPCODE_ELSE:
+        mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+        if_stack[if_stack_pos - 1] = i;
+        break;
+      case OPCODE_ENDIF:
+        mesa_instructions[if_stack[if_stack_pos - 1]].BranchTarget = i;
+        if_stack_pos--;
+        break;
+      case OPCODE_BGNLOOP:
+        loop_stack[loop_stack_pos] = i;
+        loop_stack_pos++;
+        break;
+      case OPCODE_ENDLOOP:
+        loop_stack_pos--;
+        /* Rewrite any breaks/conts at this nesting level (haven't
+         * already had a BranchTarget assigned) to point to the end
+         * of the loop.
+         */
+        for (j = loop_stack[loop_stack_pos]; j < i; j++) {
+           if (mesa_instructions[j].Opcode == OPCODE_BRK ||
+               mesa_instructions[j].Opcode == OPCODE_CONT) {
+              if (mesa_instructions[j].BranchTarget == -1) {
+                 mesa_instructions[j].BranchTarget = i;
+              }
+           }
+        }
+        /* The loop ends point at each other. */
+        mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
+        mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
+      default:
+        break;
+      }
+   }
+
+   free(if_stack);
+}
+
+static void
+print_program(struct prog_instruction *mesa_instructions,
+             ir_instruction **mesa_instruction_annotation,
+             int num_instructions)
+{
+   ir_instruction *last_ir = NULL;
+   int i;
+
+   for (i = 0; i < num_instructions; i++) {
+      struct prog_instruction *mesa_inst = mesa_instructions + i;
+      ir_instruction *ir = mesa_instruction_annotation[i];
+
+      if (last_ir != ir && ir) {
+        ir_print_visitor print;
+        ir->accept(&print);
+        printf("\n");
+        last_ir = ir;
+      }
+
+      _mesa_print_instruction(mesa_inst);
+   }
+}
+
+void
+do_ir_to_mesa(exec_list *instructions)
+{
+   ir_to_mesa_visitor v;
+   struct prog_instruction *mesa_instructions, *mesa_inst;
+   ir_instruction **mesa_instruction_annotation;
+   int i;
+
+   v.ctx = talloc_new(NULL);
+   visit_exec_list(instructions, &v);
+
+   int num_instructions = 0;
+   foreach_iter(exec_list_iterator, iter, v.instructions) {
+      num_instructions++;
+   }
+
+   mesa_instructions =
+      (struct prog_instruction *)calloc(num_instructions,
+                                       sizeof(*mesa_instructions));
+   mesa_instruction_annotation =
+      (ir_instruction **)calloc(num_instructions,
+                               sizeof(*mesa_instruction_annotation));
+
+   mesa_inst = mesa_instructions;
+   i = 0;
+   foreach_iter(exec_list_iterator, iter, v.instructions) {
+      ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
+
+      mesa_inst->Opcode = inst->op;
+      mesa_inst->DstReg.File = inst->dst_reg.file;
+      mesa_inst->DstReg.Index = inst->dst_reg.index;
+      mesa_inst->DstReg.CondMask = COND_TR;
+      mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
+      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_instruction_annotation[i] = inst->ir;
+
+      mesa_inst++;
+      i++;
+   }
+
+   set_branchtargets(mesa_instructions, num_instructions);
+   print_program(mesa_instructions, mesa_instruction_annotation, num_instructions);
+
+   free(mesa_instruction_annotation);
+   talloc_free(v.ctx);
+}
index f168b66..06e2dd4 100644 (file)
@@ -36,6 +36,8 @@
 #define MAX_DRAW_BUFFERS 8
 #define MAX_VARYING 16
 
+#include <GL/gl.h>
+
 /**
  * Indexes for vertex program attributes.
  * GL_NV_vertex_program aliases generic attributes over the conventional
@@ -218,4 +220,51 @@ typedef enum
    FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS)
 } gl_frag_result;
 
-#endif
+/**
+ * Names of the various vertex/fragment program register files, etc.
+ *
+ * NOTE: first four tokens must fit into 2 bits (see t_vb_arbprogram.c)
+ * All values should fit in a 4-bit field.
+ *
+ * NOTE: PROGRAM_ENV_PARAM, PROGRAM_STATE_VAR, PROGRAM_NAMED_PARAM,
+ * PROGRAM_CONSTANT, and PROGRAM_UNIFORM can all be considered to
+ * be "uniform" variables since they can only be set outside glBegin/End.
+ * They're also all stored in the same Parameters array.
+ */
+typedef enum
+{
+   PROGRAM_TEMPORARY,   /**< machine->Temporary[] */
+   PROGRAM_INPUT,       /**< machine->Inputs[] */
+   PROGRAM_OUTPUT,      /**< machine->Outputs[] */
+   PROGRAM_VARYING,     /**< machine->Inputs[]/Outputs[] */
+   PROGRAM_LOCAL_PARAM, /**< gl_program->LocalParams[] */
+   PROGRAM_ENV_PARAM,   /**< gl_program->Parameters[] */
+   PROGRAM_STATE_VAR,   /**< gl_program->Parameters[] */
+   PROGRAM_NAMED_PARAM, /**< gl_program->Parameters[] */
+   PROGRAM_CONSTANT,    /**< gl_program->Parameters[] */
+   PROGRAM_UNIFORM,     /**< gl_program->Parameters[] */
+   PROGRAM_WRITE_ONLY,  /**< A dummy, write-only register */
+   PROGRAM_ADDRESS,     /**< machine->AddressReg */
+   PROGRAM_SAMPLER,     /**< for shader samplers, compile-time only */
+   PROGRAM_UNDEFINED,   /**< Invalid/TBD value */
+   PROGRAM_FILE_MAX
+} gl_register_file;
+
+/**
+ * An index for each type of texture object.  These correspond to the GL
+ * texture target enums, such as GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, etc.
+ * Note: the order is from highest priority to lowest priority.
+ */
+typedef enum
+{
+   TEXTURE_2D_ARRAY_INDEX,
+   TEXTURE_1D_ARRAY_INDEX,
+   TEXTURE_CUBE_INDEX,
+   TEXTURE_3D_INDEX,
+   TEXTURE_RECT_INDEX,
+   TEXTURE_2D_INDEX,
+   TEXTURE_1D_INDEX,
+   NUM_TEXTURE_TARGETS
+} gl_texture_index;
+
+#endif /* MTYPES_H */
diff --git a/mesa/shader/prog_instruction.c b/mesa/shader/prog_instruction.c
new file mode 100644 (file)
index 0000000..fbcf868
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.3
+ *
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2009  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#if 0
+#include "main/glheader.h"
+#else
+#define _mesa_strdup strdup
+#define _mesa_snprintf snprintf
+#define ASSERT assert
+#endif
+#include "main/imports.h"
+#include "main/mtypes.h"
+#include "prog_instruction.h"
+
+
+/**
+ * Initialize program instruction fields to defaults.
+ * \param inst  first instruction to initialize
+ * \param count  number of instructions to initialize
+ */
+void
+_mesa_init_instructions(struct prog_instruction *inst, GLuint count)
+{
+   GLuint i;
+
+   memset(inst, 0, count * sizeof(struct prog_instruction));
+
+   for (i = 0; i < count; i++) {
+      inst[i].SrcReg[0].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
+      inst[i].SrcReg[1].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
+      inst[i].SrcReg[2].File = PROGRAM_UNDEFINED;
+      inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP;
+
+      inst[i].DstReg.File = PROGRAM_UNDEFINED;
+      inst[i].DstReg.WriteMask = WRITEMASK_XYZW;
+      inst[i].DstReg.CondMask = COND_TR;
+      inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP;
+
+      inst[i].SaturateMode = SATURATE_OFF;
+      inst[i].Precision = FLOAT32;
+   }
+}
+
+
+/**
+ * Allocate an array of program instructions.
+ * \param numInst  number of instructions
+ * \return pointer to instruction memory
+ */
+struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst)
+{
+   return (struct prog_instruction *)
+      calloc(1, numInst * sizeof(struct prog_instruction));
+}
+
+
+/**
+ * Reallocate memory storing an array of program instructions.
+ * This is used when we need to append additional instructions onto an
+ * program.
+ * \param oldInst  pointer to first of old/src instructions
+ * \param numOldInst  number of instructions at <oldInst>
+ * \param numNewInst  desired size of new instruction array.
+ * \return  pointer to start of new instruction array.
+ */
+struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+                           GLuint numOldInst, GLuint numNewInst)
+{
+   struct prog_instruction *newInst;
+
+   (void)numOldInst;
+   newInst = (struct prog_instruction *)
+      realloc(oldInst,
+             numNewInst * sizeof(struct prog_instruction));
+
+   return newInst;
+}
+
+
+/**
+ * Copy an array of program instructions.
+ * \param dest  pointer to destination.
+ * \param src  pointer to source.
+ * \param n  number of instructions to copy.
+ * \return pointer to destination.
+ */
+struct prog_instruction *
+_mesa_copy_instructions(struct prog_instruction *dest,
+                        const struct prog_instruction *src, GLuint n)
+{
+   GLuint i;
+   memcpy(dest, src, n * sizeof(struct prog_instruction));
+   for (i = 0; i < n; i++) {
+      if (src[i].Comment)
+         dest[i].Comment = _mesa_strdup(src[i].Comment);
+   }
+   return dest;
+}
+
+
+/**
+ * Free an array of instructions
+ */
+void
+_mesa_free_instructions(struct prog_instruction *inst, GLuint count)
+{
+   GLuint i;
+   for (i = 0; i < count; i++) {
+      if (inst[i].Data)
+         free(inst[i].Data);
+      if (inst[i].Comment)
+         free((char *) inst[i].Comment);
+   }
+   free(inst);
+}
+
+
+/**
+ * Basic info about each instruction
+ */
+struct instruction_info
+{
+   gl_inst_opcode Opcode;
+   const char *Name;
+   GLuint NumSrcRegs;
+   GLuint NumDstRegs;
+};
+
+/**
+ * Instruction info
+ * \note Opcode should equal array index!
+ */
+static const struct instruction_info InstInfo[MAX_OPCODE] = {
+   { OPCODE_NOP,    "NOP",     0, 0 },
+   { OPCODE_ABS,    "ABS",     1, 1 },
+   { OPCODE_ADD,    "ADD",     2, 1 },
+   { OPCODE_AND,    "AND",     2, 1 },
+   { OPCODE_ARA,    "ARA",     1, 1 },
+   { OPCODE_ARL,    "ARL",     1, 1 },
+   { OPCODE_ARL_NV, "ARL_NV",  1, 1 },
+   { OPCODE_ARR,    "ARL",     1, 1 },
+   { OPCODE_BGNLOOP,"BGNLOOP", 0, 0 },
+   { OPCODE_BGNSUB, "BGNSUB",  0, 0 },
+   { OPCODE_BRA,    "BRA",     0, 0 },
+   { OPCODE_BRK,    "BRK",     0, 0 },
+   { OPCODE_CAL,    "CAL",     0, 0 },
+   { OPCODE_CMP,    "CMP",     3, 1 },
+   { OPCODE_CONT,   "CONT",    0, 0 },
+   { OPCODE_COS,    "COS",     1, 1 },
+   { OPCODE_DDX,    "DDX",     1, 1 },
+   { OPCODE_DDY,    "DDY",     1, 1 },
+   { OPCODE_DP2,    "DP2",     2, 1 },
+   { OPCODE_DP2A,   "DP2A",    3, 1 },
+   { OPCODE_DP3,    "DP3",     2, 1 },
+   { OPCODE_DP4,    "DP4",     2, 1 },
+   { OPCODE_DPH,    "DPH",     2, 1 },
+   { OPCODE_DST,    "DST",     2, 1 },
+   { OPCODE_ELSE,   "ELSE",    0, 0 },
+   { OPCODE_END,    "END",     0, 0 },
+   { OPCODE_ENDIF,  "ENDIF",   0, 0 },
+   { OPCODE_ENDLOOP,"ENDLOOP", 0, 0 },
+   { OPCODE_ENDSUB, "ENDSUB",  0, 0 },
+   { OPCODE_EX2,    "EX2",     1, 1 },
+   { OPCODE_EXP,    "EXP",     1, 1 },
+   { OPCODE_FLR,    "FLR",     1, 1 },
+   { OPCODE_FRC,    "FRC",     1, 1 },
+   { OPCODE_IF,     "IF",      1, 0 },
+   { OPCODE_KIL,    "KIL",     1, 0 },
+   { OPCODE_KIL_NV, "KIL_NV",  0, 0 },
+   { OPCODE_LG2,    "LG2",     1, 1 },
+   { OPCODE_LIT,    "LIT",     1, 1 },
+   { OPCODE_LOG,    "LOG",     1, 1 },
+   { OPCODE_LRP,    "LRP",     3, 1 },
+   { OPCODE_MAD,    "MAD",     3, 1 },
+   { OPCODE_MAX,    "MAX",     2, 1 },
+   { OPCODE_MIN,    "MIN",     2, 1 },
+   { OPCODE_MOV,    "MOV",     1, 1 },
+   { OPCODE_MUL,    "MUL",     2, 1 },
+   { OPCODE_NOISE1, "NOISE1",  1, 1 },
+   { OPCODE_NOISE2, "NOISE2",  1, 1 },
+   { OPCODE_NOISE3, "NOISE3",  1, 1 },
+   { OPCODE_NOISE4, "NOISE4",  1, 1 },
+   { OPCODE_NOT,    "NOT",     1, 1 },
+   { OPCODE_NRM3,   "NRM3",    1, 1 },
+   { OPCODE_NRM4,   "NRM4",    1, 1 },
+   { OPCODE_OR,     "OR",      2, 1 },
+   { OPCODE_PK2H,   "PK2H",    1, 1 },
+   { OPCODE_PK2US,  "PK2US",   1, 1 },
+   { OPCODE_PK4B,   "PK4B",    1, 1 },
+   { OPCODE_PK4UB,  "PK4UB",   1, 1 },
+   { OPCODE_POW,    "POW",     2, 1 },
+   { OPCODE_POPA,   "POPA",    0, 0 },
+   { OPCODE_PRINT,  "PRINT",   1, 0 },
+   { OPCODE_PUSHA,  "PUSHA",   0, 0 },
+   { OPCODE_RCC,    "RCC",     1, 1 },
+   { OPCODE_RCP,    "RCP",     1, 1 },
+   { OPCODE_RET,    "RET",     0, 0 },
+   { OPCODE_RFL,    "RFL",     1, 1 },
+   { OPCODE_RSQ,    "RSQ",     1, 1 },
+   { OPCODE_SCS,    "SCS",     1, 1 },
+   { OPCODE_SEQ,    "SEQ",     2, 1 },
+   { OPCODE_SFL,    "SFL",     0, 1 },
+   { OPCODE_SGE,    "SGE",     2, 1 },
+   { OPCODE_SGT,    "SGT",     2, 1 },
+   { OPCODE_SIN,    "SIN",     1, 1 },
+   { OPCODE_SLE,    "SLE",     2, 1 },
+   { OPCODE_SLT,    "SLT",     2, 1 },
+   { OPCODE_SNE,    "SNE",     2, 1 },
+   { OPCODE_SSG,    "SSG",     1, 1 },
+   { OPCODE_STR,    "STR",     0, 1 },
+   { OPCODE_SUB,    "SUB",     2, 1 },
+   { OPCODE_SWZ,    "SWZ",     1, 1 },
+   { OPCODE_TEX,    "TEX",     1, 1 },
+   { OPCODE_TXB,    "TXB",     1, 1 },
+   { OPCODE_TXD,    "TXD",     3, 1 },
+   { OPCODE_TXL,    "TXL",     1, 1 },
+   { OPCODE_TXP,    "TXP",     1, 1 },
+   { OPCODE_TXP_NV, "TXP_NV",  1, 1 },
+   { OPCODE_TRUNC,  "TRUNC",   1, 1 },
+   { OPCODE_UP2H,   "UP2H",    1, 1 },
+   { OPCODE_UP2US,  "UP2US",   1, 1 },
+   { OPCODE_UP4B,   "UP4B",    1, 1 },
+   { OPCODE_UP4UB,  "UP4UB",   1, 1 },
+   { OPCODE_X2D,    "X2D",     3, 1 },
+   { OPCODE_XOR,    "XOR",     2, 1 },
+   { OPCODE_XPD,    "XPD",     2, 1 }
+};
+
+
+/**
+ * Return the number of src registers for the given instruction/opcode.
+ */
+GLuint
+_mesa_num_inst_src_regs(gl_inst_opcode opcode)
+{
+   ASSERT(opcode < MAX_OPCODE);
+   ASSERT(opcode == InstInfo[opcode].Opcode);
+   ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
+   return InstInfo[opcode].NumSrcRegs;
+}
+
+
+/**
+ * Return the number of dst registers for the given instruction/opcode.
+ */
+GLuint
+_mesa_num_inst_dst_regs(gl_inst_opcode opcode)
+{
+   ASSERT(opcode < MAX_OPCODE);
+   ASSERT(opcode == InstInfo[opcode].Opcode);
+   ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
+   return InstInfo[opcode].NumDstRegs;
+}
+
+
+GLboolean
+_mesa_is_tex_instruction(gl_inst_opcode opcode)
+{
+   return (opcode == OPCODE_TEX ||
+           opcode == OPCODE_TXB ||
+           opcode == OPCODE_TXD ||
+           opcode == OPCODE_TXL ||
+           opcode == OPCODE_TXP);
+}
+
+
+/**
+ * Check if there's a potential src/dst register data dependency when
+ * using SOA execution.
+ * Example:
+ *   MOV T, T.yxwz;
+ * This would expand into:
+ *   MOV t0, t1;
+ *   MOV t1, t0;
+ *   MOV t2, t3;
+ *   MOV t3, t2;
+ * The second instruction will have the wrong value for t0 if executed as-is.
+ */
+GLboolean
+_mesa_check_soa_dependencies(const struct prog_instruction *inst)
+{
+   GLuint i, chan;
+
+   if (inst->DstReg.WriteMask == WRITEMASK_X ||
+       inst->DstReg.WriteMask == WRITEMASK_Y ||
+       inst->DstReg.WriteMask == WRITEMASK_Z ||
+       inst->DstReg.WriteMask == WRITEMASK_W ||
+       inst->DstReg.WriteMask == 0x0) {
+      /* no chance of data dependency */
+      return GL_FALSE;
+   }
+
+   /* loop over src regs */
+   for (i = 0; i < 3; i++) {
+      if (inst->SrcReg[i].File == inst->DstReg.File &&
+          inst->SrcReg[i].Index == inst->DstReg.Index) {
+         /* loop over dest channels */
+         GLuint channelsWritten = 0x0;
+         for (chan = 0; chan < 4; chan++) {
+            if (inst->DstReg.WriteMask & (1 << chan)) {
+               /* check if we're reading a channel that's been written */
+               GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan);
+               if (swizzle <= SWIZZLE_W &&
+                   (channelsWritten & (1 << swizzle))) {
+                  return GL_TRUE;
+               }
+
+               channelsWritten |= (1 << chan);
+            }
+         }
+      }
+   }
+   return GL_FALSE;
+}
+
+
+/**
+ * Return string name for given program opcode.
+ */
+const char *
+_mesa_opcode_string(gl_inst_opcode opcode)
+{
+   if (opcode < MAX_OPCODE)
+      return InstInfo[opcode].Name;
+   else {
+      static char s[20];
+      _mesa_snprintf(s, sizeof(s), "OP%u", opcode);
+      return s;
+   }
+}
+
diff --git a/mesa/shader/prog_instruction.h b/mesa/shader/prog_instruction.h
new file mode 100644 (file)
index 0000000..2c95d27
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.3
+ *
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * \file prog_instruction.h
+ *
+ * Vertex/fragment program instruction datatypes and constants.
+ *
+ * \author Brian Paul
+ * \author Keith Whitwell
+ * \author Ian Romanick <idr@us.ibm.com>
+ */
+
+
+#ifndef PROG_INSTRUCTION_H
+#define PROG_INSTRUCTION_H
+
+
+#include "main/mtypes.h"
+
+
+/**
+ * Swizzle indexes.
+ * Do not change!
+ */
+/*@{*/
+#define SWIZZLE_X    0
+#define SWIZZLE_Y    1
+#define SWIZZLE_Z    2
+#define SWIZZLE_W    3
+#define SWIZZLE_ZERO 4   /**< For SWZ instruction only */
+#define SWIZZLE_ONE  5   /**< For SWZ instruction only */
+#define SWIZZLE_NIL  7   /**< used during shader code gen (undefined value) */
+/*@}*/
+
+#define MAKE_SWIZZLE4(a,b,c,d) (((a)<<0) | ((b)<<3) | ((c)<<6) | ((d)<<9))
+#define SWIZZLE_NOOP           MAKE_SWIZZLE4(0,1,2,3)
+#define GET_SWZ(swz, idx)      (((swz) >> ((idx)*3)) & 0x7)
+#define GET_BIT(msk, idx)      (((msk) >> (idx)) & 0x1)
+
+#define SWIZZLE_XYZW MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
+#define SWIZZLE_XXXX MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X)
+#define SWIZZLE_YYYY MAKE_SWIZZLE4(SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y)
+#define SWIZZLE_ZZZZ MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z, SWIZZLE_Z)
+#define SWIZZLE_WWWW MAKE_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
+
+
+/**
+ * Writemask values, 1 bit per component.
+ */
+/*@{*/
+#define WRITEMASK_X     0x1
+#define WRITEMASK_Y     0x2
+#define WRITEMASK_XY    0x3
+#define WRITEMASK_Z     0x4
+#define WRITEMASK_XZ    0x5
+#define WRITEMASK_YZ    0x6
+#define WRITEMASK_XYZ   0x7
+#define WRITEMASK_W     0x8
+#define WRITEMASK_XW    0x9
+#define WRITEMASK_YW    0xa
+#define WRITEMASK_XYW   0xb
+#define WRITEMASK_ZW    0xc
+#define WRITEMASK_XZW   0xd
+#define WRITEMASK_YZW   0xe
+#define WRITEMASK_XYZW  0xf
+/*@}*/
+
+
+/**
+ * Condition codes
+ */
+/*@{*/
+#define COND_GT  1  /**< greater than zero */
+#define COND_EQ  2  /**< equal to zero */
+#define COND_LT  3  /**< less than zero */
+#define COND_UN  4  /**< unordered (NaN) */
+#define COND_GE  5  /**< greater than or equal to zero */
+#define COND_LE  6  /**< less than or equal to zero */
+#define COND_NE  7  /**< not equal to zero */
+#define COND_TR  8  /**< always true */
+#define COND_FL  9  /**< always false */
+/*@}*/
+
+
+/**
+ * Instruction precision for GL_NV_fragment_program
+ */
+/*@{*/
+#define FLOAT32  0x1
+#define FLOAT16  0x2
+#define FIXED12  0x4
+/*@}*/
+
+
+/**
+ * Saturation modes when storing values.
+ */
+/*@{*/
+#define SATURATE_OFF            0
+#define SATURATE_ZERO_ONE       1
+/*@}*/
+
+
+/**
+ * Per-component negation masks
+ */
+/*@{*/
+#define NEGATE_X    0x1
+#define NEGATE_Y    0x2
+#define NEGATE_Z    0x4
+#define NEGATE_W    0x8
+#define NEGATE_XYZ  0x7
+#define NEGATE_XYZW 0xf
+#define NEGATE_NONE 0x0
+/*@}*/
+
+
+/**
+ * Program instruction opcodes, for both vertex and fragment programs.
+ * \note changes to this opcode list must be reflected in t_vb_arbprogram.c
+ */
+typedef enum prog_opcode {
+                     /* ARB_vp   ARB_fp   NV_vp   NV_fp     GLSL */
+                     /*------------------------------------------*/
+   OPCODE_NOP = 0,   /*                                      X   */
+   OPCODE_ABS,       /*   X        X       1.1               X   */
+   OPCODE_ADD,       /*   X        X       X       X         X   */
+   OPCODE_AND,       /*                                          */
+   OPCODE_ARA,       /*                    2                     */
+   OPCODE_ARL,       /*   X                X                     */
+   OPCODE_ARL_NV,    /*                    2                     */
+   OPCODE_ARR,       /*                    2                     */
+   OPCODE_BGNLOOP,   /*                                     opt  */
+   OPCODE_BGNSUB,    /*                                     opt  */
+   OPCODE_BRA,       /*                    2                 X   */
+   OPCODE_BRK,       /*                    2                opt  */
+   OPCODE_CAL,       /*                    2       2             */
+   OPCODE_CMP,       /*            X                             */
+   OPCODE_CONT,      /*                                     opt  */
+   OPCODE_COS,       /*            X       2       X         X   */
+   OPCODE_DDX,       /*                            X         X   */
+   OPCODE_DDY,       /*                            X         X   */
+   OPCODE_DP2,       /*                            2             */
+   OPCODE_DP2A,      /*                            2             */
+   OPCODE_DP3,       /*   X        X       X       X         X   */
+   OPCODE_DP4,       /*   X        X       X       X         X   */
+   OPCODE_DPH,       /*   X        X       1.1                   */
+   OPCODE_DST,       /*   X        X       X       X             */
+   OPCODE_ELSE,      /*                                      X   */
+   OPCODE_END,       /*   X        X       X       X        opt  */
+   OPCODE_ENDIF,     /*                                     opt  */
+   OPCODE_ENDLOOP,   /*                                     opt  */
+   OPCODE_ENDSUB,    /*                                     opt  */
+   OPCODE_EX2,       /*   X        X       2       X         X   */
+   OPCODE_EXP,       /*   X                X                 X   */
+   OPCODE_FLR,       /*   X        X       2       X         X   */
+   OPCODE_FRC,       /*   X        X       2       X         X   */
+   OPCODE_IF,        /*                                     opt  */
+   OPCODE_KIL,       /*            X                             */
+   OPCODE_KIL_NV,    /*                            X         X   */
+   OPCODE_LG2,       /*   X        X       2       X         X   */
+   OPCODE_LIT,       /*   X        X       X       X             */
+   OPCODE_LOG,       /*   X                X                 X   */
+   OPCODE_LRP,       /*            X               X             */
+   OPCODE_MAD,       /*   X        X       X       X         X   */
+   OPCODE_MAX,       /*   X        X       X       X         X   */
+   OPCODE_MIN,       /*   X        X       X       X         X   */
+   OPCODE_MOV,       /*   X        X       X       X         X   */
+   OPCODE_MUL,       /*   X        X       X       X         X   */
+   OPCODE_NOISE1,    /*                                      X   */
+   OPCODE_NOISE2,    /*                                      X   */
+   OPCODE_NOISE3,    /*                                      X   */
+   OPCODE_NOISE4,    /*                                      X   */
+   OPCODE_NOT,       /*                                          */
+   OPCODE_NRM3,      /*                                          */
+   OPCODE_NRM4,      /*                                          */
+   OPCODE_OR,        /*                                          */
+   OPCODE_PK2H,      /*                            X             */
+   OPCODE_PK2US,     /*                            X             */
+   OPCODE_PK4B,      /*                            X             */
+   OPCODE_PK4UB,     /*                            X             */
+   OPCODE_POW,       /*   X        X               X         X   */
+   OPCODE_POPA,      /*                    3                     */
+   OPCODE_PRINT,     /*                    X       X             */
+   OPCODE_PUSHA,     /*                    3                     */
+   OPCODE_RCC,       /*                    1.1                   */
+   OPCODE_RCP,       /*   X        X       X       X         X   */
+   OPCODE_RET,       /*                    2       2             */
+   OPCODE_RFL,       /*            X               X             */
+   OPCODE_RSQ,       /*   X        X       X       X         X   */
+   OPCODE_SCS,       /*            X                             */
+   OPCODE_SEQ,       /*                    2       X         X   */
+   OPCODE_SFL,       /*                    2       X             */
+   OPCODE_SGE,       /*   X        X       X       X         X   */
+   OPCODE_SGT,       /*                    2       X         X   */
+   OPCODE_SIN,       /*            X       2       X         X   */
+   OPCODE_SLE,       /*                    2       X         X   */
+   OPCODE_SLT,       /*   X        X       X       X         X   */
+   OPCODE_SNE,       /*                    2       X         X   */
+   OPCODE_SSG,       /*                    2                     */
+   OPCODE_STR,       /*                    2       X             */
+   OPCODE_SUB,       /*   X        X       1.1     X         X   */
+   OPCODE_SWZ,       /*   X        X                             */
+   OPCODE_TEX,       /*            X       3       X         X   */
+   OPCODE_TXB,       /*            X       3                 X   */
+   OPCODE_TXD,       /*                            X         X   */
+   OPCODE_TXL,       /*                    3       2         X   */
+   OPCODE_TXP,       /*            X                         X   */
+   OPCODE_TXP_NV,    /*                    3       X             */
+   OPCODE_TRUNC,     /*                                      X   */
+   OPCODE_UP2H,      /*                            X             */
+   OPCODE_UP2US,     /*                            X             */
+   OPCODE_UP4B,      /*                            X             */
+   OPCODE_UP4UB,     /*                            X             */
+   OPCODE_X2D,       /*                            X             */
+   OPCODE_XOR,       /*                                          */
+   OPCODE_XPD,       /*   X        X                         X   */
+   MAX_OPCODE
+} gl_inst_opcode;
+
+
+/**
+ * Number of bits for the src/dst register Index field.
+ * This limits the size of temp/uniform register files.
+ */
+#define INST_INDEX_BITS 10
+
+
+/**
+ * Instruction source register.
+ */
+struct prog_src_register
+{
+   GLuint File:4;      /**< One of the PROGRAM_* register file values. */
+   GLint Index:(INST_INDEX_BITS+1); /**< Extra bit here for sign bit.
+                                     * May be negative for relative addressing.
+                                     */
+   GLuint Swizzle:12;
+   GLuint RelAddr:1;
+
+   /** Take the component-wise absolute value */
+   GLuint Abs:1;
+
+   /**
+    * Post-Abs negation.
+    * This will either be NEGATE_NONE or NEGATE_XYZW, except for the SWZ
+    * instruction which allows per-component negation.
+    */
+   GLuint Negate:4;
+};
+
+
+/**
+ * Instruction destination register.
+ */
+struct prog_dst_register
+{
+   GLuint File:4;      /**< One of the PROGRAM_* register file values */
+   GLuint Index:INST_INDEX_BITS;  /**< Unsigned, never negative */
+   GLuint WriteMask:4;
+   GLuint RelAddr:1;
+
+   /**
+    * \name Conditional destination update control.
+    *
+    * \since
+    * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+    * NV_vertex_program2_option.
+    */
+   /*@{*/
+   /**
+    * Takes one of the 9 possible condition values (EQ, FL, GT, GE, LE, LT,
+    * NE, TR, or UN).  Dest reg is only written to if the matching
+    * (swizzled) condition code value passes.  When a conditional update mask
+    * is not specified, this will be \c COND_TR.
+    */
+   GLuint CondMask:4;
+
+   /**
+    * Condition code swizzle value.
+    */
+   GLuint CondSwizzle:12;
+
+   /**
+    * Selects the condition code register to use for conditional destination
+    * update masking.  In NV_fragmnet_program or NV_vertex_program2 mode, only
+    * condition code register 0 is available.  In NV_vertex_program3 mode,
+    * condition code registers 0 and 1 are available.
+    */
+   GLuint CondSrc:1;
+   /*@}*/
+};
+
+
+/**
+ * Vertex/fragment program instruction.
+ */
+struct prog_instruction
+{
+   gl_inst_opcode Opcode;
+   struct prog_src_register SrcReg[3];
+   struct prog_dst_register DstReg;
+
+   /**
+    * Indicates that the instruction should update the condition code
+    * register.
+    *
+    * \since
+    * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+    * NV_vertex_program2_option.
+    */
+   GLuint CondUpdate:1;
+
+   /**
+    * If prog_instruction::CondUpdate is \c GL_TRUE, this value selects the
+    * condition code register that is to be updated.
+    *
+    * In GL_NV_fragment_program or GL_NV_vertex_program2 mode, only condition
+    * code register 0 is available.  In GL_NV_vertex_program3 mode, condition
+    * code registers 0 and 1 are available.
+    *
+    * \since
+    * NV_fragment_program, NV_fragment_program_option, NV_vertex_program2,
+    * NV_vertex_program2_option.
+    */
+   GLuint CondDst:1;
+
+   /**
+    * Saturate each value of the vectored result to the range [0,1] or the
+    * range [-1,1].  \c SSAT mode (i.e., saturation to the range [-1,1]) is
+    * only available in NV_fragment_program2 mode.
+    * Value is one of the SATURATE_* tokens.
+    *
+    * \since
+    * NV_fragment_program, NV_fragment_program_option, NV_vertex_program3.
+    */
+   GLuint SaturateMode:2;
+
+   /**
+    * Per-instruction selectable precision: FLOAT32, FLOAT16, FIXED12.
+    *
+    * \since
+    * NV_fragment_program, NV_fragment_program_option.
+    */
+   GLuint Precision:3;
+
+   /**
+    * \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions.
+    */
+   /*@{*/
+   /** Source texture unit. */
+   GLuint TexSrcUnit:5;
+
+   /** Source texture target, one of TEXTURE_{1D,2D,3D,CUBE,RECT}_INDEX */
+   GLuint TexSrcTarget:3;
+
+   /** True if tex instruction should do shadow comparison */
+   GLuint TexShadow:1;
+   /*@}*/
+
+   /**
+    * For BRA and CAL instructions, the location to jump to.
+    * For BGNLOOP, points to ENDLOOP (and vice-versa).
+    * For BRK, points to BGNLOOP (which points to ENDLOOP).
+    * For IF, points to ELSE or ENDIF.
+    * For ELSE, points to ENDIF.
+    */
+   GLint BranchTarget;
+
+   /** for debugging purposes */
+   const char *Comment;
+
+   /** Arbitrary data.  Used for OPCODE_PRINT and some drivers */
+   void *Data;
+
+   /** for driver use (try to remove someday) */
+   GLint Aux;
+};
+
+
+extern void
+_mesa_init_instructions(struct prog_instruction *inst, GLuint count);
+
+extern struct prog_instruction *
+_mesa_alloc_instructions(GLuint numInst);
+
+extern struct prog_instruction *
+_mesa_realloc_instructions(struct prog_instruction *oldInst,
+                           GLuint numOldInst, GLuint numNewInst);
+
+extern struct prog_instruction *
+_mesa_copy_instructions(struct prog_instruction *dest,
+                        const struct prog_instruction *src, GLuint n);
+
+extern void
+_mesa_free_instructions(struct prog_instruction *inst, GLuint count);
+
+extern GLuint
+_mesa_num_inst_src_regs(gl_inst_opcode opcode);
+
+extern GLuint
+_mesa_num_inst_dst_regs(gl_inst_opcode opcode);
+
+extern GLboolean
+_mesa_is_tex_instruction(gl_inst_opcode opcode);
+
+extern GLboolean
+_mesa_check_soa_dependencies(const struct prog_instruction *inst);
+
+extern const char *
+_mesa_opcode_string(gl_inst_opcode opcode);
+
+
+#endif /* PROG_INSTRUCTION_H */
diff --git a/mesa/shader/prog_print.c b/mesa/shader/prog_print.c
new file mode 100644 (file)
index 0000000..3f1cb48
--- /dev/null
@@ -0,0 +1,1089 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.3
+ *
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file prog_print.c
+ * Print vertex/fragment programs - for debugging.
+ * \author Brian Paul
+ */
+
+#if 0
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/imports.h"
+#else
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+struct gl_program {
+   int Target;
+};
+
+void _mesa_problem(void *ctx, char *msg)
+{
+   (void)ctx;
+   fprintf(stderr, "%s", msg);
+   exit(1);
+}
+
+#endif
+
+#include "prog_instruction.h"
+#include "prog_print.h"
+
+
+
+/**
+ * Return string name for given program/register file.
+ */
+static const char *
+file_string(gl_register_file f, gl_prog_print_mode mode)
+{
+   (void)mode;
+   switch (f) {
+   case PROGRAM_TEMPORARY:
+      return "TEMP";
+   case PROGRAM_LOCAL_PARAM:
+      return "LOCAL";
+   case PROGRAM_ENV_PARAM:
+      return "ENV";
+   case PROGRAM_STATE_VAR:
+      return "STATE";
+   case PROGRAM_INPUT:
+      return "INPUT";
+   case PROGRAM_OUTPUT:
+      return "OUTPUT";
+   case PROGRAM_NAMED_PARAM:
+      return "NAMED";
+   case PROGRAM_CONSTANT:
+      return "CONST";
+   case PROGRAM_UNIFORM:
+      return "UNIFORM";
+   case PROGRAM_VARYING:
+      return "VARYING";
+   case PROGRAM_WRITE_ONLY:
+      return "WRITE_ONLY";
+   case PROGRAM_ADDRESS:
+      return "ADDR";
+   case PROGRAM_SAMPLER:
+      return "SAMPLER";
+   case PROGRAM_UNDEFINED:
+      return "UNDEFINED";
+   default:
+      {
+         static char s[20];
+         snprintf(s, sizeof(s), "FILE%u", f);
+         return s;
+      }
+   }
+}
+
+
+/**
+ * Return ARB_v/f_prog-style input attrib string.
+ */
+static const char *
+arb_input_attrib_string(GLint index, GLenum progType)
+{
+   /*
+    * These strings should match the VERT_ATTRIB_x and FRAG_ATTRIB_x tokens.
+    */
+   const char *vertAttribs[] = {
+      "vertex.position",
+      "vertex.weight",
+      "vertex.normal",
+      "vertex.color.primary",
+      "vertex.color.secondary",
+      "vertex.fogcoord",
+      "vertex.(six)",
+      "vertex.(seven)",
+      "vertex.texcoord[0]",
+      "vertex.texcoord[1]",
+      "vertex.texcoord[2]",
+      "vertex.texcoord[3]",
+      "vertex.texcoord[4]",
+      "vertex.texcoord[5]",
+      "vertex.texcoord[6]",
+      "vertex.texcoord[7]",
+      "vertex.attrib[0]",
+      "vertex.attrib[1]",
+      "vertex.attrib[2]",
+      "vertex.attrib[3]",
+      "vertex.attrib[4]",
+      "vertex.attrib[5]",
+      "vertex.attrib[6]",
+      "vertex.attrib[7]",
+      "vertex.attrib[8]",
+      "vertex.attrib[9]",
+      "vertex.attrib[10]",
+      "vertex.attrib[11]",
+      "vertex.attrib[12]",
+      "vertex.attrib[13]",
+      "vertex.attrib[14]",
+      "vertex.attrib[15]"
+   };
+   const char *fragAttribs[] = {
+      "fragment.position",
+      "fragment.color.primary",
+      "fragment.color.secondary",
+      "fragment.fogcoord",
+      "fragment.texcoord[0]",
+      "fragment.texcoord[1]",
+      "fragment.texcoord[2]",
+      "fragment.texcoord[3]",
+      "fragment.texcoord[4]",
+      "fragment.texcoord[5]",
+      "fragment.texcoord[6]",
+      "fragment.texcoord[7]",
+      "fragment.varying[0]",
+      "fragment.varying[1]",
+      "fragment.varying[2]",
+      "fragment.varying[3]",
+      "fragment.varying[4]",
+      "fragment.varying[5]",
+      "fragment.varying[6]",
+      "fragment.varying[7]"
+   };
+
+   /* sanity checks */
+   assert(strcmp(vertAttribs[VERT_ATTRIB_TEX0], "vertex.texcoord[0]") == 0);
+   assert(strcmp(vertAttribs[VERT_ATTRIB_GENERIC15], "vertex.attrib[15]") == 0);
+
+   if (progType == GL_VERTEX_PROGRAM_ARB) {
+      assert((unsigned int)index < sizeof(vertAttribs) / sizeof(vertAttribs[0]));
+      return vertAttribs[index];
+   }
+   else {
+      assert((unsigned int)index < sizeof(fragAttribs) / sizeof(fragAttribs[0]));
+      return fragAttribs[index];
+   }
+}
+
+
+/**
+ * Print a vertex program's InputsRead field in human-readable format.
+ * For debugging.
+ */
+void
+_mesa_print_vp_inputs(GLbitfield inputs)
+{
+   printf("VP Inputs 0x%x: \n", inputs);
+   while (inputs) {
+      GLint attr = ffs(inputs) - 1;
+      const char *name = arb_input_attrib_string(attr,
+                                                 GL_VERTEX_PROGRAM_ARB);
+      printf("  %d: %s\n", attr, name);
+      inputs &= ~(1 << attr);
+   }
+}
+
+
+/**
+ * Print a fragment program's InputsRead field in human-readable format.
+ * For debugging.
+ */
+void
+_mesa_print_fp_inputs(GLbitfield inputs)
+{
+   printf("FP Inputs 0x%x: \n", inputs);
+   while (inputs) {
+      GLint attr = ffs(inputs) - 1;
+      const char *name = arb_input_attrib_string(attr,
+                                                 GL_FRAGMENT_PROGRAM_ARB);
+      printf("  %d: %s\n", attr, name);
+      inputs &= ~(1 << attr);
+   }
+}
+
+
+#if 0
+/**
+ * Return ARB_v/f_prog-style output attrib string.
+ */
+static const char *
+arb_output_attrib_string(GLint index, GLenum progType)
+{
+   /*
+    * These strings should match the VERT_RESULT_x and FRAG_RESULT_x tokens.
+    */
+   const char *vertResults[] = {
+      "result.position",
+      "result.color.primary",
+      "result.color.secondary",
+      "result.fogcoord",
+      "result.texcoord[0]",
+      "result.texcoord[1]",
+      "result.texcoord[2]",
+      "result.texcoord[3]",
+      "result.texcoord[4]",
+      "result.texcoord[5]",
+      "result.texcoord[6]",
+      "result.texcoord[7]",
+      "result.varying[0]",
+      "result.varying[1]",
+      "result.varying[2]",
+      "result.varying[3]",
+      "result.varying[4]",
+      "result.varying[5]",
+      "result.varying[6]",
+      "result.varying[7]"
+   };
+   const char *fragResults[] = {
+      "result.color",
+      "result.color(half)",
+      "result.depth",
+      "result.color[0]",
+      "result.color[1]",
+      "result.color[2]",
+      "result.color[3]"
+   };
+
+   if (progType == GL_VERTEX_PROGRAM_ARB) {
+      assert(index < sizeof(vertResults) / sizeof(vertResults[0]));
+      return vertResults[index];
+   }
+   else {
+      assert(index < sizeof(fragResults) / sizeof(fragResults[0]));
+      return fragResults[index];
+   }
+}
+#endif
+
+/**
+ * Return string representation of the given register.
+ * Note that some types of registers (like PROGRAM_UNIFORM) aren't defined
+ * by the ARB/NV program languages so we've taken some liberties here.
+ * \param f  the register file (PROGRAM_INPUT, PROGRAM_TEMPORARY, etc)
+ * \param index  number of the register in the register file
+ * \param mode  the output format/mode/style
+ * \param prog  pointer to containing program
+ */
+static const char *
+reg_string(gl_register_file f, GLint index, gl_prog_print_mode mode,
+           GLboolean relAddr, const struct gl_program *prog)
+{
+   static char str[100];
+   const char *addr = relAddr ? "ADDR+" : "";
+
+   str[0] = 0;
+
+   switch (mode) {
+   case PROG_PRINT_DEBUG:
+      sprintf(str, "%s[%s%d]", file_string(f, mode), addr, index);
+      break;
+   case PROG_PRINT_ARB:
+#if 0
+      switch (f) {
+      case PROGRAM_INPUT:
+         sprintf(str, "%s", arb_input_attrib_string(index, prog->Target));
+         break;
+      case PROGRAM_OUTPUT:
+         sprintf(str, "%s", arb_output_attrib_string(index, prog->Target));
+         break;
+      case PROGRAM_TEMPORARY:
+         sprintf(str, "temp%d", index);
+         break;
+      case PROGRAM_ENV_PARAM:
+         sprintf(str, "program.env[%s%d]", addr, index);
+         break;
+      case PROGRAM_LOCAL_PARAM:
+         sprintf(str, "program.local[%s%d]", addr, index);
+         break;
+      case PROGRAM_VARYING: /* extension */
+         sprintf(str, "varying[%s%d]", addr, index);
+         break;
+      case PROGRAM_CONSTANT: /* extension */
+         sprintf(str, "constant[%s%d]", addr, index);
+         break;
+      case PROGRAM_UNIFORM: /* extension */
+         sprintf(str, "uniform[%s%d]", addr, index);
+         break;
+      case PROGRAM_STATE_VAR:
+         {
+            struct gl_program_parameter *param
+               = prog->Parameters->Parameters + index;
+            char *state = _mesa_program_state_string(param->StateIndexes);
+            sprintf(str, "%s", state);
+            free(state);
+         }
+         break;
+      case PROGRAM_ADDRESS:
+         sprintf(str, "A%d", index);
+         break;
+      default:
+         _mesa_problem(NULL, "bad file in reg_string()");
+      }
+      break;
+#else
+      assert(0);
+      break;
+#endif
+
+   case PROG_PRINT_NV:
+      switch (f) {
+      case PROGRAM_INPUT:
+         if (prog->Target == GL_VERTEX_PROGRAM_ARB)
+            sprintf(str, "v[%d]", index);
+         else
+            sprintf(str, "f[%d]", index);
+         break;
+      case PROGRAM_OUTPUT:
+         sprintf(str, "o[%d]", index);
+         break;
+      case PROGRAM_TEMPORARY:
+         sprintf(str, "R%d", index);
+         break;
+      case PROGRAM_ENV_PARAM:
+         sprintf(str, "c[%d]", index);
+         break;
+      case PROGRAM_VARYING: /* extension */
+         sprintf(str, "varying[%s%d]", addr, index);
+         break;
+      case PROGRAM_UNIFORM: /* extension */
+         sprintf(str, "uniform[%s%d]", addr, index);
+         break;
+      case PROGRAM_CONSTANT: /* extension */
+         sprintf(str, "constant[%s%d]", addr, index);
+         break;
+      case PROGRAM_STATE_VAR: /* extension */
+         sprintf(str, "state[%s%d]", addr, index);
+         break;
+      default:
+         _mesa_problem(NULL, "bad file in reg_string()");
+      }
+      break;
+
+   default:
+      _mesa_problem(NULL, "bad mode in reg_string()");
+   }
+
+   return str;
+}
+
+
+/**
+ * Return a string representation of the given swizzle word.
+ * If extended is true, use extended (comma-separated) format.
+ * \param swizzle  the swizzle field
+ * \param negateBase  4-bit negation vector
+ * \param extended  if true, also allow 0, 1 values
+ */
+const char *
+_mesa_swizzle_string(GLuint swizzle, GLuint negateMask, GLboolean extended)
+{
+   static const char swz[] = "xyzw01!?";  /* See SWIZZLE_x definitions */
+   static char s[20];
+   GLuint i = 0;
+
+   if (!extended && swizzle == SWIZZLE_NOOP && negateMask == 0)
+      return ""; /* no swizzle/negation */
+
+   if (!extended)
+      s[i++] = '.';
+
+   if (negateMask & NEGATE_X)
+      s[i++] = '-';
+   s[i++] = swz[GET_SWZ(swizzle, 0)];
+
+   if (extended) {
+      s[i++] = ',';
+   }
+
+   if (negateMask & NEGATE_Y)
+      s[i++] = '-';
+   s[i++] = swz[GET_SWZ(swizzle, 1)];
+
+   if (extended) {
+      s[i++] = ',';
+   }
+
+   if (negateMask & NEGATE_Z)
+      s[i++] = '-';
+   s[i++] = swz[GET_SWZ(swizzle, 2)];
+
+   if (extended) {
+      s[i++] = ',';
+   }
+
+   if (negateMask & NEGATE_W)
+      s[i++] = '-';
+   s[i++] = swz[GET_SWZ(swizzle, 3)];
+
+   s[i] = 0;
+   return s;
+}
+
+
+void
+_mesa_print_swizzle(GLuint swizzle)
+{
+   if (swizzle == SWIZZLE_XYZW) {
+      printf(".xyzw\n");
+   }
+   else {
+      const char *s = _mesa_swizzle_string(swizzle, 0, 0);
+      printf("%s\n", s);
+   }
+}
+
+
+const char *
+_mesa_writemask_string(GLuint writeMask)
+{
+   static char s[10];
+   GLuint i = 0;
+
+   if (writeMask == WRITEMASK_XYZW)
+      return "";
+
+   s[i++] = '.';
+   if (writeMask & WRITEMASK_X)
+      s[i++] = 'x';
+   if (writeMask & WRITEMASK_Y)
+      s[i++] = 'y';
+   if (writeMask & WRITEMASK_Z)
+      s[i++] = 'z';
+   if (writeMask & WRITEMASK_W)
+      s[i++] = 'w';
+
+   s[i] = 0;
+   return s;
+}
+
+
+const char *
+_mesa_condcode_string(GLuint condcode)
+{
+   switch (condcode) {
+   case COND_GT:  return "GT";
+   case COND_EQ:  return "EQ";
+   case COND_LT:  return "LT";
+   case COND_UN:  return "UN";
+   case COND_GE:  return "GE";
+   case COND_LE:  return "LE";
+   case COND_NE:  return "NE";
+   case COND_TR:  return "TR";
+   case COND_FL:  return "FL";
+   default: return "cond???";
+   }
+}
+
+
+static void
+fprint_dst_reg(FILE * f,
+               const struct prog_dst_register *dstReg,
+               gl_prog_print_mode mode,
+               const struct gl_program *prog)
+{
+   fprintf(f, "%s%s",
+          reg_string((gl_register_file) dstReg->File,
+                     dstReg->Index, mode, dstReg->RelAddr, prog),
+          _mesa_writemask_string(dstReg->WriteMask));
+   
+   if (dstReg->CondMask != COND_TR) {
+      fprintf(f, " (%s.%s)",
+             _mesa_condcode_string(dstReg->CondMask),
+             _mesa_swizzle_string(dstReg->CondSwizzle,
+                                  GL_FALSE, GL_FALSE));
+   }
+
+#if 0
+   fprintf(f, "%s[%d]%s",
+          file_string((gl_register_file) dstReg->File, mode),
+          dstReg->Index,
+          _mesa_writemask_string(dstReg->WriteMask));
+#endif
+}
+
+
+static void
+fprint_src_reg(FILE *f,
+               const struct prog_src_register *srcReg, 
+               gl_prog_print_mode mode,
+               const struct gl_program *prog)
+{
+   const char *abs = srcReg->Abs ? "|" : "";
+
+   fprintf(f, "%s%s%s%s",
+          abs,
+          reg_string((gl_register_file) srcReg->File,
+                     srcReg->Index, mode, srcReg->RelAddr, prog),
+          _mesa_swizzle_string(srcReg->Swizzle,
+                               srcReg->Negate, GL_FALSE),
+          abs);
+#if 0
+   fprintf(f, "%s[%d]%s",
+          file_string((gl_register_file) srcReg->File, mode),
+          srcReg->Index,
+          _mesa_swizzle_string(srcReg->Swizzle,
+                               srcReg->Negate, GL_FALSE));
+#endif
+}
+
+
+static void
+fprint_comment(FILE *f, const struct prog_instruction *inst)
+{
+   if (inst->Comment)
+      fprintf(f, ";  # %s\n", inst->Comment);
+   else
+      fprintf(f, ";\n");
+}
+
+
+static void
+fprint_alu_instruction(FILE *f,
+                       const struct prog_instruction *inst,
+                       const char *opcode_string, GLuint numRegs,
+                       gl_prog_print_mode mode,
+                       const struct gl_program *prog)
+{
+   GLuint j;
+
+   fprintf(f, "%s", opcode_string);
+   if (inst->CondUpdate)
+      fprintf(f, ".C");
+
+   /* frag prog only */
+   if (inst->SaturateMode == SATURATE_ZERO_ONE)
+      fprintf(f, "_SAT");
+
+   fprintf(f, " ");
+   if (inst->DstReg.File != PROGRAM_UNDEFINED) {
+      fprint_dst_reg(f, &inst->DstReg, mode, prog);
+   }
+   else {
+      fprintf(f, " ???");
+   }
+
+   if (numRegs > 0)
+      fprintf(f, ", ");
+
+   for (j = 0; j < numRegs; j++) {
+      fprint_src_reg(f, inst->SrcReg + j, mode, prog);
+      if (j + 1 < numRegs)
+        fprintf(f, ", ");
+   }
+
+   fprint_comment(f, inst);
+}
+
+
+void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+                            const char *opcode_string, GLuint numRegs)
+{
+   fprint_alu_instruction(stderr, inst, opcode_string,
+                          numRegs, PROG_PRINT_DEBUG, NULL);
+}
+
+
+/**
+ * Print a single vertex/fragment program instruction.
+ */
+GLint
+_mesa_fprint_instruction_opt(FILE *f,
+                            const struct prog_instruction *inst,
+                            GLint indent,
+                            gl_prog_print_mode mode,
+                            const struct gl_program *prog)
+{
+   GLint i;
+
+   if (inst->Opcode == OPCODE_ELSE ||
+       inst->Opcode == OPCODE_ENDIF ||
+       inst->Opcode == OPCODE_ENDLOOP ||
+       inst->Opcode == OPCODE_ENDSUB) {
+      indent -= 3;
+   }
+   for (i = 0; i < indent; i++) {
+      fprintf(f, " ");
+   }
+
+   switch (inst->Opcode) {
+   case OPCODE_PRINT:
+      fprintf(f, "PRINT '%s'", (char *) inst->Data);
+      if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+         fprintf(f, ", ");
+         fprintf(f, "%s[%d]%s",
+                file_string((gl_register_file) inst->SrcReg[0].File,
+                            mode),
+                inst->SrcReg[0].Index,
+                _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
+                                     inst->SrcReg[0].Negate, GL_FALSE));
+      }
+      if (inst->Comment)
+         fprintf(f, "  # %s", inst->Comment);
+      fprint_comment(f, inst);
+      break;
+   case OPCODE_SWZ:
+      fprintf(f, "SWZ");
+      if (inst->SaturateMode == SATURATE_ZERO_ONE)
+         fprintf(f, "_SAT");
+      fprintf(f, " ");
+      fprint_dst_reg(f, &inst->DstReg, mode, prog);
+      fprintf(f, ", %s[%d], %s",
+             file_string((gl_register_file) inst->SrcReg[0].File,
+                         mode),
+             inst->SrcReg[0].Index,
+             _mesa_swizzle_string(inst->SrcReg[0].Swizzle,
+                                  inst->SrcReg[0].Negate, GL_TRUE));
+      fprint_comment(f, inst);
+      break;
+   case OPCODE_TEX:
+   case OPCODE_TXP:
+   case OPCODE_TXL:
+   case OPCODE_TXB:
+      fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+      if (inst->SaturateMode == SATURATE_ZERO_ONE)
+         fprintf(f, "_SAT");
+      fprintf(f, " ");
+      fprint_dst_reg(f, &inst->DstReg, mode, prog);
+      fprintf(f, ", ");
+      fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+      fprintf(f, ", texture[%d], ", inst->TexSrcUnit);
+      switch (inst->TexSrcTarget) {
+      case TEXTURE_1D_INDEX:   fprintf(f, "1D");    break;
+      case TEXTURE_2D_INDEX:   fprintf(f, "2D");    break;
+      case TEXTURE_3D_INDEX:   fprintf(f, "3D");    break;
+      case TEXTURE_CUBE_INDEX: fprintf(f, "CUBE");  break;
+      case TEXTURE_RECT_INDEX: fprintf(f, "RECT");  break;
+      case TEXTURE_1D_ARRAY_INDEX: fprintf(f, "1D_ARRAY"); break;
+      case TEXTURE_2D_ARRAY_INDEX: fprintf(f, "2D_ARRAY"); break;
+      default:
+         ;
+      }
+      if (inst->TexShadow)
+         fprintf(f, " SHADOW");
+      fprint_comment(f, inst);
+      break;
+
+   case OPCODE_KIL:
+      fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+      fprintf(f, " ");
+      fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+      fprint_comment(f, inst);
+      break;
+   case OPCODE_KIL_NV:
+      fprintf(f, "%s", _mesa_opcode_string(inst->Opcode));
+      fprintf(f, " ");
+      fprintf(f, "%s.%s",
+             _mesa_condcode_string(inst->DstReg.CondMask),
+             _mesa_swizzle_string(inst->DstReg.CondSwizzle,
+                                  GL_FALSE, GL_FALSE));
+      fprint_comment(f, inst);
+      break;
+
+   case OPCODE_ARL:
+      fprintf(f, "ARL ");
+      fprint_dst_reg(f, &inst->DstReg, mode, prog);
+      fprintf(f, ", ");
+      fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+      fprint_comment(f, inst);
+      break;
+   case OPCODE_BRA:
+      fprintf(f, "BRA %d (%s%s)",
+             inst->BranchTarget,
+             _mesa_condcode_string(inst->DstReg.CondMask),
+             _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+      fprint_comment(f, inst);
+      break;
+   case OPCODE_IF:
+      if (inst->SrcReg[0].File != PROGRAM_UNDEFINED) {
+         /* Use ordinary register */
+         fprintf(f, "IF ");
+         fprint_src_reg(f, &inst->SrcReg[0], mode, prog);
+         fprintf(f, "; ");
+      }
+      else {
+         /* Use cond codes */
+         fprintf(f, "IF (%s%s);",
+                _mesa_condcode_string(inst->DstReg.CondMask),
+                _mesa_swizzle_string(inst->DstReg.CondSwizzle,
+                                     0, GL_FALSE));
+      }
+      fprintf(f, " # (if false, goto %d)", inst->BranchTarget);
+      fprint_comment(f, inst);
+      return indent + 3;
+   case OPCODE_ELSE:
+      fprintf(f, "ELSE; # (goto %d)\n", inst->BranchTarget);
+      return indent + 3;
+   case OPCODE_ENDIF:
+      fprintf(f, "ENDIF;\n");
+      break;
+   case OPCODE_BGNLOOP:
+      fprintf(f, "BGNLOOP; # (end at %d)\n", inst->BranchTarget);
+      return indent + 3;
+   case OPCODE_ENDLOOP:
+      fprintf(f, "ENDLOOP; # (goto %d)\n", inst->BranchTarget);
+      break;
+   case OPCODE_BRK:
+   case OPCODE_CONT:
+      fprintf(f, "%s (%s%s); # (goto %d)",
+             _mesa_opcode_string(inst->Opcode),
+             _mesa_condcode_string(inst->DstReg.CondMask),
+             _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE),
+             inst->BranchTarget);
+      fprint_comment(f, inst);
+      break;
+
+   case OPCODE_BGNSUB:
+      if (mode == PROG_PRINT_NV) {
+         fprintf(f, "%s:\n", inst->Comment); /* comment is label */
+         return indent;
+      }
+      else {
+         fprintf(f, "BGNSUB");
+         fprint_comment(f, inst);
+         return indent + 3;
+      }
+   case OPCODE_ENDSUB:
+      if (mode == PROG_PRINT_DEBUG) {
+         fprintf(f, "ENDSUB");
+         fprint_comment(f, inst);
+      }
+      break;
+   case OPCODE_CAL:
+      if (mode == PROG_PRINT_NV) {
+         fprintf(f, "CAL %s;  # (goto %d)\n", inst->Comment, inst->BranchTarget);
+      }
+      else {
+         fprintf(f, "CAL %u", inst->BranchTarget);
+         fprint_comment(f, inst);
+      }
+      break;
+   case OPCODE_RET:
+      fprintf(f, "RET (%s%s)",
+             _mesa_condcode_string(inst->DstReg.CondMask),
+             _mesa_swizzle_string(inst->DstReg.CondSwizzle, 0, GL_FALSE));
+      fprint_comment(f, inst);
+      break;
+
+   case OPCODE_END:
+      fprintf(f, "END\n");
+      break;
+   case OPCODE_NOP:
+      if (mode == PROG_PRINT_DEBUG) {
+         fprintf(f, "NOP");
+         fprint_comment(f, inst);
+      }
+      else if (inst->Comment) {
+         /* ARB/NV extensions don't have NOP instruction */
+         fprintf(f, "# %s\n", inst->Comment);
+      }
+      break;
+   /* XXX may need other special-case instructions */
+   default:
+      if (inst->Opcode < MAX_OPCODE) {
+         /* typical alu instruction */
+         fprint_alu_instruction(f, inst,
+                                _mesa_opcode_string(inst->Opcode),
+                                _mesa_num_inst_src_regs(inst->Opcode),
+                                mode, prog);
+      }
+      else {
+         fprint_alu_instruction(f, inst,
+                                _mesa_opcode_string(inst->Opcode),
+                                3/*_mesa_num_inst_src_regs(inst->Opcode)*/,
+                                mode, prog);
+      }
+      break;
+   }
+   return indent;
+}
+
+
+GLint
+_mesa_print_instruction_opt(const struct prog_instruction *inst,
+                            GLint indent,
+                            gl_prog_print_mode mode,
+                            const struct gl_program *prog)
+{
+   return _mesa_fprint_instruction_opt(stderr, inst, indent, mode, prog);
+}
+
+
+void
+_mesa_print_instruction(const struct prog_instruction *inst)
+{
+   /* note: 4th param should be ignored for PROG_PRINT_DEBUG */
+   _mesa_fprint_instruction_opt(stdout, inst, 0, PROG_PRINT_DEBUG, NULL);
+}
+
+#if 0
+/**
+ * Print program, with options.
+ */
+void
+_mesa_fprint_program_opt(FILE *f,
+                         const struct gl_program *prog,
+                         gl_prog_print_mode mode,
+                         GLboolean lineNumbers)
+{
+   GLuint i, indent = 0;
+
+   switch (prog->Target) {
+   case GL_VERTEX_PROGRAM_ARB:
+      if (mode == PROG_PRINT_ARB)
+         fprintf(f, "!!ARBvp1.0\n");
+      else if (mode == PROG_PRINT_NV)
+         fprintf(f, "!!VP1.0\n");
+      else
+         fprintf(f, "# Vertex Program/Shader %u\n", prog->Id);
+      break;
+   case GL_FRAGMENT_PROGRAM_ARB:
+   case GL_FRAGMENT_PROGRAM_NV:
+      if (mode == PROG_PRINT_ARB)
+         fprintf(f, "!!ARBfp1.0\n");
+      else if (mode == PROG_PRINT_NV)
+         fprintf(f, "!!FP1.0\n");
+      else
+         fprintf(f, "# Fragment Program/Shader %u\n", prog->Id);
+      break;
+   }
+
+   for (i = 0; i < prog->NumInstructions; i++) {
+      if (lineNumbers)
+         fprintf(f, "%3d: ", i);
+      indent = _mesa_fprint_instruction_opt(f, prog->Instructions + i,
+                                           indent, mode, prog);
+   }
+}
+
+
+/**
+ * Print program to stderr, default options.
+ */
+void
+_mesa_print_program(const struct gl_program *prog)
+{
+   _mesa_fprint_program_opt(stderr, prog, PROG_PRINT_DEBUG, GL_TRUE);
+}
+
+/**
+ * Return binary representation of 64-bit value (as a string).
+ * Insert a comma to separate each group of 8 bits.
+ * Note we return a pointer to local static storage so this is not
+ * re-entrant, etc.
+ * XXX move to imports.[ch] if useful elsewhere.
+ */
+static const char *
+binary(GLbitfield64 val)
+{
+   static char buf[80];
+   GLint i, len = 0;
+   for (i = 63; i >= 0; --i) {
+      if (val & (1ULL << i))
+         buf[len++] = '1';
+      else if (len > 0 || i == 0)
+         buf[len++] = '0';
+      if (len > 0 && ((i-1) % 8) == 7)
+         buf[len++] = ',';
+   }
+   buf[len] = '\0';
+   return buf;
+}
+
+
+/**
+ * Print all of a program's parameters/fields to given file.
+ */
+static void
+_mesa_fprint_program_parameters(FILE *f,
+                                GLcontext *ctx,
+                                const struct gl_program *prog)
+{
+   GLuint i;
+
+   fprintf(f, "InputsRead: 0x%x (0b%s)\n",
+                 prog->InputsRead, binary(prog->InputsRead));
+   fprintf(f, "OutputsWritten: 0x%llx (0b%s)\n",
+                 prog->OutputsWritten, binary(prog->OutputsWritten));
+   fprintf(f, "NumInstructions=%d\n", prog->NumInstructions);
+   fprintf(f, "NumTemporaries=%d\n", prog->NumTemporaries);
+   fprintf(f, "NumParameters=%d\n", prog->NumParameters);
+   fprintf(f, "NumAttributes=%d\n", prog->NumAttributes);
+   fprintf(f, "NumAddressRegs=%d\n", prog->NumAddressRegs);
+   fprintf(f, "SamplersUsed: 0x%x (0b%s)\n",
+                 prog->SamplersUsed, binary(prog->SamplersUsed));
+   fprintf(f, "Samplers=[ ");
+   for (i = 0; i < MAX_SAMPLERS; i++) {
+      fprintf(f, "%d ", prog->SamplerUnits[i]);
+   }
+   fprintf(f, "]\n");
+
+   _mesa_load_state_parameters(ctx, prog->Parameters);
+
+#if 0
+   fprintf(f, "Local Params:\n");
+   for (i = 0; i < MAX_PROGRAM_LOCAL_PARAMS; i++){
+      const GLfloat *p = prog->LocalParams[i];
+      fprintf(f, "%2d: %f, %f, %f, %f\n", i, p[0], p[1], p[2], p[3]);
+   }
+#endif 
+   _mesa_print_parameter_list(prog->Parameters);
+}
+
+
+/**
+ * Print all of a program's parameters/fields to stderr.
+ */
+void
+_mesa_print_program_parameters(GLcontext *ctx, const struct gl_program *prog)
+{
+   _mesa_fprint_program_parameters(stderr, ctx, prog);
+}
+
+
+/**
+ * Print a program parameter list to given file.
+ */
+static void
+_mesa_fprint_parameter_list(FILE *f,
+                            const struct gl_program_parameter_list *list)
+{
+   const gl_prog_print_mode mode = PROG_PRINT_DEBUG;
+   GLuint i;
+
+   if (!list)
+      return;
+
+   if (0)
+      fprintf(f, "param list %p\n", (void *) list);
+   fprintf(f, "dirty state flags: 0x%x\n", list->StateFlags);
+   for (i = 0; i < list->NumParameters; i++){
+      struct gl_program_parameter *param = list->Parameters + i;
+      const GLfloat *v = list->ParameterValues[i];
+      fprintf(f, "param[%d] sz=%d %s %s = {%.3g, %.3g, %.3g, %.3g}",
+             i, param->Size,
+             file_string(list->Parameters[i].Type, mode),
+             param->Name, v[0], v[1], v[2], v[3]);
+      if (param->Flags & PROG_PARAM_BIT_CENTROID)
+         fprintf(f, " Centroid");
+      if (param->Flags & PROG_PARAM_BIT_INVARIANT)
+         fprintf(f, " Invariant");
+      if (param->Flags & PROG_PARAM_BIT_FLAT)
+         fprintf(f, " Flat");
+      if (param->Flags & PROG_PARAM_BIT_LINEAR)
+         fprintf(f, " Linear");
+      fprintf(f, "\n");
+   }
+}
+
+
+/**
+ * Print a program parameter list to stderr.
+ */
+void
+_mesa_print_parameter_list(const struct gl_program_parameter_list *list)
+{
+   _mesa_fprint_parameter_list(stderr, list);
+}
+
+
+/**
+ * Write shader and associated info to a file.
+ */
+void
+_mesa_write_shader_to_file(const struct gl_shader *shader)
+{
+   const char *type;
+   char filename[100];
+   FILE *f;
+
+   if (shader->Type == GL_FRAGMENT_SHADER)
+      type = "frag";
+   else
+      type = "vert";
+
+   snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
+   f = fopen(filename, "w");
+   if (!f) {
+      fprintf(stderr, "Unable to open %s for writing\n", filename);
+      return;
+   }
+
+   fprintf(f, "/* Shader %u source, checksum %u */\n", shader->Name, shader->SourceChecksum);
+   fputs(shader->Source, f);
+   fprintf(f, "\n");
+
+   fprintf(f, "/* Compile status: %s */\n",
+           shader->CompileStatus ? "ok" : "fail");
+   if (!shader->CompileStatus) {
+      fprintf(f, "/* Log Info: */\n");
+      fputs(shader->InfoLog, f);
+   }
+   else {
+      fprintf(f, "/* GPU code */\n");
+      fprintf(f, "/*\n");
+      _mesa_fprint_program_opt(f, shader->Program, PROG_PRINT_DEBUG, GL_TRUE);
+      fprintf(f, "*/\n");
+      fprintf(f, "/* Parameters / constants */\n");
+      fprintf(f, "/*\n");
+      _mesa_fprint_parameter_list(f, shader->Program->Parameters);
+      fprintf(f, "*/\n");
+   }
+
+   fclose(f);
+}
+
+
+/**
+ * Append the shader's uniform info/values to the shader log file.
+ * The log file will typically have been created by the
+ * _mesa_write_shader_to_file function.
+ */
+void
+_mesa_append_uniforms_to_file(const struct gl_shader *shader,
+                              const struct gl_program *prog)
+{
+   const char *type;
+   char filename[100];
+   FILE *f;
+
+   if (shader->Type == GL_FRAGMENT_SHADER)
+      type = "frag";
+   else
+      type = "vert";
+
+   snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type);
+   f = fopen(filename, "a"); /* append */
+   if (!f) {
+      fprintf(stderr, "Unable to open %s for appending\n", filename);
+      return;
+   }
+
+   fprintf(f, "/* First-draw parameters / constants */\n");
+   fprintf(f, "/*\n");
+   _mesa_fprint_parameter_list(f, prog->Parameters);
+   fprintf(f, "*/\n");
+
+   fclose(f);
+}
+#endif
diff --git a/mesa/shader/prog_print.h b/mesa/shader/prog_print.h
new file mode 100644 (file)
index 0000000..f0df77b
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  6.5.3
+ *
+ * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef PROG_PRINT_H
+#define PROG_PRINT_H
+
+
+/**
+ * The output style to use when printing programs.
+ */
+typedef enum {
+   PROG_PRINT_ARB,
+   PROG_PRINT_NV,
+   PROG_PRINT_DEBUG
+} gl_prog_print_mode;
+
+
+extern void
+_mesa_print_vp_inputs(GLbitfield inputs);
+
+extern void
+_mesa_print_fp_inputs(GLbitfield inputs);
+
+extern const char *
+_mesa_condcode_string(GLuint condcode);
+
+extern const char *
+_mesa_swizzle_string(GLuint swizzle, GLuint negateBase, GLboolean extended);
+
+const char *
+_mesa_writemask_string(GLuint writeMask);
+
+extern void
+_mesa_print_swizzle(GLuint swizzle);
+
+extern void
+_mesa_print_alu_instruction(const struct prog_instruction *inst,
+                            const char *opcode_string, GLuint numRegs);
+
+extern void
+_mesa_print_instruction(const struct prog_instruction *inst);
+
+extern GLint
+_mesa_fprint_instruction_opt(FILE *f,
+                            const struct prog_instruction *inst,
+                            GLint indent,
+                            gl_prog_print_mode mode,
+                            const struct gl_program *prog);
+
+extern GLint
+_mesa_print_instruction_opt(const struct prog_instruction *inst, GLint indent,
+                            gl_prog_print_mode mode,
+                            const struct gl_program *prog);
+
+extern void
+_mesa_print_program(const struct gl_program *prog);
+
+extern void
+_mesa_fprint_program_opt(FILE *f,
+                         const struct gl_program *prog, gl_prog_print_mode mode,
+                         GLboolean lineNumbers);
+
+#if 0
+extern void
+_mesa_print_parameter_list(const struct gl_program_parameter_list *list);
+
+extern void
+_mesa_write_shader_to_file(const struct gl_shader *shader);
+
+extern void
+_mesa_append_uniforms_to_file(const struct gl_shader *shader,
+                              const struct gl_program *prog);
+#endif
+
+
+#endif /* PROG_PRINT_H */
index 5c900b5..d21b043 100644 (file)
--- a/program.h
+++ b/program.h
@@ -22,6 +22,7 @@
  */
 
 #include <GL/gl.h>
+#include "main/mtypes.h"
 
 /**
  * Based on gl_shader in Mesa's mtypes.h.
@@ -41,7 +42,6 @@ struct glsl_shader {
 };
 
 
-typedef int gl_register_file;
 typedef int gl_state_index;
 #define STATE_LENGTH 5