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