a4320128c115f88e4531bef0221a3531ce744166
[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_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 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
261 static 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
276 static boolean
277 parse_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
295 static boolean
296 parse_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 */
341 static boolean
342 parse_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 */
361 static boolean
362 parse_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 */
383 static boolean
384 parse_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
399 struct parsed_bracket {
400 int index;
401
402 uint ind_file;
403 int ind_index;
404 uint ind_comp;
405 };
406
407
408 static boolean
409 parse_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
489 static boolean
490 parse_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 */
520 static boolean
521 parse_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
535 struct parsed_dcl_bracket {
536 uint first;
537 uint last;
538 };
539
540 static boolean
541 parse_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
581 cleanup:
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 */
594 static boolean
595 parse_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.*/
638 static boolean
639 parse_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
653 static boolean
654 parse_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
697 static boolean
698 parse_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
734 static boolean
735 parse_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
805 static boolean
806 match_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
815 static boolean
816 parse_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 const char *cur;
825 uint advance;
826
827 inst = tgsi_default_full_instruction();
828
829 /* Parse predicate.
830 */
831 eat_opt_white( &ctx->cur );
832 if (*ctx->cur == '(') {
833 uint file;
834 int index;
835 uint swizzle[4];
836 boolean parsed_swizzle;
837
838 inst.Instruction.Predicate = 1;
839
840 ctx->cur++;
841 if (*ctx->cur == '!') {
842 ctx->cur++;
843 inst.Predicate.Negate = 1;
844 }
845
846 if (!parse_register_1d( ctx, &file, &index ))
847 return FALSE;
848
849 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) {
850 if (parsed_swizzle) {
851 inst.Predicate.SwizzleX = swizzle[0];
852 inst.Predicate.SwizzleY = swizzle[1];
853 inst.Predicate.SwizzleZ = swizzle[2];
854 inst.Predicate.SwizzleW = swizzle[3];
855 }
856 }
857
858 if (*ctx->cur != ')') {
859 report_error( ctx, "Expected `)'" );
860 return FALSE;
861 }
862
863 ctx->cur++;
864 }
865
866 /* Parse instruction name.
867 */
868 eat_opt_white( &ctx->cur );
869 for (i = 0; i < TGSI_OPCODE_LAST; i++) {
870 cur = ctx->cur;
871
872 info = tgsi_get_opcode_info( i );
873 if (match_inst_mnemonic(&cur, info)) {
874 if (str_match_no_case( &cur, "_SATNV" ))
875 saturate = TGSI_SAT_MINUS_PLUS_ONE;
876 else if (str_match_no_case( &cur, "_SAT" ))
877 saturate = TGSI_SAT_ZERO_ONE;
878
879 if (info->num_dst + info->num_src + info->is_tex == 0) {
880 if (!is_digit_alpha_underscore( cur )) {
881 ctx->cur = cur;
882 break;
883 }
884 }
885 else if (*cur == '\0' || eat_white( &cur )) {
886 ctx->cur = cur;
887 break;
888 }
889 }
890 }
891 if (i == TGSI_OPCODE_LAST) {
892 if (has_label)
893 report_error( ctx, "Unknown opcode" );
894 else
895 report_error( ctx, "Expected `DCL', `IMM' or a label" );
896 return FALSE;
897 }
898
899 inst.Instruction.Opcode = i;
900 inst.Instruction.Saturate = saturate;
901 inst.Instruction.NumDstRegs = info->num_dst;
902 inst.Instruction.NumSrcRegs = info->num_src;
903
904 /* Parse instruction operands.
905 */
906 for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) {
907 if (i > 0) {
908 eat_opt_white( &ctx->cur );
909 if (*ctx->cur != ',') {
910 report_error( ctx, "Expected `,'" );
911 return FALSE;
912 }
913 ctx->cur++;
914 eat_opt_white( &ctx->cur );
915 }
916
917 if (i < info->num_dst) {
918 if (!parse_dst_operand( ctx, &inst.Dst[i] ))
919 return FALSE;
920 }
921 else if (i < info->num_dst + info->num_src) {
922 if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] ))
923 return FALSE;
924 }
925 else {
926 uint j;
927
928 for (j = 0; j < TGSI_TEXTURE_COUNT; j++) {
929 if (str_match_no_case( &ctx->cur, tgsi_texture_names[j] )) {
930 if (!is_digit_alpha_underscore( ctx->cur )) {
931 inst.Instruction.Texture = 1;
932 inst.Texture.Texture = j;
933 break;
934 }
935 }
936 }
937 if (j == TGSI_TEXTURE_COUNT) {
938 report_error( ctx, "Expected texture target" );
939 return FALSE;
940 }
941 }
942 }
943
944 cur = ctx->cur;
945 eat_opt_white( &cur );
946 if (info->is_branch && *cur == ':') {
947 uint target;
948
949 cur++;
950 eat_opt_white( &cur );
951 if (!parse_uint( &cur, &target )) {
952 report_error( ctx, "Expected a label" );
953 return FALSE;
954 }
955 inst.Instruction.Label = 1;
956 inst.Label.Label = target;
957 ctx->cur = cur;
958 }
959
960 advance = tgsi_build_full_instruction(
961 &inst,
962 ctx->tokens_cur,
963 ctx->header,
964 (uint) (ctx->tokens_end - ctx->tokens_cur) );
965 if (advance == 0)
966 return FALSE;
967 ctx->tokens_cur += advance;
968
969 return TRUE;
970 }
971
972 /* parses a 4-touple of the form {x, y, z, w}
973 * where x, y, z, w are numbers */
974 static boolean parse_immediate_data(struct translate_ctx *ctx,
975 float *values)
976 {
977 unsigned i;
978
979 eat_opt_white( &ctx->cur );
980 if (*ctx->cur != '{') {
981 report_error( ctx, "Expected `{'" );
982 return FALSE;
983 }
984 ctx->cur++;
985 for (i = 0; i < 4; i++) {
986 eat_opt_white( &ctx->cur );
987 if (i > 0) {
988 if (*ctx->cur != ',') {
989 report_error( ctx, "Expected `,'" );
990 return FALSE;
991 }
992 ctx->cur++;
993 eat_opt_white( &ctx->cur );
994 }
995 if (!parse_float( &ctx->cur, &values[i] )) {
996 report_error( ctx, "Expected literal floating point" );
997 return FALSE;
998 }
999 }
1000 eat_opt_white( &ctx->cur );
1001 if (*ctx->cur != '}') {
1002 report_error( ctx, "Expected `}'" );
1003 return FALSE;
1004 }
1005 ctx->cur++;
1006
1007 return TRUE;
1008 }
1009
1010 static boolean parse_declaration( struct translate_ctx *ctx )
1011 {
1012 struct tgsi_full_declaration decl;
1013 uint file;
1014 struct parsed_dcl_bracket brackets[2];
1015 int num_brackets;
1016 uint writemask;
1017 const char *cur, *cur2;
1018 uint advance;
1019 boolean is_vs_input;
1020 boolean is_imm_array;
1021
1022 if (!eat_white( &ctx->cur )) {
1023 report_error( ctx, "Syntax error" );
1024 return FALSE;
1025 }
1026 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets))
1027 return FALSE;
1028 if (!parse_opt_writemask( ctx, &writemask ))
1029 return FALSE;
1030
1031 decl = tgsi_default_full_declaration();
1032 decl.Declaration.File = file;
1033 decl.Declaration.UsageMask = writemask;
1034
1035 if (num_brackets == 1) {
1036 decl.Range.First = brackets[0].first;
1037 decl.Range.Last = brackets[0].last;
1038 } else {
1039 decl.Range.First = brackets[1].first;
1040 decl.Range.Last = brackets[1].last;
1041
1042 decl.Declaration.Dimension = 1;
1043 decl.Dim.Index2D = brackets[0].first;
1044 }
1045
1046 is_vs_input = (file == TGSI_FILE_INPUT &&
1047 ctx->processor == TGSI_PROCESSOR_VERTEX);
1048 is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY);
1049
1050 cur = ctx->cur;
1051 eat_opt_white( &cur );
1052 if (*cur == ',' && !is_vs_input) {
1053 uint i, j;
1054
1055 cur++;
1056 eat_opt_white( &cur );
1057 if (file == TGSI_FILE_RESOURCE) {
1058 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1059 if (str_match_no_case(&cur, tgsi_texture_names[i])) {
1060 if (!is_digit_alpha_underscore(cur)) {
1061 decl.Resource.Resource = i;
1062 break;
1063 }
1064 }
1065 }
1066 if (i == TGSI_TEXTURE_COUNT) {
1067 report_error(ctx, "Expected texture target");
1068 return FALSE;
1069 }
1070
1071 cur2 = cur;
1072 eat_opt_white(&cur2);
1073 while (*cur2 == ',') {
1074 cur2++;
1075 eat_opt_white(&cur2);
1076 if (str_match_no_case(&cur2, "RAW") &&
1077 !is_digit_alpha_underscore(cur2)) {
1078 decl.Resource.Raw = 1;
1079
1080 } else if (str_match_no_case(&cur2, "WR") &&
1081 !is_digit_alpha_underscore(cur2)) {
1082 decl.Resource.Writable = 1;
1083
1084 } else {
1085 break;
1086 }
1087 cur = cur2;
1088 eat_opt_white(&cur2);
1089 }
1090
1091 ctx->cur = cur;
1092
1093 } else if (file == TGSI_FILE_SAMPLER_VIEW) {
1094 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) {
1095 if (str_match_no_case(&cur, tgsi_texture_names[i])) {
1096 if (!is_digit_alpha_underscore(cur)) {
1097 decl.SamplerView.Resource = i;
1098 break;
1099 }
1100 }
1101 }
1102 if (i == TGSI_TEXTURE_COUNT) {
1103 report_error(ctx, "Expected texture target");
1104 return FALSE;
1105 }
1106 eat_opt_white( &cur );
1107 if (*cur != ',') {
1108 report_error( ctx, "Expected `,'" );
1109 return FALSE;
1110 }
1111 ++cur;
1112 eat_opt_white( &cur );
1113 for (j = 0; j < 4; ++j) {
1114 for (i = 0; i < PIPE_TYPE_COUNT; ++i) {
1115 if (str_match_no_case(&cur, tgsi_type_names[i])) {
1116 if (!is_digit_alpha_underscore(cur)) {
1117 switch (j) {
1118 case 0:
1119 decl.SamplerView.ReturnTypeX = i;
1120 break;
1121 case 1:
1122 decl.SamplerView.ReturnTypeY = i;
1123 break;
1124 case 2:
1125 decl.SamplerView.ReturnTypeZ = i;
1126 break;
1127 case 3:
1128 decl.SamplerView.ReturnTypeW = i;
1129 break;
1130 default:
1131 assert(0);
1132 }
1133 break;
1134 }
1135 }
1136 }
1137 if (i == PIPE_TYPE_COUNT) {
1138 if (j == 0 || j > 2) {
1139 report_error(ctx, "Expected type name");
1140 return FALSE;
1141 }
1142 break;
1143 } else {
1144 cur2 = cur;
1145 eat_opt_white( &cur2 );
1146 if (*cur2 == ',') {
1147 cur2++;
1148 eat_opt_white( &cur2 );
1149 cur = cur2;
1150 continue;
1151 } else
1152 break;
1153 }
1154 }
1155 if (j < 4) {
1156 decl.SamplerView.ReturnTypeY =
1157 decl.SamplerView.ReturnTypeZ =
1158 decl.SamplerView.ReturnTypeW =
1159 decl.SamplerView.ReturnTypeX;
1160 }
1161 ctx->cur = cur;
1162 } else {
1163 if (str_match_no_case(&cur, "LOCAL") &&
1164 !is_digit_alpha_underscore(cur)) {
1165 decl.Declaration.Local = 1;
1166 ctx->cur = cur;
1167 }
1168
1169 cur = ctx->cur;
1170 eat_opt_white( &cur );
1171 if (*cur == ',') {
1172 cur++;
1173 eat_opt_white( &cur );
1174
1175 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) {
1176 if (str_match_no_case( &cur, tgsi_semantic_names[i] )) {
1177 uint index;
1178
1179 if (is_digit_alpha_underscore( cur ))
1180 continue;
1181 cur2 = cur;
1182 eat_opt_white( &cur2 );
1183 if (*cur2 == '[') {
1184 cur2++;
1185 eat_opt_white( &cur2 );
1186 if (!parse_uint( &cur2, &index )) {
1187 report_error( ctx, "Expected literal integer" );
1188 return FALSE;
1189 }
1190 eat_opt_white( &cur2 );
1191 if (*cur2 != ']') {
1192 report_error( ctx, "Expected `]'" );
1193 return FALSE;
1194 }
1195 cur2++;
1196
1197 decl.Semantic.Index = index;
1198
1199 cur = cur2;
1200 }
1201
1202 decl.Declaration.Semantic = 1;
1203 decl.Semantic.Name = i;
1204
1205 ctx->cur = cur;
1206 break;
1207 }
1208 }
1209 }
1210 }
1211 } else if (is_imm_array) {
1212 unsigned i;
1213 float *vals_itr;
1214 /* we have our immediate data */
1215 if (*cur != '{') {
1216 report_error( ctx, "Immediate array without data" );
1217 return FALSE;
1218 }
1219 ++cur;
1220 ctx->cur = cur;
1221
1222 decl.ImmediateData.u =
1223 MALLOC(sizeof(union tgsi_immediate_data) * 4 *
1224 (decl.Range.Last + 1));
1225 vals_itr = (float*)decl.ImmediateData.u;
1226 for (i = 0; i <= decl.Range.Last; ++i) {
1227 if (!parse_immediate_data(ctx, vals_itr)) {
1228 FREE(decl.ImmediateData.u);
1229 return FALSE;
1230 }
1231 vals_itr += 4;
1232 eat_opt_white( &ctx->cur );
1233 if (*ctx->cur != ',') {
1234 if (i != decl.Range.Last) {
1235 report_error( ctx, "Not enough data in immediate array!" );
1236 FREE(decl.ImmediateData.u);
1237 return FALSE;
1238 }
1239 } else
1240 ++ctx->cur;
1241 }
1242 eat_opt_white( &ctx->cur );
1243 if (*ctx->cur != '}') {
1244 FREE(decl.ImmediateData.u);
1245 report_error( ctx, "Immediate array data missing closing '}'" );
1246 return FALSE;
1247 }
1248 ++ctx->cur;
1249 }
1250
1251 cur = ctx->cur;
1252 eat_opt_white( &cur );
1253 if (*cur == ',' && !is_vs_input) {
1254 uint i;
1255
1256 cur++;
1257 eat_opt_white( &cur );
1258 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) {
1259 if (str_match_no_case( &cur, tgsi_interpolate_names[i] )) {
1260 if (is_digit_alpha_underscore( cur ))
1261 continue;
1262 decl.Declaration.Interpolate = 1;
1263 decl.Interp.Interpolate = i;
1264
1265 ctx->cur = cur;
1266 break;
1267 }
1268 }
1269 if (i == TGSI_INTERPOLATE_COUNT) {
1270 report_error( ctx, "Expected semantic or interpolate attribute" );
1271 return FALSE;
1272 }
1273 }
1274
1275 advance = tgsi_build_full_declaration(
1276 &decl,
1277 ctx->tokens_cur,
1278 ctx->header,
1279 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1280
1281 if (is_imm_array)
1282 FREE(decl.ImmediateData.u);
1283
1284 if (advance == 0)
1285 return FALSE;
1286 ctx->tokens_cur += advance;
1287
1288 return TRUE;
1289 }
1290
1291 static boolean parse_immediate( struct translate_ctx *ctx )
1292 {
1293 struct tgsi_full_immediate imm;
1294 float values[4];
1295 uint advance;
1296
1297 if (!eat_white( &ctx->cur )) {
1298 report_error( ctx, "Syntax error" );
1299 return FALSE;
1300 }
1301 if (!str_match_no_case( &ctx->cur, "FLT32" ) ||
1302 is_digit_alpha_underscore( ctx->cur )) {
1303 report_error( ctx, "Expected `FLT32'" );
1304 return FALSE;
1305 }
1306
1307 parse_immediate_data(ctx, values);
1308
1309 imm = tgsi_default_full_immediate();
1310 imm.Immediate.NrTokens += 4;
1311 imm.Immediate.DataType = TGSI_IMM_FLOAT32;
1312 imm.u[0].Float = values[0];
1313 imm.u[1].Float = values[1];
1314 imm.u[2].Float = values[2];
1315 imm.u[3].Float = values[3];
1316
1317 advance = tgsi_build_full_immediate(
1318 &imm,
1319 ctx->tokens_cur,
1320 ctx->header,
1321 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1322 if (advance == 0)
1323 return FALSE;
1324 ctx->tokens_cur += advance;
1325
1326 return TRUE;
1327 }
1328
1329 static boolean
1330 parse_primitive( const char **pcur, uint *primitive )
1331 {
1332 uint i;
1333
1334 for (i = 0; i < PIPE_PRIM_MAX; i++) {
1335 const char *cur = *pcur;
1336
1337 if (str_match_no_case( &cur, tgsi_primitive_names[i])) {
1338 *primitive = i;
1339 *pcur = cur;
1340 return TRUE;
1341 }
1342 }
1343 return FALSE;
1344 }
1345
1346 static boolean
1347 parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin )
1348 {
1349 uint i;
1350
1351 for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) {
1352 const char *cur = *pcur;
1353
1354 if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) {
1355 *fs_coord_origin = i;
1356 *pcur = cur;
1357 return TRUE;
1358 }
1359 }
1360 return FALSE;
1361 }
1362
1363 static boolean
1364 parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center )
1365 {
1366 uint i;
1367
1368 for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) {
1369 const char *cur = *pcur;
1370
1371 if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) {
1372 *fs_coord_pixel_center = i;
1373 *pcur = cur;
1374 return TRUE;
1375 }
1376 }
1377 return FALSE;
1378 }
1379
1380
1381 static boolean parse_property( struct translate_ctx *ctx )
1382 {
1383 struct tgsi_full_property prop;
1384 uint property_name;
1385 uint values[8];
1386 uint advance;
1387 char id[64];
1388
1389 if (!eat_white( &ctx->cur )) {
1390 report_error( ctx, "Syntax error" );
1391 return FALSE;
1392 }
1393 if (!parse_identifier( &ctx->cur, id )) {
1394 report_error( ctx, "Syntax error" );
1395 return FALSE;
1396 }
1397 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT;
1398 ++property_name) {
1399 if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) {
1400 break;
1401 }
1402 }
1403 if (property_name >= TGSI_PROPERTY_COUNT) {
1404 debug_printf( "\nError: Unknown property : '%s'", id );
1405 return FALSE;
1406 }
1407
1408 eat_opt_white( &ctx->cur );
1409 switch(property_name) {
1410 case TGSI_PROPERTY_GS_INPUT_PRIM:
1411 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
1412 if (!parse_primitive(&ctx->cur, &values[0] )) {
1413 report_error( ctx, "Unknown primitive name as property!" );
1414 return FALSE;
1415 }
1416 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM &&
1417 ctx->processor == TGSI_PROCESSOR_GEOMETRY) {
1418 ctx->implied_array_size = u_vertices_per_prim(values[0]);
1419 }
1420 break;
1421 case TGSI_PROPERTY_FS_COORD_ORIGIN:
1422 if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) {
1423 report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1424 return FALSE;
1425 }
1426 break;
1427 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
1428 if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) {
1429 report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1430 return FALSE;
1431 }
1432 break;
1433 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
1434 default:
1435 if (!parse_uint(&ctx->cur, &values[0] )) {
1436 report_error( ctx, "Expected unsigned integer as property!" );
1437 return FALSE;
1438 }
1439 }
1440
1441 prop = tgsi_default_full_property();
1442 prop.Property.PropertyName = property_name;
1443 prop.Property.NrTokens += 1;
1444 prop.u[0].Data = values[0];
1445
1446 advance = tgsi_build_full_property(
1447 &prop,
1448 ctx->tokens_cur,
1449 ctx->header,
1450 (uint) (ctx->tokens_end - ctx->tokens_cur) );
1451 if (advance == 0)
1452 return FALSE;
1453 ctx->tokens_cur += advance;
1454
1455 return TRUE;
1456 }
1457
1458
1459 static boolean translate( struct translate_ctx *ctx )
1460 {
1461 eat_opt_white( &ctx->cur );
1462 if (!parse_header( ctx ))
1463 return FALSE;
1464
1465 while (*ctx->cur != '\0') {
1466 uint label_val = 0;
1467 if (!eat_white( &ctx->cur )) {
1468 report_error( ctx, "Syntax error" );
1469 return FALSE;
1470 }
1471
1472 if (*ctx->cur == '\0')
1473 break;
1474 if (parse_label( ctx, &label_val )) {
1475 if (!parse_instruction( ctx, TRUE ))
1476 return FALSE;
1477 }
1478 else if (str_match_no_case( &ctx->cur, "DCL" )) {
1479 if (!parse_declaration( ctx ))
1480 return FALSE;
1481 }
1482 else if (str_match_no_case( &ctx->cur, "IMM" )) {
1483 if (!parse_immediate( ctx ))
1484 return FALSE;
1485 }
1486 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) {
1487 if (!parse_property( ctx ))
1488 return FALSE;
1489 }
1490 else if (!parse_instruction( ctx, FALSE )) {
1491 return FALSE;
1492 }
1493 }
1494
1495 return TRUE;
1496 }
1497
1498 boolean
1499 tgsi_text_translate(
1500 const char *text,
1501 struct tgsi_token *tokens,
1502 uint num_tokens )
1503 {
1504 struct translate_ctx ctx;
1505
1506 ctx.text = text;
1507 ctx.cur = text;
1508 ctx.tokens = tokens;
1509 ctx.tokens_cur = tokens;
1510 ctx.tokens_end = tokens + num_tokens;
1511
1512 if (!translate( &ctx ))
1513 return FALSE;
1514
1515 return tgsi_sanity_check( tokens );
1516 }