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