fixes for C++ warnings/errors
[mesa.git] / src / mesa / tnl / t_vb_arbprogram.c
index 5494eed098421a16af10e2b78997af3238f9d16d..524472a7772d27fee17a622f5063e3cc5026401d 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  6.3
+ * Version:  6.5.1
  *
- * Copyright (C) 1999-2004  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2006  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"),
 #include "macros.h"
 #include "mtypes.h"
 #include "arbprogparse.h"
+#include "light.h"
 #include "program.h"
 #include "math/m_matrix.h"
-#include "math/m_translate.h"
 #include "t_context.h"
 #include "t_pipeline.h"
-#include "t_vp_build.h"
+#include "t_vb_arbprogram.h"
+#include "tnl.h"
+#include "program_instruction.h"
 
-/* Define to see the compiled program on stderr:
- */
-#define DISASSEM 0
-
-
-/* New, internal instructions:
- */
-#define RSW        (VP_MAX_OPCODE)
-#define SEL        (VP_MAX_OPCODE+1)
-#define REL        (VP_MAX_OPCODE+2)
-
-
-/* Layout of register file:
-
-  0 -- Scratch (Arg0)
-  1 -- Scratch (Arg1)
-  2 -- Scratch (Result)
-  4 -- Program Temporary 0
-  16 -- Program Temporary 12 (max for NV_VERTEX_PROGRAM)
-  17 -- Output 0
-  31 -- Output 15 (max for NV_VERTEX_PROGRAM) (Last writeable register)
-  32 -- Parameter 0
-  ..
-  127 -- Parameter 63 (max for NV_VERTEX_PROGRAM)
-
-*/
-
-#define FILE_REG         0
-#define FILE_LOCAL_PARAM 1
-#define FILE_ENV_PARAM   2
-#define FILE_STATE_PARAM 3
-
-
-#define REG_ARG0   0
-#define REG_ARG1   1
-#define REG_ARG2   2
-#define REG_RES    3
-#define REG_ADDR   4
-#define REG_TMP0   5
-#define REG_TMP11  16
-#define REG_OUT0   17
-#define REG_OUT14  31
-#define REG_IN0    32
-#define REG_IN15   47
-#define REG_ID     48          /* 0,0,0,1 */
-#define REG_MAX    128
-#define REG_INVALID ~0
-
-/* ARB_vp instructions are broken down into one or more of the
- * following micro-instructions, each representable in a 32 bit packed
- * structure.
- */
-
-struct reg {
-   GLuint file:2;
-   GLuint idx:7;
-};
-
-
-union instruction {
-   struct {
-      GLuint opcode:6;
-      GLuint dst:5;
-      GLuint file0:2;
-      GLuint idx0:7;
-      GLuint file1:2;
-      GLuint idx1:7;
-      GLuint pad:3;
-   } alu;
-
-   struct {
-      GLuint opcode:6;
-      GLuint dst:5;
-      GLuint file0:2;
-      GLuint idx0:7;
-      GLuint neg:4;
-      GLuint swz:8;            /* xyzw only */
-   } rsw;
-
-   struct {
-      GLuint opcode:6;
-      GLuint dst:5;
-      GLuint idx0:7;           /* note! */
-      GLuint file1:2;
-      GLuint idx1:7;
-      GLuint mask:4;
-      GLuint pad:1;
-   } sel;
-
-   GLuint dword;
-};
 
+#define DISASSEM 0
 
 
 struct compilation {
    GLuint reg_active;
    union instruction *csr;
-   struct vertex_buffer *VB;   /* for input sizes! */
-};
-
-struct input {
-   GLuint idx;
-   GLfloat *data;
-   GLuint stride;
-   GLuint size;
-};
-
-struct output {
-   GLuint idx;
-   GLfloat *data;
-};
-
-/*--------------------------------------------------------------------------- */
-
-/*!
- * Private storage for the vertex program pipeline stage.
- */
-struct arb_vp_machine {
-   GLfloat reg[REG_MAX][4];    /* Program temporaries, inputs and outputs */
-   GLfloat (*File[4])[4];      /* All values reference-able from the program. */
-   GLint AddressReg;
-
-   struct input input[16];
-   GLuint nr_inputs;
-
-   struct output output[15];
-   GLuint nr_outputs;
-
-   union instruction store[1024];
-   union instruction *instructions;
-   GLint nr_instructions;
-
-   GLvector4f attribs[VERT_RESULT_MAX]; /**< result vectors. */
-   GLvector4f ndcCoords;              /**< normalized device coords */
-   GLubyte *clipmask;                 /**< clip flags */
-   GLubyte ormask, andmask;           /**< for clipping */
-
-   GLuint vtx_nr;              /**< loop counter */
-
-   struct vertex_buffer *VB;
-   GLcontext *ctx;
-};
-
-
-/*--------------------------------------------------------------------------- */
-
-struct opcode_info {
-   GLuint nr_args;
-   const char *string;
-   void (*print)( union instruction , const struct opcode_info * );
 };
 
 
 #define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr))
 
-
-
-/**
- * Set x to positive or negative infinity.
- *
- * XXX: FIXME - type punning.
- */
-#if defined(USE_IEEE) || defined(_WIN32)
-#define SET_POS_INFINITY(x)  ( *((GLuint *) (void *)&x) = 0x7F800000 )
-#define SET_NEG_INFINITY(x)  ( *((GLuint *) (void *)&x) = 0xFF800000 )
-#elif defined(VMS)
-#define SET_POS_INFINITY(x)  x = __MAXFLOAT
-#define SET_NEG_INFINITY(x)  x = -__MAXFLOAT
-#define IS_INF_OR_NAN(t)   ((t) == __MAXFLOAT)
-#else
-#define SET_POS_INFINITY(x)  x = (GLfloat) HUGE_VAL
-#define SET_NEG_INFINITY(x)  x = (GLfloat) -HUGE_VAL
-#endif
-
-#define FREXPF(a,b) frexpf(a,b)
-
 #define PUFF(x) ((x)[1] = (x)[2] = (x)[3] = (x)[0])
 
-/* FIXME: more type punning (despite use of fi_type...)
- */
-#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits
 
 
+/* Lower precision functions for the EXP, LOG and LIT opcodes.  The
+ * LOG2() implementation is probably not accurate enough, and the
+ * attempted optimization for Exp2 is definitely not accurate
+ * enough - it discards all of t's fractional bits!
+ */
 static GLfloat RoughApproxLog2(GLfloat t)
 {
    return LOG2(t);
 }
 
-static GLfloat RoughApproxPow2(GLfloat t)
+static GLfloat RoughApproxExp2(GLfloat t)
 {   
-   GLfloat q;
-#ifdef USE_IEEE
-   GLint ii = (GLint) t;
-   ii = (ii < 23) + 0x3f800000;
-   SET_FLOAT_BITS(q, ii);
-   q = *((GLfloat *) (void *)&ii);
+#if 0
+   fi_type fi;
+   fi.i = (GLint) t;
+   fi.i = (fi.i << 23) + 0x3f800000;
+   return fi.f;
 #else
-   q = (GLfloat) pow(2.0, floor_t0);
+   return (GLfloat) _mesa_pow(2.0, t);
 #endif
-   return q;
 }
 
 static GLfloat RoughApproxPower(GLfloat x, GLfloat y)
 {
-   return (GLfloat) _mesa_pow(x, y);
+   if (x == 0.0 && y == 0.0)
+      return 1.0;  /* spec requires this */
+   else
+      return RoughApproxExp2(y * RoughApproxLog2(x));
 }
 
 
