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