tgsi_text.c revision e7ccd703a28e14431b90f29540cec0bf67be1e0f
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "util/u_debug.h"
29#include "util/u_memory.h"
30#include "util/u_prim.h"
31#include "pipe/p_defines.h"
32#include "util/u_inlines.h"
33#include "tgsi_text.h"
34#include "tgsi_build.h"
35#include "tgsi_info.h"
36#include "tgsi_parse.h"
37#include "tgsi_sanity.h"
38#include "tgsi_util.h"
39#include "tgsi_dump.h"
40
41static boolean is_alpha_underscore( const char *cur )
42{
43   return
44      (*cur >= 'a' && *cur <= 'z') ||
45      (*cur >= 'A' && *cur <= 'Z') ||
46      *cur == '_';
47}
48
49static boolean is_digit( const char *cur )
50{
51   return *cur >= '0' && *cur <= '9';
52}
53
54static boolean is_digit_alpha_underscore( const char *cur )
55{
56   return is_digit( cur ) || is_alpha_underscore( cur );
57}
58
59static char uprcase( char c )
60{
61   if (c >= 'a' && c <= 'z')
62      return c + 'A' - 'a';
63   return c;
64}
65
66/*
67 * Ignore case of str1 and assume str1 is already uppercase.
68 * Return TRUE iff str1 and str2 are equal.
69 */
70static int
71streq_nocase_uprcase(const char *str1,
72                     const char *str2)
73{
74   while (*str1 && *str2) {
75      if (*str1 != uprcase(*str2))
76         return FALSE;
77      str1++;
78      str2++;
79   }
80   return *str1 == 0 && *str2 == 0;
81}
82
83static boolean str_match_no_case( const char **pcur, const char *str )
84{
85   const char *cur = *pcur;
86
87   while (*str != '\0' && *str == uprcase( *cur )) {
88      str++;
89      cur++;
90   }
91   if (*str == '\0') {
92      *pcur = cur;
93      return TRUE;
94   }
95   return FALSE;
96}
97
98/* Eat zero or more whitespaces.
99 */
100static void eat_opt_white( const char **pcur )
101{
102   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
103      (*pcur)++;
104}
105
106/* Eat one or more whitespaces.
107 * Return TRUE if at least one whitespace eaten.
108 */
109static boolean eat_white( const char **pcur )
110{
111   const char *cur = *pcur;
112
113   eat_opt_white( pcur );
114   return *pcur > cur;
115}
116
117/* Parse unsigned integer.
118 * No checks for overflow.
119 */
120static boolean parse_uint( const char **pcur, uint *val )
121{
122   const char *cur = *pcur;
123
124   if (is_digit( cur )) {
125      *val = *cur++ - '0';
126      while (is_digit( cur ))
127         *val = *val * 10 + *cur++ - '0';
128      *pcur = cur;
129      return TRUE;
130   }
131   return FALSE;
132}
133
134static boolean parse_identifier( const char **pcur, char *ret )
135{
136   const char *cur = *pcur;
137   int i = 0;
138   if (is_alpha_underscore( cur )) {
139      ret[i++] = *cur++;
140      while (is_alpha_underscore( cur ) || is_digit( cur ))
141         ret[i++] = *cur++;
142      ret[i++] = '\0';
143      *pcur = cur;
144      return TRUE;
145   }
146   return FALSE;
147}
148
149/* Parse floating point.
150 */
151static boolean parse_float( const char **pcur, float *val )
152{
153   const char *cur = *pcur;
154   boolean integral_part = FALSE;
155   boolean fractional_part = FALSE;
156
157   *val = (float) atof( cur );
158
159   if (*cur == '-' || *cur == '+')
160      cur++;
161   if (is_digit( cur )) {
162      cur++;
163      integral_part = TRUE;
164      while (is_digit( cur ))
165         cur++;
166   }
167   if (*cur == '.') {
168      cur++;
169      if (is_digit( cur )) {
170         cur++;
171         fractional_part = TRUE;
172         while (is_digit( cur ))
173            cur++;
174      }
175   }
176   if (!integral_part && !fractional_part)
177      return FALSE;
178   if (uprcase( *cur ) == 'E') {
179      cur++;
180      if (*cur == '-' || *cur == '+')
181         cur++;
182      if (is_digit( cur )) {
183         cur++;
184         while (is_digit( cur ))
185            cur++;
186      }
187      else
188         return FALSE;
189   }
190   *pcur = cur;
191   return TRUE;
192}
193
194struct translate_ctx
195{
196   const char *text;
197   const char *cur;
198   struct tgsi_token *tokens;
199   struct tgsi_token *tokens_cur;
200   struct tgsi_token *tokens_end;
201   struct tgsi_header *header;
202   unsigned processor : 4;
203   int implied_array_size : 5;
204};
205
206static void report_error( struct translate_ctx *ctx, const char *msg )
207{
208   int line = 1;
209   int column = 1;
210   const char *itr = ctx->text;
211
212   while (itr != ctx->cur) {
213      if (*itr == '\n') {
214         column = 1;
215         ++line;
216      }
217      ++column;
218      ++itr;
219   }
220
221   debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column );
222}
223
224/* Parse shader header.
225 * Return TRUE for one of the following headers.
226 *    FRAG
227 *    GEOM
228 *    VERT
229 */
230static boolean parse_header( struct translate_ctx *ctx )
231{
232   uint processor;
233
234   if (str_match_no_case( &ctx->cur, "FRAG" ))
235      processor = TGSI_PROCESSOR_FRAGMENT;
236   else if (str_match_no_case( &ctx->cur, "VERT" ))
237      processor = TGSI_PROCESSOR_VERTEX;
238   else if (str_match_no_case( &ctx->cur, "GEOM" ))
239      processor = TGSI_PROCESSOR_GEOMETRY;
240   else {
241      report_error( ctx, "Unknown header" );
242      return FALSE;
243   }
244
245   if (ctx->tokens_cur >= ctx->tokens_end)
246      return FALSE;
247   ctx->header = (struct tgsi_header *) ctx->tokens_cur++;
248   *ctx->header = tgsi_build_header();
249
250   if (ctx->tokens_cur >= ctx->tokens_end)
251      return FALSE;
252   *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header );
253   ctx->processor = processor;
254
255   return TRUE;
256}
257
258static boolean parse_label( struct translate_ctx *ctx, uint *val )
259{
260   const char *cur = ctx->cur;
261
262   if (parse_uint( &cur, val )) {
263      eat_opt_white( &cur );
264      if (*cur == ':') {
265         cur++;
266         ctx->cur = cur;
267         return TRUE;
268      }
269   }
270   return FALSE;
271}
272
273static const char *file_names[TGSI_FILE_COUNT] =
274{
275   "NULL",
276   "CONST",
277   "IN",
278   "OUT",
279   "TEMP",
280   "SAMP",
281   "ADDR",
282   "IMM",
283   "PRED",
284   "SV",
285   "IMMX",
286   "TEMPX",
287   "RES"
288};
289
290static boolean
291parse_file( const char **pcur, uint *file )
292{
293   uint i;
294
295   for (i = 0; i < TGSI_FILE_COUNT; i++) {
296      const char *cur = *pcur;
297
298      if (str_match_no_case( &cur, file_names[i] )) {
299         if (!is_digit_alpha_underscore( cur )) {
300            *pcur = cur;
301            *file = i;
302            return TRUE;
303         }
304      }
305   }
306   return FALSE;
307}
308
309static boolean
310parse_opt_writemask(
311   struct translate_ctx *ctx,
312   uint *writemask )
313{
314   const char *cur;
315
316   cur = ctx->cur;
317   eat_opt_white( &cur );
318   if (*cur == '.') {
319      cur++;
320      *writemask = TGSI_WRITEMASK_NONE;
321      eat_opt_white( &cur );
322      if (uprcase( *cur ) == 'X') {
323         cur++;
324         *writemask |= TGSI_WRITEMASK_X;
325      }
326      if (uprcase( *cur ) == 'Y') {
327         cur++;
328         *writemask |= TGSI_WRITEMASK_Y;
329      }
330      if (uprcase( *cur ) == 'Z') {
331         cur++;
332         *writemask |= TGSI_WRITEMASK_Z;
333      }
334      if (uprcase( *cur ) == 'W') {
335         cur++;
336         *writemask |= TGSI_WRITEMASK_W;
337      }
338
339      if (*writemask == TGSI_WRITEMASK_NONE) {
340         report_error( ctx, "Writemask expected" );
341         return FALSE;
342      }
343
344      ctx->cur = cur;
345   }
346   else {
347      *writemask = TGSI_WRITEMASK_XYZW;
348   }
349   return TRUE;
350}
351
352
353/* <register_file_bracket> ::= <file> `['
354 */
355static boolean
356parse_register_file_bracket(
357   struct translate_ctx *ctx,
358   uint *file )
359{
360   if (!parse_file( &ctx->cur, file )) {
361      report_error( ctx, "Unknown register file" );
362      return FALSE;
363   }
364   eat_opt_white( &ctx->cur );
365   if (*ctx->cur != '[') {
366      report_error( ctx, "Expected `['" );
367      return FALSE;
368   }
369   ctx->cur++;
370   return TRUE;
371}
372
373/* <register_file_bracket_index> ::= <register_file_bracket> <uint>
374 */
375static boolean
376parse_register_file_bracket_index(
377   struct translate_ctx *ctx,
378   uint *file,
379   int *index )
380{
381   uint uindex;
382
383   if (!parse_register_file_bracket( ctx, file ))
384      return FALSE;
385   eat_opt_white( &ctx->cur );
386   if (!parse_uint( &ctx->cur, &uindex )) {
387      report_error( ctx, "Expected literal unsigned integer" );
388      return FALSE;
389   }
390   *index = (int) uindex;
391   return TRUE;
392}
393
394/* Parse simple 1d register operand.
395 *    <register_dst> ::= <register_file_bracket_index> `]'
396 */
397static boolean
398parse_register_1d(struct translate_ctx *ctx,
399                  uint *file,
400                  int *index )
401{
402   if (!parse_register_file_bracket_index( ctx, file, index ))
403      return FALSE;
404   eat_opt_white( &ctx->cur );
405   if (*ctx->cur != ']') {
406      report_error( ctx, "Expected `]'" );
407      return FALSE;
408   }
409   ctx->cur++;
410   return TRUE;
411}
412
413struct parsed_bracket {
414   int index;
415
416   uint ind_file;
417   int ind_index;
418   uint ind_comp;
419};
420
421
422static boolean
423parse_register_bracket(
424   struct translate_ctx *ctx,
425   struct parsed_bracket *brackets)
426{
427   const char *cur;
428   uint uindex;
429
430   memset(brackets, 0, sizeof(struct parsed_bracket));
431
432   eat_opt_white( &ctx->cur );
433
434   cur = ctx->cur;
435   if (parse_file( &cur, &brackets->ind_file )) {
436      if (!parse_register_1d( ctx, &brackets->ind_file,
437                              &brackets->ind_index ))
438         return FALSE;
439      eat_opt_white( &ctx->cur );
440
441      if (*ctx->cur == '.') {
442         ctx->cur++;
443         eat_opt_white(&ctx->cur);
444
445         switch (uprcase(*ctx->cur)) {
446         case 'X':
447            brackets->ind_comp = TGSI_SWIZZLE_X;
448            break;
449         case 'Y':
450            brackets->ind_comp = TGSI_SWIZZLE_Y;
451            break;
452         case 'Z':
453            brackets->ind_comp = TGSI_SWIZZLE_Z;
454            break;
455         case 'W':
456            brackets->ind_comp = TGSI_SWIZZLE_W;
457            break;
458         default:
459            report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
460            return FALSE;
461         }
462         ctx->cur++;
463         eat_opt_white(&ctx->cur);
464      }
465
466      if (*ctx->cur == '+' || *ctx->cur == '-') {
467         boolean negate;
468
469         negate = *ctx->cur == '-';
470         ctx->cur++;
471         eat_opt_white( &ctx->cur );
472         if (!parse_uint( &ctx->cur, &uindex )) {
473            report_error( ctx, "Expected literal unsigned integer" );
474            return FALSE;
475         }
476         if (negate)
477            brackets->index = -(int) uindex;
478         else
479            brackets->index = (int) uindex;
480      }
481      else {
482         brackets->index = 0;
483      }
484   }
485   else {
486      if (!parse_uint( &ctx->cur, &uindex )) {
487         report_error( ctx, "Expected literal unsigned integer" );
488         return FALSE;
489      }
490      brackets->index = (int) uindex;
491      brackets->ind_file = TGSI_FILE_NULL;
492      brackets->ind_index = 0;
493   }
494   eat_opt_white( &ctx->cur );
495   if (*ctx->cur != ']') {
496      report_error( ctx, "Expected `]'" );
497      return FALSE;
498   }
499   ctx->cur++;
500   return TRUE;
501}
502
503static boolean
504parse_opt_register_src_bracket(
505   struct translate_ctx *ctx,
506   struct parsed_bracket *brackets,
507   int *parsed_brackets)
508{
509   const char *cur = ctx->cur;
510
511   *parsed_brackets = 0;
512
513   eat_opt_white( &cur );
514   if (cur[0] == '[') {
515      ++cur;
516      ctx->cur = cur;
517
518      if (!parse_register_bracket(ctx, brackets))
519         return FALSE;
520
521      *parsed_brackets = 1;
522   }
523
524   return TRUE;
525}
526
527
528/* Parse source register operand.
529 *    <register_src> ::= <register_file_bracket_index> `]' |
530 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
531 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
532 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
533 */
534static boolean
535parse_register_src(
536   struct translate_ctx *ctx,
537   uint *file,
538   struct parsed_bracket *brackets)
539{
540   brackets->ind_comp = TGSI_SWIZZLE_X;
541   if (!parse_register_file_bracket( ctx, file ))
542      return FALSE;
543   if (!parse_register_bracket( ctx, brackets ))
544       return FALSE;
545
546   return TRUE;
547}
548
549struct parsed_dcl_bracket {
550   uint first;
551   uint last;
552};
553
554static boolean
555parse_register_dcl_bracket(
556   struct translate_ctx *ctx,
557   struct parsed_dcl_bracket *bracket)
558{
559   uint uindex;
560   memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
561
562   eat_opt_white( &ctx->cur );
563
564   if (!parse_uint( &ctx->cur, &uindex )) {
565      /* it can be an empty bracket [] which means its range
566       * is from 0 to some implied size */
567      if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
568         bracket->first = 0;
569         bracket->last = ctx->implied_array_size - 1;
570         goto cleanup;
571      }
572      report_error( ctx, "Expected literal unsigned integer" );
573      return FALSE;
574   }
575   bracket->first = uindex;
576
577   eat_opt_white( &ctx->cur );
578
579   if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
580      uint uindex;
581
582      ctx->cur += 2;
583      eat_opt_white( &ctx->cur );
584      if (!parse_uint( &ctx->cur, &uindex )) {
585         report_error( ctx, "Expected literal integer" );
586         return FALSE;
587      }
588      bracket->last = (int) uindex;
589      eat_opt_white( &ctx->cur );
590   }
591   else {
592      bracket->last = bracket->first;
593   }
594
595cleanup:
596   if (*ctx->cur != ']') {
597      report_error( ctx, "Expected `]' or `..'" );
598      return FALSE;
599   }
600   ctx->cur++;
601   return TRUE;
602}
603
604/* Parse register declaration.
605 *    <register_dcl> ::= <register_file_bracket_index> `]' |
606 *                       <register_file_bracket_index> `..' <index> `]'
607 */
608static boolean
609parse_register_dcl(
610   struct translate_ctx *ctx,
611   uint *file,
612   struct parsed_dcl_bracket *brackets,
613   int *num_brackets)
614{
615   const char *cur;
616
617   *num_brackets = 0;
618
619   if (!parse_register_file_bracket( ctx, file ))
620      return FALSE;
621   if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
622      return FALSE;
623
624   *num_brackets = 1;
625
626   cur = ctx->cur;
627   eat_opt_white( &cur );
628
629   if (cur[0] == '[') {
630      ++cur;
631      ctx->cur = cur;
632      if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
633         return FALSE;
634      /* for geometry shader we don't really care about
635       * the first brackets it's always the size of the
636       * input primitive. so we want to declare just
637       * the index relevant to the semantics which is in
638       * the second bracket */
639      if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
640         brackets[0] = brackets[1];
641         *num_brackets = 1;
642      } else {
643         *num_brackets = 2;
644      }
645   }
646
647   return TRUE;
648}
649
650
651/* Parse destination register operand.*/
652static boolean
653parse_register_dst(
654   struct translate_ctx *ctx,
655   uint *file,
656   struct parsed_bracket *brackets)
657{
658   brackets->ind_comp = TGSI_SWIZZLE_X;
659   if (!parse_register_file_bracket( ctx, file ))
660      return FALSE;
661   if (!parse_register_bracket( ctx, brackets ))
662       return FALSE;
663
664   return TRUE;
665}
666
667static boolean
668parse_dst_operand(
669   struct translate_ctx *ctx,
670   struct tgsi_full_dst_register *dst )
671{
672   uint file;
673   uint writemask;
674   const char *cur;
675   struct parsed_bracket bracket[2];
676   int parsed_opt_brackets;
677
678   if (!parse_register_dst( ctx, &file, &bracket[0] ))
679      return FALSE;
680   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
681      return FALSE;
682
683   cur = ctx->cur;
684   eat_opt_white( &cur );
685
686   if (!parse_opt_writemask( ctx, &writemask ))
687      return FALSE;
688
689   dst->Register.File = file;
690   if (parsed_opt_brackets) {
691      dst->Register.Dimension = 1;
692      dst->Dimension.Indirect = 0;
693      dst->Dimension.Dimension = 0;
694      dst->Dimension.Index = bracket[0].index;
695      bracket[0] = bracket[1];
696   }
697   dst->Register.Index = bracket[0].index;
698   dst->Register.WriteMask = writemask;
699   if (bracket[0].ind_file != TGSI_FILE_NULL) {
700      dst->Register.Indirect = 1;
701      dst->Indirect.File = bracket[0].ind_file;
702      dst->Indirect.Index = bracket[0].ind_index;
703      dst->Indirect.SwizzleX = bracket[0].ind_comp;
704      dst->Indirect.SwizzleY = bracket[0].ind_comp;
705      dst->Indirect.SwizzleZ = bracket[0].ind_comp;
706      dst->Indirect.SwizzleW = bracket[0].ind_comp;
707   }
708   return TRUE;
709}
710
711static boolean
712parse_optional_swizzle(
713   struct translate_ctx *ctx,
714   uint swizzle[4],
715   boolean *parsed_swizzle )
716{
717   const char *cur = ctx->cur;
718
719   *parsed_swizzle = FALSE;
720
721   eat_opt_white( &cur );
722   if (*cur == '.') {
723      uint i;
724
725      cur++;
726      eat_opt_white( &cur );
727      for (i = 0; i < 4; i++) {
728         if (uprcase( *cur ) == 'X')
729            swizzle[i] = TGSI_SWIZZLE_X;
730         else if (uprcase( *cur ) == 'Y')
731            swizzle[i] = TGSI_SWIZZLE_Y;
732         else if (uprcase( *cur ) == 'Z')
733            swizzle[i] = TGSI_SWIZZLE_Z;
734         else if (uprcase( *cur ) == 'W')
735            swizzle[i] = TGSI_SWIZZLE_W;
736         else {
737	    report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" );
738	    return FALSE;
739         }
740         cur++;
741      }
742      *parsed_swizzle = TRUE;
743      ctx->cur = cur;
744   }
745   return TRUE;
746}
747
748static boolean
749parse_src_operand(
750   struct translate_ctx *ctx,
751   struct tgsi_full_src_register *src )
752{
753   uint file;
754   uint swizzle[4];
755   boolean parsed_swizzle;
756   struct parsed_bracket bracket[2];
757   int parsed_opt_brackets;
758
759   if (*ctx->cur == '-') {
760      ctx->cur++;
761      eat_opt_white( &ctx->cur );
762      src->Register.Negate = 1;
763   }
764
765   if (*ctx->cur == '|') {
766      ctx->cur++;
767      eat_opt_white( &ctx->cur );
768      src->Register.Absolute = 1;
769   }
770
771   if (!parse_register_src(ctx, &file, &bracket[0]))
772      return FALSE;
773   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
774      return FALSE;
775
776   src->Register.File = file;
777   if (parsed_opt_brackets) {
778      src->Register.Dimension = 1;
779      src->Dimension.Indirect = 0;
780      src->Dimension.Dimension = 0;
781      src->Dimension.Index = bracket[0].index;
782      bracket[0] = bracket[1];
783   }
784   src->Register.Index = bracket[0].index;
785   if (bracket[0].ind_file != TGSI_FILE_NULL) {
786      src->Register.Indirect = 1;
787      src->Indirect.File = bracket[0].ind_file;
788      src->Indirect.Index = bracket[0].ind_index;
789      src->Indirect.SwizzleX = bracket[0].ind_comp;
790      src->Indirect.SwizzleY = bracket[0].ind_comp;
791      src->Indirect.SwizzleZ = bracket[0].ind_comp;
792      src->Indirect.SwizzleW = bracket[0].ind_comp;
793   }
794
795   /* Parse optional swizzle.
796    */
797   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
798      if (parsed_swizzle) {
799         src->Register.SwizzleX = swizzle[0];
800         src->Register.SwizzleY = swizzle[1];
801         src->Register.SwizzleZ = swizzle[2];
802         src->Register.SwizzleW = swizzle[3];
803      }
804   }
805
806   if (src->Register.Absolute) {
807      eat_opt_white( &ctx->cur );
808      if (*ctx->cur != '|') {
809         report_error( ctx, "Expected `|'" );
810         return FALSE;
811      }
812      ctx->cur++;
813   }
814
815
816   return TRUE;
817}
818
819static const char *texture_names[TGSI_TEXTURE_COUNT] =
820{
821   "UNKNOWN",
822   "1D",
823   "2D",
824   "3D",
825   "CUBE",
826   "RECT",
827   "SHADOW1D",
828   "SHADOW2D",
829   "SHADOWRECT",
830   "1DARRAY",
831   "2DARRAY",
832   "SHADOW1DARRAY",
833   "SHADOW2DARRAY"
834};
835
836static const char *type_names[] =
837{
838   "UNORM",
839   "SNORM",
840   "SINT",
841   "UINT",
842   "FLOAT"
843};
844
845static boolean
846match_inst_mnemonic(const char **pcur,
847                    const struct tgsi_opcode_info *info)
848{
849   if (str_match_no_case(pcur, info->mnemonic)) {
850      return TRUE;
851   }
852   return FALSE;
853}
854
855static boolean
856parse_instruction(
857   struct translate_ctx *ctx,
858   boolean has_label )
859{
860   uint i;
861   uint saturate = TGSI_SAT_NONE;
862   const struct tgsi_opcode_info *info;
863   struct tgsi_full_instruction inst;
864   uint advance;
865
866   inst = tgsi_default_full_instruction();
867
868   /* Parse predicate.
869    */
870   eat_opt_white( &ctx->cur );
871   if (*ctx->cur == '(') {
872      uint file;
873      int index;
874      uint swizzle[4];
875      boolean parsed_swizzle;
876
877      inst.Instruction.Predicate = 1;
878
879      ctx->cur++;
880      if (*ctx->cur == '!') {
881         ctx->cur++;
882         inst.Predicate.Negate = 1;
883      }
884
885      if (!parse_register_1d( ctx, &file, &index ))
886         return FALSE;
887
888      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
889         if (parsed_swizzle) {
890            inst.Predicate.SwizzleX = swizzle[0];
891            inst.Predicate.SwizzleY = swizzle[1];
892            inst.Predicate.SwizzleZ = swizzle[2];
893            inst.Predicate.SwizzleW = swizzle[3];
894         }
895      }
896
897      if (*ctx->cur != ')') {
898         report_error( ctx, "Expected `)'" );
899         return FALSE;
900      }
901
902      ctx->cur++;
903   }
904
905   /* Parse instruction name.
906    */
907   eat_opt_white( &ctx->cur );
908   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
909      const char *cur = ctx->cur;
910
911      info = tgsi_get_opcode_info( i );
912      if (match_inst_mnemonic(&cur, info)) {
913         if (str_match_no_case( &cur, "_SATNV" ))
914            saturate = TGSI_SAT_MINUS_PLUS_ONE;
915         else if (str_match_no_case( &cur, "_SAT" ))
916            saturate = TGSI_SAT_ZERO_ONE;
917
918         if (info->num_dst + info->num_src + info->is_tex == 0) {
919            if (!is_digit_alpha_underscore( cur )) {
920               ctx->cur = cur;
921               break;
922            }
923         }
924         else if (*cur == '\0' || eat_white( &cur )) {
925            ctx->cur = cur;
926            break;
927         }
928      }
929   }
930   if (i == TGSI_OPCODE_LAST) {
931      if (has_label)
932         report_error( ctx, "Unknown opcode" );
933      else
934         report_error( ctx, "Expected `DCL', `IMM' or a label" );
935      return FALSE;
936   }
937
938   inst.Instruction.Opcode = i;
939   inst.Instruction.Saturate = saturate;
940   inst.Instruction.NumDstRegs = info->num_dst;
941   inst.Instruction.NumSrcRegs = info->num_src;
942
943   /* Parse instruction operands.
944    */
945   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
946      if (i > 0) {
947         eat_opt_white( &ctx->cur );
948         if (*ctx->cur != ',') {
949            report_error( ctx, "Expected `,'" );
950            return FALSE;
951         }
952         ctx->cur++;
953         eat_opt_white( &ctx->cur );
954      }
955
956      if (i < info->num_dst) {
957         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
958            return FALSE;
959      }
960      else if (i < info->num_dst + info->num_src) {
961         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
962            return FALSE;
963      }
964      else {
965         uint j;
966
967         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
968            if (str_match_no_case( &ctx->cur, texture_names[j] )) {
969               if (!is_digit_alpha_underscore( ctx->cur )) {
970                  inst.Instruction.Texture = 1;
971                  inst.Texture.Texture = j;
972                  break;
973               }
974            }
975         }
976         if (j == TGSI_TEXTURE_COUNT) {
977            report_error( ctx, "Expected texture target" );
978            return FALSE;
979         }
980      }
981   }
982
983   if (info->is_branch) {
984      uint target;
985
986      eat_opt_white( &ctx->cur );
987      if (*ctx->cur != ':') {
988         report_error( ctx, "Expected `:'" );
989         return FALSE;
990      }
991      ctx->cur++;
992      eat_opt_white( &ctx->cur );
993      if (!parse_uint( &ctx->cur, &target )) {
994         report_error( ctx, "Expected a label" );
995         return FALSE;
996      }
997      inst.Instruction.Label = 1;
998      inst.Label.Label = target;
999   }
1000
1001   advance = tgsi_build_full_instruction(
1002      &inst,
1003      ctx->tokens_cur,
1004      ctx->header,
1005      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1006   if (advance == 0)
1007      return FALSE;
1008   ctx->tokens_cur += advance;
1009
1010   return TRUE;
1011}
1012
1013static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
1014{
1015   "POSITION",
1016   "COLOR",
1017   "BCOLOR",
1018   "FOG",
1019   "PSIZE",
1020   "GENERIC",
1021   "NORMAL",
1022   "FACE",
1023   "EDGEFLAG",
1024   "PRIM_ID",
1025   "INSTANCEID",
1026   "VERTEXID",
1027   "STENCIL"
1028};
1029
1030static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
1031{
1032   "CONSTANT",
1033   "LINEAR",
1034   "PERSPECTIVE"
1035};
1036
1037
1038/* parses a 4-touple of the form {x, y, z, w}
1039 * where x, y, z, w are numbers */
1040static boolean parse_immediate_data(struct translate_ctx *ctx,
1041                                    float *values)
1042{
1043   unsigned i;
1044
1045   eat_opt_white( &ctx->cur );
1046   if (*ctx->cur != '{') {
1047      report_error( ctx, "Expected `{'" );
1048      return FALSE;
1049   }
1050   ctx->cur++;
1051   for (i = 0; i < 4; i++) {
1052      eat_opt_white( &ctx->cur );
1053      if (i > 0) {
1054         if (*ctx->cur != ',') {
1055            report_error( ctx, "Expected `,'" );
1056            return FALSE;
1057         }
1058         ctx->cur++;
1059         eat_opt_white( &ctx->cur );
1060      }
1061      if (!parse_float( &ctx->cur, &values[i] )) {
1062         report_error( ctx, "Expected literal floating point" );
1063         return FALSE;
1064      }
1065   }
1066   eat_opt_white( &ctx->cur );
1067   if (*ctx->cur != '}') {
1068      report_error( ctx, "Expected `}'" );
1069      return FALSE;
1070   }
1071   ctx->cur++;
1072
1073   return TRUE;
1074}
1075
1076static boolean parse_declaration( struct translate_ctx *ctx )
1077{
1078   struct tgsi_full_declaration decl;
1079   uint file;
1080   struct parsed_dcl_bracket brackets[2];
1081   int num_brackets;
1082   uint writemask;
1083   const char *cur;
1084   uint advance;
1085   boolean is_vs_input;
1086   boolean is_imm_array;
1087
1088   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
1089   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
1090
1091   if (!eat_white( &ctx->cur )) {
1092      report_error( ctx, "Syntax error" );
1093      return FALSE;
1094   }
1095   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1096      return FALSE;
1097   if (!parse_opt_writemask( ctx, &writemask ))
1098      return FALSE;
1099
1100   decl = tgsi_default_full_declaration();
1101   decl.Declaration.File = file;
1102   decl.Declaration.UsageMask = writemask;
1103
1104   if (num_brackets == 1) {
1105      decl.Range.First = brackets[0].first;
1106      decl.Range.Last = brackets[0].last;
1107   } else {
1108      decl.Range.First = brackets[1].first;
1109      decl.Range.Last = brackets[1].last;
1110
1111      decl.Declaration.Dimension = 1;
1112      decl.Dim.Index2D = brackets[0].first;
1113   }
1114
1115   is_vs_input = (file == TGSI_FILE_INPUT &&
1116                  ctx->processor == TGSI_PROCESSOR_VERTEX);
1117   is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
1118
1119   cur = ctx->cur;
1120   eat_opt_white( &cur );
1121   if (*cur == ',' && !is_vs_input) {
1122      uint i, j;
1123
1124      cur++;
1125      eat_opt_white( &cur );
1126      if (file == TGSI_FILE_RESOURCE) {
1127         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1128            if (str_match_no_case(&cur, texture_names[i])) {
1129               if (!is_digit_alpha_underscore(cur)) {
1130                  decl.Resource.Resource = i;
1131                  break;
1132               }
1133            }
1134         }
1135         if (i == TGSI_TEXTURE_COUNT) {
1136            report_error(ctx, "Expected texture target");
1137            return FALSE;
1138         }
1139         eat_opt_white( &cur );
1140         if (*cur != ',') {
1141            report_error( ctx, "Expected `,'" );
1142            return FALSE;
1143         }
1144         ++cur;
1145         eat_opt_white( &cur );
1146         for (j = 0; j < 4; ++j) {
1147            for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
1148               if (str_match_no_case(&cur, type_names[i])) {
1149                  if (!is_digit_alpha_underscore(cur)) {
1150                     switch (j) {
1151                     case 0:
1152                        decl.Resource.ReturnTypeX = i;
1153                        break;
1154                     case 1:
1155                        decl.Resource.ReturnTypeY = i;
1156                        break;
1157                     case 2:
1158                        decl.Resource.ReturnTypeZ = i;
1159                        break;
1160                     case 3:
1161                        decl.Resource.ReturnTypeW = i;
1162                        break;
1163                     default:
1164                        assert(0);
1165                     }
1166                     break;
1167                  }
1168               }
1169            }
1170            if (i == PIPE_TYPE_COUNT) {
1171               if (j == 0 || j >  2) {
1172                  report_error(ctx, "Expected type name");
1173                  return FALSE;
1174               }
1175               break;
1176            } else {
1177               const char *cur2 = cur;
1178               eat_opt_white( &cur2 );
1179               if (*cur2 == ',') {
1180                  cur2++;
1181                  eat_opt_white( &cur2 );
1182                  cur = cur2;
1183                  continue;
1184               } else
1185                  break;
1186            }
1187         }
1188         if (j < 4) {
1189            decl.Resource.ReturnTypeY =
1190               decl.Resource.ReturnTypeZ =
1191               decl.Resource.ReturnTypeW =
1192               decl.Resource.ReturnTypeX;
1193         }
1194         ctx->cur = cur;
1195      } else {
1196         for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1197            if (str_match_no_case( &cur, semantic_names[i] )) {
1198               const char *cur2 = cur;
1199               uint index;
1200
1201               if (is_digit_alpha_underscore( cur ))
1202                  continue;
1203               eat_opt_white( &cur2 );
1204               if (*cur2 == '[') {
1205                  cur2++;
1206                  eat_opt_white( &cur2 );
1207                  if (!parse_uint( &cur2, &index )) {
1208                     report_error( ctx, "Expected literal integer" );
1209                     return FALSE;
1210                  }
1211                  eat_opt_white( &cur2 );
1212                  if (*cur2 != ']') {
1213                     report_error( ctx, "Expected `]'" );
1214                     return FALSE;
1215                  }
1216                  cur2++;
1217
1218                  decl.Semantic.Index = index;
1219
1220                  cur = cur2;
1221               }
1222
1223               decl.Declaration.Semantic = 1;
1224               decl.Semantic.Name = i;
1225
1226               ctx->cur = cur;
1227               break;
1228            }
1229         }
1230      }
1231   } else if (is_imm_array) {
1232      unsigned i;
1233      float *vals_itr;
1234      /* we have our immediate data */
1235      if (*cur != '{') {
1236         report_error( ctx, "Immediate array without data" );
1237         return FALSE;
1238      }
1239      ++cur;
1240      ctx->cur = cur;
1241
1242      decl.ImmediateData.u =
1243         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1244                (decl.Range.Last + 1));
1245      vals_itr = (float*)decl.ImmediateData.u;
1246      for (i = 0; i <= decl.Range.Last; ++i) {
1247         if (!parse_immediate_data(ctx, vals_itr)) {
1248            FREE(decl.ImmediateData.u);
1249            return FALSE;
1250         }
1251         vals_itr += 4;
1252         eat_opt_white( &ctx->cur );
1253         if (*ctx->cur != ',') {
1254            if (i !=  decl.Range.Last) {
1255               report_error( ctx, "Not enough data in immediate array!" );
1256               FREE(decl.ImmediateData.u);
1257               return FALSE;
1258            }
1259         } else
1260            ++ctx->cur;
1261      }
1262      eat_opt_white( &ctx->cur );
1263      if (*ctx->cur != '}') {
1264         FREE(decl.ImmediateData.u);
1265         report_error( ctx, "Immediate array data missing closing '}'" );
1266         return FALSE;
1267      }
1268      ++ctx->cur;
1269   }
1270
1271   cur = ctx->cur;
1272   eat_opt_white( &cur );
1273   if (*cur == ',' && !is_vs_input) {
1274      uint i;
1275
1276      cur++;
1277      eat_opt_white( &cur );
1278      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1279         if (str_match_no_case( &cur, interpolate_names[i] )) {
1280            if (is_digit_alpha_underscore( cur ))
1281               continue;
1282            decl.Declaration.Interpolate = i;
1283
1284            ctx->cur = cur;
1285            break;
1286         }
1287      }
1288      if (i == TGSI_INTERPOLATE_COUNT) {
1289         report_error( ctx, "Expected semantic or interpolate attribute" );
1290         return FALSE;
1291      }
1292   }
1293
1294   advance = tgsi_build_full_declaration(
1295      &decl,
1296      ctx->tokens_cur,
1297      ctx->header,
1298      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1299
1300   if (is_imm_array)
1301      FREE(decl.ImmediateData.u);
1302
1303   if (advance == 0)
1304      return FALSE;
1305   ctx->tokens_cur += advance;
1306
1307   return TRUE;
1308}
1309
1310static boolean parse_immediate( struct translate_ctx *ctx )
1311{
1312   struct tgsi_full_immediate imm;
1313   float values[4];
1314   uint advance;
1315
1316   if (!eat_white( &ctx->cur )) {
1317      report_error( ctx, "Syntax error" );
1318      return FALSE;
1319   }
1320   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1321       is_digit_alpha_underscore( ctx->cur )) {
1322      report_error( ctx, "Expected `FLT32'" );
1323      return FALSE;
1324   }
1325
1326   parse_immediate_data(ctx, values);
1327
1328   imm = tgsi_default_full_immediate();
1329   imm.Immediate.NrTokens += 4;
1330   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1331   imm.u[0].Float = values[0];
1332   imm.u[1].Float = values[1];
1333   imm.u[2].Float = values[2];
1334   imm.u[3].Float = values[3];
1335
1336   advance = tgsi_build_full_immediate(
1337      &imm,
1338      ctx->tokens_cur,
1339      ctx->header,
1340      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1341   if (advance == 0)
1342      return FALSE;
1343   ctx->tokens_cur += advance;
1344
1345   return TRUE;
1346}
1347
1348static boolean
1349parse_primitive( const char **pcur, uint *primitive )
1350{
1351   uint i;
1352
1353   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1354      const char *cur = *pcur;
1355
1356      if (str_match_no_case( &cur, tgsi_primitive_names[i])) {
1357         *primitive = i;
1358         *pcur = cur;
1359         return TRUE;
1360      }
1361   }
1362   return FALSE;
1363}
1364
1365static boolean
1366parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1367{
1368   uint i;
1369
1370   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1371      const char *cur = *pcur;
1372
1373      if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) {
1374         *fs_coord_origin = i;
1375         *pcur = cur;
1376         return TRUE;
1377      }
1378   }
1379   return FALSE;
1380}
1381
1382static boolean
1383parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1384{
1385   uint i;
1386
1387   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1388      const char *cur = *pcur;
1389
1390      if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1391         *fs_coord_pixel_center = i;
1392         *pcur = cur;
1393         return TRUE;
1394      }
1395   }
1396   return FALSE;
1397}
1398
1399
1400static boolean parse_property( struct translate_ctx *ctx )
1401{
1402   struct tgsi_full_property prop;
1403   uint property_name;
1404   uint values[8];
1405   uint advance;
1406   char id[64];
1407
1408   if (!eat_white( &ctx->cur )) {
1409      report_error( ctx, "Syntax error" );
1410      return FALSE;
1411   }
1412   if (!parse_identifier( &ctx->cur, id )) {
1413      report_error( ctx, "Syntax error" );
1414      return FALSE;
1415   }
1416   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1417        ++property_name) {
1418      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1419         break;
1420      }
1421   }
1422   if (property_name >= TGSI_PROPERTY_COUNT) {
1423      debug_printf( "\nError: Unknown property : '%s'", id );
1424      return FALSE;
1425   }
1426
1427   eat_opt_white( &ctx->cur );
1428   switch(property_name) {
1429   case TGSI_PROPERTY_GS_INPUT_PRIM:
1430   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1431      if (!parse_primitive(&ctx->cur, &values[0] )) {
1432         report_error( ctx, "Unknown primitive name as property!" );
1433         return FALSE;
1434      }
1435      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1436          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1437         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1438      }
1439      break;
1440   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1441      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1442         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1443         return FALSE;
1444      }
1445      break;
1446   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1447      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1448         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1449         return FALSE;
1450      }
1451      break;
1452   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1453   default:
1454      if (!parse_uint(&ctx->cur, &values[0] )) {
1455         report_error( ctx, "Expected unsigned integer as property!" );
1456         return FALSE;
1457      }
1458   }
1459
1460   prop = tgsi_default_full_property();
1461   prop.Property.PropertyName = property_name;
1462   prop.Property.NrTokens += 1;
1463   prop.u[0].Data = values[0];
1464
1465   advance = tgsi_build_full_property(
1466      &prop,
1467      ctx->tokens_cur,
1468      ctx->header,
1469      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1470   if (advance == 0)
1471      return FALSE;
1472   ctx->tokens_cur += advance;
1473
1474   return TRUE;
1475}
1476
1477
1478static boolean translate( struct translate_ctx *ctx )
1479{
1480   eat_opt_white( &ctx->cur );
1481   if (!parse_header( ctx ))
1482      return FALSE;
1483
1484   while (*ctx->cur != '\0') {
1485      uint label_val = 0;
1486      if (!eat_white( &ctx->cur )) {
1487         report_error( ctx, "Syntax error" );
1488         return FALSE;
1489      }
1490
1491      if (*ctx->cur == '\0')
1492         break;
1493      if (parse_label( ctx, &label_val )) {
1494         if (!parse_instruction( ctx, TRUE ))
1495            return FALSE;
1496      }
1497      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1498         if (!parse_declaration( ctx ))
1499            return FALSE;
1500      }
1501      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1502         if (!parse_immediate( ctx ))
1503            return FALSE;
1504      }
1505      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1506         if (!parse_property( ctx ))
1507            return FALSE;
1508      }
1509      else if (!parse_instruction( ctx, FALSE )) {
1510         return FALSE;
1511      }
1512   }
1513
1514   return TRUE;
1515}
1516
1517boolean
1518tgsi_text_translate(
1519   const char *text,
1520   struct tgsi_token *tokens,
1521   uint num_tokens )
1522{
1523   struct translate_ctx ctx;
1524
1525   ctx.text = text;
1526   ctx.cur = text;
1527   ctx.tokens = tokens;
1528   ctx.tokens_cur = tokens;
1529   ctx.tokens_end = tokens + num_tokens;
1530
1531   if (!translate( &ctx ))
1532      return FALSE;
1533
1534   return tgsi_sanity_check( tokens );
1535}
1536