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