tgsi_text.c revision 92209314df4f12e8b47336a25ba14cb6b9a23df2
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 ))
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};
288
289static boolean
290parse_file( const char **pcur, uint *file )
291{
292   uint i;
293
294   for (i = 0; i < TGSI_FILE_COUNT; i++) {
295      const char *cur = *pcur;
296
297      if (str_match_no_case( &cur, file_names[i] )) {
298         if (!is_digit_alpha_underscore( cur )) {
299            *pcur = cur;
300            *file = i;
301            return TRUE;
302         }
303      }
304   }
305   return FALSE;
306}
307
308static boolean
309parse_opt_writemask(
310   struct translate_ctx *ctx,
311   uint *writemask )
312{
313   const char *cur;
314
315   cur = ctx->cur;
316   eat_opt_white( &cur );
317   if (*cur == '.') {
318      cur++;
319      *writemask = TGSI_WRITEMASK_NONE;
320      eat_opt_white( &cur );
321      if (uprcase( *cur ) == 'X') {
322         cur++;
323         *writemask |= TGSI_WRITEMASK_X;
324      }
325      if (uprcase( *cur ) == 'Y') {
326         cur++;
327         *writemask |= TGSI_WRITEMASK_Y;
328      }
329      if (uprcase( *cur ) == 'Z') {
330         cur++;
331         *writemask |= TGSI_WRITEMASK_Z;
332      }
333      if (uprcase( *cur ) == 'W') {
334         cur++;
335         *writemask |= TGSI_WRITEMASK_W;
336      }
337
338      if (*writemask == TGSI_WRITEMASK_NONE) {
339         report_error( ctx, "Writemask expected" );
340         return FALSE;
341      }
342
343      ctx->cur = cur;
344   }
345   else {
346      *writemask = TGSI_WRITEMASK_XYZW;
347   }
348   return TRUE;
349}
350
351
352/* <register_file_bracket> ::= <file> `['
353 */
354static boolean
355parse_register_file_bracket(
356   struct translate_ctx *ctx,
357   uint *file )
358{
359   if (!parse_file( &ctx->cur, file )) {
360      report_error( ctx, "Unknown register file" );
361      return FALSE;
362   }
363   eat_opt_white( &ctx->cur );
364   if (*ctx->cur != '[') {
365      report_error( ctx, "Expected `['" );
366      return FALSE;
367   }
368   ctx->cur++;
369   return TRUE;
370}
371
372/* <register_file_bracket_index> ::= <register_file_bracket> <uint>
373 */
374static boolean
375parse_register_file_bracket_index(
376   struct translate_ctx *ctx,
377   uint *file,
378   int *index )
379{
380   uint uindex;
381
382   if (!parse_register_file_bracket( ctx, file ))
383      return FALSE;
384   eat_opt_white( &ctx->cur );
385   if (!parse_uint( &ctx->cur, &uindex )) {
386      report_error( ctx, "Expected literal unsigned integer" );
387      return FALSE;
388   }
389   *index = (int) uindex;
390   return TRUE;
391}
392
393/* Parse simple 1d register operand.
394 *    <register_dst> ::= <register_file_bracket_index> `]'
395 */
396static boolean
397parse_register_1d(struct translate_ctx *ctx,
398                  uint *file,
399                  int *index )
400{
401   if (!parse_register_file_bracket_index( ctx, file, index ))
402      return FALSE;
403   eat_opt_white( &ctx->cur );
404   if (*ctx->cur != ']') {
405      report_error( ctx, "Expected `]'" );
406      return FALSE;
407   }
408   ctx->cur++;
409   return TRUE;
410}
411
412struct parsed_bracket {
413   int index;
414
415   uint ind_file;
416   int ind_index;
417   uint ind_comp;
418};
419
420
421static boolean
422parse_register_bracket(
423   struct translate_ctx *ctx,
424   struct parsed_bracket *brackets)
425{
426   const char *cur;
427   uint uindex;
428
429   memset(brackets, 0, sizeof(struct parsed_bracket));
430
431   eat_opt_white( &ctx->cur );
432
433   cur = ctx->cur;
434   if (parse_file( &cur, &brackets->ind_file )) {
435      if (!parse_register_1d( ctx, &brackets->ind_file,
436                              &brackets->ind_index ))
437         return FALSE;
438      eat_opt_white( &ctx->cur );
439
440      if (*ctx->cur == '.') {
441         ctx->cur++;
442         eat_opt_white(&ctx->cur);
443
444         switch (uprcase(*ctx->cur)) {
445         case 'X':
446            brackets->ind_comp = TGSI_SWIZZLE_X;
447            break;
448         case 'Y':
449            brackets->ind_comp = TGSI_SWIZZLE_Y;
450            break;
451         case 'Z':
452            brackets->ind_comp = TGSI_SWIZZLE_Z;
453            break;
454         case 'W':
455            brackets->ind_comp = TGSI_SWIZZLE_W;
456            break;
457         default:
458            report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'");
459            return FALSE;
460         }
461         ctx->cur++;
462         eat_opt_white(&ctx->cur);
463      }
464
465      if (*ctx->cur == '+' || *ctx->cur == '-') {
466         boolean negate;
467
468         negate = *ctx->cur == '-';
469         ctx->cur++;
470         eat_opt_white( &ctx->cur );
471         if (!parse_uint( &ctx->cur, &uindex )) {
472            report_error( ctx, "Expected literal unsigned integer" );
473            return FALSE;
474         }
475         if (negate)
476            brackets->index = -(int) uindex;
477         else
478            brackets->index = (int) uindex;
479      }
480      else {
481         brackets->index = 0;
482      }
483   }
484   else {
485      if (!parse_uint( &ctx->cur, &uindex )) {
486         report_error( ctx, "Expected literal unsigned integer" );
487         return FALSE;
488      }
489      brackets->index = (int) uindex;
490      brackets->ind_file = TGSI_FILE_NULL;
491      brackets->ind_index = 0;
492   }
493   eat_opt_white( &ctx->cur );
494   if (*ctx->cur != ']') {
495      report_error( ctx, "Expected `]'" );
496      return FALSE;
497   }
498   ctx->cur++;
499   return TRUE;
500}
501
502static boolean
503parse_opt_register_src_bracket(
504   struct translate_ctx *ctx,
505   struct parsed_bracket *brackets,
506   int *parsed_brackets)
507{
508   const char *cur = ctx->cur;
509
510   *parsed_brackets = 0;
511
512   eat_opt_white( &cur );
513   if (cur[0] == '[') {
514      ++cur;
515      ctx->cur = cur;
516
517      if (!parse_register_bracket(ctx, brackets))
518         return FALSE;
519
520      *parsed_brackets = 1;
521   }
522
523   return TRUE;
524}
525
526
527/* Parse source register operand.
528 *    <register_src> ::= <register_file_bracket_index> `]' |
529 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
530 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
531 *                       <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
532 */
533static boolean
534parse_register_src(
535   struct translate_ctx *ctx,
536   uint *file,
537   struct parsed_bracket *brackets)
538{
539   brackets->ind_comp = TGSI_SWIZZLE_X;
540   if (!parse_register_file_bracket( ctx, file ))
541      return FALSE;
542   if (!parse_register_bracket( ctx, brackets ))
543       return FALSE;
544
545   return TRUE;
546}
547
548struct parsed_dcl_bracket {
549   uint first;
550   uint last;
551};
552
553static boolean
554parse_register_dcl_bracket(
555   struct translate_ctx *ctx,
556   struct parsed_dcl_bracket *bracket)
557{
558   uint uindex;
559   memset(bracket, 0, sizeof(struct parsed_dcl_bracket));
560
561   eat_opt_white( &ctx->cur );
562
563   if (!parse_uint( &ctx->cur, &uindex )) {
564      /* it can be an empty bracket [] which means its range
565       * is from 0 to some implied size */
566      if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) {
567         bracket->first = 0;
568         bracket->last = ctx->implied_array_size - 1;
569         goto cleanup;
570      }
571      report_error( ctx, "Expected literal unsigned integer" );
572      return FALSE;
573   }
574   bracket->first = uindex;
575
576   eat_opt_white( &ctx->cur );
577
578   if (ctx->cur[0] == '.' && ctx->cur[1] == '.') {
579      uint uindex;
580
581      ctx->cur += 2;
582      eat_opt_white( &ctx->cur );
583      if (!parse_uint( &ctx->cur, &uindex )) {
584         report_error( ctx, "Expected literal integer" );
585         return FALSE;
586      }
587      bracket->last = (int) uindex;
588      eat_opt_white( &ctx->cur );
589   }
590   else {
591      bracket->last = bracket->first;
592   }
593
594cleanup:
595   if (*ctx->cur != ']') {
596      report_error( ctx, "Expected `]' or `..'" );
597      return FALSE;
598   }
599   ctx->cur++;
600   return TRUE;
601}
602
603/* Parse register declaration.
604 *    <register_dcl> ::= <register_file_bracket_index> `]' |
605 *                       <register_file_bracket_index> `..' <index> `]'
606 */
607static boolean
608parse_register_dcl(
609   struct translate_ctx *ctx,
610   uint *file,
611   struct parsed_dcl_bracket *brackets,
612   int *num_brackets)
613{
614   const char *cur;
615
616   *num_brackets = 0;
617
618   if (!parse_register_file_bracket( ctx, file ))
619      return FALSE;
620   if (!parse_register_dcl_bracket( ctx, &brackets[0] ))
621      return FALSE;
622
623   *num_brackets = 1;
624
625   cur = ctx->cur;
626   eat_opt_white( &cur );
627
628   if (cur[0] == '[') {
629      ++cur;
630      ctx->cur = cur;
631      if (!parse_register_dcl_bracket( ctx, &brackets[1] ))
632         return FALSE;
633      /* for geometry shader we don't really care about
634       * the first brackets it's always the size of the
635       * input primitive. so we want to declare just
636       * the index relevant to the semantics which is in
637       * the second bracket */
638      if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) {
639         brackets[0] = brackets[1];
640         *num_brackets = 1;
641      } else {
642         *num_brackets = 2;
643      }
644   }
645
646   return TRUE;
647}
648
649
650/* Parse destination register operand.*/
651static boolean
652parse_register_dst(
653   struct translate_ctx *ctx,
654   uint *file,
655   struct parsed_bracket *brackets)
656{
657   brackets->ind_comp = TGSI_SWIZZLE_X;
658   if (!parse_register_file_bracket( ctx, file ))
659      return FALSE;
660   if (!parse_register_bracket( ctx, brackets ))
661       return FALSE;
662
663   return TRUE;
664}
665
666static boolean
667parse_dst_operand(
668   struct translate_ctx *ctx,
669   struct tgsi_full_dst_register *dst )
670{
671   uint file;
672   uint writemask;
673   const char *cur;
674   struct parsed_bracket bracket[2];
675   int parsed_opt_brackets;
676
677   if (!parse_register_dst( ctx, &file, &bracket[0] ))
678      return FALSE;
679   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
680      return FALSE;
681
682   cur = ctx->cur;
683   eat_opt_white( &cur );
684
685   if (!parse_opt_writemask( ctx, &writemask ))
686      return FALSE;
687
688   dst->Register.File = file;
689   if (parsed_opt_brackets) {
690      dst->Register.Dimension = 1;
691      dst->Dimension.Indirect = 0;
692      dst->Dimension.Dimension = 0;
693      dst->Dimension.Index = bracket[0].index;
694      bracket[0] = bracket[1];
695   }
696   dst->Register.Index = bracket[0].index;
697   dst->Register.WriteMask = writemask;
698   if (bracket[0].ind_file != TGSI_FILE_NULL) {
699      dst->Register.Indirect = 1;
700      dst->Indirect.File = bracket[0].ind_file;
701      dst->Indirect.Index = bracket[0].ind_index;
702      dst->Indirect.SwizzleX = bracket[0].ind_comp;
703      dst->Indirect.SwizzleY = bracket[0].ind_comp;
704      dst->Indirect.SwizzleZ = bracket[0].ind_comp;
705      dst->Indirect.SwizzleW = bracket[0].ind_comp;
706   }
707   return TRUE;
708}
709
710static boolean
711parse_optional_swizzle(
712   struct translate_ctx *ctx,
713   uint swizzle[4],
714   boolean *parsed_swizzle )
715{
716   const char *cur = ctx->cur;
717
718   *parsed_swizzle = FALSE;
719
720   eat_opt_white( &cur );
721   if (*cur == '.') {
722      uint i;
723
724      cur++;
725      eat_opt_white( &cur );
726      for (i = 0; i < 4; i++) {
727         if (uprcase( *cur ) == 'X')
728            swizzle[i] = TGSI_SWIZZLE_X;
729         else if (uprcase( *cur ) == 'Y')
730            swizzle[i] = TGSI_SWIZZLE_Y;
731         else if (uprcase( *cur ) == 'Z')
732            swizzle[i] = TGSI_SWIZZLE_Z;
733         else if (uprcase( *cur ) == 'W')
734            swizzle[i] = TGSI_SWIZZLE_W;
735         else {
736	    report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" );
737	    return FALSE;
738         }
739         cur++;
740      }
741      *parsed_swizzle = TRUE;
742      ctx->cur = cur;
743   }
744   return TRUE;
745}
746
747static boolean
748parse_src_operand(
749   struct translate_ctx *ctx,
750   struct tgsi_full_src_register *src )
751{
752   uint file;
753   uint swizzle[4];
754   boolean parsed_swizzle;
755   struct parsed_bracket bracket[2];
756   int parsed_opt_brackets;
757
758   if (*ctx->cur == '-') {
759      ctx->cur++;
760      eat_opt_white( &ctx->cur );
761      src->Register.Negate = 1;
762   }
763
764   if (*ctx->cur == '|') {
765      ctx->cur++;
766      eat_opt_white( &ctx->cur );
767      src->Register.Absolute = 1;
768   }
769
770   if (!parse_register_src(ctx, &file, &bracket[0]))
771      return FALSE;
772   if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets))
773      return FALSE;
774
775   src->Register.File = file;
776   if (parsed_opt_brackets) {
777      src->Register.Dimension = 1;
778      src->Dimension.Indirect = 0;
779      src->Dimension.Dimension = 0;
780      src->Dimension.Index = bracket[0].index;
781      bracket[0] = bracket[1];
782   }
783   src->Register.Index = bracket[0].index;
784   if (bracket[0].ind_file != TGSI_FILE_NULL) {
785      src->Register.Indirect = 1;
786      src->Indirect.File = bracket[0].ind_file;
787      src->Indirect.Index = bracket[0].ind_index;
788      src->Indirect.SwizzleX = bracket[0].ind_comp;
789      src->Indirect.SwizzleY = bracket[0].ind_comp;
790      src->Indirect.SwizzleZ = bracket[0].ind_comp;
791      src->Indirect.SwizzleW = bracket[0].ind_comp;
792   }
793
794   /* Parse optional swizzle.
795    */
796   if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
797      if (parsed_swizzle) {
798         src->Register.SwizzleX = swizzle[0];
799         src->Register.SwizzleY = swizzle[1];
800         src->Register.SwizzleZ = swizzle[2];
801         src->Register.SwizzleW = swizzle[3];
802      }
803   }
804
805   if (src->Register.Absolute) {
806      eat_opt_white( &ctx->cur );
807      if (*ctx->cur != '|') {
808         report_error( ctx, "Expected `|'" );
809         return FALSE;
810      }
811      ctx->cur++;
812   }
813
814
815   return TRUE;
816}
817
818static const char *texture_names[TGSI_TEXTURE_COUNT] =
819{
820   "UNKNOWN",
821   "1D",
822   "2D",
823   "3D",
824   "CUBE",
825   "RECT",
826   "SHADOW1D",
827   "SHADOW2D",
828   "SHADOWRECT"
829};
830
831static boolean
832match_inst_mnemonic(const char **pcur,
833                    const struct tgsi_opcode_info *info)
834{
835   if (str_match_no_case(pcur, info->mnemonic)) {
836      return TRUE;
837   }
838   return FALSE;
839}
840
841static boolean
842parse_instruction(
843   struct translate_ctx *ctx,
844   boolean has_label )
845{
846   uint i;
847   uint saturate = TGSI_SAT_NONE;
848   const struct tgsi_opcode_info *info;
849   struct tgsi_full_instruction inst;
850   uint advance;
851
852   inst = tgsi_default_full_instruction();
853
854   /* Parse predicate.
855    */
856   eat_opt_white( &ctx->cur );
857   if (*ctx->cur == '(') {
858      uint file;
859      int index;
860      uint swizzle[4];
861      boolean parsed_swizzle;
862
863      inst.Instruction.Predicate = 1;
864
865      ctx->cur++;
866      if (*ctx->cur == '!') {
867         ctx->cur++;
868         inst.Predicate.Negate = 1;
869      }
870
871      if (!parse_register_1d( ctx, &file, &index ))
872         return FALSE;
873
874      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
875         if (parsed_swizzle) {
876            inst.Predicate.SwizzleX = swizzle[0];
877            inst.Predicate.SwizzleY = swizzle[1];
878            inst.Predicate.SwizzleZ = swizzle[2];
879            inst.Predicate.SwizzleW = swizzle[3];
880         }
881      }
882
883      if (*ctx->cur != ')') {
884         report_error( ctx, "Expected `)'" );
885         return FALSE;
886      }
887
888      ctx->cur++;
889   }
890
891   /* Parse instruction name.
892    */
893   eat_opt_white( &ctx->cur );
894   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
895      const char *cur = ctx->cur;
896
897      info = tgsi_get_opcode_info( i );
898      if (match_inst_mnemonic(&cur, info)) {
899         if (str_match_no_case( &cur, "_SATNV" ))
900            saturate = TGSI_SAT_MINUS_PLUS_ONE;
901         else if (str_match_no_case( &cur, "_SAT" ))
902            saturate = TGSI_SAT_ZERO_ONE;
903
904         if (info->num_dst + info->num_src + info->is_tex == 0) {
905            if (!is_digit_alpha_underscore( cur )) {
906               ctx->cur = cur;
907               break;
908            }
909         }
910         else if (*cur == '\0' || eat_white( &cur )) {
911            ctx->cur = cur;
912            break;
913         }
914      }
915   }
916   if (i == TGSI_OPCODE_LAST) {
917      if (has_label)
918         report_error( ctx, "Unknown opcode" );
919      else
920         report_error( ctx, "Expected `DCL', `IMM' or a label" );
921      return FALSE;
922   }
923
924   inst.Instruction.Opcode = i;
925   inst.Instruction.Saturate = saturate;
926   inst.Instruction.NumDstRegs = info->num_dst;
927   inst.Instruction.NumSrcRegs = info->num_src;
928
929   /* Parse instruction operands.
930    */
931   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
932      if (i > 0) {
933         eat_opt_white( &ctx->cur );
934         if (*ctx->cur != ',') {
935            report_error( ctx, "Expected `,'" );
936            return FALSE;
937         }
938         ctx->cur++;
939         eat_opt_white( &ctx->cur );
940      }
941
942      if (i < info->num_dst) {
943         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
944            return FALSE;
945      }
946      else if (i < info->num_dst + info->num_src) {
947         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
948            return FALSE;
949      }
950      else {
951         uint j;
952
953         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
954            if (str_match_no_case( &ctx->cur, texture_names[j] )) {
955               if (!is_digit_alpha_underscore( ctx->cur )) {
956                  inst.Instruction.Texture = 1;
957                  inst.Texture.Texture = j;
958                  break;
959               }
960            }
961         }
962         if (j == TGSI_TEXTURE_COUNT) {
963            report_error( ctx, "Expected texture target" );
964            return FALSE;
965         }
966      }
967   }
968
969   if (info->is_branch) {
970      uint target;
971
972      eat_opt_white( &ctx->cur );
973      if (*ctx->cur != ':') {
974         report_error( ctx, "Expected `:'" );
975         return FALSE;
976      }
977      ctx->cur++;
978      eat_opt_white( &ctx->cur );
979      if (!parse_uint( &ctx->cur, &target )) {
980         report_error( ctx, "Expected a label" );
981         return FALSE;
982      }
983      inst.Instruction.Label = 1;
984      inst.Label.Label = target;
985   }
986
987   advance = tgsi_build_full_instruction(
988      &inst,
989      ctx->tokens_cur,
990      ctx->header,
991      (uint) (ctx->tokens_end - ctx->tokens_cur) );
992   if (advance == 0)
993      return FALSE;
994   ctx->tokens_cur += advance;
995
996   return TRUE;
997}
998
999static const char *semantic_names[TGSI_SEMANTIC_COUNT] =
1000{
1001   "POSITION",
1002   "COLOR",
1003   "BCOLOR",
1004   "FOG",
1005   "PSIZE",
1006   "GENERIC",
1007   "NORMAL",
1008   "FACE",
1009   "EDGEFLAG",
1010   "PRIM_ID",
1011   "INSTANCEID",
1012   "STENCIL"
1013};
1014
1015static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
1016{
1017   "CONSTANT",
1018   "LINEAR",
1019   "PERSPECTIVE"
1020};
1021
1022
1023/* parses a 4-touple of the form {x, y, z, w}
1024 * where x, y, z, w are numbers */
1025static boolean parse_immediate_data(struct translate_ctx *ctx,
1026                                    float *values)
1027{
1028   unsigned i;
1029
1030   eat_opt_white( &ctx->cur );
1031   if (*ctx->cur != '{') {
1032      report_error( ctx, "Expected `{'" );
1033      return FALSE;
1034   }
1035   ctx->cur++;
1036   for (i = 0; i < 4; i++) {
1037      eat_opt_white( &ctx->cur );
1038      if (i > 0) {
1039         if (*ctx->cur != ',') {
1040            report_error( ctx, "Expected `,'" );
1041            return FALSE;
1042         }
1043         ctx->cur++;
1044         eat_opt_white( &ctx->cur );
1045      }
1046      if (!parse_float( &ctx->cur, &values[i] )) {
1047         report_error( ctx, "Expected literal floating point" );
1048         return FALSE;
1049      }
1050   }
1051   eat_opt_white( &ctx->cur );
1052   if (*ctx->cur != '}') {
1053      report_error( ctx, "Expected `}'" );
1054      return FALSE;
1055   }
1056   ctx->cur++;
1057
1058   return TRUE;
1059}
1060
1061static boolean parse_declaration( struct translate_ctx *ctx )
1062{
1063   struct tgsi_full_declaration decl;
1064   uint file;
1065   struct parsed_dcl_bracket brackets[2];
1066   int num_brackets;
1067   uint writemask;
1068   const char *cur;
1069   uint advance;
1070   boolean is_vs_input;
1071   boolean is_imm_array;
1072
1073   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
1074   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
1075
1076   if (!eat_white( &ctx->cur )) {
1077      report_error( ctx, "Syntax error" );
1078      return FALSE;
1079   }
1080   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1081      return FALSE;
1082   if (!parse_opt_writemask( ctx, &writemask ))
1083      return FALSE;
1084
1085   decl = tgsi_default_full_declaration();
1086   decl.Declaration.File = file;
1087   decl.Declaration.UsageMask = writemask;
1088
1089   if (num_brackets == 1) {
1090      decl.Range.First = brackets[0].first;
1091      decl.Range.Last = brackets[0].last;
1092   } else {
1093      decl.Range.First = brackets[1].first;
1094      decl.Range.Last = brackets[1].last;
1095
1096      decl.Declaration.Dimension = 1;
1097      decl.Dim.Index2D = brackets[0].first;
1098   }
1099
1100   is_vs_input = (file == TGSI_FILE_INPUT &&
1101                  ctx->processor == TGSI_PROCESSOR_VERTEX);
1102   is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
1103
1104   cur = ctx->cur;
1105   eat_opt_white( &cur );
1106   if (*cur == ',' && !is_vs_input) {
1107      uint i;
1108
1109      cur++;
1110      eat_opt_white( &cur );
1111      for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1112         if (str_match_no_case( &cur, semantic_names[i] )) {
1113            const char *cur2 = cur;
1114            uint index;
1115
1116            if (is_digit_alpha_underscore( cur ))
1117               continue;
1118            eat_opt_white( &cur2 );
1119            if (*cur2 == '[') {
1120               cur2++;
1121               eat_opt_white( &cur2 );
1122               if (!parse_uint( &cur2, &index )) {
1123                  report_error( ctx, "Expected literal integer" );
1124                  return FALSE;
1125               }
1126               eat_opt_white( &cur2 );
1127               if (*cur2 != ']') {
1128                  report_error( ctx, "Expected `]'" );
1129                  return FALSE;
1130               }
1131               cur2++;
1132
1133               decl.Semantic.Index = index;
1134
1135               cur = cur2;
1136            }
1137
1138            decl.Declaration.Semantic = 1;
1139            decl.Semantic.Name = i;
1140
1141            ctx->cur = cur;
1142            break;
1143         }
1144      }
1145   } else if (is_imm_array) {
1146      unsigned i;
1147      float *vals_itr;
1148      /* we have our immediate data */
1149      if (*cur != '{') {
1150         report_error( ctx, "Immediate array without data" );
1151         return FALSE;
1152      }
1153      ++cur;
1154      ctx->cur = cur;
1155
1156      decl.ImmediateData.u =
1157         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1158                (decl.Range.Last + 1));
1159      vals_itr = (float*)decl.ImmediateData.u;
1160      for (i = 0; i <= decl.Range.Last; ++i) {
1161         if (!parse_immediate_data(ctx, vals_itr)) {
1162            FREE(decl.ImmediateData.u);
1163            return FALSE;
1164         }
1165         vals_itr += 4;
1166         eat_opt_white( &ctx->cur );
1167         if (*ctx->cur != ',') {
1168            if (i !=  decl.Range.Last) {
1169               report_error( ctx, "Not enough data in immediate array!" );
1170               FREE(decl.ImmediateData.u);
1171               return FALSE;
1172            }
1173         } else
1174            ++ctx->cur;
1175      }
1176      eat_opt_white( &ctx->cur );
1177      if (*ctx->cur != '}') {
1178         FREE(decl.ImmediateData.u);
1179         report_error( ctx, "Immediate array data missing closing '}'" );
1180         return FALSE;
1181      }
1182      ++ctx->cur;
1183   }
1184
1185   cur = ctx->cur;
1186   eat_opt_white( &cur );
1187   if (*cur == ',' && !is_vs_input) {
1188      uint i;
1189
1190      cur++;
1191      eat_opt_white( &cur );
1192      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1193         if (str_match_no_case( &cur, interpolate_names[i] )) {
1194            if (is_digit_alpha_underscore( cur ))
1195               continue;
1196            decl.Declaration.Interpolate = i;
1197
1198            ctx->cur = cur;
1199            break;
1200         }
1201      }
1202      if (i == TGSI_INTERPOLATE_COUNT) {
1203         report_error( ctx, "Expected semantic or interpolate attribute" );
1204         return FALSE;
1205      }
1206   }
1207
1208   advance = tgsi_build_full_declaration(
1209      &decl,
1210      ctx->tokens_cur,
1211      ctx->header,
1212      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1213
1214   if (is_imm_array)
1215      FREE(decl.ImmediateData.u);
1216
1217   if (advance == 0)
1218      return FALSE;
1219   ctx->tokens_cur += advance;
1220
1221   return TRUE;
1222}
1223
1224static boolean parse_immediate( struct translate_ctx *ctx )
1225{
1226   struct tgsi_full_immediate imm;
1227   float values[4];
1228   uint advance;
1229
1230   if (!eat_white( &ctx->cur )) {
1231      report_error( ctx, "Syntax error" );
1232      return FALSE;
1233   }
1234   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1235       is_digit_alpha_underscore( ctx->cur )) {
1236      report_error( ctx, "Expected `FLT32'" );
1237      return FALSE;
1238   }
1239
1240   parse_immediate_data(ctx, values);
1241
1242   imm = tgsi_default_full_immediate();
1243   imm.Immediate.NrTokens += 4;
1244   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1245   imm.u[0].Float = values[0];
1246   imm.u[1].Float = values[1];
1247   imm.u[2].Float = values[2];
1248   imm.u[3].Float = values[3];
1249
1250   advance = tgsi_build_full_immediate(
1251      &imm,
1252      ctx->tokens_cur,
1253      ctx->header,
1254      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1255   if (advance == 0)
1256      return FALSE;
1257   ctx->tokens_cur += advance;
1258
1259   return TRUE;
1260}
1261
1262static boolean
1263parse_primitive( const char **pcur, uint *primitive )
1264{
1265   uint i;
1266
1267   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1268      const char *cur = *pcur;
1269
1270      if (str_match_no_case( &cur, tgsi_primitive_names[i])) {
1271         *primitive = i;
1272         *pcur = cur;
1273         return TRUE;
1274      }
1275   }
1276   return FALSE;
1277}
1278
1279static boolean
1280parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1281{
1282   uint i;
1283
1284   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1285      const char *cur = *pcur;
1286
1287      if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) {
1288         *fs_coord_origin = i;
1289         *pcur = cur;
1290         return TRUE;
1291      }
1292   }
1293   return FALSE;
1294}
1295
1296static boolean
1297parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1298{
1299   uint i;
1300
1301   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1302      const char *cur = *pcur;
1303
1304      if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1305         *fs_coord_pixel_center = i;
1306         *pcur = cur;
1307         return TRUE;
1308      }
1309   }
1310   return FALSE;
1311}
1312
1313
1314static boolean parse_property( struct translate_ctx *ctx )
1315{
1316   struct tgsi_full_property prop;
1317   uint property_name;
1318   uint values[8];
1319   uint advance;
1320   char id[64];
1321
1322   if (!eat_white( &ctx->cur )) {
1323      report_error( ctx, "Syntax error" );
1324      return FALSE;
1325   }
1326   if (!parse_identifier( &ctx->cur, id )) {
1327      report_error( ctx, "Syntax error" );
1328      return FALSE;
1329   }
1330   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1331        ++property_name) {
1332      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1333         break;
1334      }
1335   }
1336   if (property_name >= TGSI_PROPERTY_COUNT) {
1337      debug_printf( "\nError: Unknown property : '%s'", id );
1338      return FALSE;
1339   }
1340
1341   eat_opt_white( &ctx->cur );
1342   switch(property_name) {
1343   case TGSI_PROPERTY_GS_INPUT_PRIM:
1344   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1345      if (!parse_primitive(&ctx->cur, &values[0] )) {
1346         report_error( ctx, "Unknown primitive name as property!" );
1347         return FALSE;
1348      }
1349      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1350          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1351         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1352      }
1353      break;
1354   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1355      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1356         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1357         return FALSE;
1358      }
1359      break;
1360   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1361      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1362         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1363         return FALSE;
1364      }
1365      break;
1366   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1367   default:
1368      if (!parse_uint(&ctx->cur, &values[0] )) {
1369         report_error( ctx, "Expected unsigned integer as property!" );
1370         return FALSE;
1371      }
1372   }
1373
1374   prop = tgsi_default_full_property();
1375   prop.Property.PropertyName = property_name;
1376   prop.Property.NrTokens += 1;
1377   prop.u[0].Data = values[0];
1378
1379   advance = tgsi_build_full_property(
1380      &prop,
1381      ctx->tokens_cur,
1382      ctx->header,
1383      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1384   if (advance == 0)
1385      return FALSE;
1386   ctx->tokens_cur += advance;
1387
1388   return TRUE;
1389}
1390
1391
1392static boolean translate( struct translate_ctx *ctx )
1393{
1394   eat_opt_white( &ctx->cur );
1395   if (!parse_header( ctx ))
1396      return FALSE;
1397
1398   while (*ctx->cur != '\0') {
1399      uint label_val = 0;
1400      if (!eat_white( &ctx->cur )) {
1401         report_error( ctx, "Syntax error" );
1402         return FALSE;
1403      }
1404
1405      if (*ctx->cur == '\0')
1406         break;
1407      if (parse_label( ctx, &label_val )) {
1408         if (!parse_instruction( ctx, TRUE ))
1409            return FALSE;
1410      }
1411      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1412         if (!parse_declaration( ctx ))
1413            return FALSE;
1414      }
1415      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1416         if (!parse_immediate( ctx ))
1417            return FALSE;
1418      }
1419      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1420         if (!parse_property( ctx ))
1421            return FALSE;
1422      }
1423      else if (!parse_instruction( ctx, FALSE )) {
1424         return FALSE;
1425      }
1426   }
1427
1428   return TRUE;
1429}
1430
1431boolean
1432tgsi_text_translate(
1433   const char *text,
1434   struct tgsi_token *tokens,
1435   uint num_tokens )
1436{
1437   struct translate_ctx ctx;
1438
1439   ctx.text = text;
1440   ctx.cur = text;
1441   ctx.tokens = tokens;
1442   ctx.tokens_cur = tokens;
1443   ctx.tokens_end = tokens + num_tokens;
1444
1445   if (!translate( &ctx ))
1446      return FALSE;
1447
1448   return tgsi_sanity_check( tokens );
1449}
1450