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