-static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
-
+/* Higher precision functions for the EX2, LG2 and POW opcodes:
+ */
+static GLfloat ApproxLog2(GLfloat t)
+{
+   return (GLfloat) (LOGF(t) * 1.442695F);
+}
 
+static GLfloat ApproxExp2(GLfloat t)
+{   
+   return (GLfloat) _mesa_pow(2.0, t);
+}
 
-#define GET_RSW(swz, idx)      (((swz) >> ((idx)*2)) & 0x3)
+static GLfloat ApproxPower(GLfloat x, GLfloat y)
+{
+   return (GLfloat) _mesa_pow(x, y);
+}
 
 
 /**
@@ -262,16 +114,51 @@ static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };
  */
 static void do_RSW( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.rsw.dst];
+   GLfloat *result = m->File[0][op.rsw.dst];
    const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
-   GLuint swz = op.rsw.swz;
-   GLuint neg = op.rsw.neg;
+   const GLuint swz = op.rsw.swz;
+   const GLuint neg = op.rsw.neg;
+   GLfloat tmp[4];
+
+   /* Need a temporary to be correct in the case where result == arg0.
+    */
+   COPY_4V(tmp, arg0);
+
+   result[0] = tmp[GET_SWZ(swz, 0)];
+   result[1] = tmp[GET_SWZ(swz, 1)];
+   result[2] = tmp[GET_SWZ(swz, 2)];
+   result[3] = tmp[GET_SWZ(swz, 3)];
+
+   if (neg) {
+      if (neg & 0x1) result[0] = -result[0];
+      if (neg & 0x2) result[1] = -result[1];
+      if (neg & 0x4) result[2] = -result[2];
+      if (neg & 0x8) result[3] = -result[3];
+   }
+}
+
+/**
+ * Perform a full swizzle
+ */
+static void do_SWZ( struct arb_vp_machine *m, union instruction op ) 
+{
+   GLfloat *result = m->File[0][op.rsw.dst];
+   const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
+   const GLuint swz = op.rsw.swz;
+   const GLuint neg = op.rsw.neg;
+   GLfloat tmp[6];
+   tmp[4] = 0.0;
+   tmp[5] = 1.0;
+
+   /* Need a temporary to be correct in the case where result == arg0.
+    */
+   COPY_4V(tmp, arg0);
+
+   result[0] = tmp[GET_SWZ(swz, 0)];
+   result[1] = tmp[GET_SWZ(swz, 1)];
+   result[2] = tmp[GET_SWZ(swz, 2)];
+   result[3] = tmp[GET_SWZ(swz, 3)];
 
-   result[0] = arg0[GET_RSW(swz, 0)];
-   result[1] = arg0[GET_RSW(swz, 1)];
-   result[2] = arg0[GET_RSW(swz, 2)];
-   result[3] = arg0[GET_RSW(swz, 3)];
-   
    if (neg) {
       if (neg & 0x1) result[0] = -result[0];
       if (neg & 0x2) result[1] = -result[1];
@@ -280,18 +167,25 @@ static void do_RSW( struct arb_vp_machine *m, union instruction op )
    }
 }
 
-/* Used to implement write masking
+/* Used to implement write masking.  To make things easier for the sse
+ * generator I've gone back to a 1 argument version of this function
+ * (dst.msk = arg), rather than the semantically cleaner (dst = SEL
+ * arg0, arg1, msk)
+ *
+ * That means this is the only instruction which doesn't write a full
+ * 4 dwords out.  This would make such a program harder to analyse,
+ * but it looks like analysis is going to take place on a higher level
+ * anyway.
  */
-static void do_SEL( struct arb_vp_machine *m, union instruction op )
+static void do_MSK( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *dst = m->reg[op.sel.dst];
-   const GLfloat *arg0 = m->reg[op.sel.idx0];
-   const GLfloat *arg1 = m->File[op.sel.file1][op.sel.idx1];
+   GLfloat *dst = m->File[0][op.msk.dst];
+   const GLfloat *arg = m->File[op.msk.file][op.msk.idx];
  
-   dst[0] = (op.sel.mask & 0x1) ? arg0[0] : arg1[0];
-   dst[1] = (op.sel.mask & 0x2) ? arg0[1] : arg1[1];
-   dst[2] = (op.sel.mask & 0x4) ? arg0[2] : arg1[2];
-   dst[3] = (op.sel.mask & 0x8) ? arg0[3] : arg1[3];
+   if (op.msk.mask & WRITEMASK_X) dst[0] = arg[0];
+   if (op.msk.mask & WRITEMASK_Y) dst[1] = arg[1];
+   if (op.msk.mask & WRITEMASK_Z) dst[2] = arg[2];
+   if (op.msk.mask & WRITEMASK_W) dst[3] = arg[3];
 }
 
 
@@ -311,7 +205,7 @@ static void do_PRT( struct arb_vp_machine *m, union instruction op )
 
 static void do_ABS( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0];
@@ -322,7 +216,7 @@ static void do_ABS( struct arb_vp_machine *m, union instruction op )
 
 static void do_ADD( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -333,16 +227,9 @@ static void do_ADD( struct arb_vp_machine *m, union instruction op )
 }
 
 
