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