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