-static void do_ARL( struct arb_vp_machine *m, union instruction op )
-{
-   const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
-   m->reg[REG_ADDR][0] = FLOORF(arg0[0]);
-}
-
-
 static void do_DP3( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -357,7 +244,7 @@ static void do_DP3( struct arb_vp_machine *m, union instruction op )
 
 static void do_DP4( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -371,7 +258,7 @@ static void do_DP4( struct arb_vp_machine *m, union instruction op )
 
 static void do_DPH( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -385,10 +272,12 @@ static void do_DPH( struct arb_vp_machine *m, union instruction op )
 
 static void do_DST( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
+   /* This should be ok even if result == arg0 or result == arg1.
+    */
    result[0] = 1.0F;
    result[1] = arg0[1] * arg1[1];
    result[2] = arg0[2];
@@ -396,34 +285,37 @@ static void do_DST( struct arb_vp_machine *m, union instruction op )
 }
 
 
+/* Intended to be high precision:
+ */
 static void do_EX2( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
-   result[0] = (GLfloat)RoughApproxPow2(arg0[0]);
+   result[0] = (GLfloat)ApproxExp2(arg0[0]);
    PUFF(result);
 }
 
+
+/* Allowed to be lower precision:
+ */
 static void do_EXP( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
-   GLfloat tmp = arg0[0];
-   GLfloat flr_tmp = FLOORF(tmp);
+   const GLfloat tmp = arg0[0];
+   const GLfloat flr_tmp = FLOORF(tmp);
+   const GLfloat frac_tmp = tmp - flr_tmp;
 
-   /* KW: nvvertexec has an optimized version of this which is pretty
-    * hard to understand/validate, but avoids the RoughApproxPow2.
-    */
-   result[0] = (GLfloat) (1 << (int)flr_tmp);
-   result[1] = tmp - flr_tmp;
-   result[2] = RoughApproxPow2(tmp);
+   result[0] = LDEXPF(1.0, (int)flr_tmp);
+   result[1] = frac_tmp;
+   result[2] = RoughApproxExp2(tmp);
    result[3] = 1.0F;
 }
 
 static void do_FLR( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = FLOORF(arg0[0]);
@@ -434,7 +326,7 @@ static void do_FLR( struct arb_vp_machine *m, union instruction op )
 
 static void do_FRC( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = arg0[0] - FLOORF(arg0[0]);
@@ -443,12 +335,14 @@ static void do_FRC( struct arb_vp_machine *m, union instruction op )
    result[3] = arg0[3] - FLOORF(arg0[3]);
 }
 
+/* High precision log base 2:
+ */
 static void do_LG2( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
-   result[0] = RoughApproxLog2(arg0[0]);
+   result[0] = ApproxLog2(arg0[0]);
    PUFF(result);
 }
 
@@ -456,40 +350,43 @@ static void do_LG2( struct arb_vp_machine *m, union instruction op )
 
 static void do_LIT( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
+   GLfloat tmp[4]; /* use temp in case arg0 == result register */
 
-   const GLfloat epsilon = 1.0F / 256.0F; /* per NV spec */
-   GLfloat tmp[4];
-
-   tmp[0] = MAX2(arg0[0], 0.0F);
-   tmp[1] = MAX2(arg0[1], 0.0F);
-   tmp[3] = CLAMP(arg0[3], -(128.0F - epsilon), (128.0F - epsilon));
+   tmp[0] = 1.0;
+   tmp[1] = arg0[0];
+   if (arg0[0] > 0.0) {
+      tmp[2] = RoughApproxPower(arg0[1], arg0[3]);
+   }
+   else {
+      tmp[2] = 0.0;
+   }
+   tmp[3] = 1.0;
 
-   result[0] = 1.0;
-   result[1] = tmp[0];
-   result[2] = (tmp[0] > 0.0) ? RoughApproxPower(tmp[1], tmp[3]) : 0.0F;
-   result[3] = 1.0;
+   COPY_4V(result, tmp);
 }
 
 
+/* Intended to allow a lower precision than required for LG2 above.
+ */
 static void do_LOG( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
-   GLfloat tmp = FABSF(arg0[0]);
+   const GLfloat tmp = FABSF(arg0[0]);
    int exponent;
-   GLfloat mantissa = FREXPF(tmp, &exponent);
+   const GLfloat mantissa = FREXPF(tmp, &exponent);
 
    result[0] = (GLfloat) (exponent - 1);
    result[1] = 2.0 * mantissa; /* map [.5, 1) -> [1, 2) */
-   result[2] = result[0] + LOG2(result[1]);
+   result[2] = exponent + LOG2(mantissa);
    result[3] = 1.0;
 }
 
 static void do_MAX( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -502,7 +399,7 @@ static void do_MAX( struct arb_vp_machine *m, union instruction op )
 
 static void do_MIN( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -514,7 +411,7 @@ static void do_MIN( struct arb_vp_machine *m, union instruction op )
 
 static void do_MOV( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = arg0[0];
@@ -525,7 +422,7 @@ static void do_MOV( struct arb_vp_machine *m, union instruction op )
 
 static void do_MUL( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -536,20 +433,22 @@ static void do_MUL( struct arb_vp_machine *m, union instruction op )
 }
 
 
+/* Intended to be "high" precision
+ */
 static void do_POW( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
-   result[0] = (GLfloat)RoughApproxPower(arg0[0], arg1[0]);
+   result[0] = (GLfloat)ApproxPower(arg0[0], arg1[0]);
    PUFF(result);
 }
 
 static void do_REL( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
-   GLuint idx = (op.alu.idx0 + (GLint)m->reg[REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1);
+   GLfloat *result = m->File[0][op.alu.dst];
+   const GLuint idx = (op.alu.idx0 + (GLint)m->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1);
    const GLfloat *arg0 = m->File[op.alu.file0][idx];
 
    result[0] = arg0[0];
@@ -560,7 +459,7 @@ static void do_REL( struct arb_vp_machine *m, union instruction op )
 
 static void do_RCP( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = 1.0F / arg0[0];  
@@ -569,7 +468,7 @@ static void do_RCP( struct arb_vp_machine *m, union instruction op )
 
 static void do_RSQ( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
 
    result[0] = INV_SQRTF(FABSF(arg0[0]));
@@ -579,7 +478,7 @@ static void do_RSQ( struct arb_vp_machine *m, union instruction op )
 
 static void do_SGE( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -592,7 +491,7 @@ static void do_SGE( struct arb_vp_machine *m, union instruction op )
 
 static void do_SLT( struct arb_vp_machine *m, union instruction op )
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -604,7 +503,7 @@ static void do_SLT( struct arb_vp_machine *m, union instruction op )
 
 static void do_SUB( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
 
@@ -617,13 +516,21 @@ static void do_SUB( struct arb_vp_machine *m, union instruction op )
 
 static void do_XPD( struct arb_vp_machine *m, union instruction op ) 
 {
-   GLfloat *result = m->reg[op.alu.dst];
+   GLfloat *result = m->File[0][op.alu.dst];
    const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
    const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
+   GLfloat tmp[3];
 
-   result[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1];
-   result[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2];
-   result[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0];
+   tmp[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1];
+   tmp[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2];
+   tmp[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0];
+
+   /* Need a temporary to be correct in the case where result == arg0
+    * or result == arg1.
+    */
+   result[0] = tmp[0];
+   result[1] = tmp[1];
+   result[2] = tmp[2];
 }
 
 static void do_NOP( struct arb_vp_machine *m, union instruction op ) 
@@ -635,10 +542,10 @@ static void do_NOP( struct arb_vp_machine *m, union instruction op )
 static void print_mask( GLuint mask )
 {
    _mesa_printf(".");
-   if (mask&0x1) _mesa_printf("x");
-   if (mask&0x2) _mesa_printf("y");
-   if (mask&0x4) _mesa_printf("z");
-   if (mask&0x8) _mesa_printf("w");
+   if (mask & WRITEMASK_X) _mesa_printf("x");
+   if (mask & WRITEMASK_Y) _mesa_printf("y");
+   if (mask & WRITEMASK_Z) _mesa_printf("z");
+   if (mask & WRITEMASK_W) _mesa_printf("w");
 }
 
 static void print_reg( GLuint file, GLuint reg )
@@ -657,7 +564,7 @@ static void print_reg( GLuint file, GLuint reg )
         _mesa_printf("ARG%d", reg - REG_ARG0);
       else if (reg >= REG_TMP0 && reg <= REG_TMP11)
         _mesa_printf("TMP%d", reg - REG_TMP0);
-      else if (reg >= REG_IN0 && reg <= REG_IN15)
+      else if (reg >= REG_IN0 && reg <= REG_IN31)
         _mesa_printf("IN%d", reg - REG_IN0);
       else if (reg >= REG_OUT0 && reg <= REG_OUT14)
         _mesa_printf("OUT%d", reg - REG_OUT0);
@@ -673,105 +580,152 @@ static void print_reg( GLuint file, GLuint reg )
 }
 
 
-static void print_RSW( union instruction op, const struct opcode_info *info )
+static void print_RSW( union instruction op )
 {
    GLuint swz = op.rsw.swz;
    GLuint neg = op.rsw.neg;
    GLuint i;
 
-   _mesa_printf("%s ", info->string);
+   _mesa_printf("RSW ");
    print_reg(0, op.rsw.dst);
    _mesa_printf(", ");
    print_reg(op.rsw.file0, op.rsw.idx0);
    _mesa_printf(".");
-   for (i = 0; i < 4; i++, swz >>= 2) {
-      const char *cswz = "xyzw";
+   for (i = 0; i < 4; i++, swz >>= 3) {
+      const char *cswz = "xyzw01";
       if (neg & (1<<i))   
         _mesa_printf("-");
-      _mesa_printf("%c", cswz[swz&0x3]);
+      _mesa_printf("%c", cswz[swz&0x7]);
    }
    _mesa_printf("\n");
 }
 
+static void print_SWZ( union instruction op )
+{
+   GLuint swz = op.rsw.swz;
+   GLuint neg = op.rsw.neg;
+   GLuint i;
 
-static void print_ALU( union instruction op, const struct opcode_info *info )
+   _mesa_printf("SWZ ");
+   print_reg(0, op.rsw.dst);
+   _mesa_printf(", ");
+   print_reg(op.rsw.file0, op.rsw.idx0);
+   _mesa_printf(".");
+   for (i = 0; i < 4; i++, swz >>= 3) {
+      const char *cswz = "xyzw01";
+      if (neg & (1<<i))   
+        _mesa_printf("-");
+      _mesa_printf("%c", cswz[swz&0x7]);
+   }
+   _mesa_printf("\n");
+}
+
+
+static void print_ALU( union instruction op )
 {
-   _mesa_printf("%s ", info->string);
+   _mesa_printf("%s ", _mesa_opcode_string((enum prog_opcode) op.alu.opcode));
    print_reg(0, op.alu.dst);
    _mesa_printf(", ");
    print_reg(op.alu.file0, op.alu.idx0);
-   if (info->nr_args > 1) {
+   if (_mesa_num_inst_src_regs((enum prog_opcode) op.alu.opcode) > 1) {
       _mesa_printf(", ");
       print_reg(op.alu.file1, op.alu.idx1);
    }
    _mesa_printf("\n");
 }
 
-static void print_SEL( union instruction op, const struct opcode_info *info )
+static void print_MSK( union instruction op )
 {
-   _mesa_printf("%s ", info->string);
-   print_reg(0, op.sel.dst);
+   _mesa_printf("MSK ");
+   print_reg(0, op.msk.dst);
+   print_mask(op.msk.mask);
    _mesa_printf(", ");
-   print_reg(0, op.sel.idx0);
-   print_mask(op.sel.mask);
-   _mesa_printf(", ");
-   print_reg(op.sel.file1, op.sel.idx1);
-   print_mask(~op.sel.mask);
+   print_reg(op.msk.file, op.msk.idx);
    _mesa_printf("\n");
 }
 
-
-static void print_NOP( union instruction op, const struct opcode_info *info )
+static void print_NOP( union instruction op )
 {
 }
 
-#define NOP 0
-#define ALU 1
-#define SWZ 2
-
-static const struct opcode_info opcode_info[] = 
+void
+_tnl_disassem_vba_insn( union instruction op )
 {
-   { 1, "ABS", print_ALU },
-   { 2, "ADD", print_ALU },
-   { 1, "ARL", print_ALU },
-   { 2, "DP3", print_ALU },
-   { 2, "DP4", print_ALU },
-   { 2, "DPH", print_ALU },
-   { 2, "DST", print_ALU },
-   { 0, "END", print_NOP },
-   { 1, "EX2", print_ALU },
-   { 1, "EXP", print_ALU },
-   { 1, "FLR", print_ALU },
-   { 1, "FRC", print_ALU },
-   { 1, "LG2", print_ALU },
-   { 1, "LIT", print_ALU },
-   { 1, "LOG", print_ALU },
-   { 3, "MAD", print_NOP },
-   { 2, "MAX", print_ALU },
-   { 2, "MIN", print_ALU },
-   { 1, "MOV", print_ALU },
-   { 2, "MUL", print_ALU },
-   { 2, "POW", print_ALU },
-   { 1, "PRT", print_ALU }, /* PRINT */
-   { 1, "RCC", print_NOP },
-   { 1, "RCP", print_ALU },
-   { 1, "RSQ", print_ALU },
-   { 2, "SGE", print_ALU },
-   { 2, "SLT", print_ALU },
-   { 2, "SUB", print_ALU },
-   { 1, "SWZ", print_NOP },
-   { 2, "XPD", print_ALU },
-   { 1, "RSW", print_RSW },
-   { 2, "SEL", print_SEL },
-   { 1, "REL", print_ALU },
-};
+   switch (op.alu.opcode) {
+   case OPCODE_ABS:
+   case OPCODE_ADD:
+   case OPCODE_DP3:
+   case OPCODE_DP4:
+   case OPCODE_DPH:
+   case OPCODE_DST:
+   case OPCODE_EX2:
+   case OPCODE_EXP:
+   case OPCODE_FLR:
+   case OPCODE_FRC:
+   case OPCODE_LG2:
+   case OPCODE_LIT:
+   case OPCODE_LOG:
+   case OPCODE_MAX:
+   case OPCODE_MIN:
+   case OPCODE_MOV:
+   case OPCODE_MUL:
+   case OPCODE_POW:
+   case OPCODE_PRINT:
+   case OPCODE_RCP:
+   case OPCODE_RSQ:
+   case OPCODE_SGE:
+   case OPCODE_SLT:
+   case OPCODE_SUB:
+   case OPCODE_XPD:
+      print_ALU(op);
+      break;
+   case OPCODE_ARA:
+   case OPCODE_ARL:
+   case OPCODE_ARL_NV:
+   case OPCODE_ARR:
+   case OPCODE_BRA:
+   case OPCODE_CAL:
+   case OPCODE_END:
+   case OPCODE_MAD:
+   case OPCODE_POPA:
+   case OPCODE_PUSHA:
+   case OPCODE_RCC:
+   case OPCODE_RET:
+   case OPCODE_SSG:
+      print_NOP(op);
+      break;
+   case OPCODE_SWZ:
+      print_SWZ(op);
+      break;
+   case RSW:
+      print_RSW(op);
+      break;
+   case MSK:
+      print_MSK(op);
+      break;
+   case REL:
+      print_ALU(op);
+      break;
+   default:
+      _mesa_problem(NULL, "Bad opcode in _tnl_disassem_vba_insn()");
+   }
+}
 
 
-static void (* const opcode_func[])(struct arb_vp_machine *, union instruction) = 
+static void (* const opcode_func[MAX_OPCODE+3])(struct arb_vp_machine *, union instruction) = 
 {
    do_ABS,
    do_ADD,
-   do_ARL,
+   do_NOP,/*ARA*/
+   do_NOP,/*ARL*/
+   do_NOP,/*ARL_NV*/
+   do_NOP,/*ARR*/
+   do_NOP,/*BRA*/
+   do_NOP,/*CAL*/
+   do_NOP,/*CMP*/
+   do_NOP,/*COS*/
+   do_NOP,/*DDX*/
+   do_NOP,/*DDY*/
    do_DP3,
    do_DP4,
    do_DPH,
@@ -781,33 +735,64 @@ static void (* const opcode_func[])(struct arb_vp_machine *, union instruction)
    do_EXP,
    do_FLR,
    do_FRC,
+   do_NOP,/*KIL*/
+   do_NOP,/*KIL_NV*/
    do_LG2,
    do_LIT,
    do_LOG,
-   do_NOP,
+   do_NOP,/*LRP*/
+   do_NOP,/*MAD*/
    do_MAX,
    do_MIN,
    do_MOV,
    do_MUL,
+   do_NOP,/*PK2H*/
+   do_NOP,/*PK2US*/
+   do_NOP,/*PK4B*/
+   do_NOP,/*PK4UB*/
    do_POW,
+   do_NOP,/*POPA*/
    do_PRT,
-   do_NOP,
-   do_RCP,
+   do_NOP,/*PUSHA*/
+   do_NOP,/*RCC*/
+   do_RCP,/*RCP*/
+   do_NOP,/*RET*/
+   do_NOP,/*RFL*/
    do_RSQ,
+   do_NOP,/*SCS*/
+   do_NOP,/*SEQ*/
+   do_NOP,/*SFL*/
    do_SGE,
+   do_NOP,/*SGT*/
+   do_NOP,/*SIN*/
+   do_NOP,/*SLE*/
    do_SLT,
+   do_NOP,/*SNE*/
+   do_NOP,/*SSG*/
+   do_NOP,/*STR*/
    do_SUB,
-   do_RSW,
+   do_SWZ,/*SWZ*/
+   do_NOP,/*TEX*/
+   do_NOP,/*TXB*/
+   do_NOP,/*TXD*/
+   do_NOP,/*TXL*/
+   do_NOP,/*TXP*/
+   do_NOP,/*TXP_NV*/
+   do_NOP,/*UP2H*/
+   do_NOP,/*UP2US*/
+   do_NOP,/*UP4B*/
+   do_NOP,/*UP4UB*/
+   do_NOP,/*X2D*/
    do_XPD,
    do_RSW,
-   do_SEL,
+   do_MSK,
    do_REL,
 };
 
 static union instruction *cvp_next_instruction( struct compilation *cp )
 {
    union instruction *op = cp->csr++;
-   op->dword = 0;
+   _mesa_bzero(op, sizeof(*op));
    return op;
 }
 
@@ -879,38 +864,42 @@ static struct reg cvp_load_reg( struct compilation *cp,
    case PROGRAM_WRITE_ONLY:
    case PROGRAM_ADDRESS:
    default:
+      _mesa_problem(NULL, "Invalid register file %d in cvp_load_reg()");
       assert(0);
       return tmpreg;           /* can't happen */
    }
 }
 
 static struct reg cvp_emit_arg( struct compilation *cp,
-                               const struct vp_src_register *src,
+                               const struct prog_src_register *src,
                                GLuint arg )
 {
    struct reg reg = cvp_load_reg( cp, src->File, src->Index, src->RelAddr, arg );
    union instruction rsw, noop;
-   
+
    /* Emit any necessary swizzling.  
     */
-   rsw.dword = 0;
-   rsw.rsw.neg = src->Negate ? 1 : 0;
-   rsw.rsw.swz = ((GET_SWZ(src->Swizzle, 0) << 0) |
-                 (GET_SWZ(src->Swizzle, 1) << 2) |
-                 (GET_SWZ(src->Swizzle, 2) << 4) |
-                 (GET_SWZ(src->Swizzle, 3) << 6));
-
-   noop.dword = 0;
+   _mesa_bzero(&rsw, sizeof(rsw));
+   rsw.rsw.neg = src->NegateBase ? WRITEMASK_XYZW : 0;
+
+   /* we're expecting 2-bit swizzles below... */
+#if 1 /* XXX THESE ASSERTIONS CURRENTLY FAIL DURING GLEAN TESTS! */
+/* hopefully no longer happens? */
+   ASSERT(GET_SWZ(src->Swizzle, 0) < 4);
+   ASSERT(GET_SWZ(src->Swizzle, 1) < 4);
+   ASSERT(GET_SWZ(src->Swizzle, 2) < 4);
+   ASSERT(GET_SWZ(src->Swizzle, 3) < 4);
+#endif
+   rsw.rsw.swz = src->Swizzle;
+
+   _mesa_bzero(&noop, sizeof(noop));
    noop.rsw.neg = 0;
-   noop.rsw.swz = ((0<<0) |
-                  (1<<2) |
-                  (2<<4) |
-                  (3<<6));
+   noop.rsw.swz = SWIZZLE_NOOP;
 
-   if (rsw.dword != noop.dword) {
+   if (_mesa_memcmp(&rsw, &noop, sizeof(rsw)) !=0) {
       union instruction *op = cvp_next_instruction(cp);
       struct reg rsw_reg = cvp_make_reg(FILE_REG, REG_ARG0 + arg);
-      op->dword = rsw.dword;
+      *op = rsw;
       op->rsw.opcode = RSW;
       op->rsw.file0 = reg.file;
       op->rsw.idx0 = reg.idx;
@@ -922,7 +911,7 @@ static struct reg cvp_emit_arg( struct compilation *cp,
 }
 
 static GLuint cvp_choose_result( struct compilation *cp,
-                                const struct vp_dst_register *dst,
+                                const struct prog_dst_register *dst,
                                 union instruction *fixup )
 {
    GLuint mask = dst->WriteMask;
@@ -944,86 +933,42 @@ static GLuint cvp_choose_result( struct compilation *cp,
     * value for the first time, the writemask may be ignored. 
     */
    if (mask != WRITEMASK_XYZW && (cp->reg_active & (1 << idx))) {
-      fixup->sel.opcode = SEL;
-      fixup->sel.idx0 = REG_RES;
-      fixup->sel.file1 = FILE_REG;
-      fixup->sel.idx1 = idx;
-      fixup->sel.dst = idx;
-      fixup->sel.mask = mask;
+      fixup->msk.opcode = MSK;
+      fixup->msk.dst = idx;
+      fixup->msk.file = FILE_REG;
+      fixup->msk.idx = REG_RES;
+      fixup->msk.mask = mask;
       cp->reg_active |= 1 << idx;
       return REG_RES;
    }
    else {
-      fixup->dword = 0;
+      _mesa_bzero(fixup, sizeof(*fixup));
       cp->reg_active |= 1 << idx;
       return idx;
    }
 }
 
-#define RSW_NOOP ((0<<0) | (1<<2) | (2<<4) | (3<<6))
-
-static struct reg cvp_emit_rsw( struct compilation *cp, 
-                               GLuint dst,
-                               struct reg src,
-                               GLuint neg, 
-                               GLuint swz,
-                               GLboolean force)
-{
-   struct reg retval;
-
-   if (swz != RSW_NOOP || neg != 0) {
-      union instruction *op = cvp_next_instruction(cp);
-      op->rsw.opcode = RSW;
-      op->rsw.dst = dst;
-      op->rsw.file0 = src.file;
-      op->rsw.idx0 = src.idx;
-      op->rsw.neg = neg;
-      op->rsw.swz = swz;
-           
-      retval.file = FILE_REG;
-      retval.idx = dst;
-      return retval;
-   }
-   else if (force) {
-      /* Oops.  Degenerate case:
-       */
-      union instruction *op = cvp_next_instruction(cp);
-      op->alu.opcode = VP_OPCODE_MOV;
-      op->alu.dst = dst;
-      op->alu.file0 = src.file;
-      op->alu.idx0 = src.idx;
-      
-      retval.file = FILE_REG;
-      retval.idx = dst;
-      return retval;
-   }
-   else {
-      return src;
-   }
-}
-
 
 static void cvp_emit_inst( struct compilation *cp,
-                          const struct vp_instruction *inst )
+                          const struct prog_instruction *inst )
 {
-   const struct opcode_info *info = &opcode_info[inst->Opcode];
    union instruction *op;
    union instruction fixup;
    struct reg reg[3];
-   GLuint result, i;
+   GLuint result, nr_args, i;
 
    /* Need to handle SWZ, ARL specially.
     */
    switch (inst->Opcode) {
       /* Split into mul and add:
        */
-   case VP_OPCODE_MAD:
+   case OPCODE_MAD:
       result = cvp_choose_result( cp, &inst->DstReg, &fixup );
       for (i = 0; i < 3; i++) 
         reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0+i );
 
       op = cvp_next_instruction(cp);
-      op->alu.opcode = VP_OPCODE_MUL;
+      op->alu.opcode = OPCODE_MUL;
       op->alu.file0 = reg[0].file;
       op->alu.idx0 = reg[0].idx;
       op->alu.file1 = reg[1].file;
@@ -1031,89 +976,54 @@ static void cvp_emit_inst( struct compilation *cp,
       op->alu.dst = REG_ARG0;
 
       op = cvp_next_instruction(cp);
-      op->alu.opcode = VP_OPCODE_ADD;
+      op->alu.opcode = OPCODE_ADD;
       op->alu.file0 = FILE_REG;
       op->alu.idx0 = REG_ARG0;
       op->alu.file1 = reg[2].file;
       op->alu.idx1 = reg[2].idx;
       op->alu.dst = result;
+
+      if (result == REG_RES) {
+        op = cvp_next_instruction(cp);
+        *op = fixup;
+      }
       break;
 
-   case VP_OPCODE_ARL:
+   case OPCODE_ARL:
       reg[0] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 );
 
       op = cvp_next_instruction(cp);
-      op->alu.opcode = inst->Opcode;
+      op->alu.opcode = OPCODE_FLR;
       op->alu.dst = REG_ADDR;
       op->alu.file0 = reg[0].file;
       op->alu.idx0 = reg[0].idx;
       break;
 
-   case VP_OPCODE_SWZ: {
-      GLuint swz0, swz1;
-      GLuint neg0, neg1;
-      GLuint mask = 0;
-
-      /* Translate 3-bit-per-element swizzle into two 2-bit swizzles,
-       * one from the source register the other from a constant
-       * {0,0,0,1}.
-       */
-      for (i = 0; i < 4; i++) {
-        GLuint swzelt = GET_SWZ(inst->SrcReg[0].Swizzle, i);
-        if (swzelt >= SWIZZLE_ZERO) {
-           neg0 |= inst->SrcReg[0].Negate & (1<<i);
-           if (swzelt == SWIZZLE_ONE)
-              swz0 |= SWIZZLE_W << (i*2);
-           else if (i < SWIZZLE_W)
-              swz0 |= i << (i*2);
-        }
-        else {
-           mask |= 1<<i;
-           neg1 |= inst->SrcReg[0].Negate & (1<<i);
-           swz1 |= swzelt << (i*2);
-        }
-      }
+   case OPCODE_END:
+      break;
 
+   case OPCODE_SWZ:
       result = cvp_choose_result( cp, &inst->DstReg, &fixup );
-      reg[0].file = FILE_REG;
-      reg[0].idx = REG_ID;
-      reg[1] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 );
-
-      if (mask == WRITEMASK_XYZW) {
-        cvp_emit_rsw(cp, result, reg[0], neg0, swz0, GL_TRUE);
-        
-      }
-      else if (mask == 0) {
-        cvp_emit_rsw(cp, result, reg[1], neg1, swz1, GL_TRUE);
-      }
-      else {
-        reg[0] = cvp_emit_rsw(cp, REG_ARG0, reg[0], neg0, swz0, GL_FALSE);
-        reg[1] = cvp_emit_rsw(cp, REG_ARG1, reg[1], neg1, swz1, GL_FALSE);
-
-        assert(reg[0].file == FILE_REG);
-
-        op = cvp_next_instruction(cp);
-        op->sel.opcode = SEL;
-        op->sel.dst = result;
-        op->sel.idx0 = reg[0].idx;
-        op->sel.file1 = reg[1].file;
-        op->sel.idx1 = reg[1].idx;
-        op->sel.mask = mask;
-      }
+      reg[0] = cvp_load_reg( cp, inst->SrcReg[0].File,
+                       inst->SrcReg[0].Index, inst->SrcReg[0].RelAddr, REG_ARG0 );
+      op = cvp_next_instruction(cp);
+      op->rsw.opcode = inst->Opcode;
+      op->rsw.file0 = reg[0].file;
+      op->rsw.idx0 = reg[0].idx;
+      op->rsw.dst = result;
+      op->rsw.swz = inst->SrcReg[0].Swizzle;
+      op->rsw.neg = inst->SrcReg[0].NegateBase;
 
       if (result == REG_RES) {
         op = cvp_next_instruction(cp);
-        op->dword = fixup.dword;
+        *op = fixup;
       }
       break;
-   }
-   case VP_OPCODE_PRINT:
-   case VP_OPCODE_END:
-      break;
 
    default:
       result = cvp_choose_result( cp, &inst->DstReg, &fixup );
-      for (i = 0; i < info->nr_args; i++) 
+      nr_args = _mesa_num_inst_src_regs(inst->Opcode);
+      for (i = 0; i < nr_args; i++) 
         reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0 + i );
 
       op = cvp_next_instruction(cp);
@@ -1126,47 +1036,63 @@ static void cvp_emit_inst( struct compilation *cp,
 
       if (result == REG_RES) {
         op = cvp_next_instruction(cp);
-        op->dword = fixup.dword;
-      }         
+        *op = fixup;
+      }
       break;
    }
 }
 
+static void free_tnl_data( struct gl_vertex_program *program  )
+{
+   struct tnl_compiled_program *p = (struct tnl_compiled_program *) program->TnlData;
+   if (p->compiled_func)
+      _mesa_free((void *)p->compiled_func);
+   _mesa_free(p);
+   program->TnlData = NULL;
+}
 
-static void compile_vertex_program( struct arb_vp_machine *m,
-                                   const struct vertex_program *program )
+static void compile_vertex_program( struct gl_vertex_program *program,
+                                   GLboolean try_codegen )
 { 
    struct compilation cp;
-   GLuint i;
+   struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program);
+   GLint i;
+
+   if (program->TnlData) 
+      free_tnl_data( program );
+   
+   program->TnlData = p;
 
-   /* Initialize cp:
+   /* Initialize cp.  Note that ctx and VB aren't used in compilation
+    * so we don't have to worry about statechanges:
     */
-   memset(&cp, 0, sizeof(cp));
-   cp.VB = m->VB;
-   cp.csr = m->store;
+   _mesa_memset(&cp, 0, sizeof(cp));
+   cp.csr = p->instructions;
 
    /* Compile instructions:
     */
    for (i = 0; i < program->Base.NumInstructions; i++) {
-      cvp_emit_inst(&cp, &program->Instructions[i]);
+      cvp_emit_inst(&cp, &program->Base.Instructions[i]);
    }
 
    /* Finish up:
     */
-   m->instructions = m->store;
-   m->nr_instructions = cp.csr - m->store;
-
+   p->nr_instructions = cp.csr - p->instructions;
 
    /* Print/disassemble:
     */
    if (DISASSEM) {
-      for (i = 0; i < m->nr_instructions; i++) {
-        union instruction insn = m->instructions[i];
-        const struct opcode_info *info = &opcode_info[insn.alu.opcode];
-        info->print( insn, info );
+      for (i = 0; i < p->nr_instructions; i++) {
+        _tnl_disassem_vba_insn(p->instructions[i]);
       }
       _mesa_printf("\n\n");
    }
+   
+#ifdef USE_SSE_ASM
+   if (try_codegen)
+      _tnl_sse_codegen_vertex_program(p);
+#endif
+
 }
 
 
@@ -1183,7 +1109,7 @@ static void userclip( GLcontext *ctx,
 {
    GLuint p;
 
-   for (p = 0; p < ctx->Const.MaxClipPlanes; p++)
+   for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
       if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
         GLuint nr, i;
         const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
@@ -1216,12 +1142,13 @@ static void userclip( GLcontext *ctx,
            }
         }
       }
+   }
 }
 
 
-static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
+static GLboolean
+do_ndc_cliptest(GLcontext *ctx, struct arb_vp_machine *m)
 {
-   GLcontext *ctx = m->ctx;
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct vertex_buffer *VB = m->VB;
 
@@ -1229,7 +1156,7 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
     * the clipmask.
     */
    m->ormask = 0;
-   m->andmask = CLIP_ALL_BITS;
+   m->andmask = CLIP_FRUSTUM_BITS;
 
    if (tnl->NeedNdcCoords) {
       VB->NdcPtr =
@@ -1255,7 +1182,8 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
 
    /* Test userclip planes.  This contributes to VB->ClipMask.
     */
-   if (ctx->Transform.ClipPlanesEnabled && !ctx->VertexProgram._Enabled) {
+   if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled ||
+      ctx->VertexProgram.Current->IsPositionInvariant)) {
       userclip( ctx,
                VB->ClipPtr,
                m->clipmask,
@@ -1275,7 +1203,11 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
 }
 
 
-
+static INLINE void call_func( struct tnl_compiled_program *p,
+                             struct arb_vp_machine *m )
+{
+   p->compiled_func(m);
+}
 
 /**
  * Execute the given vertex program.  
@@ -1289,40 +1221,51 @@ static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
 static GLboolean
 run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
 {
-   struct vertex_program *program = (ctx->VertexProgram._Enabled ?
-                                    ctx->VertexProgram.Current :
-                                    ctx->_TnlProgram);
+   const struct gl_vertex_program *program;
    struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
    struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
-   GLuint i, j, outputs = program->OutputsWritten;
+   struct tnl_compiled_program *p;
+   GLuint i, j;
+   GLbitfield outputs;
+
+   if (ctx->ShaderObjects._VertexShaderPresent)
+      return GL_TRUE;
 
-   if (program->Parameters) {
-      _mesa_load_state_parameters(ctx, program->Parameters);
+   program = ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : NULL;
+   if (!program && ctx->_MaintainTnlProgram) {
+      program = ctx->_TnlProgram;
+   }
+   if (!program || program->IsNVProgram)
+      return GL_TRUE;   
+
+   if (program->Base.Parameters) {
+      _mesa_load_state_parameters(ctx, program->Base.Parameters);
    }   
    
+   p = (struct tnl_compiled_program *)program->TnlData;
+   assert(p);
 
-   /* Initialize regs where necessary:
-    */
-   ASSIGN_4V(m->reg[REG_ID], 0, 0, 0, 1);
 
    m->nr_inputs = m->nr_outputs = 0;
 
-   for (i = 0; i < 16; i++) {
-      if (program->InputsRead & (1<<i)) {
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      if (program->Base.InputsRead & (1<<i) ||
+         (i == VERT_ATTRIB_POS && program->IsPositionInvariant)) {
         GLuint j = m->nr_inputs++;
         m->input[j].idx = i;
-        m->input[j].data = m->VB->AttribPtr[i]->data;
+        m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data;
         m->input[j].stride = m->VB->AttribPtr[i]->stride;
         m->input[j].size = m->VB->AttribPtr[i]->size;
-        ASSIGN_4V(m->reg[REG_IN0 + i], 0, 0, 0, 1);
+        ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
       }
    }     
 
-   for (i = 0; i < 15; i++) {
-      if (program->OutputsWritten & (1<<i)) {
+   for (i = 0; i < VERT_RESULT_MAX; i++) {
+      if (program->Base.OutputsWritten & (1 << i) ||
+         (i == VERT_RESULT_HPOS && program->IsPositionInvariant)) {
         GLuint j = m->nr_outputs++;
         m->output[j].idx = i;
-        m->output[j].data = m->attribs[i].data;
+        m->output[j].data = (GLfloat *)m->attribs[i].data;
       }
    }     
 
@@ -1333,28 +1276,45 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
       for (j = 0; j < m->nr_inputs; j++) {
         GLuint idx = REG_IN0 + m->input[j].idx;
         switch (m->input[j].size) {
-        case 4: m->reg[idx][3] = m->input[j].data[3];
-        case 3: m->reg[idx][2] = m->input[j].data[2];
-        case 2: m->reg[idx][1] = m->input[j].data[1];
-        case 1: m->reg[idx][0] = m->input[j].data[0];
+        case 4: m->File[0][idx][3] = m->input[j].data[3];
+        case 3: m->File[0][idx][2] = m->input[j].data[2];
+        case 2: m->File[0][idx][1] = m->input[j].data[1];
+        case 1: m->File[0][idx][0] = m->input[j].data[0];
         }
 
         STRIDE_F(m->input[j].data, m->input[j].stride);
       }
 
-      for (j = 0; j < m->nr_instructions; j++) {
-        union instruction inst = m->instructions[j];    
-        opcode_func[inst.alu.opcode]( m, inst );
+
+      if (p->compiled_func) {
+        call_func( p, m );
+      }
+      else {
+         GLint j;
+        for (j = 0; j < p->nr_instructions; j++) {
+           union instruction inst = p->instructions[j];         
+           opcode_func[inst.alu.opcode]( m, inst );
+        }
+      }
+
+      /* If the program is position invariant, multiply the input position
+       * by the MVP matrix and store in the vertex position result register.
+       */
+      if (program->IsPositionInvariant) {
+        TRANSFORM_POINT( m->File[0][REG_OUT0+0], 
+                         ctx->_ModelProjectMatrix.m, 
+                         m->File[0][REG_IN0+0]);
       }
 
       for (j = 0; j < m->nr_outputs; j++) {
         GLuint idx = REG_OUT0 + m->output[j].idx;
-        m->output[j].data[0] = m->reg[idx][0];
-        m->output[j].data[1] = m->reg[idx][1];
-        m->output[j].data[2] = m->reg[idx][2];
-        m->output[j].data[3] = m->reg[idx][3];
+        m->output[j].data[0] = m->File[0][idx][0];
+        m->output[j].data[1] = m->File[0][idx][1];
+        m->output[j].data[2] = m->File[0][idx][2];
+        m->output[j].data[3] = m->File[0][idx][3];
         m->output[j].data += 4;
       }
+
    }
 
    /* Setup the VB pointers so that the next pipeline stages get
@@ -1370,9 +1330,16 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
    VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS];
    VB->ClipPtr->count = VB->Count;
 
+   /* XXX There seems to be confusion between using the VERT_ATTRIB_*
+    * values vs _TNL_ATTRIB_* tokens here:
+    */
+   outputs = program->Base.OutputsWritten;
+   if (program->IsPositionInvariant) 
+      outputs |= (1<<VERT_RESULT_HPOS);
+
    if (outputs & (1<<VERT_RESULT_COL0)) {
-      VB->ColorPtr[0] = &m->attribs[VERT_RESULT_COL0];
-      VB->AttribPtr[VERT_ATTRIB_COLOR0] = VB->ColorPtr[0];
+      VB->ColorPtr[0] =
+      VB->AttribPtr[VERT_ATTRIB_COLOR0] = &m->attribs[VERT_RESULT_COL0];
    }
 
    if (outputs & (1<<VERT_RESULT_BFC0)) {
@@ -1380,8 +1347,8 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
    }
 
    if (outputs & (1<<VERT_RESULT_COL1)) {
-      VB->SecondaryColorPtr[0] = &m->attribs[VERT_RESULT_COL1];
-      VB->AttribPtr[VERT_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
+      VB->SecondaryColorPtr[0] =
+      VB->AttribPtr[VERT_ATTRIB_COLOR1] = &m->attribs[VERT_RESULT_COL1];
    }
 
    if (outputs & (1<<VERT_RESULT_BFC1)) {
@@ -1389,19 +1356,18 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
    }
 
    if (outputs & (1<<VERT_RESULT_FOGC)) {
-      VB->FogCoordPtr = &m->attribs[VERT_RESULT_FOGC];
-      VB->AttribPtr[VERT_ATTRIB_FOG] = VB->FogCoordPtr;
+      VB->FogCoordPtr =
+      VB->AttribPtr[VERT_ATTRIB_FOG] = &m->attribs[VERT_RESULT_FOGC];
    }
 
    if (outputs & (1<<VERT_RESULT_PSIZ)) {
-      VB->PointSizePtr = &m->attribs[VERT_RESULT_PSIZ];
       VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &m->attribs[VERT_RESULT_PSIZ];
    }
 
-   for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
       if (outputs & (1<<(VERT_RESULT_TEX0+i))) {
-        VB->TexCoordPtr[i] = &m->attribs[VERT_RESULT_TEX0 + i];
-        VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i];
+        VB->TexCoordPtr[i] =
+        VB->AttribPtr[VERT_ATTRIB_TEX0+i] = &m->attribs[VERT_RESULT_TEX0 + i];
       }
    }
 
@@ -1412,16 +1378,16 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
             VEC_ELT(VB->ClipPtr, GLfloat, i)[1],
             VEC_ELT(VB->ClipPtr, GLfloat, i)[2],
             VEC_ELT(VB->ClipPtr, GLfloat, i)[3],
-            VEC_ELT(VB->ColorPtr[0], GLfloat, i)[0],
-            VEC_ELT(VB->ColorPtr[0], GLfloat, i)[1],
-            VEC_ELT(VB->ColorPtr[0], GLfloat, i)[2],
-            VEC_ELT(VB->ColorPtr[0], GLfloat, i)[3]);
+            VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[0],
+            VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[1],
+            VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[2],
+            VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[3]);
    }
 #endif
 
    /* Perform NDC and cliptest operations:
     */
-   return do_ndc_cliptest(m);
+   return do_ndc_cliptest(ctx, m);
 }
 
 
@@ -1429,24 +1395,29 @@ static void
 validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
 {
    struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
-   struct vertex_program *program = 
-      (ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
+   struct gl_vertex_program *program;
 
-#if TNL_FIXED_FUNCTION_PROGRAM
-   if (!program) {
+   if (ctx->ShaderObjects._VertexShaderPresent)
+      return;
+
+   program = (ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
+   if (!program && ctx->_MaintainTnlProgram) {
       program = ctx->_TnlProgram;
    }
-#endif
 
    if (program) {
-      compile_vertex_program( m, program );
+      if (!program->TnlData)
+        compile_vertex_program( program, m->try_codegen );
       
       /* Grab the state GL state and put into registers:
        */
-      m->File[FILE_REG] = m->reg;
       m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams;
       m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters;
-      m->File[FILE_STATE_PARAM] = program->Parameters->ParameterValues;
+      /* GL_NV_vertex_programs can't reference GL state */
+      if (program->Base.Parameters)
+         m->File[FILE_STATE_PARAM] = program->Base.Parameters->ParameterValues;
+      else
+         m->File[FILE_STATE_PARAM] = NULL;
    }
 }
 
@@ -1469,7 +1440,7 @@ static GLboolean init_vertex_program( GLcontext *ctx,
    const GLuint size = VB->Size;
    GLuint i;
 
-   stage->privatePtr = MALLOC(sizeof(*m));
+   stage->privatePtr = _mesa_calloc(sizeof(*m));
    m = ARB_VP_MACHINE(stage);
    if (!m)
       return GL_FALSE;
@@ -1477,7 +1448,20 @@ static GLboolean init_vertex_program( GLcontext *ctx,
    /* arb_vertex_machine struct should subsume the VB:
     */
    m->VB = VB;
-   m->ctx = ctx;
+
+   m->File[0] = (GLfloat(*)[4])ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16);
+
+   /* Initialize regs where necessary:
+    */
+   ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1);
+   ASSIGN_4V(m->File[0][REG_ONES], 1, 1, 1, 1);
+   ASSIGN_4V(m->File[0][REG_SWZ], 1, -1, 0, 0);
+   ASSIGN_4V(m->File[0][REG_NEG], -1, -1, -1, -1);
+   ASSIGN_4V(m->File[0][REG_LIT], 1, 0, 0, 1);
+   ASSIGN_4V(m->File[0][REG_LIT2], 1, .5, .2, 1); /* debug value */
+
+   if (_mesa_getenv("MESA_EXPERIMENTAL"))
+      m->try_codegen = GL_TRUE;
 
    /* Allocate arrays of vertex output values */
    for (i = 0; i < VERT_RESULT_MAX; i++) {
@@ -1489,11 +1473,11 @@ static GLboolean init_vertex_program( GLcontext *ctx,
    _mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
    m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
 
+   if (ctx->_MaintainTnlProgram)
+      _mesa_allow_light_in_model( ctx, GL_FALSE );
 
-#if TNL_FIXED_FUNCTION_PROGRAM
-   _mesa_allow_light_in_model( ctx, GL_FALSE );
-#endif
-
+   m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */
+   m->fpucntl_restore = RESTORE_FPU; /* const value */
 
    return GL_TRUE;
 }
@@ -1518,8 +1502,9 @@ static void dtr( struct tnl_pipeline_stage *stage )
       /* free misc arrays */
       _mesa_vector4f_free( &m->ndcCoords );
       ALIGN_FREE( m->clipmask );
+      ALIGN_FREE( m->File[0] );
 
-      FREE( m );
+      _mesa_free( m );
       stage->privatePtr = NULL;
    }
 }
@@ -1529,10 +1514,27 @@ static void dtr( struct tnl_pipeline_stage *stage )
  */
 const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage =
 {
-   "vertex-program",
+   "arb-vertex-program",
    NULL,                       /* private_data */
    init_vertex_program,                /* create */
    dtr,                                /* destroy */
    validate_vertex_program,    /* validate */
    run_arb_vertex_program      /* run */
 };
+
+
+/**
+ * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
+ * string has been parsed.
+ */
+void
+_tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
+{
+   if (target == GL_VERTEX_PROGRAM_ARB) {
+      /* free any existing tnl data hanging off the program */
+      struct gl_vertex_program *vprog = (struct gl_vertex_program *) program;
+      if (vprog->TnlData) {
+         free_tnl_data(vprog);
+      }
+   }
+}