tgsi_text.c revision e36a08221400af025f1585f4e1ddbd3715810368
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#include "util/u_debug.h"
29#include "util/u_memory.h"
30#include "util/u_prim.h"
31#include "pipe/p_defines.h"
32#include "util/u_inlines.h"
33#include "tgsi_text.h"
34#include "tgsi_build.h"
35#include "tgsi_info.h"
36#include "tgsi_parse.h"
37#include "tgsi_sanity.h"
38#include "tgsi_util.h"
39
40static boolean is_alpha_underscore( const char *cur )
41{
42   return
43      (*cur >= 'a' && *cur <= 'z') ||
44      (*cur >= 'A' && *cur <= 'Z') ||
45      *cur == '_';
46}
47
48static boolean is_digit( const char *cur )
49{
50   return *cur >= '0' && *cur <= '9';
51}
52
53static boolean is_digit_alpha_underscore( const char *cur )
54{
55   return is_digit( cur ) || is_alpha_underscore( cur );
56}
57
58static char uprcase( char c )
59{
60   if (c >= 'a' && c <= 'z')
61      return c + 'A' - 'a';
62   return c;
63}
64
65/*
66 * Ignore case of str1 and assume str1 is already uppercase.
67 * Return TRUE iff str1 and str2 are equal.
68 */
69static int
70streq_nocase_uprcase(const char *str1,
71                     const char *str2)
72{
73   while (*str1 && *str2) {
74      if (*str1 != uprcase(*str2))
75         return FALSE;
76      str1++;
77      str2++;
78   }
79   return *str1 == 0 && *str2 == 0;
80}
81
82static boolean str_match_no_case( const char **pcur, const char *str )
83{
84   const char *cur = *pcur;
85
86   while (*str != '\0' && *str == uprcase( *cur )) {
87      str++;
88      cur++;
89   }
90   if (*str == '\0') {
91      *pcur = cur;
92      return TRUE;
93   }
94   return FALSE;
95}
96
97/* Eat zero or more whitespaces.
98 */
99static void eat_opt_white( const char **pcur )
100{
101   while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n')
102      (*pcur)++;
103}
104
105/* Eat one or more whitespaces.
106 * Return TRUE if at least one whitespace eaten.
107 */
108static boolean eat_white( const char **pcur )
109{
110   const char *cur = *pcur;
111
112   eat_opt_white( pcur );
113   return *pcur > cur;
114}
115
116/* Parse unsigned integer.
117 * No checks for overflow.
118 */
119static boolean parse_uint( const char **pcur, uint *val )
120{
121   const char *cur = *pcur;
122
123   if (is_digit( cur )) {
124      *val = *cur++ - '0';
125      while (is_digit( cur ))
126         *val = *val * 10 + *cur++ - '0';
127      *pcur = cur;
128      return TRUE;
129   }
130   return FALSE;
131}
132
133static boolean parse_identifier( const char **pcur, char *ret )
134{
135   const char *cur = *pcur;
136   int i = 0;
137   if (is_alpha_underscore( cur )) {
138      ret[i++] = *cur++;
139      while (is_alpha_underscore( cur ))
140         ret[i++] = *cur++;
141      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};
1012
1013static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] =
1014{
1015   "CONSTANT",
1016   "LINEAR",
1017   "PERSPECTIVE"
1018};
1019
1020
1021/* parses a 4-touple of the form {x, y, z, w}
1022 * where x, y, z, w are numbers */
1023static boolean parse_immediate_data(struct translate_ctx *ctx,
1024                                    float *values)
1025{
1026   unsigned i;
1027
1028   eat_opt_white( &ctx->cur );
1029   if (*ctx->cur != '{') {
1030      report_error( ctx, "Expected `{'" );
1031      return FALSE;
1032   }
1033   ctx->cur++;
1034   for (i = 0; i < 4; i++) {
1035      eat_opt_white( &ctx->cur );
1036      if (i > 0) {
1037         if (*ctx->cur != ',') {
1038            report_error( ctx, "Expected `,'" );
1039            return FALSE;
1040         }
1041         ctx->cur++;
1042         eat_opt_white( &ctx->cur );
1043      }
1044      if (!parse_float( &ctx->cur, &values[i] )) {
1045         report_error( ctx, "Expected literal floating point" );
1046         return FALSE;
1047      }
1048   }
1049   eat_opt_white( &ctx->cur );
1050   if (*ctx->cur != '}') {
1051      report_error( ctx, "Expected `}'" );
1052      return FALSE;
1053   }
1054   ctx->cur++;
1055
1056   return TRUE;
1057}
1058
1059static boolean parse_declaration( struct translate_ctx *ctx )
1060{
1061   struct tgsi_full_declaration decl;
1062   uint file;
1063   struct parsed_dcl_bracket brackets[2];
1064   int num_brackets;
1065   uint writemask;
1066   const char *cur;
1067   uint advance;
1068   boolean is_vs_input;
1069   boolean is_imm_array;
1070
1071   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
1072   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
1073
1074   if (!eat_white( &ctx->cur )) {
1075      report_error( ctx, "Syntax error" );
1076      return FALSE;
1077   }
1078   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1079      return FALSE;
1080   if (!parse_opt_writemask( ctx, &writemask ))
1081      return FALSE;
1082
1083   decl = tgsi_default_full_declaration();
1084   decl.Declaration.File = file;
1085   decl.Declaration.UsageMask = writemask;
1086
1087   if (num_brackets == 1) {
1088      decl.Range.First = brackets[0].first;
1089      decl.Range.Last = brackets[0].last;
1090   } else {
1091      decl.Range.First = brackets[1].first;
1092      decl.Range.Last = brackets[1].last;
1093
1094      decl.Declaration.Dimension = 1;
1095      decl.Dim.Index2D = brackets[0].first;
1096   }
1097
1098   is_vs_input = (file == TGSI_FILE_INPUT &&
1099                  ctx->processor == TGSI_PROCESSOR_VERTEX);
1100   is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
1101
1102   cur = ctx->cur;
1103   eat_opt_white( &cur );
1104   if (*cur == ',' && !is_vs_input) {
1105      uint i;
1106
1107      cur++;
1108      eat_opt_white( &cur );
1109      for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1110         if (str_match_no_case( &cur, semantic_names[i] )) {
1111            const char *cur2 = cur;
1112            uint index;
1113
1114            if (is_digit_alpha_underscore( cur ))
1115               continue;
1116            eat_opt_white( &cur2 );
1117            if (*cur2 == '[') {
1118               cur2++;
1119               eat_opt_white( &cur2 );
1120               if (!parse_uint( &cur2, &index )) {
1121                  report_error( ctx, "Expected literal integer" );
1122                  return FALSE;
1123               }
1124               eat_opt_white( &cur2 );
1125               if (*cur2 != ']') {
1126                  report_error( ctx, "Expected `]'" );
1127                  return FALSE;
1128               }
1129               cur2++;
1130
1131               decl.Semantic.Index = index;
1132
1133               cur = cur2;
1134            }
1135
1136            decl.Declaration.Semantic = 1;
1137            decl.Semantic.Name = i;
1138
1139            ctx->cur = cur;
1140            break;
1141         }
1142      }
1143   } else if (is_imm_array) {
1144      unsigned i;
1145      float *vals_itr;
1146      /* we have our immediate data */
1147      if (*cur != '{') {
1148         report_error( ctx, "Immediate array without data" );
1149         return FALSE;
1150      }
1151      ++cur;
1152      ctx->cur = cur;
1153
1154      decl.ImmediateData.u =
1155         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1156                (decl.Range.Last + 1));
1157      vals_itr = (float*)decl.ImmediateData.u;
1158      for (i = 0; i <= decl.Range.Last; ++i) {
1159         if (!parse_immediate_data(ctx, vals_itr)) {
1160            FREE(decl.ImmediateData.u);
1161            return FALSE;
1162         }
1163         vals_itr += 4;
1164         eat_opt_white( &ctx->cur );
1165         if (*ctx->cur != ',') {
1166            if (i !=  decl.Range.Last) {
1167               report_error( ctx, "Not enough data in immediate array!" );
1168               FREE(decl.ImmediateData.u);
1169               return FALSE;
1170            }
1171         } else
1172            ++ctx->cur;
1173      }
1174      eat_opt_white( &ctx->cur );
1175      if (*ctx->cur != '}') {
1176         FREE(decl.ImmediateData.u);
1177         report_error( ctx, "Immediate array data missing closing '}'" );
1178         return FALSE;
1179      }
1180      ++ctx->cur;
1181   }
1182
1183   cur = ctx->cur;
1184   eat_opt_white( &cur );
1185   if (*cur == ',' && !is_vs_input) {
1186      uint i;
1187
1188      cur++;
1189      eat_opt_white( &cur );
1190      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1191         if (str_match_no_case( &cur, interpolate_names[i] )) {
1192            if (is_digit_alpha_underscore( cur ))
1193               continue;
1194            decl.Declaration.Interpolate = i;
1195
1196            ctx->cur = cur;
1197            break;
1198         }
1199      }
1200      if (i == TGSI_INTERPOLATE_COUNT) {
1201         report_error( ctx, "Expected semantic or interpolate attribute" );
1202         return FALSE;
1203      }
1204   }
1205
1206   advance = tgsi_build_full_declaration(
1207      &decl,
1208      ctx->tokens_cur,
1209      ctx->header,
1210      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1211
1212   if (is_imm_array)
1213      FREE(decl.ImmediateData.u);
1214
1215   if (advance == 0)
1216      return FALSE;
1217   ctx->tokens_cur += advance;
1218
1219   return TRUE;
1220}
1221
1222static boolean parse_immediate( struct translate_ctx *ctx )
1223{
1224   struct tgsi_full_immediate imm;
1225   float values[4];
1226   uint advance;
1227
1228   if (!eat_white( &ctx->cur )) {
1229      report_error( ctx, "Syntax error" );
1230      return FALSE;
1231   }
1232   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1233       is_digit_alpha_underscore( ctx->cur )) {
1234      report_error( ctx, "Expected `FLT32'" );
1235      return FALSE;
1236   }
1237
1238   parse_immediate_data(ctx, values);
1239
1240   imm = tgsi_default_full_immediate();
1241   imm.Immediate.NrTokens += 4;
1242   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1243   imm.u[0].Float = values[0];
1244   imm.u[1].Float = values[1];
1245   imm.u[2].Float = values[2];
1246   imm.u[3].Float = values[3];
1247
1248   advance = tgsi_build_full_immediate(
1249      &imm,
1250      ctx->tokens_cur,
1251      ctx->header,
1252      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1253   if (advance == 0)
1254      return FALSE;
1255   ctx->tokens_cur += advance;
1256
1257   return TRUE;
1258}
1259
1260static const char *property_names[] =
1261{
1262   "GS_INPUT_PRIMITIVE",
1263   "GS_OUTPUT_PRIMITIVE",
1264   "GS_MAX_OUTPUT_VERTICES",
1265   "FS_COORD_ORIGIN",
1266   "FS_COORD_PIXEL_CENTER"
1267};
1268
1269static const char *primitive_names[] =
1270{
1271   "POINTS",
1272   "LINES",
1273   "LINE_LOOP",
1274   "LINE_STRIP",
1275   "TRIANGLES",
1276   "TRIANGLE_STRIP",
1277   "TRIANGLE_FAN",
1278   "QUADS",
1279   "QUAD_STRIP",
1280   "POLYGON"
1281};
1282
1283static const char *fs_coord_origin_names[] =
1284{
1285   "UPPER_LEFT",
1286   "LOWER_LEFT"
1287};
1288
1289static const char *fs_coord_pixel_center_names[] =
1290{
1291   "HALF_INTEGER",
1292   "INTEGER"
1293};
1294
1295
1296static boolean
1297parse_primitive( const char **pcur, uint *primitive )
1298{
1299   uint i;
1300
1301   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1302      const char *cur = *pcur;
1303
1304      if (str_match_no_case( &cur, primitive_names[i])) {
1305         *primitive = i;
1306         *pcur = cur;
1307         return TRUE;
1308      }
1309   }
1310   return FALSE;
1311}
1312
1313static boolean
1314parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1315{
1316   uint i;
1317
1318   for (i = 0; i < sizeof(fs_coord_origin_names) / sizeof(fs_coord_origin_names[0]); i++) {
1319      const char *cur = *pcur;
1320
1321      if (str_match_no_case( &cur, fs_coord_origin_names[i])) {
1322         *fs_coord_origin = i;
1323         *pcur = cur;
1324         return TRUE;
1325      }
1326   }
1327   return FALSE;
1328}
1329
1330static boolean
1331parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1332{
1333   uint i;
1334
1335   for (i = 0; i < sizeof(fs_coord_pixel_center_names) / sizeof(fs_coord_pixel_center_names[0]); i++) {
1336      const char *cur = *pcur;
1337
1338      if (str_match_no_case( &cur, fs_coord_pixel_center_names[i])) {
1339         *fs_coord_pixel_center = i;
1340         *pcur = cur;
1341         return TRUE;
1342      }
1343   }
1344   return FALSE;
1345}
1346
1347
1348static boolean parse_property( struct translate_ctx *ctx )
1349{
1350   struct tgsi_full_property prop;
1351   uint property_name;
1352   uint values[8];
1353   uint advance;
1354   char id[64];
1355
1356   if (!eat_white( &ctx->cur )) {
1357      report_error( ctx, "Syntax error" );
1358      return FALSE;
1359   }
1360   if (!parse_identifier( &ctx->cur, id )) {
1361      report_error( ctx, "Syntax error" );
1362      return FALSE;
1363   }
1364   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1365        ++property_name) {
1366      if (streq_nocase_uprcase(property_names[property_name], id)) {
1367         break;
1368      }
1369   }
1370   if (property_name >= TGSI_PROPERTY_COUNT) {
1371      debug_printf( "\nError: Unknown property : '%s'", id );
1372      return FALSE;
1373   }
1374
1375   eat_opt_white( &ctx->cur );
1376   switch(property_name) {
1377   case TGSI_PROPERTY_GS_INPUT_PRIM:
1378   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1379      if (!parse_primitive(&ctx->cur, &values[0] )) {
1380         report_error( ctx, "Unknown primitive name as property!" );
1381         return FALSE;
1382      }
1383      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1384          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1385         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1386      }
1387      break;
1388   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1389      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1390         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1391         return FALSE;
1392      }
1393      break;
1394   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1395      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1396         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1397         return FALSE;
1398      }
1399      break;
1400   default:
1401      if (!parse_uint(&ctx->cur, &values[0] )) {
1402         report_error( ctx, "Expected unsigned integer as property!" );
1403         return FALSE;
1404      }
1405   }
1406
1407   prop = tgsi_default_full_property();
1408   prop.Property.PropertyName = property_name;
1409   prop.Property.NrTokens += 1;
1410   prop.u[0].Data = values[0];
1411
1412   advance = tgsi_build_full_property(
1413      &prop,
1414      ctx->tokens_cur,
1415      ctx->header,
1416      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1417   if (advance == 0)
1418      return FALSE;
1419   ctx->tokens_cur += advance;
1420
1421   return TRUE;
1422}
1423
1424
1425static boolean translate( struct translate_ctx *ctx )
1426{
1427   eat_opt_white( &ctx->cur );
1428   if (!parse_header( ctx ))
1429      return FALSE;
1430
1431   while (*ctx->cur != '\0') {
1432      uint label_val = 0;
1433      if (!eat_white( &ctx->cur )) {
1434         report_error( ctx, "Syntax error" );
1435         return FALSE;
1436      }
1437
1438      if (*ctx->cur == '\0')
1439         break;
1440      if (parse_label( ctx, &label_val )) {
1441         if (!parse_instruction( ctx, TRUE ))
1442            return FALSE;
1443      }
1444      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1445         if (!parse_declaration( ctx ))
1446            return FALSE;
1447      }
1448      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1449         if (!parse_immediate( ctx ))
1450            return FALSE;
1451      }
1452      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1453         if (!parse_property( ctx ))
1454            return FALSE;
1455      }
1456      else if (!parse_instruction( ctx, FALSE )) {
1457         return FALSE;
1458      }
1459   }
1460
1461   return TRUE;
1462}
1463
1464boolean
1465tgsi_text_translate(
1466   const char *text,
1467   struct tgsi_token *tokens,
1468   uint num_tokens )
1469{
1470   struct translate_ctx ctx;
1471
1472   ctx.text = text;
1473   ctx.cur = text;
1474   ctx.tokens = tokens;
1475   ctx.tokens_cur = tokens;
1476   ctx.tokens_end = tokens + num_tokens;
1477
1478   if (!translate( &ctx ))
1479      return FALSE;
1480
1481   return tgsi_sanity_check( tokens );
1482}
1483