Merge branch 'mesa_7_6_branch'
[mesa.git] / src / mesa / shader / program_parse.y
index 9e7c9e444d40659799f3e418b022de8d563e1379..20bde83af72ee14f97ed17d3d923bb3c5fe9aefd 100644 (file)
@@ -68,10 +68,19 @@ static void init_dst_reg(struct prog_dst_register *r);
 
 static void init_src_reg(struct asm_src_register *r);
 
+static void asm_instruction_set_operands(struct asm_instruction *inst,
+    const struct prog_dst_register *dst, const struct asm_src_register *src0,
+    const struct asm_src_register *src1, const struct asm_src_register *src2);
+
 static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
     const struct prog_dst_register *dst, const struct asm_src_register *src0,
     const struct asm_src_register *src1, const struct asm_src_register *src2);
 
+static struct asm_instruction *asm_instruction_copy_ctor(
+    const struct prog_instruction *base, const struct prog_dst_register *dst,
+    const struct asm_src_register *src0, const struct asm_src_register *src1,
+    const struct asm_src_register *src2);
+
 #ifndef FALSE
 #define FALSE 0
 #define TRUE (!FALSE)
@@ -117,10 +126,17 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
    unsigned attrib;
    int integer;
    float real;
-   unsigned state[5];
+   gl_state_index state[STATE_LENGTH];
    int negate;
    struct asm_vector vector;
    gl_inst_opcode opcode;
+
+   struct {
+      unsigned swz;
+      unsigned rgba_valid:1;
+      unsigned xyzw_valid:1;
+      unsigned negate:1;
+   } ext_swizzle;
 }
 
 %token ARBvp_10 ARBfp_10
@@ -135,7 +151,7 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 
  /* Tokens for instructions */
 %token <temp_inst> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP
-%token <temp_inst> ARL KIL SWZ
+%token <temp_inst> ARL KIL SWZ TXD_OP
 
 %token <integer> INTEGER
 %token <real> REAL
@@ -152,9 +168,9 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 %token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP
 %token NORMAL
 %token OBJECT
-%token PALETTE PARAMS PLANE POINT POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
+%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
 %token RANGE RESULT ROW
-%token SCENECOLOR SECONDARY SHININESS SIZE SPECULAR SPOT STATE
+%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE
 %token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE
 %token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT
 %token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT
@@ -162,7 +178,8 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 %token VERTEX VTXATTRIB
 %token WEIGHT
 
-%token <string> IDENTIFIER
+%token <string> IDENTIFIER USED_IDENTIFIER
+%type <string> string
 %token <swiz_mask> MASK4 MASK3 MASK2 MASK1 SWIZZLE
 %token DOT_DOT
 %token DOT
@@ -170,14 +187,14 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 %type <inst> instruction ALU_instruction TexInstruction
 %type <inst> ARL_instruction VECTORop_instruction
 %type <inst> SCALARop_instruction BINSCop_instruction BINop_instruction
-%type <inst> TRIop_instruction SWZ_instruction SAMPLE_instruction
+%type <inst> TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction
 %type <inst> KIL_instruction
 
 %type <dst_reg> dstReg maskedDstReg maskedAddrReg
-%type <src_reg> srcReg scalarSrcReg swizzleSrcReg
-%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle extSwizComp
+%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
+%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
+%type <ext_swizzle> extSwizComp extSwizSel
 %type <swiz_mask> optionalMask
-%type <integer> extSwizSel
 
 %type <sym> progParamArray
 %type <integer> addrRegRelOffset addrRegPosOffset addrRegNegOffset
@@ -185,6 +202,8 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 %type <sym> addrReg
 %type <swiz_mask> addrComponent addrWriteMask
 
+%type <dst_reg> ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask
+
 %type <result> resultBinding resultColBinding
 %type <integer> optFaceType optColorType
 %type <integer> optResultFaceType optResultColorType
@@ -205,7 +224,7 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
 %type <state> stateLightItem stateLightModelItem stateLightProdItem
 %type <state> stateTexGenItem stateFogItem stateClipPlaneItem statePointItem
 %type <state> stateMatrixItem stateMatrixRow stateMatrixRows
-%type <state> stateTexEnvItem
+%type <state> stateTexEnvItem stateDepthItem
 
 %type <state> stateLModProperty
 %type <state> stateMatrixName optMatrixRows
