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