tgsi_text.c revision 63428372cadc73a7124f4e7d383eb86a0c7affd7
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;
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         ctx->cur = cur;
1073
1074      } else if (file == TGSI_FILE_SAMPLER_VIEW) {
1075         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1076            if (str_match_no_case(&cur, tgsi_texture_names[i])) {
1077               if (!is_digit_alpha_underscore(cur)) {
1078                  decl.SamplerView.Resource = i;
1079                  break;
1080               }
1081            }
1082         }
1083         if (i == TGSI_TEXTURE_COUNT) {
1084            report_error(ctx, "Expected texture target");
1085            return FALSE;
1086         }
1087         eat_opt_white( &cur );
1088         if (*cur != ',') {
1089            report_error( ctx, "Expected `,'" );
1090            return FALSE;
1091         }
1092         ++cur;
1093         eat_opt_white( &cur );
1094         for (j = 0; j < 4; ++j) {
1095            for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
1096               if (str_match_no_case(&cur, tgsi_type_names[i])) {
1097                  if (!is_digit_alpha_underscore(cur)) {
1098                     switch (j) {
1099                     case 0:
1100                        decl.SamplerView.ReturnTypeX = i;
1101                        break;
1102                     case 1:
1103                        decl.SamplerView.ReturnTypeY = i;
1104                        break;
1105                     case 2:
1106                        decl.SamplerView.ReturnTypeZ = i;
1107                        break;
1108                     case 3:
1109                        decl.SamplerView.ReturnTypeW = i;
1110                        break;
1111                     default:
1112                        assert(0);
1113                     }
1114                     break;
1115                  }
1116               }
1117            }
1118            if (i == PIPE_TYPE_COUNT) {
1119               if (j == 0 || j >  2) {
1120                  report_error(ctx, "Expected type name");
1121                  return FALSE;
1122               }
1123               break;
1124            } else {
1125               const char *cur2 = cur;
1126               eat_opt_white( &cur2 );
1127               if (*cur2 == ',') {
1128                  cur2++;
1129                  eat_opt_white( &cur2 );
1130                  cur = cur2;
1131                  continue;
1132               } else
1133                  break;
1134            }
1135         }
1136         if (j < 4) {
1137            decl.SamplerView.ReturnTypeY =
1138               decl.SamplerView.ReturnTypeZ =
1139               decl.SamplerView.ReturnTypeW =
1140               decl.SamplerView.ReturnTypeX;
1141         }
1142         ctx->cur = cur;
1143      } else {
1144         for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1145            if (str_match_no_case( &cur, tgsi_semantic_names[i] )) {
1146               const char *cur2 = cur;
1147               uint index;
1148
1149               if (is_digit_alpha_underscore( cur ))
1150                  continue;
1151               eat_opt_white( &cur2 );
1152               if (*cur2 == '[') {
1153                  cur2++;
1154                  eat_opt_white( &cur2 );
1155                  if (!parse_uint( &cur2, &index )) {
1156                     report_error( ctx, "Expected literal integer" );
1157                     return FALSE;
1158                  }
1159                  eat_opt_white( &cur2 );
1160                  if (*cur2 != ']') {
1161                     report_error( ctx, "Expected `]'" );
1162                     return FALSE;
1163                  }
1164                  cur2++;
1165
1166                  decl.Semantic.Index = index;
1167
1168                  cur = cur2;
1169               }
1170
1171               decl.Declaration.Semantic = 1;
1172               decl.Semantic.Name = i;
1173
1174               ctx->cur = cur;
1175               break;
1176            }
1177         }
1178      }
1179   } else if (is_imm_array) {
1180      unsigned i;
1181      float *vals_itr;
1182      /* we have our immediate data */
1183      if (*cur != '{') {
1184         report_error( ctx, "Immediate array without data" );
1185         return FALSE;
1186      }
1187      ++cur;
1188      ctx->cur = cur;
1189
1190      decl.ImmediateData.u =
1191         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1192                (decl.Range.Last + 1));
1193      vals_itr = (float*)decl.ImmediateData.u;
1194      for (i = 0; i <= decl.Range.Last; ++i) {
1195         if (!parse_immediate_data(ctx, vals_itr)) {
1196            FREE(decl.ImmediateData.u);
1197            return FALSE;
1198         }
1199         vals_itr += 4;
1200         eat_opt_white( &ctx->cur );
1201         if (*ctx->cur != ',') {
1202            if (i !=  decl.Range.Last) {
1203               report_error( ctx, "Not enough data in immediate array!" );
1204               FREE(decl.ImmediateData.u);
1205               return FALSE;
1206            }
1207         } else
1208            ++ctx->cur;
1209      }
1210      eat_opt_white( &ctx->cur );
1211      if (*ctx->cur != '}') {
1212         FREE(decl.ImmediateData.u);
1213         report_error( ctx, "Immediate array data missing closing '}'" );
1214         return FALSE;
1215      }
1216      ++ctx->cur;
1217   }
1218
1219   cur = ctx->cur;
1220   eat_opt_white( &cur );
1221   if (*cur == ',' && !is_vs_input) {
1222      uint i;
1223
1224      cur++;
1225      eat_opt_white( &cur );
1226      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1227         if (str_match_no_case( &cur, tgsi_interpolate_names[i] )) {
1228            if (is_digit_alpha_underscore( cur ))
1229               continue;
1230            decl.Declaration.Interpolate = 1;
1231            decl.Interp.Interpolate = i;
1232
1233            ctx->cur = cur;
1234            break;
1235         }
1236      }
1237      if (i == TGSI_INTERPOLATE_COUNT) {
1238         report_error( ctx, "Expected semantic or interpolate attribute" );
1239         return FALSE;
1240      }
1241   }
1242
1243   advance = tgsi_build_full_declaration(
1244      &decl,
1245      ctx->tokens_cur,
1246      ctx->header,
1247      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1248
1249   if (is_imm_array)
1250      FREE(decl.ImmediateData.u);
1251
1252   if (advance == 0)
1253      return FALSE;
1254   ctx->tokens_cur += advance;
1255
1256   return TRUE;
1257}
1258
1259static boolean parse_immediate( struct translate_ctx *ctx )
1260{
1261   struct tgsi_full_immediate imm;
1262   float values[4];
1263   uint advance;
1264
1265   if (!eat_white( &ctx->cur )) {
1266      report_error( ctx, "Syntax error" );
1267      return FALSE;
1268   }
1269   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1270       is_digit_alpha_underscore( ctx->cur )) {
1271      report_error( ctx, "Expected `FLT32'" );
1272      return FALSE;
1273   }
1274
1275   parse_immediate_data(ctx, values);
1276
1277   imm = tgsi_default_full_immediate();
1278   imm.Immediate.NrTokens += 4;
1279   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1280   imm.u[0].Float = values[0];
1281   imm.u[1].Float = values[1];
1282   imm.u[2].Float = values[2];
1283   imm.u[3].Float = values[3];
1284
1285   advance = tgsi_build_full_immediate(
1286      &imm,
1287      ctx->tokens_cur,
1288      ctx->header,
1289      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1290   if (advance == 0)
1291      return FALSE;
1292   ctx->tokens_cur += advance;
1293
1294   return TRUE;
1295}
1296
1297static boolean
1298parse_primitive( const char **pcur, uint *primitive )
1299{
1300   uint i;
1301
1302   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1303      const char *cur = *pcur;
1304
1305      if (str_match_no_case( &cur, tgsi_primitive_names[i])) {
1306         *primitive = i;
1307         *pcur = cur;
1308         return TRUE;
1309      }
1310   }
1311   return FALSE;
1312}
1313
1314static boolean
1315parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1316{
1317   uint i;
1318
1319   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1320      const char *cur = *pcur;
1321
1322      if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) {
1323         *fs_coord_origin = i;
1324         *pcur = cur;
1325         return TRUE;
1326      }
1327   }
1328   return FALSE;
1329}
1330
1331static boolean
1332parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1333{
1334   uint i;
1335
1336   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1337      const char *cur = *pcur;
1338
1339      if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1340         *fs_coord_pixel_center = i;
1341         *pcur = cur;
1342         return TRUE;
1343      }
1344   }
1345   return FALSE;
1346}
1347
1348
1349static boolean parse_property( struct translate_ctx *ctx )
1350{
1351   struct tgsi_full_property prop;
1352   uint property_name;
1353   uint values[8];
1354   uint advance;
1355   char id[64];
1356
1357   if (!eat_white( &ctx->cur )) {
1358      report_error( ctx, "Syntax error" );
1359      return FALSE;
1360   }
1361   if (!parse_identifier( &ctx->cur, id )) {
1362      report_error( ctx, "Syntax error" );
1363      return FALSE;
1364   }
1365   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1366        ++property_name) {
1367      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1368         break;
1369      }
1370   }
1371   if (property_name >= TGSI_PROPERTY_COUNT) {
1372      debug_printf( "\nError: Unknown property : '%s'", id );
1373      return FALSE;
1374   }
1375
1376   eat_opt_white( &ctx->cur );
1377   switch(property_name) {
1378   case TGSI_PROPERTY_GS_INPUT_PRIM:
1379   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1380      if (!parse_primitive(&ctx->cur, &values[0] )) {
1381         report_error( ctx, "Unknown primitive name as property!" );
1382         return FALSE;
1383      }
1384      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1385          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1386         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1387      }
1388      break;
1389   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1390      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1391         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1392         return FALSE;
1393      }
1394      break;
1395   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1396      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1397         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1398         return FALSE;
1399      }
1400      break;
1401   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1402   default:
1403      if (!parse_uint(&ctx->cur, &values[0] )) {
1404         report_error( ctx, "Expected unsigned integer as property!" );
1405         return FALSE;
1406      }
1407   }
1408
1409   prop = tgsi_default_full_property();
1410   prop.Property.PropertyName = property_name;
1411   prop.Property.NrTokens += 1;
1412   prop.u[0].Data = values[0];
1413
1414   advance = tgsi_build_full_property(
1415      &prop,
1416      ctx->tokens_cur,
1417      ctx->header,
1418      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1419   if (advance == 0)
1420      return FALSE;
1421   ctx->tokens_cur += advance;
1422
1423   return TRUE;
1424}
1425
1426
1427static boolean translate( struct translate_ctx *ctx )
1428{
1429   eat_opt_white( &ctx->cur );
1430   if (!parse_header( ctx ))
1431      return FALSE;
1432
1433   while (*ctx->cur != '\0') {
1434      uint label_val = 0;
1435      if (!eat_white( &ctx->cur )) {
1436         report_error( ctx, "Syntax error" );
1437         return FALSE;
1438      }
1439
1440      if (*ctx->cur == '\0')
1441         break;
1442      if (parse_label( ctx, &label_val )) {
1443         if (!parse_instruction( ctx, TRUE ))
1444            return FALSE;
1445      }
1446      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1447         if (!parse_declaration( ctx ))
1448            return FALSE;
1449      }
1450      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1451         if (!parse_immediate( ctx ))
1452            return FALSE;
1453      }
1454      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1455         if (!parse_property( ctx ))
1456            return FALSE;
1457      }
1458      else if (!parse_instruction( ctx, FALSE )) {
1459         return FALSE;
1460      }
1461   }
1462
1463   return TRUE;
1464}
1465
1466boolean
1467tgsi_text_translate(
1468   const char *text,
1469   struct tgsi_token *tokens,
1470   uint num_tokens )
1471{
1472   struct translate_ctx ctx;
1473
1474   ctx.text = text;
1475   ctx.cur = text;
1476   ctx.tokens = tokens;
1477   ctx.tokens_cur = tokens;
1478   ctx.tokens_end = tokens + num_tokens;
1479
1480   if (!translate( &ctx ))
1481      return FALSE;
1482
1483   return tgsi_sanity_check( tokens );
1484}
1485