@@ -273,7 +292,7 @@ optionSequence: optionSequence option
        |
        ;
 
-option: OPTION IDENTIFIER ';'
+option: OPTION string ';'
        {
           int valid = 0;
 
@@ -340,6 +359,7 @@ ALU_instruction: ARL_instruction
 
 TexInstruction: SAMPLE_instruction
        | KIL_instruction
+       | TXD_instruction
        ;
 
 ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
@@ -350,51 +370,45 @@ ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
 
 VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
        }
        ;
 
 SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
        }
        ;
 
 BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
        }
        ;
 
 
 BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
        }
        ;
 
 TRIop_instruction: TRI_OP maskedDstReg ','
                    swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, & $8);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
        }
        ;
 
 SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
        {
-          $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
           if ($$ != NULL) {
              const GLbitfield tex_mask = (1U << $6);
              GLbitfield shadow_tex = 0;
              GLbitfield target_mask = 0;
 
 
-             $$->Base.SaturateMode = $1.SaturateMode;
              $$->Base.TexSrcUnit = $6;
 
              if ($8 < 0) {
@@ -435,6 +449,58 @@ KIL_instruction: KIL swizzleSrcReg
           $$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL);
           state->fragment.UsesKill = 1;
        }
+       | KIL ccTest
+       {
+          $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
+          $$->Base.DstReg.CondMask = $2.CondMask;
+          $$->Base.DstReg.CondSwizzle = $2.CondSwizzle;
+          $$->Base.DstReg.CondSrc = $2.CondSrc;
+          state->fragment.UsesKill = 1;
+       }
+       ;
+
+TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+       {
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
+          if ($$ != NULL) {
+             const GLbitfield tex_mask = (1U << $10);
+             GLbitfield shadow_tex = 0;
+             GLbitfield target_mask = 0;
+
+
+             $$->Base.TexSrcUnit = $10;
+
+             if ($12 < 0) {
+                shadow_tex = tex_mask;
+
+                $$->Base.TexSrcTarget = -$12;
+                $$->Base.TexShadow = 1;
+             } else {
+                $$->Base.TexSrcTarget = $12;
+             }
+
+             target_mask = (1U << $$->Base.TexSrcTarget);
+
+             /* If this texture unit was previously accessed and that access
+              * had a different texture target, generate an error.
+              *
+              * If this texture unit was previously accessed and that access
+              * had a different shadow mode, generate an error.
+              */
+             if ((state->prog->TexturesUsed[$10] != 0)
+                 && ((state->prog->TexturesUsed[$10] != target_mask)
+                     || ((state->prog->ShadowSamplers & tex_mask)
+                         != shadow_tex))) {
+                yyerror(& @12, state,
+                        "multiple targets used on one texture image unit");
+                YYERROR;
+             }
+
+
+             state->prog->TexturesUsed[$10] |= target_mask;
+             state->prog->ShadowSamplers |= shadow_tex;
+          }
+       }
        ;
 
 texImageUnit: TEXTURE_UNIT optTexImageUnitNum
@@ -463,22 +529,60 @@ SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
            * FIXME: to the existing swizzle?
            */
           $4.Base.Swizzle = $6.swizzle;
+          $4.Base.Negate = $6.mask;
 
-          $$ = asm_instruction_ctor(OPCODE_SWZ, & $2, & $4, NULL, NULL);
-          $$->Base.SaturateMode = $1.SaturateMode;
+          $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
        }
        ;
 
-scalarSrcReg: optionalSign srcReg scalarSuffix
+scalarSrcReg: optionalSign scalarUse
        {
           $$ = $2;
 
           if ($1) {
              $$.Base.Negate = ~$$.Base.Negate;
           }
+       }
+       | optionalSign '|' scalarUse '|'
+       {
+          $$ = $3;
+
+          if (!state->option.NV_fragment) {
+             yyerror(& @2, state, "unexpected character '|'");
+             YYERROR;
+          }
+
+          if ($1) {
+             $$.Base.Negate = ~$$.Base.Negate;
+          }
+
+          $$.Base.Abs = 1;
+       }
+       ;
+
+scalarUse:  srcReg scalarSuffix
+       {
+          $$ = $1;
 
           $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
-                                                   $3.swizzle);
+                                                   $2.swizzle);
+       }
+       | paramConstScalarUse
+       {
+          struct asm_symbol temp_sym;
+
+          if (!state->option.NV_fragment) {
+             yyerror(& @1, state, "expected scalar suffix");
+             YYERROR;
+          }
+
+          memset(& temp_sym, 0, sizeof(temp_sym));
+          temp_sym.param_binding_begin = ~0;
+          initialize_symbol_from_const(state->prog, & temp_sym, & $1);
+
+          init_src_reg(& $$);
+          $$.Base.File = PROGRAM_CONSTANT;
+          $$.Base.Index = temp_sym.param_binding_begin;
        }
        ;
 
