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