tgsi: show textual format representation
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_text.c
index 9a38c37979cc34afc87f525ebdff14eb9f895323..91baa01ad8bdebad44ec44ba43f9d7a5166080d2 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2008 VMware, Inc.
  * All Rights Reserved.
  * 
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
@@ -35,7 +35,9 @@
 #include "tgsi_info.h"
 #include "tgsi_parse.h"
 #include "tgsi_sanity.h"
+#include "tgsi_strings.h"
 #include "tgsi_util.h"
+#include "tgsi_dump.h"
 
 static boolean is_alpha_underscore( const char *cur )
 {
@@ -79,6 +81,11 @@ streq_nocase_uprcase(const char *str1,
    return *str1 == 0 && *str2 == 0;
 }
 
+/* Return TRUE if both strings match.
+ * The second string is terminated by zero.
+ * The pointer to the first string is moved at end of the read word
+ * on success.
+ */
 static boolean str_match_no_case( const char **pcur, const char *str )
 {
    const char *cur = *pcur;
@@ -94,6 +101,24 @@ static boolean str_match_no_case( const char **pcur, const char *str )
    return FALSE;
 }
 
+/* Return TRUE if both strings match.
+ * The first string is be terminated by a non-digit non-letter non-underscore
+ * character, the second string is terminated by zero.
+ * The pointer to the first string is moved at end of the read word
+ * on success.
+ */
+static boolean str_match_nocase_whole( const char **pcur, const char *str )
+{
+   const char *cur = *pcur;
+
+   if (str_match_no_case(&cur, str) &&
+       !is_digit_alpha_underscore(cur)) {
+      *pcur = cur;
+      return TRUE;
+   }
+   return FALSE;
+}
+
 /* Eat zero or more whitespaces.
  */
 static void eat_opt_white( const char **pcur )
@@ -130,13 +155,30 @@ static boolean parse_uint( const char **pcur, uint *val )
    return FALSE;
 }
 
