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