@@ -493,12 +597,33 @@ swizzleSrcReg: optionalSign srcReg swizzleSuffix
           $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
                                                    $3.swizzle);
        }
+       | optionalSign '|' srcReg swizzleSuffix '|'
+       {
+          $$ = $3;
+
+          if (!state->option.NV_fragment) {
+             yyerror(& @2, state, "unexpected character '|'");
+             YYERROR;
+          }
+
+          if ($1) {
+             $$.Base.Negate = ~$$.Base.Negate;
+          }
+
+          $$.Base.Abs = 1;
+          $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
+                                                   $4.swizzle);
+       }
+
        ;
 
-maskedDstReg: dstReg optionalMask
+maskedDstReg: dstReg optionalMask optionalCcMask
        {
           $$ = $1;
           $$.WriteMask = $2.mask;
+          $$.CondMask = $3.CondMask;
+          $$.CondSwizzle = $3.CondSwizzle;
+          $$.CondSrc = $3.CondSrc;
 
           if ($$.File == PROGRAM_OUTPUT) {
              /* Technically speaking, this should check that it is in
@@ -528,17 +653,41 @@ maskedAddrReg: addrReg addrWriteMask
 
 extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp
        {
-          $$.swizzle = MAKE_SWIZZLE4($1.swizzle, $3.swizzle,
-                                     $5.swizzle, $7.swizzle);
-          $$.mask = ($1.mask) | ($3.mask << 1) | ($5.mask << 2)
-             | ($7.mask << 3);
+          const unsigned xyzw_valid =
+             ($1.xyzw_valid << 0)
+             | ($3.xyzw_valid << 1)
+             | ($5.xyzw_valid << 2)
+             | ($7.xyzw_valid << 3);
+          const unsigned rgba_valid =
+             ($1.rgba_valid << 0)
+             | ($3.rgba_valid << 1)
+             | ($5.rgba_valid << 2)
+             | ($7.rgba_valid << 3);
+
+          /* All of the swizzle components have to be valid in either RGBA
+           * or XYZW.  Note that 0 and 1 are valid in both, so both masks
+           * can have some bits set.
+           *
+           * We somewhat deviate from the spec here.  It would be really hard
+           * to figure out which component is the error, and there probably
+           * isn't a lot of benefit.
+           */
+          if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
+             yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle "
+                     "components");
+             YYERROR;
+          }
+
+          $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz);
+          $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2)
+             | ($7.negate << 3);
        }
        ;
 
 extSwizComp: optionalSign extSwizSel
        {
-          $$.swizzle = $2;
-          $$.mask = ($1) ? 1 : 0;
+          $$ = $2;
+          $$.negate = ($1) ? 1 : 0;
        }
        ;
 
@@ -549,9 +698,15 @@ extSwizSel: INTEGER
              YYERROR;
           }
 
-          $$ = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+          $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+
+          /* 0 and 1 are valid for both RGBA swizzle names and XYZW
+           * swizzle names.
+           */
+          $$.xyzw_valid = 1;
+          $$.rgba_valid = 1;
        }