+static boolean parse_int( const char **pcur, int *val )
+{
+   const char *cur = *pcur;
+   int sign = (*cur == '-' ? -1 : 1);
+
+   if (*cur == '+' || *cur == '-')
+      cur++;
+
+   if (parse_uint(&cur, (uint *)val)) {
+      *val *= sign;
+      *pcur = cur;
+      return TRUE;
+   }
+
+   return FALSE;
+}
+
 static boolean parse_identifier( const char **pcur, char *ret )
 {
    const char *cur = *pcur;
    int i = 0;
    if (is_alpha_underscore( cur )) {
       ret[i++] = *cur++;
-      while (is_alpha_underscore( cur ))
+      while (is_alpha_underscore( cur ) || is_digit( cur ))
          ret[i++] = *cur++;
       ret[i++] = '\0';
       *pcur = cur;
@@ -153,8 +195,15 @@ static boolean parse_float( const char **pcur, float *val )
    boolean integral_part = FALSE;
    boolean fractional_part = FALSE;
 
-   *val = (float) atof( cur );
+   if (*cur == '0' && *(cur + 1) == 'x') {
+      union fi fi;
+      fi.ui = strtoul(cur, NULL, 16);
+      *val = fi.f;
+      cur += 10;
+      goto out;
+   }
 
+   *val = (float) atof( cur );
    if (*cur == '-' || *cur == '+')
       cur++;
    if (is_digit( cur )) {
@@ -186,10 +235,30 @@ static boolean parse_float( const char **pcur, float *val )
       else
          return FALSE;
    }
+
+out:
    *pcur = cur;
    return TRUE;
 }
 
+static boolean parse_double( const char **pcur, uint32_t *val0, uint32_t *val1)
+{
+   const char *cur = *pcur;
+   union {
+      double dval;
+      uint32_t uval[2];
+   } v;
+
+   v.dval = strtod(cur, (char**)pcur);
+   if (*pcur == cur)
+      return FALSE;
+
+   *val0 = v.uval[0];
+   *val1 = v.uval[1];
+
+   return TRUE;
+}
+
 struct translate_ctx
 {
    const char *text;
@@ -199,7 +268,8 @@ struct translate_ctx
    struct tgsi_token *tokens_end;
    struct tgsi_header *header;
    unsigned processor : 4;
-   int implied_array_size : 5;
+   unsigned implied_array_size : 6;
+   unsigned num_immediates;
 };
 
 static void report_error( struct translate_ctx *ctx, const char *msg )
@@ -230,12 +300,18 @@ static boolean parse_header( struct translate_ctx *ctx )
 {
    uint processor;
 
-   if (str_match_no_case( &ctx->cur, "FRAG" ))
+   if (str_match_nocase_whole( &ctx->cur, "FRAG" ))
       processor = TGSI_PROCESSOR_FRAGMENT;
-   else if (str_match_no_case( &ctx->cur, "VERT" ))
+   else if (str_match_nocase_whole( &ctx->cur, "VERT" ))
       processor = TGSI_PROCESSOR_VERTEX;
-   else if (str_match_no_case( &ctx->cur, "GEOM" ))
+   else if (str_match_nocase_whole( &ctx->cur, "GEOM" ))
       processor = TGSI_PROCESSOR_GEOMETRY;
+   else if (str_match_nocase_whole( &ctx->cur, "TESS_CTRL" ))
+      processor = TGSI_PROCESSOR_TESS_CTRL;
+   else if (str_match_nocase_whole( &ctx->cur, "TESS_EVAL" ))
+      processor = TGSI_PROCESSOR_TESS_EVAL;
+   else if (str_match_nocase_whole( &ctx->cur, "COMP" ))
+      processor = TGSI_PROCESSOR_COMPUTE;
    else {
       report_error( ctx, "Unknown header" );
       return FALSE;
@@ -269,22 +345,6 @@ static boolean parse_label( struct translate_ctx *ctx, uint *val )
    return FALSE;
 }
 
-static const char *file_names[TGSI_FILE_COUNT] =
-{
-   "NULL",
-   "CONST",
-   "IN",
-   "OUT",
-   "TEMP",
-   "SAMP",
-   "ADDR",
-   "IMM",
-   "PRED",
-   "SV",
-   "IMMX",
-   "TEMPX"
-};
-
 static boolean
 parse_file( const char **pcur, uint *file )
 {
@@ -293,12 +353,10 @@ parse_file( const char **pcur, uint *file )
    for (i = 0; i < TGSI_FILE_COUNT; i++) {
       const char *cur = *pcur;
 
-      if (str_match_no_case( &cur, file_names[i] )) {
-         if (!is_digit_alpha_underscore( cur )) {
-            *pcur = cur;
-            *file = i;
-            return TRUE;
-         }
+      if (str_match_nocase_whole( &cur, tgsi_file_name(i) )) {
+         *pcur = cur;
+         *file = i;
+         return TRUE;
       }
    }
    return FALSE;
@@ -414,6 +472,7 @@ struct parsed_bracket {
    uint ind_file;
    int ind_index;
    uint ind_comp;
+   uint ind_array;
 };
 
 
@@ -461,24 +520,10 @@ parse_register_bracket(
          eat_opt_white(&ctx->cur);
       }
 
-      if (*ctx->cur == '+' || *ctx->cur == '-') {
-         boolean negate;
-
-         negate = *ctx->cur == '-';
-         ctx->cur++;
-         eat_opt_white( &ctx->cur );
-         if (!parse_uint( &ctx->cur, &uindex )) {
-            report_error( ctx, "Expected literal unsigned integer" );
-            return FALSE;
-         }
-         if (negate)
-            brackets->index = -(int) uindex;
-         else
-            brackets->index = (int) uindex;
-      }
-      else {
+      if (*ctx->cur == '+' || *ctx->cur == '-')
+         parse_int( &ctx->cur, &brackets->index );
+      else
          brackets->index = 0;
-      }
    }
    else {
       if (!parse_uint( &ctx->cur, &uindex )) {
@@ -495,6 +540,20 @@ parse_register_bracket(
       return FALSE;
    }
    ctx->cur++;
+   if (*ctx->cur == '(') {
+      ctx->cur++;
+      eat_opt_white( &ctx->cur );
+      if (!parse_uint( &ctx->cur, &brackets->ind_array )) {
+         report_error( ctx, "Expected literal unsigned integer" );
+         return FALSE;
+      }
+      eat_opt_white( &ctx->cur );
+      if (*ctx->cur != ')') {
+         report_error( ctx, "Expected `)'" );
+         return FALSE;
+      }
+      ctx->cur++;
+   }
    return TRUE;
 }
 
@@ -625,6 +684,9 @@ parse_register_dcl(
    eat_opt_white( &cur );
 
    if (cur[0] == '[') {
+      bool is_in = *file == TGSI_FILE_INPUT;
+      bool is_out = *file == TGSI_FILE_OUTPUT;
+
       ++cur;
       ctx->cur = cur;
       if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
@@ -634,7 +696,11 @@ parse_register_dcl(
        * input primitive. so we want to declare just
        * the index relevant to the semantics which is in
        * the second bracket */
-      if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
+
+      /* tessellation has similar constraints to geometry shader */
+      if ((ctx->processor == TGSI_PROCESSOR_GEOMETRY && is_in) ||
+          (ctx->processor == TGSI_PROCESSOR_TESS_EVAL && is_in) ||
+          (ctx->processor == TGSI_PROCESSOR_TESS_CTRL && (is_in || is_out))) {
          brackets[0] = brackets[1];
          *num_brackets = 1;
       } else {
@@ -690,6 +756,14 @@ parse_dst_operand(
       dst->Dimension.Indirect = 0;
       dst->Dimension.Dimension = 0;
       dst->Dimension.Index = bracket[0].index;
+
+      if (bracket[0].ind_file != TGSI_FILE_NULL) {
+         dst->Dimension.Indirect = 1;
+         dst->DimIndirect.File = bracket[0].ind_file;
+         dst->DimIndirect.Index = bracket[0].ind_index;
+         dst->DimIndirect.Swizzle = bracket[0].ind_comp;
+         dst->DimIndirect.ArrayID = bracket[0].ind_array;
+      }
       bracket[0] = bracket[1];
    }
    dst->Register.Index = bracket[0].index;
@@ -698,10 +772,8 @@ parse_dst_operand(
       dst->Register.Indirect = 1;
       dst->Indirect.File = bracket[0].ind_file;
       dst->Indirect.Index = bracket[0].ind_index;
-      dst->Indirect.SwizzleX = bracket[0].ind_comp;
-      dst->Indirect.SwizzleY = bracket[0].ind_comp;
-      dst->Indirect.SwizzleZ = bracket[0].ind_comp;
-      dst->Indirect.SwizzleW = bracket[0].ind_comp;
+      dst->Indirect.Swizzle = bracket[0].ind_comp;
+      dst->Indirect.ArrayID = bracket[0].ind_array;
    }
    return TRUE;
 }
@@ -709,8 +781,9 @@ parse_dst_operand(
 static boolean
 parse_optional_swizzle(
    struct translate_ctx *ctx,
-   uint swizzle[4],
-   boolean *parsed_swizzle )
+   uint *swizzle,
+   boolean *parsed_swizzle,
+   int components)
 {
    const char *cur = ctx->cur;
 
@@ -722,7 +795,7 @@ parse_optional_swizzle(
 
       cur++;
       eat_opt_white( &cur );
-      for (i = 0; i < 4; i++) {
+      for (i = 0; i < components; i++) {
          if (uprcase( *cur ) == 'X')
             swizzle[i] = TGSI_SWIZZLE_X;
          else if (uprcase( *cur ) == 'Y')
@@ -777,6 +850,13 @@ parse_src_operand(
       src->Dimension.Indirect = 0;
       src->Dimension.Dimension = 0;
       src->Dimension.Index = bracket[0].index;
+      if (bracket[0].ind_file != TGSI_FILE_NULL) {
+         src->Dimension.Indirect = 1;
+         src->DimIndirect.File = bracket[0].ind_file;
+         src->DimIndirect.Index = bracket[0].ind_index;
+         src->DimIndirect.Swizzle = bracket[0].ind_comp;
+         src->DimIndirect.ArrayID = bracket[0].ind_array;
+      }
       bracket[0] = bracket[1];
    }
    src->Register.Index = bracket[0].index;
@@ -784,15 +864,13 @@ parse_src_operand(
       src->Register.Indirect = 1;
       src->Indirect.File = bracket[0].ind_file;
       src->Indirect.Index = bracket[0].ind_index;
-      src->Indirect.SwizzleX = bracket[0].ind_comp;
-      src->Indirect.SwizzleY = bracket[0].ind_comp;
-      src->Indirect.SwizzleZ = bracket[0].ind_comp;
-      src->Indirect.SwizzleW = bracket[0].ind_comp;
+      src->Indirect.Swizzle = bracket[0].ind_comp;
+      src->Indirect.ArrayID = bracket[0].ind_array;
    }
 
    /* Parse optional swizzle.
     */
-   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
+   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) {
       if (parsed_swizzle) {
          src->Register.SwizzleX = swizzle[0];
          src->Register.SwizzleY = swizzle[1];
@@ -814,26 +892,58 @@ parse_src_operand(
    return TRUE;
 }
 
-static const char *texture_names[TGSI_TEXTURE_COUNT] =
+static boolean
+parse_texoffset_operand(
+   struct translate_ctx *ctx,
+   struct tgsi_texture_offset *src )
 {
-   "UNKNOWN",
-   "1D",
-   "2D",
-   "3D",
-   "CUBE",
-   "RECT",
-   "SHADOW1D",
-   "SHADOW2D",
-   "SHADOWRECT"
-};
+   uint file;
+   uint swizzle[3];
+   boolean parsed_swizzle;
+   struct parsed_bracket bracket;
+
+   if (!parse_register_src(ctx, &file, &bracket))
+      return FALSE;
+
+   src->File = file;
+   src->Index = bracket.index;
+
+   /* Parse optional swizzle.
+    */
+   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 3 )) {
+      if (parsed_swizzle) {
+         src->SwizzleX = swizzle[0];
+         src->SwizzleY = swizzle[1];
+         src->SwizzleZ = swizzle[2];
+      }
+   }
+
+   return TRUE;
+}
 
 static boolean
-match_inst_mnemonic(const char **pcur,
-                    const struct tgsi_opcode_info *info)
+match_inst(const char **pcur,
+           unsigned *saturate,
+           const struct tgsi_opcode_info *info)
 {
-   if (str_match_no_case(pcur, info->mnemonic)) {
+   const char *cur = *pcur;
+
+   /* simple case: the whole string matches the instruction name */
+   if (str_match_nocase_whole(&cur, info->mnemonic)) {
+      *pcur = cur;
+      *saturate = 0;
       return TRUE;
    }
+
+   if (str_match_no_case(&cur, info->mnemonic)) {
+      /* the instruction has a suffix, figure it out */
+      if (str_match_nocase_whole(&cur, "_SAT")) {
+         *pcur = cur;
+         *saturate = 1;
+         return TRUE;
+      }
+   }
+
    return FALSE;
 }
 
@@ -843,9 +953,10 @@ parse_instruction(
    boolean has_label )
 {
    uint i;
-   uint saturate = TGSI_SAT_NONE;
+   uint saturate = 0;
    const struct tgsi_opcode_info *info;
    struct tgsi_full_instruction inst;
+   const char *cur;
    uint advance;
 
    inst = tgsi_default_full_instruction();
@@ -870,7 +981,7 @@ parse_instruction(
       if (!parse_register_1d( ctx, &file, &index ))
          return FALSE;
 
-      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
+      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle, 4 )) {
          if (parsed_swizzle) {
             inst.Predicate.SwizzleX = swizzle[0];
             inst.Predicate.SwizzleY = swizzle[1];
@@ -891,20 +1002,13 @@ parse_instruction(
     */
    eat_opt_white( &ctx->cur );
    for (i = 0; i < TGSI_OPCODE_LAST; i++) {
-      const char *cur = ctx->cur;
+      cur = ctx->cur;
 
       info = tgsi_get_opcode_info( i );
-      if (match_inst_mnemonic(&cur, info)) {
-         if (str_match_no_case( &cur, "_SATNV" ))
-            saturate = TGSI_SAT_MINUS_PLUS_ONE;
-         else if (str_match_no_case( &cur, "_SAT" ))
-            saturate = TGSI_SAT_ZERO_ONE;
-
+      if (match_inst(&cur, &saturate, info)) {
          if (info->num_dst + info->num_src + info->is_tex == 0) {
-            if (!is_digit_alpha_underscore( cur )) {
-               ctx->cur = cur;
-               break;
-            }
+            ctx->cur = cur;
+            break;
          }
          else if (*cur == '\0' || eat_white( &cur )) {
             ctx->cur = cur;
@@ -925,6 +1029,22 @@ parse_instruction(
    inst.Instruction.NumDstRegs = info->num_dst;
    inst.Instruction.NumSrcRegs = info->num_src;
 
+   if (i >= TGSI_OPCODE_SAMPLE && i <= TGSI_OPCODE_GATHER4) {
+      /*
+       * These are not considered tex opcodes here (no additional
+       * target argument) however we're required to set the Texture
+       * bit so we can set the number of tex offsets.
+       */
+      inst.Instruction.Texture = 1;
+      inst.Texture.Texture = TGSI_TEXTURE_UNKNOWN;
+   }
+
+   if ((i >= TGSI_OPCODE_LOAD && i <= TGSI_OPCODE_ATOMIMAX) ||
+       i == TGSI_OPCODE_RESQ) {
+      inst.Instruction.Memory = 1;
+      inst.Memory.Qualifier = 0;
+   }
+
    /* Parse instruction operands.
     */
    for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
@@ -950,12 +1070,10 @@ parse_instruction(
          uint j;
 
          for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
-            if (str_match_no_case( &ctx->cur, texture_names[j] )) {
-               if (!is_digit_alpha_underscore( ctx->cur )) {
-                  inst.Instruction.Texture = 1;
-                  inst.Texture.Texture = j;
-                  break;
-               }
+            if (str_match_nocase_whole( &ctx->cur, tgsi_texture_names[j] )) {
+               inst.Instruction.Texture = 1;
+               inst.Texture.Texture = j;
+               break;
             }
          }
          if (j == TGSI_TEXTURE_COUNT) {
@@ -965,22 +1083,54 @@ parse_instruction(
       }
    }
 
-   if (info->is_branch) {
-      uint target;
+   cur = ctx->cur;
+   eat_opt_white( &cur );
+   for (i = 0; inst.Instruction.Texture && *cur == ','; i++) {
+         cur++;
+         eat_opt_white( &cur );
+         ctx->cur = cur;
+         if (!parse_texoffset_operand( ctx, &inst.TexOffsets[i] ))
+            return FALSE;
+         cur = ctx->cur;
+         eat_opt_white( &cur );
+   }
+   inst.Texture.NumOffsets = i;
 
-      eat_opt_white( &ctx->cur );
-      if (*ctx->cur != ':') {
-         report_error( ctx, "Expected `:'" );
+   cur = ctx->cur;
+   eat_opt_white(&cur);
+   for (i = 0; inst.Instruction.Memory && *cur == ','; i++) {
+      uint j;
+      cur++;
+      eat_opt_white(&cur);
+      ctx->cur = cur;
+      for (j = 0; j < 3; j++) {
+         if (str_match_nocase_whole(&ctx->cur, tgsi_memory_names[j])) {
+            inst.Memory.Qualifier |= 1U << j;
+            break;
+         }
+      }
+      if (j == 3) {
+         report_error(ctx, "Expected memory qualifier");
          return FALSE;
       }
-      ctx->cur++;
-      eat_opt_white( &ctx->cur );
-      if (!parse_uint( &ctx->cur, &target )) {
+      cur = ctx->cur;
+      eat_opt_white(&cur);
+   }
+
+   cur = ctx->cur;
+   eat_opt_white( &cur );
+   if (info->is_branch && *cur == ':') {
+      uint target;
+
+      cur++;
+      eat_opt_white( &cur );
+      if (!parse_uint( &cur, &target )) {
          report_error( ctx, "Expected a label" );
          return FALSE;
       }
       inst.Instruction.Label = 1;
       inst.Label.Label = target;
+      ctx->cur = cur;
    }
 
    advance = tgsi_build_full_instruction(
@@ -995,36 +1145,13 @@ parse_instruction(
    return TRUE;
 }
 
-static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
-{
-   "POSITION",
-   "COLOR",
-   "BCOLOR",
-   "FOG",
-   "PSIZE",
-   "GENERIC",
-   "NORMAL",
-   "FACE",
-   "EDGEFLAG",
-   "PRIM_ID",
-   "INSTANCEID",
-   "STENCIL"
-};
-
-static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
-{
-   "CONSTANT",
-   "LINEAR",
-   "PERSPECTIVE"
-};
-
-
 /* parses a 4-touple of the form {x, y, z, w}
  * where x, y, z, w are numbers */
-static boolean parse_immediate_data(struct translate_ctx *ctx,
-                                    float *values)
+static boolean parse_immediate_data(struct translate_ctx *ctx, unsigned type,
+                                    union tgsi_immediate_data *values)
 {
    unsigned i;
+   int ret;
 
    eat_opt_white( &ctx->cur );
    if (*ctx->cur != '{') {
@@ -1042,8 +1169,29 @@ static boolean parse_immediate_data(struct translate_ctx *ctx,
          ctx->cur++;
          eat_opt_white( &ctx->cur );
       }
-      if (!parse_float( &ctx->cur, &values[i] )) {
-         report_error( ctx, "Expected literal floating point" );
+
+      switch (type) {
+      case TGSI_IMM_FLOAT64:
+         ret = parse_double(&ctx->cur, &values[i].Uint, &values[i+1].Uint);
+         i++;
+         break;
+      case TGSI_IMM_FLOAT32:
+         ret = parse_float(&ctx->cur, &values[i].Float);
+         break;
+      case TGSI_IMM_UINT32:
+         ret = parse_uint(&ctx->cur, &values[i].Uint);
+         break;
+      case TGSI_IMM_INT32:
+         ret = parse_int(&ctx->cur, &values[i].Int);
+         break;
+      default:
+         assert(0);
+         ret = FALSE;
+         break;
+      }
+
+      if (!ret) {
+         report_error( ctx, "Expected immediate constant" );
          return FALSE;
       }
    }
@@ -1064,13 +1212,9 @@ static boolean parse_declaration( struct translate_ctx *ctx )
    struct parsed_dcl_bracket brackets[2];
    int num_brackets;
    uint writemask;
-   const char *cur;
+   const char *cur, *cur2;
    uint advance;
    boolean is_vs_input;
-   boolean is_imm_array;
-
-   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
-   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
 
    if (!eat_white( &ctx->cur )) {
       report_error( ctx, "Syntax error" );
@@ -1098,87 +1242,202 @@ static boolean parse_declaration( struct translate_ctx *ctx )
 
    is_vs_input = (file == TGSI_FILE_INPUT &&
                   ctx->processor == TGSI_PROCESSOR_VERTEX);
-   is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
 
    cur = ctx->cur;
    eat_opt_white( &cur );
+   if (*cur == ',') {
+      cur2 = cur;
+      cur2++;
+      eat_opt_white( &cur2 );
+      if (str_match_nocase_whole( &cur2, "ARRAY" )) {
+         int arrayid;
+         if (*cur2 != '(') {
+            report_error( ctx, "Expected `('" );
+            return FALSE;
+         }
+         cur2++;
+         eat_opt_white( &cur2 );
+         if (!parse_int( &cur2, &arrayid )) {
+            report_error( ctx, "Expected `,'" );
+            return FALSE;
+         }
+         eat_opt_white( &cur2 );
+         if (*cur2 != ')') {
+            report_error( ctx, "Expected `)'" );
+            return FALSE;
+         }
+         cur2++;
+         decl.Declaration.Array = 1;
+         decl.Array.ArrayID = arrayid;
+         ctx->cur = cur = cur2;
+      }
+   }
+
    if (*cur == ',' && !is_vs_input) {
-      uint i;
+      uint i, j;
 
       cur++;
       eat_opt_white( &cur );
-      for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
-         if (str_match_no_case( &cur, semantic_names[i] )) {
-            const char *cur2 = cur;
-            uint index;
-
-            if (is_digit_alpha_underscore( cur ))
-               continue;
-            eat_opt_white( &cur2 );
-            if (*cur2 == '[') {
-               cur2++;
-               eat_opt_white( &cur2 );
-               if (!parse_uint( &cur2, &index )) {
-                  report_error( ctx, "Expected literal integer" );
-                  return FALSE;
-               }
-               eat_opt_white( &cur2 );
-               if (*cur2 != ']') {
-                  report_error( ctx, "Expected `]'" );
-                  return FALSE;
-               }
-               cur2++;
-
-               decl.Semantic.Index = index;
+      if (file == TGSI_FILE_IMAGE) {
+         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
+            if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
+               decl.Image.Resource = i;
+               break;
+            }
+         }
+         if (i == TGSI_TEXTURE_COUNT) {
+            report_error(ctx, "Expected texture target");
+            return FALSE;
+         }
 
-               cur = cur2;
+         cur2 = cur;
+         eat_opt_white(&cur2);
+         while (*cur2 == ',') {
+            cur2++;
+            eat_opt_white(&cur2);
+            if (str_match_nocase_whole(&cur2, "RAW")) {
+               decl.Image.Raw = 1;
+
+            } else if (str_match_nocase_whole(&cur2, "WR")) {
+               decl.Image.Writable = 1;
+
+            } else {
+               for (i = 0; i < PIPE_FORMAT_COUNT; i++) {
+                  const struct util_format_description *desc =
+                     util_format_description(i);
+                  if (desc && str_match_nocase_whole(&cur2, desc->name)) {
+                     decl.Image.Format = i;
+                     break;
+                  }
+               }
+               if (i == PIPE_FORMAT_COUNT)
+                  break;
             }
+            cur = cur2;
+            eat_opt_white(&cur2);
+         }
 
-            decl.Declaration.Semantic = 1;
-            decl.Semantic.Name = i;
+         ctx->cur = cur;
 
-            ctx->cur = cur;
-            break;
+      } else if (file == TGSI_FILE_SAMPLER_VIEW) {
+         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
+            if (str_match_nocase_whole(&cur, tgsi_texture_names[i])) {
+               decl.SamplerView.Resource = i;
+               break;
+            }
          }
-      }
-   } else if (is_imm_array) {
-      unsigned i;
-      float *vals_itr;
-      /* we have our immediate data */
-      if (*cur != '{') {
-         report_error( ctx, "Immediate array without data" );
-         return FALSE;
-      }
-      ++cur;
-      ctx->cur = cur;
-
-      decl.ImmediateData.u =
-         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
-                (decl.Range.Last + 1));
-      vals_itr = (float*)decl.ImmediateData.u;
-      for (i = 0; i <= decl.Range.Last; ++i) {
-         if (!parse_immediate_data(ctx, vals_itr)) {
-            FREE(decl.ImmediateData.u);
+         if (i == TGSI_TEXTURE_COUNT) {
+            report_error(ctx, "Expected texture target");
             return FALSE;
          }
-         vals_itr += 4;
-         eat_opt_white( &ctx->cur );
-         if (*ctx->cur != ',') {
-            if (i !=  decl.Range.Last) {
-               report_error( ctx, "Not enough data in immediate array!" );
-               FREE(decl.ImmediateData.u);
-               return FALSE;
+         eat_opt_white( &cur );
+         if (*cur != ',') {
+            report_error( ctx, "Expected `,'" );
+            return FALSE;
+         }
+         ++cur;
+         eat_opt_white( &cur );
+         for (j = 0; j < 4; ++j) {
+            for (i = 0; i < TGSI_RETURN_TYPE_COUNT; ++i) {
+               if (str_match_nocase_whole(&cur, tgsi_return_type_names[i])) {
+                  switch (j) {
+                  case 0:
+                     decl.SamplerView.ReturnTypeX = i;
+                     break;
+                  case 1:
+                     decl.SamplerView.ReturnTypeY = i;
+                     break;
+                  case 2:
+                     decl.SamplerView.ReturnTypeZ = i;
+                     break;
+                  case 3:
+                     decl.SamplerView.ReturnTypeW = i;
+                     break;
+                  default:
+                     assert(0);
+                  }
+                  break;
+               }
             }
-         } else
-            ++ctx->cur;
-      }
-      eat_opt_white( &ctx->cur );
-      if (*ctx->cur != '}') {
-         FREE(decl.ImmediateData.u);
-         report_error( ctx, "Immediate array data missing closing '}'" );
-         return FALSE;
+            if (i == TGSI_RETURN_TYPE_COUNT) {
+               if (j == 0 || j >  2) {
+                  report_error(ctx, "Expected type name");
+                  return FALSE;
+               }
+               break;
+            } else {
+               cur2 = cur;
+               eat_opt_white( &cur2 );
+               if (*cur2 == ',') {
+                  cur2++;
+                  eat_opt_white( &cur2 );
+                  cur = cur2;
+                  continue;
+               } else
+                  break;
+            }
+         }
+         if (j < 4) {
+            decl.SamplerView.ReturnTypeY =
+               decl.SamplerView.ReturnTypeZ =
+               decl.SamplerView.ReturnTypeW =
+               decl.SamplerView.ReturnTypeX;
+         }
+         ctx->cur = cur;
+      } else if (file == TGSI_FILE_BUFFER) {
+         if (str_match_nocase_whole(&cur, "ATOMIC")) {
+            decl.Declaration.Atomic = 1;
+            ctx->cur = cur;
+         } else if (str_match_nocase_whole(&cur, "SHARED")) {
+            decl.Declaration.Shared = 1;
+            ctx->cur = cur;
+         }
+      } else {
+         if (str_match_nocase_whole(&cur, "LOCAL")) {
+            decl.Declaration.Local = 1;
+            ctx->cur = cur;
+         }
+
+         cur = ctx->cur;
+         eat_opt_white( &cur );
+         if (*cur == ',') {
+            cur++;
+            eat_opt_white( &cur );
+
+            for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
+               if (str_match_nocase_whole(&cur, tgsi_semantic_names[i])) {
+                  uint index;
+
+                  cur2 = cur;
+                  eat_opt_white( &cur2 );
+                  if (*cur2 == '[') {
+                     cur2++;
+                     eat_opt_white( &cur2 );
+                     if (!parse_uint( &cur2, &index )) {
+                        report_error( ctx, "Expected literal integer" );
+                        return FALSE;
+                     }
+                     eat_opt_white( &cur2 );
+                     if (*cur2 != ']') {
+                        report_error( ctx, "Expected `]'" );
+                        return FALSE;
+                     }
+                     cur2++;
+
+                     decl.Semantic.Index = index;
+
+                     cur = cur2;
+                  }
+
+                  decl.Declaration.Semantic = 1;
+                  decl.Semantic.Name = i;
+
+                  ctx->cur = cur;
+                  break;
+               }
+            }
+         }
       }
-      ++ctx->cur;
    }
 
    cur = ctx->cur;
@@ -1189,10 +1448,9 @@ static boolean parse_declaration( struct translate_ctx *ctx )
       cur++;
       eat_opt_white( &cur );
       for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
-         if (str_match_no_case( &cur, interpolate_names[i] )) {
-            if (is_digit_alpha_underscore( cur ))
-               continue;
-            decl.Declaration.Interpolate = i;
+         if (str_match_nocase_whole( &cur, tgsi_interpolate_names[i] )) {
+            decl.Declaration.Interpolate = 1;
+            decl.Interp.Interpolate = i;
 
             ctx->cur = cur;
             break;
@@ -1204,15 +1462,29 @@ static boolean parse_declaration( struct translate_ctx *ctx )
       }
    }
 
+   cur = ctx->cur;
+   eat_opt_white( &cur );
+   if (*cur == ',' && !is_vs_input) {
+      uint i;
+
+      cur++;
+      eat_opt_white( &cur );
+      for (i = 0; i < TGSI_INTERPOLATE_LOC_COUNT; i++) {
+         if (str_match_nocase_whole( &cur, tgsi_interpolate_locations[i] )) {
+            decl.Interp.Location = i;
+
+            ctx->cur = cur;
+            break;
+         }
+      }
+   }
+
    advance = tgsi_build_full_declaration(
       &decl,
       ctx->tokens_cur,
       ctx->header,
       (uint) (ctx->tokens_end - ctx->tokens_cur) );
 
-   if (is_imm_array)
-      FREE(decl.ImmediateData.u);
-
    if (advance == 0)
       return FALSE;
    ctx->tokens_cur += advance;
@@ -1223,28 +1495,51 @@ static boolean parse_declaration( struct translate_ctx *ctx )
 static boolean parse_immediate( struct translate_ctx *ctx )
 {
    struct tgsi_full_immediate imm;
-   float values[4];
    uint advance;
+   int type;
+
+   if (*ctx->cur == '[') {
+      uint uindex;
+
+      ++ctx->cur;
+
+      eat_opt_white( &ctx->cur );
+      if (!parse_uint( &ctx->cur, &uindex )) {
+         report_error( ctx, "Expected literal unsigned integer" );
+         return FALSE;
+      }
+
+      if (uindex != ctx->num_immediates) {
+         report_error( ctx, "Immediates must be sorted" );
+         return FALSE;
+      }
+
+      eat_opt_white( &ctx->cur );
+      if (*ctx->cur != ']') {
+         report_error( ctx, "Expected `]'" );
+         return FALSE;
+      }
+
+      ctx->cur++;
+   }
 
    if (!eat_white( &ctx->cur )) {
       report_error( ctx, "Syntax error" );
       return FALSE;
    }
-   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
-       is_digit_alpha_underscore( ctx->cur )) {
-      report_error( ctx, "Expected `FLT32'" );
+   for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) {
+      if (str_match_nocase_whole(&ctx->cur, tgsi_immediate_type_names[type]))
+         break;
+   }
+   if (type == Elements(tgsi_immediate_type_names)) {
+      report_error( ctx, "Expected immediate type" );
       return FALSE;
    }
 
-   parse_immediate_data(ctx, values);
-
    imm = tgsi_default_full_immediate();
    imm.Immediate.NrTokens += 4;
-   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
-   imm.u[0].Float = values[0];
-   imm.u[1].Float = values[1];
-   imm.u[2].Float = values[2];
-   imm.u[3].Float = values[3];
+   imm.Immediate.DataType = type;
+   parse_immediate_data(ctx, type, imm.u);
 
    advance = tgsi_build_full_immediate(
       &imm,
@@ -1255,45 +1550,11 @@ static boolean parse_immediate( struct translate_ctx *ctx )
       return FALSE;
    ctx->tokens_cur += advance;
 
+   ctx->num_immediates++;
+
    return TRUE;
 }
 
-static const char *property_names[] =
-{
-   "GS_INPUT_PRIMITIVE",
-   "GS_OUTPUT_PRIMITIVE",
-   "GS_MAX_OUTPUT_VERTICES",
-   "FS_COORD_ORIGIN",
-   "FS_COORD_PIXEL_CENTER"
-};
-
-static const char *primitive_names[] =
-{
-   "POINTS",
-   "LINES",
-   "LINE_LOOP",
-   "LINE_STRIP",
-   "TRIANGLES",
-   "TRIANGLE_STRIP",
-   "TRIANGLE_FAN",
-   "QUADS",
-   "QUAD_STRIP",
-   "POLYGON"
-};
-
-static const char *fs_coord_origin_names[] =
-{
-   "UPPER_LEFT",
-   "LOWER_LEFT"
-};
-
-static const char *fs_coord_pixel_center_names[] =
-{
-   "HALF_INTEGER",
-   "INTEGER"
-};
-
-
 static boolean
 parse_primitive( const char **pcur, uint *primitive )
 {
@@ -1302,7 +1563,7 @@ parse_primitive( const char **pcur, uint *primitive )
    for (i = 0; i < PIPE_PRIM_MAX; i++) {
       const char *cur = *pcur;
 
-      if (str_match_no_case( &cur, primitive_names[i])) {
+      if (str_match_nocase_whole( &cur, tgsi_primitive_names[i])) {
          *primitive = i;
          *pcur = cur;
          return TRUE;
@@ -1316,10 +1577,10 @@ parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
 {
    uint i;
 
-   for (i = 0; i < sizeof(fs_coord_origin_names) / sizeof(fs_coord_origin_names[0]); i++) {
+   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
       const char *cur = *pcur;
 
-      if (str_match_no_case( &cur, fs_coord_origin_names[i])) {
+      if (str_match_nocase_whole( &cur, tgsi_fs_coord_origin_names[i])) {
          *fs_coord_origin = i;
          *pcur = cur;
          return TRUE;
@@ -1333,10 +1594,10 @@ parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
 {
    uint i;
 
-   for (i = 0; i < sizeof(fs_coord_pixel_center_names) / sizeof(fs_coord_pixel_center_names[0]); i++) {
+   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
       const char *cur = *pcur;
 
-      if (str_match_no_case( &cur, fs_coord_pixel_center_names[i])) {
+      if (str_match_nocase_whole( &cur, tgsi_fs_coord_pixel_center_names[i])) {
          *fs_coord_pixel_center = i;
          *pcur = cur;
          return TRUE;
@@ -1364,7 +1625,7 @@ static boolean parse_property( struct translate_ctx *ctx )
    }
    for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
         ++property_name) {
-      if (streq_nocase_uprcase(property_names[property_name], id)) {
+      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
          break;
       }
    }
@@ -1398,6 +1659,7 @@ static boolean parse_property( struct translate_ctx *ctx )
          return FALSE;
       }
       break;
+   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
    default:
       if (!parse_uint(&ctx->cur, &values[0] )) {
          report_error( ctx, "Expected unsigned integer as property!" );
@@ -1429,6 +1691,10 @@ static boolean translate( struct translate_ctx *ctx )
    if (!parse_header( ctx ))
       return FALSE;
 
+   if (ctx->processor == TGSI_PROCESSOR_TESS_CTRL ||
+       ctx->processor == TGSI_PROCESSOR_TESS_EVAL)
+       ctx->implied_array_size = 32;
+
    while (*ctx->cur != '\0') {
       uint label_val = 0;
       if (!eat_white( &ctx->cur )) {
@@ -1442,15 +1708,15 @@ static boolean translate( struct translate_ctx *ctx )
          if (!parse_instruction( ctx, TRUE ))
             return FALSE;
       }
-      else if (str_match_no_case( &ctx->cur, "DCL" )) {
+      else if (str_match_nocase_whole( &ctx->cur, "DCL" )) {
          if (!parse_declaration( ctx ))
             return FALSE;
       }
-      else if (str_match_no_case( &ctx->cur, "IMM" )) {
+      else if (str_match_nocase_whole( &ctx->cur, "IMM" )) {
          if (!parse_immediate( ctx ))
             return FALSE;
       }
-      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
+      else if (str_match_nocase_whole( &ctx->cur, "PROPERTY" )) {
          if (!parse_property( ctx ))
             return FALSE;
       }
@@ -1468,7 +1734,7 @@ tgsi_text_translate(
    struct tgsi_token *tokens,
    uint num_tokens )
 {
-   struct translate_ctx ctx;
+   struct translate_ctx ctx = {0};
 
    ctx.text = text;
    ctx.cur = text;