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