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