-       | IDENTIFIER
+       | string
        {
           if (strlen($1) > 1) {
              yyerror(& @1, state, "invalid extended swizzle selector");
@@ -560,17 +715,39 @@ extSwizSel: INTEGER
 
           switch ($1[0]) {
           case 'x':
-             $$ = SWIZZLE_X;
+             $$.swz = SWIZZLE_X;
+             $$.xyzw_valid = 1;
              break;
           case 'y':
-             $$ = SWIZZLE_Y;
+             $$.swz = SWIZZLE_Y;
+             $$.xyzw_valid = 1;
              break;
           case 'z':
-             $$ = SWIZZLE_Z;
+             $$.swz = SWIZZLE_Z;
+             $$.xyzw_valid = 1;
              break;
           case 'w':
-             $$ = SWIZZLE_W;
+             $$.swz = SWIZZLE_W;
+             $$.xyzw_valid = 1;
+             break;
+
+          case 'r':
+             $$.swz = SWIZZLE_X;
+             $$.rgba_valid = 1;
+             break;
+          case 'g':
+             $$.swz = SWIZZLE_Y;
+             $$.rgba_valid = 1;
+             break;
+          case 'b':
+             $$.swz = SWIZZLE_Z;
+             $$.rgba_valid = 1;
              break;
+          case 'a':
+             $$.swz = SWIZZLE_W;
+             $$.rgba_valid = 1;
+             break;
+
           default:
              yyerror(& @1, state, "invalid extended swizzle selector");
              YYERROR;
@@ -579,7 +756,7 @@ extSwizSel: INTEGER
        }
        ;
 
-srcReg: IDENTIFIER /* temporaryReg | progParamSingle */
+srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */
        {
           struct asm_symbol *const s = (struct asm_symbol *)
              _mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -607,14 +784,14 @@ srcReg: IDENTIFIER /* temporaryReg | progParamSingle */
              $$.Base.Index = s->param_binding_begin;
              break;
           case at_attrib:
-            $$.Base.File = PROGRAM_INPUT;
-            $$.Base.Index = s->attrib_binding;
-            state->prog->InputsRead |= (1U << $$.Base.Index);
+             $$.Base.File = PROGRAM_INPUT;
+             $$.Base.Index = s->attrib_binding;
+             state->prog->InputsRead |= (1U << $$.Base.Index);
 
-            if (!validate_inputs(& @1, state)) {
-               YYERROR;
-            }
-            break;
+             if (!validate_inputs(& @1, state)) {
+                YYERROR;
+             }
+             break;
 
           default:
              YYERROR;
@@ -669,7 +846,7 @@ dstReg: resultBinding
           $$.File = PROGRAM_OUTPUT;
           $$.Index = $1;
        }
-       | IDENTIFIER /* temporaryReg | vertexResultReg */
+       | USED_IDENTIFIER /* temporaryReg | vertexResultReg */
        {
           struct asm_symbol *const s = (struct asm_symbol *)
              _mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -683,17 +860,24 @@ dstReg: resultBinding
           }
 
           init_dst_reg(& $$);
-          if (s->type == at_temp) {
+          switch (s->type) {
+          case at_temp:
              $$.File = PROGRAM_TEMPORARY;
              $$.Index = s->temp_binding;
-          } else {
+             break;
+          case at_output:
+             $$.File = PROGRAM_OUTPUT;
+             $$.Index = s->output_binding;
+             break;
+          default:
              $$.File = s->param_binding_type;
              $$.Index = s->param_binding_begin;
+             break;
           }
        }
        ;
 
-progParamArray: IDENTIFIER
+progParamArray: USED_IDENTIFIER
        {
           struct asm_symbol *const s = (struct asm_symbol *)
              _mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -739,8 +923,10 @@ addrRegRelOffset:              { $$ = 0; }
 addrRegPosOffset: INTEGER
        {
           if (($1 < 0) || ($1 > 63)) {
-             yyerror(& @1, state,
-                     "relative address offset too large (positive)");
+              char s[100];
+              _mesa_snprintf(s, sizeof(s),
+                             "relative address offset too large (%d)", $1);
+             yyerror(& @1, state, s);
              YYERROR;
           } else {
              $$ = $1;
@@ -751,8 +937,10 @@ addrRegPosOffset: INTEGER
 addrRegNegOffset: INTEGER
        {
           if (($1 < 0) || ($1 > 64)) {
-             yyerror(& @1, state,
-                     "relative address offset too large (negative)");
+              char s[100];
+              _mesa_snprintf(s, sizeof(s),
+                             "relative address offset too large (%d)", $1);
+             yyerror(& @1, state, s);
              YYERROR;
           } else {
              $$ = $1;
@@ -760,7 +948,7 @@ addrRegNegOffset: INTEGER
        }
        ;
 
-addrReg: IDENTIFIER
+addrReg: USED_IDENTIFIER
        {
           struct asm_symbol *const s = (struct asm_symbol *)
              _mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -813,6 +1001,82 @@ optionalMask: MASK4 | MASK3 | MASK2 | MASK1
        |              { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
        ;
 
+optionalCcMask: '(' ccTest ')'
+       {
+          $$ = $2;
+       }
+       | '(' ccTest2 ')'
+       {
+          $$ = $2;
+       }
+       |
+       {
+          $$.CondMask = COND_TR;
+          $$.CondSwizzle = SWIZZLE_NOOP;
+          $$.CondSrc = 0;
+       }
+       ;
+
+ccTest: ccMaskRule swizzleSuffix
+       {
+          $$ = $1;
+          $$.CondSwizzle = $2.swizzle;
+       }
+       ;
+
+ccTest2: ccMaskRule2 swizzleSuffix
+       {
+          $$ = $1;
+          $$.CondSwizzle = $2.swizzle;
+       }
+       ;
+
+ccMaskRule: IDENTIFIER
+       {
+          const int cond = _mesa_parse_cc($1);
+          if ((cond == 0) || ($1[2] != '\0')) {
+             char *const err_str =
+                make_error_string("invalid condition code \"%s\"", $1);
+
+             yyerror(& @1, state, (err_str != NULL)
+                     ? err_str : "invalid condition code");
+
+             if (err_str != NULL) {
+                _mesa_free(err_str);
+             }
+
+             YYERROR;
+          }
+
+          $$.CondMask = cond;
+          $$.CondSwizzle = SWIZZLE_NOOP;
+          $$.CondSrc = 0;
+       }
+       ;
+
+ccMaskRule2: USED_IDENTIFIER
+       {
+          const int cond = _mesa_parse_cc($1);
+          if ((cond == 0) || ($1[2] != '\0')) {
+             char *const err_str =
+                make_error_string("invalid condition code \"%s\"", $1);
+
+             yyerror(& @1, state, (err_str != NULL)
+                     ? err_str : "invalid condition code");
+
+             if (err_str != NULL) {
+                _mesa_free(err_str);
+             }
+
+             YYERROR;
+          }
+
+          $$.CondMask = cond;
+          $$.CondSwizzle = SWIZZLE_NOOP;
+          $$.CondSrc = 0;
+       }
+       ;
+
 namingStatement: ATTRIB_statement
        | PARAM_statement
        | TEMP_statement
@@ -972,7 +1236,7 @@ optArraySize:
        }
        | INTEGER
         {
-          if (($1 < 1) || ((unsigned) $1 >= state->limits->MaxParameters)) {
+          if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) {
              yyerror(& @1, state, "invalid parameter array size");
              YYERROR;
           } else {
@@ -1075,6 +1339,7 @@ stateSingleItem: STATE stateMaterialItem  { memcpy($$, $2, sizeof($$)); }
        | STATE stateClipPlaneItem        { memcpy($$, $2, sizeof($$)); }
        | STATE statePointItem            { memcpy($$, $2, sizeof($$)); }
        | STATE stateMatrixRow            { memcpy($$, $2, sizeof($$)); }
+       | STATE stateDepthItem            { memcpy($$, $2, sizeof($$)); }
        ;
 
 stateMaterialItem: MATERIAL optFaceType stateMatProperty
@@ -1285,14 +1550,14 @@ stateClipPlaneNum: INTEGER
        }
        ;
 
-statePointItem: POINT statePointProperty
+statePointItem: POINT_TOK statePointProperty
        {
           memset($$, 0, sizeof($$));
           $$[0] = $2;
        }
        ;
 
-statePointProperty: SIZE
+statePointProperty: SIZE_TOK
        {
           $$ = STATE_POINT_SIZE;
        }
@@ -1424,9 +1689,9 @@ stateOptModMatNum:
        {
           $$ = 0;
        }
-       | stateModMatNum
+       | '[' stateModMatNum ']'
        {
-          $$ = $1;
+          $$ = $2;
        }
        ;
 stateModMatNum: INTEGER
@@ -1461,6 +1726,12 @@ stateProgramMatNum: INTEGER
        }
        ;
 
+stateDepthItem: DEPTH RANGE
+       {
+          memset($$, 0, sizeof($$));
+          $$[0] = STATE_DEPTH_RANGE;
+       }
+       ;
 
 
 programSingleItem: progEnvParam | progLocalParam;
@@ -1557,8 +1828,11 @@ paramConstUse: paramConstScalarUse | paramConstVector;
 
 paramConstScalarDecl: signedFloatConstant
        {
-          $$.count = 1;
+          $$.count = 4;
           $$.data[0] = $1;
+          $$.data[1] = $1;
+          $$.data[2] = $1;
+          $$.data[3] = $1;
        }
        ;
 
@@ -1566,38 +1840,44 @@ paramConstScalarUse: REAL
        {
           $$.count = 1;
           $$.data[0] = $1;
+          $$.data[1] = $1;
+          $$.data[2] = $1;
+          $$.data[3] = $1;
        }
        | INTEGER
        {
           $$.count = 1;
           $$.data[0] = (float) $1;
+          $$.data[1] = (float) $1;
+          $$.data[2] = (float) $1;
+          $$.data[3] = (float) $1;
        }
        ;
 
 paramConstVector: '{' signedFloatConstant '}'
        {
-          $$.count = 1;
+          $$.count = 4;
           $$.data[0] = $2;
           $$.data[1] = 0.0f;
           $$.data[2] = 0.0f;
-          $$.data[3] = 0.0f;
+          $$.data[3] = 1.0f;
        }
        | '{' signedFloatConstant ',' signedFloatConstant '}'
        {
-          $$.count = 2;
+          $$.count = 4;
           $$.data[0] = $2;
           $$.data[1] = $4;
           $$.data[2] = 0.0f;
-          $$.data[3] = 0.0f;
+          $$.data[3] = 1.0f;
        }
        | '{' signedFloatConstant ',' signedFloatConstant ','
               signedFloatConstant '}'
        {
-          $$.count = 3;
+          $$.count = 4;
           $$.data[0] = $2;
           $$.data[1] = $4;
           $$.data[2] = $6;
-          $$.data[3] = 0.0f;
+          $$.data[3] = 1.0f;
        }
        | '{' signedFloatConstant ',' signedFloatConstant ','
               signedFloatConstant ',' signedFloatConstant '}'
@@ -1625,7 +1905,46 @@ optionalSign: '+'        { $$ = FALSE; }
        |                { $$ = FALSE; }
        ;
 
-TEMP_statement: TEMP { $<integer>$ = $1; } varNameList
+TEMP_statement: optVarSize TEMP { $<integer>$ = $2; } varNameList
+       ;
+
+optVarSize: string
+       {
+          /* NV_fragment_program_option defines the size qualifiers in a
+           * fairly broken way.  "SHORT" or "LONG" can optionally be used
+           * before TEMP or OUTPUT.  However, neither is a reserved word!
+           * This means that we have to parse it as an identifier, then check
+           * to make sure it's one of the valid values.  *sigh*
+           *
+           * In addition, the grammar in the extension spec does *not* allow
+           * the size specifier to be optional, but all known implementations
+           * do.
+           */
+          if (!state->option.NV_fragment) {
+             yyerror(& @1, state, "unexpected IDENTIFIER");
+             YYERROR;
+          }
+
+          if (strcmp("SHORT", $1) == 0) {
+          } else if (strcmp("LONG", $1) == 0) {
+          } else {
+             char *const err_str =
+                make_error_string("invalid storage size specifier \"%s\"",
+                                  $1);
+
+             yyerror(& @1, state, (err_str != NULL)
+                     ? err_str : "invalid storage size specifier");
+
+             if (err_str != NULL) {
+                _mesa_free(err_str);
+             }
+
+             YYERROR;
+          }
+       }
+       |
+       {
+       }
        ;
 
 ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList
@@ -1645,15 +1964,15 @@ varNameList: varNameList ',' IDENTIFIER
        }
        ;
 
-OUTPUT_statement: OUTPUT IDENTIFIER '=' resultBinding
+OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding
        {
           struct asm_symbol *const s =
-             declare_variable(state, $2, at_output, & @2);
+             declare_variable(state, $3, at_output, & @3);
 
           if (s == NULL) {
              YYERROR;
           } else {
-             s->output_binding = $4;
+             s->output_binding = $5;
           }
        }
        ;
@@ -1820,7 +2139,7 @@ legacyTexUnitNum: INTEGER
        }
        ;
 
-ALIAS_statement: ALIAS IDENTIFIER '=' IDENTIFIER
+ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER
        {
           struct asm_symbol *exist = (struct asm_symbol *)
              _mesa_symbol_table_find_symbol(state->st, 0, $2);
@@ -1836,13 +2155,59 @@ ALIAS_statement: ALIAS IDENTIFIER '=' IDENTIFIER
                      "undefined variable binding in ALIAS statement");
              YYERROR;
           } else {
-             _mesa_symbol_table_add_symbol(state->st, 0, $2, target);
+             _mesa_symbol_table_add_symbol(state->st, 0, strdup($2), target);
           }
        }
        ;
 
+string: IDENTIFIER
+       | USED_IDENTIFIER
+       ;
+
 %%
 
+void
+asm_instruction_set_operands(struct asm_instruction *inst,
+                            const struct prog_dst_register *dst,
+                            const struct asm_src_register *src0,
+                            const struct asm_src_register *src1,
+                            const struct asm_src_register *src2)
+{
+   /* In the core ARB extensions only the KIL instruction doesn't have a
+    * destination register.
+    */
+   if (dst == NULL) {
+      init_dst_reg(& inst->Base.DstReg);
+   } else {
+      inst->Base.DstReg = *dst;
+   }
+
+   /* The only instruction that doesn't have any source registers is the
+    * condition-code based KIL instruction added by NV_fragment_program_option.
+    */
+   if (src0 != NULL) {
+      inst->Base.SrcReg[0] = src0->Base;
+      inst->SrcReg[0] = *src0;
+   } else {
+      init_src_reg(& inst->SrcReg[0]);
+   }
+
+   if (src1 != NULL) {
+      inst->Base.SrcReg[1] = src1->Base;
+      inst->SrcReg[1] = *src1;
+   } else {
+      init_src_reg(& inst->SrcReg[1]);
+   }
+
+   if (src2 != NULL) {
+      inst->Base.SrcReg[2] = src2->Base;
+      inst->SrcReg[2] = *src2;
+   } else {
+      init_src_reg(& inst->SrcReg[2]);
+   }
+}
+
+
 struct asm_instruction *
 asm_instruction_ctor(gl_inst_opcode op,
                     const struct prog_dst_register *dst,
@@ -1850,29 +2215,37 @@ asm_instruction_ctor(gl_inst_opcode op,
                     const struct asm_src_register *src1,
                     const struct asm_src_register *src2)
 {
-   struct asm_instruction *inst = calloc(1, sizeof(struct asm_instruction));
+   struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
 
    if (inst) {
       _mesa_init_instructions(& inst->Base, 1);
       inst->Base.Opcode = op;
-      inst->Base.DstReg = *dst;
 
-      inst->Base.SrcReg[0] = src0->Base;
-      inst->SrcReg[0] = *src0;
+      asm_instruction_set_operands(inst, dst, src0, src1, src2);
+   }
 
-      if (src1 != NULL) {
-        inst->Base.SrcReg[1] = src1->Base;
-        inst->SrcReg[1] = *src1;
-      } else {
-        init_src_reg(& inst->SrcReg[1]);
-      }
+   return inst;
+}
 
-      if (src2 != NULL) {
-        inst->Base.SrcReg[2] = src2->Base;
-        inst->SrcReg[2] = *src2;
-      } else {
-        init_src_reg(& inst->SrcReg[2]);
-      }
+
+struct asm_instruction *
+asm_instruction_copy_ctor(const struct prog_instruction *base,
+                         const struct prog_dst_register *dst,
+                         const struct asm_src_register *src0,
+                         const struct asm_src_register *src1,
+                         const struct asm_src_register *src2)
+{
+   struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+   if (inst) {
+      _mesa_init_instructions(& inst->Base, 1);
+      inst->Base.Opcode = base->Opcode;
+      inst->Base.CondUpdate = base->CondUpdate;
+      inst->Base.CondDst = base->CondDst;
+      inst->Base.SaturateMode = base->SaturateMode;
+      inst->Base.Precision = base->Precision;
+
+      asm_instruction_set_operands(inst, dst, src0, src1, src2);
    }
 
    return inst;
@@ -1936,10 +2309,14 @@ declare_variable(struct asm_parser_state *state, char *name, enum asm_type t,
    if (exist != NULL) {
       yyerror(locp, state, "redeclared identifier");
    } else {
-      s = calloc(1, sizeof(struct asm_symbol));
-      s->name = name;
+      const size_t name_len = strlen(name);
+
+      s = calloc(1, sizeof(struct asm_symbol) + name_len + 1);
+      s->name = (char *)(s + 1);
       s->type = t;
 
+      memcpy((char *) s->name, name, name_len + 1);
+
       switch (t) {
       case at_temp:
         if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
@@ -1986,8 +2363,7 @@ int add_state_reference(struct gl_program_parameter_list *param_list,
 
    name = _mesa_program_state_string(tokens);
    index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
-                               size, GL_NONE,
-                               NULL, (gl_state_index *) tokens, 0x0);
+                               size, GL_NONE, NULL, tokens, 0x0);
    param_list->StateFlags |= _mesa_program_state_flags(tokens);
 
    /* free name string here since we duplicated it in add_parameter() */
@@ -2167,7 +2543,6 @@ GLboolean
 _mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
                        GLsizei len, struct asm_parser_state *state)
 {
-   struct gl_program_constants limits;
    struct asm_instruction *inst;
    unsigned i;
    GLubyte *strz;
@@ -2189,40 +2564,25 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
    _mesa_memcpy (strz, str, len);
    strz[len] = '\0';
 
+   if (state->prog->String != NULL) {
+      _mesa_free(state->prog->String);
+      state->prog->String = NULL;
+   }
+
    state->prog->String = strz;
 
    state->st = _mesa_symbol_table_ctor();
 
-   /* All of these limits should come from ctx.
-    */
-   limits.MaxInstructions = 128;
-   limits.MaxAluInstructions = 128;
-   limits.MaxTexInstructions = 128;
-   limits.MaxTexIndirections = 128; 
-   limits.MaxAttribs = 16;
-   limits.MaxTemps = 128;
-   limits.MaxAddressRegs = 1;
-   limits.MaxParameters = 128;
-   limits.MaxLocalParams = 256;
-   limits.MaxEnvParams = 128;
-   limits.MaxNativeInstructions = 128;
-   limits.MaxNativeAluInstructions = 128;
-   limits.MaxNativeTexInstructions = 128;
-   limits.MaxNativeTexIndirections = 128;
-   limits.MaxNativeAttribs = 16;
-   limits.MaxNativeTemps = 128;
-   limits.MaxNativeAddressRegs = 1;
-   limits.MaxNativeParameters = 128;
-   limits.MaxUniformComponents = 0;
-
-   state->limits = & limits;
-
-   state->MaxTextureImageUnits = 16;
-   state->MaxTextureCoordUnits = 8;
-   state->MaxTextureUnits = 8;
-   state->MaxClipPlanes = 6;
-   state->MaxLights = 8;
-   state->MaxProgramMatrices = 8;
+   state->limits = (target == GL_VERTEX_PROGRAM_ARB)
+      ? & ctx->Const.VertexProgram
+      : & ctx->Const.FragmentProgram;
+
+   state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+   state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
+   state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
+   state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
+   state->MaxLights = ctx->Const.MaxLights;
+   state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
 
    state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
       ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
@@ -2272,6 +2632,7 @@ _mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
    state->prog->NumInstructions++;
 
    state->prog->NumParameters = state->prog->Parameters->NumParameters;
+   state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
 
    /*
     * Initialize native counts to logical counts.  The device driver may
@@ -2297,7 +2658,6 @@ error:
    for (sym = state->sym; sym != NULL; sym = temp) {
       temp = sym->next;
 
-      _mesa_free((void *) sym->name);
       _mesa_free(sym);
    }
    state->sym = NULL;
@@ -2305,5 +2665,10 @@ error:
    _mesa_symbol_table_dtor(state->st);
    state->st = NULL;
 
+   if (state->string_dumpster != NULL) {
+      _mesa_free(state->string_dumpster);
+      state->dumpster_size = 0;
+   }
+
    return result;
 }