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