tgsi_text.c revision a426b0d5bce24659a19c72af27a5aa4871782f9d
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   const char *cur;
825   uint advance;
826
827   inst = tgsi_default_full_instruction();
828
829   /* Parse predicate.
830    */
831   eat_opt_white( &ctx->cur );
832   if (*ctx->cur == '(') {
833      uint file;
834      int index;
835      uint swizzle[4];
836      boolean parsed_swizzle;
837
838      inst.Instruction.Predicate = 1;
839
840      ctx->cur++;
841      if (*ctx->cur == '!') {
842         ctx->cur++;
843         inst.Predicate.Negate = 1;
844      }
845
846      if (!parse_register_1d( ctx, &file, &index ))
847         return FALSE;
848
849      if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
850         if (parsed_swizzle) {
851            inst.Predicate.SwizzleX = swizzle[0];
852            inst.Predicate.SwizzleY = swizzle[1];
853            inst.Predicate.SwizzleZ = swizzle[2];
854            inst.Predicate.SwizzleW = swizzle[3];
855         }
856      }
857
858      if (*ctx->cur != ')') {
859         report_error( ctx, "Expected `)'" );
860         return FALSE;
861      }
862
863      ctx->cur++;
864   }
865
866   /* Parse instruction name.
867    */
868   eat_opt_white( &ctx->cur );
869   for (i = 0; i < TGSI_OPCODE_LAST; i++) {
870      cur = ctx->cur;
871
872      info = tgsi_get_opcode_info( i );
873      if (match_inst_mnemonic(&cur, info)) {
874         if (str_match_no_case( &cur, "_SATNV" ))
875            saturate = TGSI_SAT_MINUS_PLUS_ONE;
876         else if (str_match_no_case( &cur, "_SAT" ))
877            saturate = TGSI_SAT_ZERO_ONE;
878
879         if (info->num_dst + info->num_src + info->is_tex == 0) {
880            if (!is_digit_alpha_underscore( cur )) {
881               ctx->cur = cur;
882               break;
883            }
884         }
885         else if (*cur == '\0' || eat_white( &cur )) {
886            ctx->cur = cur;
887            break;
888         }
889      }
890   }
891   if (i == TGSI_OPCODE_LAST) {
892      if (has_label)
893         report_error( ctx, "Unknown opcode" );
894      else
895         report_error( ctx, "Expected `DCL', `IMM' or a label" );
896      return FALSE;
897   }
898
899   inst.Instruction.Opcode = i;
900   inst.Instruction.Saturate = saturate;
901   inst.Instruction.NumDstRegs = info->num_dst;
902   inst.Instruction.NumSrcRegs = info->num_src;
903
904   /* Parse instruction operands.
905    */
906   for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
907      if (i > 0) {
908         eat_opt_white( &ctx->cur );
909         if (*ctx->cur != ',') {
910            report_error( ctx, "Expected `,'" );
911            return FALSE;
912         }
913         ctx->cur++;
914         eat_opt_white( &ctx->cur );
915      }
916
917      if (i < info->num_dst) {
918         if (!parse_dst_operand( ctx, &inst.Dst[i] ))
919            return FALSE;
920      }
921      else if (i < info->num_dst + info->num_src) {
922         if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
923            return FALSE;
924      }
925      else {
926         uint j;
927
928         for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
929            if (str_match_no_case( &ctx->cur, tgsi_texture_names[j] )) {
930               if (!is_digit_alpha_underscore( ctx->cur )) {
931                  inst.Instruction.Texture = 1;
932                  inst.Texture.Texture = j;
933                  break;
934               }
935            }
936         }
937         if (j == TGSI_TEXTURE_COUNT) {
938            report_error( ctx, "Expected texture target" );
939            return FALSE;
940         }
941      }
942   }
943
944   cur = ctx->cur;
945   eat_opt_white( &cur );
946   if (info->is_branch && *cur == ':') {
947      uint target;
948
949      cur++;
950      eat_opt_white( &cur );
951      if (!parse_uint( &cur, &target )) {
952         report_error( ctx, "Expected a label" );
953         return FALSE;
954      }
955      inst.Instruction.Label = 1;
956      inst.Label.Label = target;
957      ctx->cur = cur;
958   }
959
960   advance = tgsi_build_full_instruction(
961      &inst,
962      ctx->tokens_cur,
963      ctx->header,
964      (uint) (ctx->tokens_end - ctx->tokens_cur) );
965   if (advance == 0)
966      return FALSE;
967   ctx->tokens_cur += advance;
968
969   return TRUE;
970}
971
972/* parses a 4-touple of the form {x, y, z, w}
973 * where x, y, z, w are numbers */
974static boolean parse_immediate_data(struct translate_ctx *ctx,
975                                    float *values)
976{
977   unsigned i;
978
979   eat_opt_white( &ctx->cur );
980   if (*ctx->cur != '{') {
981      report_error( ctx, "Expected `{'" );
982      return FALSE;
983   }
984   ctx->cur++;
985   for (i = 0; i < 4; i++) {
986      eat_opt_white( &ctx->cur );
987      if (i > 0) {
988         if (*ctx->cur != ',') {
989            report_error( ctx, "Expected `,'" );
990            return FALSE;
991         }
992         ctx->cur++;
993         eat_opt_white( &ctx->cur );
994      }
995      if (!parse_float( &ctx->cur, &values[i] )) {
996         report_error( ctx, "Expected literal floating point" );
997         return FALSE;
998      }
999   }
1000   eat_opt_white( &ctx->cur );
1001   if (*ctx->cur != '}') {
1002      report_error( ctx, "Expected `}'" );
1003      return FALSE;
1004   }
1005   ctx->cur++;
1006
1007   return TRUE;
1008}
1009
1010static boolean parse_declaration( struct translate_ctx *ctx )
1011{
1012   struct tgsi_full_declaration decl;
1013   uint file;
1014   struct parsed_dcl_bracket brackets[2];
1015   int num_brackets;
1016   uint writemask;
1017   const char *cur, *cur2;
1018   uint advance;
1019   boolean is_vs_input;
1020   boolean is_imm_array;
1021
1022   if (!eat_white( &ctx->cur )) {
1023      report_error( ctx, "Syntax error" );
1024      return FALSE;
1025   }
1026   if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1027      return FALSE;
1028   if (!parse_opt_writemask( ctx, &writemask ))
1029      return FALSE;
1030
1031   decl = tgsi_default_full_declaration();
1032   decl.Declaration.File = file;
1033   decl.Declaration.UsageMask = writemask;
1034
1035   if (num_brackets == 1) {
1036      decl.Range.First = brackets[0].first;
1037      decl.Range.Last = brackets[0].last;
1038   } else {
1039      decl.Range.First = brackets[1].first;
1040      decl.Range.Last = brackets[1].last;
1041
1042      decl.Declaration.Dimension = 1;
1043      decl.Dim.Index2D = brackets[0].first;
1044   }
1045
1046   is_vs_input = (file == TGSI_FILE_INPUT &&
1047                  ctx->processor == TGSI_PROCESSOR_VERTEX);
1048   is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
1049
1050   cur = ctx->cur;
1051   eat_opt_white( &cur );
1052   if (*cur == ',' && !is_vs_input) {
1053      uint i, j;
1054
1055      cur++;
1056      eat_opt_white( &cur );
1057      if (file == TGSI_FILE_RESOURCE) {
1058         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1059            if (str_match_no_case(&cur, tgsi_texture_names[i])) {
1060               if (!is_digit_alpha_underscore(cur)) {
1061                  decl.Resource.Resource = i;
1062                  break;
1063               }
1064            }
1065         }
1066         if (i == TGSI_TEXTURE_COUNT) {
1067            report_error(ctx, "Expected texture target");
1068            return FALSE;
1069         }
1070
1071         cur2 = cur;
1072         eat_opt_white(&cur2);
1073         while (*cur2 == ',') {
1074            cur2++;
1075            eat_opt_white(&cur2);
1076            if (str_match_no_case(&cur2, "RAW") &&
1077                !is_digit_alpha_underscore(cur2)) {
1078               decl.Resource.Raw = 1;
1079
1080            } else if (str_match_no_case(&cur2, "WR") &&
1081                !is_digit_alpha_underscore(cur2)) {
1082               decl.Resource.Writable = 1;
1083
1084            } else {
1085               break;
1086            }
1087            cur = cur2;
1088            eat_opt_white(&cur2);
1089         }
1090
1091         ctx->cur = cur;
1092
1093      } else if (file == TGSI_FILE_SAMPLER_VIEW) {
1094         for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1095            if (str_match_no_case(&cur, tgsi_texture_names[i])) {
1096               if (!is_digit_alpha_underscore(cur)) {
1097                  decl.SamplerView.Resource = i;
1098                  break;
1099               }
1100            }
1101         }
1102         if (i == TGSI_TEXTURE_COUNT) {
1103            report_error(ctx, "Expected texture target");
1104            return FALSE;
1105         }
1106         eat_opt_white( &cur );
1107         if (*cur != ',') {
1108            report_error( ctx, "Expected `,'" );
1109            return FALSE;
1110         }
1111         ++cur;
1112         eat_opt_white( &cur );
1113         for (j = 0; j < 4; ++j) {
1114            for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
1115               if (str_match_no_case(&cur, tgsi_type_names[i])) {
1116                  if (!is_digit_alpha_underscore(cur)) {
1117                     switch (j) {
1118                     case 0:
1119                        decl.SamplerView.ReturnTypeX = i;
1120                        break;
1121                     case 1:
1122                        decl.SamplerView.ReturnTypeY = i;
1123                        break;
1124                     case 2:
1125                        decl.SamplerView.ReturnTypeZ = i;
1126                        break;
1127                     case 3:
1128                        decl.SamplerView.ReturnTypeW = i;
1129                        break;
1130                     default:
1131                        assert(0);
1132                     }
1133                     break;
1134                  }
1135               }
1136            }
1137            if (i == PIPE_TYPE_COUNT) {
1138               if (j == 0 || j >  2) {
1139                  report_error(ctx, "Expected type name");
1140                  return FALSE;
1141               }
1142               break;
1143            } else {
1144               cur2 = cur;
1145               eat_opt_white( &cur2 );
1146               if (*cur2 == ',') {
1147                  cur2++;
1148                  eat_opt_white( &cur2 );
1149                  cur = cur2;
1150                  continue;
1151               } else
1152                  break;
1153            }
1154         }
1155         if (j < 4) {
1156            decl.SamplerView.ReturnTypeY =
1157               decl.SamplerView.ReturnTypeZ =
1158               decl.SamplerView.ReturnTypeW =
1159               decl.SamplerView.ReturnTypeX;
1160         }
1161         ctx->cur = cur;
1162      } else {
1163         if (str_match_no_case(&cur, "LOCAL") &&
1164             !is_digit_alpha_underscore(cur)) {
1165            decl.Declaration.Local = 1;
1166            ctx->cur = cur;
1167         }
1168
1169         cur = ctx->cur;
1170         eat_opt_white( &cur );
1171         if (*cur == ',') {
1172            cur++;
1173            eat_opt_white( &cur );
1174
1175            for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1176               if (str_match_no_case( &cur, tgsi_semantic_names[i] )) {
1177                  uint index;
1178
1179                  if (is_digit_alpha_underscore( cur ))
1180                     continue;
1181                  cur2 = cur;
1182                  eat_opt_white( &cur2 );
1183                  if (*cur2 == '[') {
1184                     cur2++;
1185                     eat_opt_white( &cur2 );
1186                     if (!parse_uint( &cur2, &index )) {
1187                        report_error( ctx, "Expected literal integer" );
1188                        return FALSE;
1189                     }
1190                     eat_opt_white( &cur2 );
1191                     if (*cur2 != ']') {
1192                        report_error( ctx, "Expected `]'" );
1193                        return FALSE;
1194                     }
1195                     cur2++;
1196
1197                     decl.Semantic.Index = index;
1198
1199                     cur = cur2;
1200                  }
1201
1202                  decl.Declaration.Semantic = 1;
1203                  decl.Semantic.Name = i;
1204
1205                  ctx->cur = cur;
1206                  break;
1207               }
1208            }
1209         }
1210      }
1211   } else if (is_imm_array) {
1212      unsigned i;
1213      float *vals_itr;
1214      /* we have our immediate data */
1215      if (*cur != '{') {
1216         report_error( ctx, "Immediate array without data" );
1217         return FALSE;
1218      }
1219      ++cur;
1220      ctx->cur = cur;
1221
1222      decl.ImmediateData.u =
1223         MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1224                (decl.Range.Last + 1));
1225      vals_itr = (float*)decl.ImmediateData.u;
1226      for (i = 0; i <= decl.Range.Last; ++i) {
1227         if (!parse_immediate_data(ctx, vals_itr)) {
1228            FREE(decl.ImmediateData.u);
1229            return FALSE;
1230         }
1231         vals_itr += 4;
1232         eat_opt_white( &ctx->cur );
1233         if (*ctx->cur != ',') {
1234            if (i !=  decl.Range.Last) {
1235               report_error( ctx, "Not enough data in immediate array!" );
1236               FREE(decl.ImmediateData.u);
1237               return FALSE;
1238            }
1239         } else
1240            ++ctx->cur;
1241      }
1242      eat_opt_white( &ctx->cur );
1243      if (*ctx->cur != '}') {
1244         FREE(decl.ImmediateData.u);
1245         report_error( ctx, "Immediate array data missing closing '}'" );
1246         return FALSE;
1247      }
1248      ++ctx->cur;
1249   }
1250
1251   cur = ctx->cur;
1252   eat_opt_white( &cur );
1253   if (*cur == ',' && !is_vs_input) {
1254      uint i;
1255
1256      cur++;
1257      eat_opt_white( &cur );
1258      for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1259         if (str_match_no_case( &cur, tgsi_interpolate_names[i] )) {
1260            if (is_digit_alpha_underscore( cur ))
1261               continue;
1262            decl.Declaration.Interpolate = 1;
1263            decl.Interp.Interpolate = i;
1264
1265            ctx->cur = cur;
1266            break;
1267         }
1268      }
1269      if (i == TGSI_INTERPOLATE_COUNT) {
1270         report_error( ctx, "Expected semantic or interpolate attribute" );
1271         return FALSE;
1272      }
1273   }
1274
1275   advance = tgsi_build_full_declaration(
1276      &decl,
1277      ctx->tokens_cur,
1278      ctx->header,
1279      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1280
1281   if (is_imm_array)
1282      FREE(decl.ImmediateData.u);
1283
1284   if (advance == 0)
1285      return FALSE;
1286   ctx->tokens_cur += advance;
1287
1288   return TRUE;
1289}
1290
1291static boolean parse_immediate( struct translate_ctx *ctx )
1292{
1293   struct tgsi_full_immediate imm;
1294   float values[4];
1295   uint advance;
1296
1297   if (!eat_white( &ctx->cur )) {
1298      report_error( ctx, "Syntax error" );
1299      return FALSE;
1300   }
1301   if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1302       is_digit_alpha_underscore( ctx->cur )) {
1303      report_error( ctx, "Expected `FLT32'" );
1304      return FALSE;
1305   }
1306
1307   parse_immediate_data(ctx, values);
1308
1309   imm = tgsi_default_full_immediate();
1310   imm.Immediate.NrTokens += 4;
1311   imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1312   imm.u[0].Float = values[0];
1313   imm.u[1].Float = values[1];
1314   imm.u[2].Float = values[2];
1315   imm.u[3].Float = values[3];
1316
1317   advance = tgsi_build_full_immediate(
1318      &imm,
1319      ctx->tokens_cur,
1320      ctx->header,
1321      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1322   if (advance == 0)
1323      return FALSE;
1324   ctx->tokens_cur += advance;
1325
1326   return TRUE;
1327}
1328
1329static boolean
1330parse_primitive( const char **pcur, uint *primitive )
1331{
1332   uint i;
1333
1334   for (i = 0; i < PIPE_PRIM_MAX; i++) {
1335      const char *cur = *pcur;
1336
1337      if (str_match_no_case( &cur, tgsi_primitive_names[i])) {
1338         *primitive = i;
1339         *pcur = cur;
1340         return TRUE;
1341      }
1342   }
1343   return FALSE;
1344}
1345
1346static boolean
1347parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1348{
1349   uint i;
1350
1351   for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1352      const char *cur = *pcur;
1353
1354      if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) {
1355         *fs_coord_origin = i;
1356         *pcur = cur;
1357         return TRUE;
1358      }
1359   }
1360   return FALSE;
1361}
1362
1363static boolean
1364parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1365{
1366   uint i;
1367
1368   for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1369      const char *cur = *pcur;
1370
1371      if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1372         *fs_coord_pixel_center = i;
1373         *pcur = cur;
1374         return TRUE;
1375      }
1376   }
1377   return FALSE;
1378}
1379
1380
1381static boolean parse_property( struct translate_ctx *ctx )
1382{
1383   struct tgsi_full_property prop;
1384   uint property_name;
1385   uint values[8];
1386   uint advance;
1387   char id[64];
1388
1389   if (!eat_white( &ctx->cur )) {
1390      report_error( ctx, "Syntax error" );
1391      return FALSE;
1392   }
1393   if (!parse_identifier( &ctx->cur, id )) {
1394      report_error( ctx, "Syntax error" );
1395      return FALSE;
1396   }
1397   for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1398        ++property_name) {
1399      if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1400         break;
1401      }
1402   }
1403   if (property_name >= TGSI_PROPERTY_COUNT) {
1404      debug_printf( "\nError: Unknown property : '%s'", id );
1405      return FALSE;
1406   }
1407
1408   eat_opt_white( &ctx->cur );
1409   switch(property_name) {
1410   case TGSI_PROPERTY_GS_INPUT_PRIM:
1411   case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1412      if (!parse_primitive(&ctx->cur, &values[0] )) {
1413         report_error( ctx, "Unknown primitive name as property!" );
1414         return FALSE;
1415      }
1416      if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1417          ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1418         ctx->implied_array_size = u_vertices_per_prim(values[0]);
1419      }
1420      break;
1421   case TGSI_PROPERTY_FS_COORD_ORIGIN:
1422      if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1423         report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1424         return FALSE;
1425      }
1426      break;
1427   case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1428      if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1429         report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1430         return FALSE;
1431      }
1432      break;
1433   case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1434   default:
1435      if (!parse_uint(&ctx->cur, &values[0] )) {
1436         report_error( ctx, "Expected unsigned integer as property!" );
1437         return FALSE;
1438      }
1439   }
1440
1441   prop = tgsi_default_full_property();
1442   prop.Property.PropertyName = property_name;
1443   prop.Property.NrTokens += 1;
1444   prop.u[0].Data = values[0];
1445
1446   advance = tgsi_build_full_property(
1447      &prop,
1448      ctx->tokens_cur,
1449      ctx->header,
1450      (uint) (ctx->tokens_end - ctx->tokens_cur) );
1451   if (advance == 0)
1452      return FALSE;
1453   ctx->tokens_cur += advance;
1454
1455   return TRUE;
1456}
1457
1458
1459static boolean translate( struct translate_ctx *ctx )
1460{
1461   eat_opt_white( &ctx->cur );
1462   if (!parse_header( ctx ))
1463      return FALSE;
1464
1465   while (*ctx->cur != '\0') {
1466      uint label_val = 0;
1467      if (!eat_white( &ctx->cur )) {
1468         report_error( ctx, "Syntax error" );
1469         return FALSE;
1470      }
1471
1472      if (*ctx->cur == '\0')
1473         break;
1474      if (parse_label( ctx, &label_val )) {
1475         if (!parse_instruction( ctx, TRUE ))
1476            return FALSE;
1477      }
1478      else if (str_match_no_case( &ctx->cur, "DCL" )) {
1479         if (!parse_declaration( ctx ))
1480            return FALSE;
1481      }
1482      else if (str_match_no_case( &ctx->cur, "IMM" )) {
1483         if (!parse_immediate( ctx ))
1484            return FALSE;
1485      }
1486      else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1487         if (!parse_property( ctx ))
1488            return FALSE;
1489      }
1490      else if (!parse_instruction( ctx, FALSE )) {
1491         return FALSE;
1492      }
1493   }
1494
1495   return TRUE;
1496}
1497
1498boolean
1499tgsi_text_translate(
1500   const char *text,
1501   struct tgsi_token *tokens,
1502   uint num_tokens )
1503{
1504   struct translate_ctx ctx;
1505
1506   ctx.text = text;
1507   ctx.cur = text;
1508   ctx.tokens = tokens;
1509   ctx.tokens_cur = tokens;
1510   ctx.tokens_end = tokens + num_tokens;
1511
1512   if (!translate( &ctx ))
1513      return FALSE;
1514
1515   return tgsi_sanity_check( tokens );
1516}
1517