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