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