1 /**************************************************************************
3 * Copyright 2008 VMware, Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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 VMWARE 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.
26 **************************************************************************/
28 #include "util/u_debug.h"
29 #include "util/u_memory.h"
30 #include "util/u_prim.h"
31 #include "pipe/p_defines.h"
32 #include "util/u_inlines.h"
33 #include "tgsi_text.h"
34 #include "tgsi_build.h"
35 #include "tgsi_info.h"
36 #include "tgsi_parse.h"
37 #include "tgsi_sanity.h"
38 #include "tgsi_strings.h"
39 #include "tgsi_util.h"
40 #include "tgsi_dump.h"
42 static boolean
is_alpha_underscore( const char *cur
)
45 (*cur
>= 'a' && *cur
<= 'z') ||
46 (*cur
>= 'A' && *cur
<= 'Z') ||
50 static boolean
is_digit( const char *cur
)
52 return *cur
>= '0' && *cur
<= '9';
55 static boolean
is_digit_alpha_underscore( const char *cur
)
57 return is_digit( cur
) || is_alpha_underscore( cur
);
60 static char uprcase( char c
)
62 if (c
>= 'a' && c
<= 'z')
68 * Ignore case of str1 and assume str1 is already uppercase.
69 * Return TRUE iff str1 and str2 are equal.
72 streq_nocase_uprcase(const char *str1
,
75 while (*str1
&& *str2
) {
76 if (*str1
!= uprcase(*str2
))
81 return *str1
== 0 && *str2
== 0;
84 /* Return TRUE if both strings match.
85 * The second string is terminated by zero.
86 * The pointer to the first string is moved at end of the read word
89 static boolean
str_match_no_case( const char **pcur
, const char *str
)
91 const char *cur
= *pcur
;
93 while (*str
!= '\0' && *str
== uprcase( *cur
)) {
104 /* Return TRUE if both strings match.
105 * The first string is be terminated by a non-digit non-letter non-underscore
106 * character, the second string is terminated by zero.
107 * The pointer to the first string is moved at end of the read word
110 static boolean
str_match_nocase_whole( const char **pcur
, const char *str
)
112 const char *cur
= *pcur
;
114 if (str_match_no_case(&cur
, str
) &&
115 !is_digit_alpha_underscore(cur
)) {
122 /* Eat zero or more whitespaces.
124 static void eat_opt_white( const char **pcur
)
126 while (**pcur
== ' ' || **pcur
== '\t' || **pcur
== '\n')
130 /* Eat one or more whitespaces.
131 * Return TRUE if at least one whitespace eaten.
133 static boolean
eat_white( const char **pcur
)
135 const char *cur
= *pcur
;
137 eat_opt_white( pcur
);
141 /* Parse unsigned integer.
142 * No checks for overflow.
144 static boolean
parse_uint( const char **pcur
, uint
*val
)
146 const char *cur
= *pcur
;
148 if (is_digit( cur
)) {
150 while (is_digit( cur
))
151 *val
= *val
* 10 + *cur
++ - '0';
158 static boolean
parse_int( const char **pcur
, int *val
)
160 const char *cur
= *pcur
;
161 int sign
= (*cur
== '-' ? -1 : 1);
163 if (*cur
== '+' || *cur
== '-')
166 if (parse_uint(&cur
, (uint
*)val
)) {
175 static boolean
parse_identifier( const char **pcur
, char *ret
)
177 const char *cur
= *pcur
;
179 if (is_alpha_underscore( cur
)) {
181 while (is_alpha_underscore( cur
) || is_digit( cur
))
190 /* Parse floating point.
192 static boolean
parse_float( const char **pcur
, float *val
)
194 const char *cur
= *pcur
;
195 boolean integral_part
= FALSE
;
196 boolean fractional_part
= FALSE
;
198 if (*cur
== '0' && *(cur
+ 1) == 'x') {
200 fi
.ui
= strtoul(cur
, NULL
, 16);
206 *val
= (float) atof( cur
);
207 if (*cur
== '-' || *cur
== '+')
209 if (is_digit( cur
)) {
211 integral_part
= TRUE
;
212 while (is_digit( cur
))
217 if (is_digit( cur
)) {
219 fractional_part
= TRUE
;
220 while (is_digit( cur
))
224 if (!integral_part
&& !fractional_part
)
226 if (uprcase( *cur
) == 'E') {
228 if (*cur
== '-' || *cur
== '+')
230 if (is_digit( cur
)) {
232 while (is_digit( cur
))
244 static boolean
parse_double( const char **pcur
, uint32_t *val0
, uint32_t *val1
)
246 const char *cur
= *pcur
;
252 v
.dval
= strtod(cur
, (char**)pcur
);
266 struct tgsi_token
*tokens
;
267 struct tgsi_token
*tokens_cur
;
268 struct tgsi_token
*tokens_end
;
269 struct tgsi_header
*header
;
270 unsigned processor
: 4;
271 unsigned implied_array_size
: 6;
272 unsigned num_immediates
;
275 static void report_error( struct translate_ctx
*ctx
, const char *msg
)
279 const char *itr
= ctx
->text
;
281 while (itr
!= ctx
->cur
) {
290 debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg
, line
, column
);
293 /* Parse shader header.
294 * Return TRUE for one of the following headers.
299 static boolean
parse_header( struct translate_ctx
*ctx
)
303 if (str_match_nocase_whole( &ctx
->cur
, "FRAG" ))
304 processor
= TGSI_PROCESSOR_FRAGMENT
;
305 else if (str_match_nocase_whole( &ctx
->cur
, "VERT" ))
306 processor
= TGSI_PROCESSOR_VERTEX
;
307 else if (str_match_nocase_whole( &ctx
->cur
, "GEOM" ))
308 processor
= TGSI_PROCESSOR_GEOMETRY
;
309 else if (str_match_nocase_whole( &ctx
->cur
, "TESS_CTRL" ))
310 processor
= TGSI_PROCESSOR_TESS_CTRL
;
311 else if (str_match_nocase_whole( &ctx
->cur
, "TESS_EVAL" ))
312 processor
= TGSI_PROCESSOR_TESS_EVAL
;
313 else if (str_match_nocase_whole( &ctx
->cur
, "COMP" ))
314 processor
= TGSI_PROCESSOR_COMPUTE
;
316 report_error( ctx
, "Unknown header" );
320 if (ctx
->tokens_cur
>= ctx
->tokens_end
)
322 ctx
->header
= (struct tgsi_header
*) ctx
->tokens_cur
++;
323 *ctx
->header
= tgsi_build_header();
325 if (ctx
->tokens_cur
>= ctx
->tokens_end
)
327 *(struct tgsi_processor
*) ctx
->tokens_cur
++ = tgsi_build_processor( processor
, ctx
->header
);
328 ctx
->processor
= processor
;
333 static boolean
parse_label( struct translate_ctx
*ctx
, uint
*val
)
335 const char *cur
= ctx
->cur
;
337 if (parse_uint( &cur
, val
)) {
338 eat_opt_white( &cur
);
349 parse_file( const char **pcur
, uint
*file
)
353 for (i
= 0; i
< TGSI_FILE_COUNT
; i
++) {
354 const char *cur
= *pcur
;
356 if (str_match_nocase_whole( &cur
, tgsi_file_name(i
) )) {
367 struct translate_ctx
*ctx
,
373 eat_opt_white( &cur
);
376 *writemask
= TGSI_WRITEMASK_NONE
;
377 eat_opt_white( &cur
);
378 if (uprcase( *cur
) == 'X') {
380 *writemask
|= TGSI_WRITEMASK_X
;
382 if (uprcase( *cur
) == 'Y') {
384 *writemask
|= TGSI_WRITEMASK_Y
;
386 if (uprcase( *cur
) == 'Z') {
388 *writemask
|= TGSI_WRITEMASK_Z
;
390 if (uprcase( *cur
) == 'W') {
392 *writemask
|= TGSI_WRITEMASK_W
;
395 if (*writemask
== TGSI_WRITEMASK_NONE
) {
396 report_error( ctx
, "Writemask expected" );
403 *writemask
= TGSI_WRITEMASK_XYZW
;
409 /* <register_file_bracket> ::= <file> `['
412 parse_register_file_bracket(
413 struct translate_ctx
*ctx
,
416 if (!parse_file( &ctx
->cur
, file
)) {
417 report_error( ctx
, "Unknown register file" );
420 eat_opt_white( &ctx
->cur
);
421 if (*ctx
->cur
!= '[') {
422 report_error( ctx
, "Expected `['" );
429 /* <register_file_bracket_index> ::= <register_file_bracket> <uint>
432 parse_register_file_bracket_index(
433 struct translate_ctx
*ctx
,
439 if (!parse_register_file_bracket( ctx
, file
))
441 eat_opt_white( &ctx
->cur
);
442 if (!parse_uint( &ctx
->cur
, &uindex
)) {
443 report_error( ctx
, "Expected literal unsigned integer" );
446 *index
= (int) uindex
;
450 /* Parse simple 1d register operand.
451 * <register_dst> ::= <register_file_bracket_index> `]'
454 parse_register_1d(struct translate_ctx
*ctx
,
458 if (!parse_register_file_bracket_index( ctx
, file
, index
))
460 eat_opt_white( &ctx
->cur
);
461 if (*ctx
->cur
!= ']') {
462 report_error( ctx
, "Expected `]'" );
469 struct parsed_bracket
{
480 parse_register_bracket(
481 struct translate_ctx
*ctx
,
482 struct parsed_bracket
*brackets
)
487 memset(brackets
, 0, sizeof(struct parsed_bracket
));
489 eat_opt_white( &ctx
->cur
);
492 if (parse_file( &cur
, &brackets
->ind_file
)) {
493 if (!parse_register_1d( ctx
, &brackets
->ind_file
,
494 &brackets
->ind_index
))
496 eat_opt_white( &ctx
->cur
);
498 if (*ctx
->cur
== '.') {
500 eat_opt_white(&ctx
->cur
);
502 switch (uprcase(*ctx
->cur
)) {
504 brackets
->ind_comp
= TGSI_SWIZZLE_X
;
507 brackets
->ind_comp
= TGSI_SWIZZLE_Y
;
510 brackets
->ind_comp
= TGSI_SWIZZLE_Z
;
513 brackets
->ind_comp
= TGSI_SWIZZLE_W
;
516 report_error(ctx
, "Expected indirect register swizzle component `x', `y', `z' or `w'");
520 eat_opt_white(&ctx
->cur
);
523 if (*ctx
->cur
== '+' || *ctx
->cur
== '-')
524 parse_int( &ctx
->cur
, &brackets
->index
);
529 if (!parse_uint( &ctx
->cur
, &uindex
)) {
530 report_error( ctx
, "Expected literal unsigned integer" );
533 brackets
->index
= (int) uindex
;
534 brackets
->ind_file
= TGSI_FILE_NULL
;
535 brackets
->ind_index
= 0;
537 eat_opt_white( &ctx
->cur
);
538 if (*ctx
->cur
!= ']') {
539 report_error( ctx
, "Expected `]'" );
543 if (*ctx
->cur
== '(') {
545 eat_opt_white( &ctx
->cur
);
546 if (!parse_uint( &ctx
->cur
, &brackets
->ind_array
)) {
547 report_error( ctx
, "Expected literal unsigned integer" );
550 eat_opt_white( &ctx
->cur
);
551 if (*ctx
->cur
!= ')') {
552 report_error( ctx
, "Expected `)'" );
561 parse_opt_register_src_bracket(
562 struct translate_ctx
*ctx
,
563 struct parsed_bracket
*brackets
,
564 int *parsed_brackets
)
566 const char *cur
= ctx
->cur
;
568 *parsed_brackets
= 0;
570 eat_opt_white( &cur
);
575 if (!parse_register_bracket(ctx
, brackets
))
578 *parsed_brackets
= 1;
585 /* Parse source register operand.
586 * <register_src> ::= <register_file_bracket_index> `]' |
587 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' |
588 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' |
589 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]'
593 struct translate_ctx
*ctx
,
595 struct parsed_bracket
*brackets
)
597 brackets
->ind_comp
= TGSI_SWIZZLE_X
;
598 if (!parse_register_file_bracket( ctx
, file
))
600 if (!parse_register_bracket( ctx
, brackets
))
606 struct parsed_dcl_bracket
{
612 parse_register_dcl_bracket(
613 struct translate_ctx
*ctx
,
614 struct parsed_dcl_bracket
*bracket
)
617 memset(bracket
, 0, sizeof(struct parsed_dcl_bracket
));
619 eat_opt_white( &ctx
->cur
);
621 if (!parse_uint( &ctx
->cur
, &uindex
)) {
622 /* it can be an empty bracket [] which means its range
623 * is from 0 to some implied size */
624 if (ctx
->cur
[0] == ']' && ctx
->implied_array_size
!= 0) {
626 bracket
->last
= ctx
->implied_array_size
- 1;
629 report_error( ctx
, "Expected literal unsigned integer" );
632 bracket
->first
= uindex
;
634 eat_opt_white( &ctx
->cur
);
636 if (ctx
->cur
[0] == '.' && ctx
->cur
[1] == '.') {
640 eat_opt_white( &ctx
->cur
);
641 if (!parse_uint( &ctx
->cur
, &uindex
)) {
642 report_error( ctx
, "Expected literal integer" );
645 bracket
->last
= (int) uindex
;
646 eat_opt_white( &ctx
->cur
);
649 bracket
->last
= bracket
->first
;
653 if (*ctx
->cur
!= ']') {
654 report_error( ctx
, "Expected `]' or `..'" );
661 /* Parse register declaration.
662 * <register_dcl> ::= <register_file_bracket_index> `]' |
663 * <register_file_bracket_index> `..' <index> `]'
667 struct translate_ctx
*ctx
,
669 struct parsed_dcl_bracket
*brackets
,
676 if (!parse_register_file_bracket( ctx
, file
))
678 if (!parse_register_dcl_bracket( ctx
, &brackets
[0] ))
684 eat_opt_white( &cur
);
687 bool is_in
= *file
== TGSI_FILE_INPUT
;
688 bool is_out
= *file
== TGSI_FILE_OUTPUT
;
692 if (!parse_register_dcl_bracket( ctx
, &brackets
[1] ))
694 /* for geometry shader we don't really care about
695 * the first brackets it's always the size of the
696 * input primitive. so we want to declare just
697 * the index relevant to the semantics which is in
698 * the second bracket */
700 /* tessellation has similar constraints to geometry shader */
701 if ((ctx
->processor
== TGSI_PROCESSOR_GEOMETRY
&& is_in
) ||
702 (ctx
->processor
== TGSI_PROCESSOR_TESS_EVAL
&& is_in
) ||
703 (ctx
->processor
== TGSI_PROCESSOR_TESS_CTRL
&& (is_in
|| is_out
))) {
704 brackets
[0] = brackets
[1];
715 /* Parse destination register operand.*/
718 struct translate_ctx
*ctx
,
720 struct parsed_bracket
*brackets
)
722 brackets
->ind_comp
= TGSI_SWIZZLE_X
;
723 if (!parse_register_file_bracket( ctx
, file
))
725 if (!parse_register_bracket( ctx
, brackets
))
733 struct translate_ctx
*ctx
,
734 struct tgsi_full_dst_register
*dst
)
739 struct parsed_bracket bracket
[2];
740 int parsed_opt_brackets
;
742 if (!parse_register_dst( ctx
, &file
, &bracket
[0] ))
744 if (!parse_opt_register_src_bracket(ctx
, &bracket
[1], &parsed_opt_brackets
))
748 eat_opt_white( &cur
);
750 if (!parse_opt_writemask( ctx
, &writemask
))
753 dst
->Register
.File
= file
;
754 if (parsed_opt_brackets
) {
755 dst
->Register
.Dimension
= 1;
756 dst
->Dimension
.Indirect
= 0;
757 dst
->Dimension
.Dimension
= 0;
758 dst
->Dimension
.Index
= bracket
[0].index
;
760 if (bracket
[0].ind_file
!= TGSI_FILE_NULL
) {
761 dst
->Dimension
.Indirect
= 1;
762 dst
->DimIndirect
.File
= bracket
[0].ind_file
;
763 dst
->DimIndirect
.Index
= bracket
[0].ind_index
;
764 dst
->DimIndirect
.Swizzle
= bracket
[0].ind_comp
;
765 dst
->DimIndirect
.ArrayID
= bracket
[0].ind_array
;
767 bracket
[0] = bracket
[1];
769 dst
->Register
.Index
= bracket
[0].index
;
770 dst
->Register
.WriteMask
= writemask
;
771 if (bracket
[0].ind_file
!= TGSI_FILE_NULL
) {
772 dst
->Register
.Indirect
= 1;
773 dst
->Indirect
.File
= bracket
[0].ind_file
;
774 dst
->Indirect
.Index
= bracket
[0].ind_index
;
775 dst
->Indirect
.Swizzle
= bracket
[0].ind_comp
;
776 dst
->Indirect
.ArrayID
= bracket
[0].ind_array
;
782 parse_optional_swizzle(
783 struct translate_ctx
*ctx
,
785 boolean
*parsed_swizzle
,
788 const char *cur
= ctx
->cur
;
790 *parsed_swizzle
= FALSE
;
792 eat_opt_white( &cur
);
797 eat_opt_white( &cur
);
798 for (i
= 0; i
< components
; i
++) {
799 if (uprcase( *cur
) == 'X')
800 swizzle
[i
] = TGSI_SWIZZLE_X
;
801 else if (uprcase( *cur
) == 'Y')
802 swizzle
[i
] = TGSI_SWIZZLE_Y
;
803 else if (uprcase( *cur
) == 'Z')
804 swizzle
[i
] = TGSI_SWIZZLE_Z
;
805 else if (uprcase( *cur
) == 'W')
806 swizzle
[i
] = TGSI_SWIZZLE_W
;
808 report_error( ctx
, "Expected register swizzle component `x', `y', `z' or `w'" );
813 *parsed_swizzle
= TRUE
;
821 struct translate_ctx
*ctx
,
822 struct tgsi_full_src_register
*src
)
826 boolean parsed_swizzle
;
827 struct parsed_bracket bracket
[2];
828 int parsed_opt_brackets
;
830 if (*ctx
->cur
== '-') {
832 eat_opt_white( &ctx
->cur
);
833 src
->Register
.Negate
= 1;
836 if (*ctx
->cur
== '|') {
838 eat_opt_white( &ctx
->cur
);
839 src
->Register
.Absolute
= 1;
842 if (!parse_register_src(ctx
, &file
, &bracket
[0]))
844 if (!parse_opt_register_src_bracket(ctx
, &bracket
[1], &parsed_opt_brackets
))
847 src
->Register
.File
= file
;
848 if (parsed_opt_brackets
) {
849 src
->Register
.Dimension
= 1;
850 src
->Dimension
.Indirect
= 0;
851 src
->Dimension
.Dimension
= 0;
852 src
->Dimension
.Index
= bracket
[0].index
;
853 if (bracket
[0].ind_file
!= TGSI_FILE_NULL
) {
854 src
->Dimension
.Indirect
= 1;
855 src
->DimIndirect
.File
= bracket
[0].ind_file
;
856 src
->DimIndirect
.Index
= bracket
[0].ind_index
;
857 src
->DimIndirect
.Swizzle
= bracket
[0].ind_comp
;
858 src
->DimIndirect
.ArrayID
= bracket
[0].ind_array
;
860 bracket
[0] = bracket
[1];
862 src
->Register
.Index
= bracket
[0].index
;
863 if (bracket
[0].ind_file
!= TGSI_FILE_NULL
) {
864 src
->Register
.Indirect
= 1;
865 src
->Indirect
.File
= bracket
[0].ind_file
;
866 src
->Indirect
.Index
= bracket
[0].ind_index
;
867 src
->Indirect
.Swizzle
= bracket
[0].ind_comp
;
868 src
->Indirect
.ArrayID
= bracket
[0].ind_array
;
871 /* Parse optional swizzle.
873 if (parse_optional_swizzle( ctx
, swizzle
, &parsed_swizzle
, 4 )) {
874 if (parsed_swizzle
) {
875 src
->Register
.SwizzleX
= swizzle
[0];
876 src
->Register
.SwizzleY
= swizzle
[1];
877 src
->Register
.SwizzleZ
= swizzle
[2];
878 src
->Register
.SwizzleW
= swizzle
[3];
882 if (src
->Register
.Absolute
) {
883 eat_opt_white( &ctx
->cur
);
884 if (*ctx
->cur
!= '|') {
885 report_error( ctx
, "Expected `|'" );
896 parse_texoffset_operand(
897 struct translate_ctx
*ctx
,
898 struct tgsi_texture_offset
*src
)
902 boolean parsed_swizzle
;
903 struct parsed_bracket bracket
;
905 if (!parse_register_src(ctx
, &file
, &bracket
))
909 src
->Index
= bracket
.index
;
911 /* Parse optional swizzle.
913 if (parse_optional_swizzle( ctx
, swizzle
, &parsed_swizzle
, 3 )) {
914 if (parsed_swizzle
) {
915 src
->SwizzleX
= swizzle
[0];
916 src
->SwizzleY
= swizzle
[1];
917 src
->SwizzleZ
= swizzle
[2];
925 match_inst(const char **pcur
,
927 const struct tgsi_opcode_info
*info
)
929 const char *cur
= *pcur
;
931 /* simple case: the whole string matches the instruction name */
932 if (str_match_nocase_whole(&cur
, info
->mnemonic
)) {
938 if (str_match_no_case(&cur
, info
->mnemonic
)) {
939 /* the instruction has a suffix, figure it out */
940 if (str_match_nocase_whole(&cur
, "_SAT")) {
952 struct translate_ctx
*ctx
,
957 const struct tgsi_opcode_info
*info
;
958 struct tgsi_full_instruction inst
;
962 inst
= tgsi_default_full_instruction();
966 eat_opt_white( &ctx
->cur
);
967 if (*ctx
->cur
== '(') {
971 boolean parsed_swizzle
;
973 inst
.Instruction
.Predicate
= 1;
976 if (*ctx
->cur
== '!') {
978 inst
.Predicate
.Negate
= 1;
981 if (!parse_register_1d( ctx
, &file
, &index
))
984 if (parse_optional_swizzle( ctx
, swizzle
, &parsed_swizzle
, 4 )) {
985 if (parsed_swizzle
) {
986 inst
.Predicate
.SwizzleX
= swizzle
[0];
987 inst
.Predicate
.SwizzleY
= swizzle
[1];
988 inst
.Predicate
.SwizzleZ
= swizzle
[2];
989 inst
.Predicate
.SwizzleW
= swizzle
[3];
993 if (*ctx
->cur
!= ')') {
994 report_error( ctx
, "Expected `)'" );
1001 /* Parse instruction name.
1003 eat_opt_white( &ctx
->cur
);
1004 for (i
= 0; i
< TGSI_OPCODE_LAST
; i
++) {
1007 info
= tgsi_get_opcode_info( i
);
1008 if (match_inst(&cur
, &saturate
, info
)) {
1009 if (info
->num_dst
+ info
->num_src
+ info
->is_tex
== 0) {
1013 else if (*cur
== '\0' || eat_white( &cur
)) {
1019 if (i
== TGSI_OPCODE_LAST
) {
1021 report_error( ctx
, "Unknown opcode" );
1023 report_error( ctx
, "Expected `DCL', `IMM' or a label" );
1027 inst
.Instruction
.Opcode
= i
;
1028 inst
.Instruction
.Saturate
= saturate
;
1029 inst
.Instruction
.NumDstRegs
= info
->num_dst
;
1030 inst
.Instruction
.NumSrcRegs
= info
->num_src
;
1032 if (i
>= TGSI_OPCODE_SAMPLE
&& i
<= TGSI_OPCODE_GATHER4
) {
1034 * These are not considered tex opcodes here (no additional
1035 * target argument) however we're required to set the Texture
1036 * bit so we can set the number of tex offsets.
1038 inst
.Instruction
.Texture
= 1;
1039 inst
.Texture
.Texture
= TGSI_TEXTURE_UNKNOWN
;
1042 if ((i
>= TGSI_OPCODE_LOAD
&& i
<= TGSI_OPCODE_ATOMIMAX
) ||
1043 i
== TGSI_OPCODE_RESQ
) {
1044 inst
.Instruction
.Memory
= 1;
1045 inst
.Memory
.Qualifier
= 0;
1048 /* Parse instruction operands.
1050 for (i
= 0; i
< info
->num_dst
+ info
->num_src
+ info
->is_tex
; i
++) {
1052 eat_opt_white( &ctx
->cur
);
1053 if (*ctx
->cur
!= ',') {
1054 report_error( ctx
, "Expected `,'" );
1058 eat_opt_white( &ctx
->cur
);
1061 if (i
< info
->num_dst
) {
1062 if (!parse_dst_operand( ctx
, &inst
.Dst
[i
] ))
1065 else if (i
< info
->num_dst
+ info
->num_src
) {
1066 if (!parse_src_operand( ctx
, &inst
.Src
[i
- info
->num_dst
] ))
1072 for (j
= 0; j
< TGSI_TEXTURE_COUNT
; j
++) {
1073 if (str_match_nocase_whole( &ctx
->cur
, tgsi_texture_names
[j
] )) {
1074 inst
.Instruction
.Texture
= 1;
1075 inst
.Texture
.Texture
= j
;
1079 if (j
== TGSI_TEXTURE_COUNT
) {
1080 report_error( ctx
, "Expected texture target" );
1087 eat_opt_white( &cur
);
1088 for (i
= 0; inst
.Instruction
.Texture
&& *cur
== ','; i
++) {
1090 eat_opt_white( &cur
);
1092 if (!parse_texoffset_operand( ctx
, &inst
.TexOffsets
[i
] ))
1095 eat_opt_white( &cur
);
1097 inst
.Texture
.NumOffsets
= i
;
1100 eat_opt_white(&cur
);
1101 for (i
= 0; inst
.Instruction
.Memory
&& *cur
== ','; i
++) {
1104 eat_opt_white(&cur
);
1106 for (j
= 0; j
< 3; j
++) {
1107 if (str_match_nocase_whole(&ctx
->cur
, tgsi_memory_names
[j
])) {
1108 inst
.Memory
.Qualifier
|= 1U << j
;
1113 report_error(ctx
, "Expected memory qualifier");
1117 eat_opt_white(&cur
);
1121 eat_opt_white( &cur
);
1122 if (info
->is_branch
&& *cur
== ':') {
1126 eat_opt_white( &cur
);
1127 if (!parse_uint( &cur
, &target
)) {
1128 report_error( ctx
, "Expected a label" );
1131 inst
.Instruction
.Label
= 1;
1132 inst
.Label
.Label
= target
;
1136 advance
= tgsi_build_full_instruction(
1140 (uint
) (ctx
->tokens_end
- ctx
->tokens_cur
) );
1143 ctx
->tokens_cur
+= advance
;
1148 /* parses a 4-touple of the form {x, y, z, w}
1149 * where x, y, z, w are numbers */
1150 static boolean
parse_immediate_data(struct translate_ctx
*ctx
, unsigned type
,
1151 union tgsi_immediate_data
*values
)
1156 eat_opt_white( &ctx
->cur
);
1157 if (*ctx
->cur
!= '{') {
1158 report_error( ctx
, "Expected `{'" );
1162 for (i
= 0; i
< 4; i
++) {
1163 eat_opt_white( &ctx
->cur
);
1165 if (*ctx
->cur
!= ',') {
1166 report_error( ctx
, "Expected `,'" );
1170 eat_opt_white( &ctx
->cur
);
1174 case TGSI_IMM_FLOAT64
:
1175 ret
= parse_double(&ctx
->cur
, &values
[i
].Uint
, &values
[i
+1].Uint
);
1178 case TGSI_IMM_FLOAT32
:
1179 ret
= parse_float(&ctx
->cur
, &values
[i
].Float
);
1181 case TGSI_IMM_UINT32
:
1182 ret
= parse_uint(&ctx
->cur
, &values
[i
].Uint
);
1184 case TGSI_IMM_INT32
:
1185 ret
= parse_int(&ctx
->cur
, &values
[i
].Int
);
1194 report_error( ctx
, "Expected immediate constant" );
1198 eat_opt_white( &ctx
->cur
);
1199 if (*ctx
->cur
!= '}') {
1200 report_error( ctx
, "Expected `}'" );
1208 static boolean
parse_declaration( struct translate_ctx
*ctx
)
1210 struct tgsi_full_declaration decl
;
1212 struct parsed_dcl_bracket brackets
[2];
1215 const char *cur
, *cur2
;
1217 boolean is_vs_input
;
1219 if (!eat_white( &ctx
->cur
)) {
1220 report_error( ctx
, "Syntax error" );
1223 if (!parse_register_dcl( ctx
, &file
, brackets
, &num_brackets
))
1225 if (!parse_opt_writemask( ctx
, &writemask
))
1228 decl
= tgsi_default_full_declaration();
1229 decl
.Declaration
.File
= file
;
1230 decl
.Declaration
.UsageMask
= writemask
;
1232 if (num_brackets
== 1) {
1233 decl
.Range
.First
= brackets
[0].first
;
1234 decl
.Range
.Last
= brackets
[0].last
;
1236 decl
.Range
.First
= brackets
[1].first
;
1237 decl
.Range
.Last
= brackets
[1].last
;
1239 decl
.Declaration
.Dimension
= 1;
1240 decl
.Dim
.Index2D
= brackets
[0].first
;
1243 is_vs_input
= (file
== TGSI_FILE_INPUT
&&
1244 ctx
->processor
== TGSI_PROCESSOR_VERTEX
);
1247 eat_opt_white( &cur
);
1251 eat_opt_white( &cur2
);
1252 if (str_match_nocase_whole( &cur2
, "ARRAY" )) {
1255 report_error( ctx
, "Expected `('" );
1259 eat_opt_white( &cur2
);
1260 if (!parse_int( &cur2
, &arrayid
)) {
1261 report_error( ctx
, "Expected `,'" );
1264 eat_opt_white( &cur2
);
1266 report_error( ctx
, "Expected `)'" );
1270 decl
.Declaration
.Array
= 1;
1271 decl
.Array
.ArrayID
= arrayid
;
1272 ctx
->cur
= cur
= cur2
;
1276 if (*cur
== ',' && !is_vs_input
) {
1280 eat_opt_white( &cur
);
1281 if (file
== TGSI_FILE_IMAGE
) {
1282 for (i
= 0; i
< TGSI_TEXTURE_COUNT
; i
++) {
1283 if (str_match_nocase_whole(&cur
, tgsi_texture_names
[i
])) {
1284 decl
.Image
.Resource
= i
;
1288 if (i
== TGSI_TEXTURE_COUNT
) {
1289 report_error(ctx
, "Expected texture target");
1296 eat_opt_white(&cur2
);
1297 while (*cur2
== ',') {
1299 eat_opt_white(&cur2
);
1300 if (str_match_nocase_whole(&cur2
, "RAW")) {
1303 } else if (str_match_nocase_whole(&cur2
, "WR")) {
1304 decl
.Image
.Writable
= 1;
1310 eat_opt_white(&cur2
);
1315 } else if (file
== TGSI_FILE_SAMPLER_VIEW
) {
1316 for (i
= 0; i
< TGSI_TEXTURE_COUNT
; i
++) {
1317 if (str_match_nocase_whole(&cur
, tgsi_texture_names
[i
])) {
1318 decl
.SamplerView
.Resource
= i
;
1322 if (i
== TGSI_TEXTURE_COUNT
) {
1323 report_error(ctx
, "Expected texture target");
1326 eat_opt_white( &cur
);
1328 report_error( ctx
, "Expected `,'" );
1332 eat_opt_white( &cur
);
1333 for (j
= 0; j
< 4; ++j
) {
1334 for (i
= 0; i
< TGSI_RETURN_TYPE_COUNT
; ++i
) {
1335 if (str_match_nocase_whole(&cur
, tgsi_return_type_names
[i
])) {
1338 decl
.SamplerView
.ReturnTypeX
= i
;
1341 decl
.SamplerView
.ReturnTypeY
= i
;
1344 decl
.SamplerView
.ReturnTypeZ
= i
;
1347 decl
.SamplerView
.ReturnTypeW
= i
;
1355 if (i
== TGSI_RETURN_TYPE_COUNT
) {
1356 if (j
== 0 || j
> 2) {
1357 report_error(ctx
, "Expected type name");
1363 eat_opt_white( &cur2
);
1366 eat_opt_white( &cur2
);
1374 decl
.SamplerView
.ReturnTypeY
=
1375 decl
.SamplerView
.ReturnTypeZ
=
1376 decl
.SamplerView
.ReturnTypeW
=
1377 decl
.SamplerView
.ReturnTypeX
;
1380 } else if (file
== TGSI_FILE_BUFFER
) {
1381 if (str_match_nocase_whole(&cur
, "ATOMIC")) {
1382 decl
.Declaration
.Atomic
= 1;
1386 if (str_match_nocase_whole(&cur
, "LOCAL")) {
1387 decl
.Declaration
.Local
= 1;
1392 eat_opt_white( &cur
);
1395 eat_opt_white( &cur
);
1397 for (i
= 0; i
< TGSI_SEMANTIC_COUNT
; i
++) {
1398 if (str_match_nocase_whole(&cur
, tgsi_semantic_names
[i
])) {
1402 eat_opt_white( &cur2
);
1405 eat_opt_white( &cur2
);
1406 if (!parse_uint( &cur2
, &index
)) {
1407 report_error( ctx
, "Expected literal integer" );
1410 eat_opt_white( &cur2
);
1412 report_error( ctx
, "Expected `]'" );
1417 decl
.Semantic
.Index
= index
;
1422 decl
.Declaration
.Semantic
= 1;
1423 decl
.Semantic
.Name
= i
;
1434 eat_opt_white( &cur
);
1435 if (*cur
== ',' && !is_vs_input
) {
1439 eat_opt_white( &cur
);
1440 for (i
= 0; i
< TGSI_INTERPOLATE_COUNT
; i
++) {
1441 if (str_match_nocase_whole( &cur
, tgsi_interpolate_names
[i
] )) {
1442 decl
.Declaration
.Interpolate
= 1;
1443 decl
.Interp
.Interpolate
= i
;
1449 if (i
== TGSI_INTERPOLATE_COUNT
) {
1450 report_error( ctx
, "Expected semantic or interpolate attribute" );
1456 eat_opt_white( &cur
);
1457 if (*cur
== ',' && !is_vs_input
) {
1461 eat_opt_white( &cur
);
1462 for (i
= 0; i
< TGSI_INTERPOLATE_LOC_COUNT
; i
++) {
1463 if (str_match_nocase_whole( &cur
, tgsi_interpolate_locations
[i
] )) {
1464 decl
.Interp
.Location
= i
;
1472 advance
= tgsi_build_full_declaration(
1476 (uint
) (ctx
->tokens_end
- ctx
->tokens_cur
) );
1480 ctx
->tokens_cur
+= advance
;
1485 static boolean
parse_immediate( struct translate_ctx
*ctx
)
1487 struct tgsi_full_immediate imm
;
1491 if (*ctx
->cur
== '[') {
1496 eat_opt_white( &ctx
->cur
);
1497 if (!parse_uint( &ctx
->cur
, &uindex
)) {
1498 report_error( ctx
, "Expected literal unsigned integer" );
1502 if (uindex
!= ctx
->num_immediates
) {
1503 report_error( ctx
, "Immediates must be sorted" );
1507 eat_opt_white( &ctx
->cur
);
1508 if (*ctx
->cur
!= ']') {
1509 report_error( ctx
, "Expected `]'" );
1516 if (!eat_white( &ctx
->cur
)) {
1517 report_error( ctx
, "Syntax error" );
1520 for (type
= 0; type
< Elements(tgsi_immediate_type_names
); ++type
) {
1521 if (str_match_nocase_whole(&ctx
->cur
, tgsi_immediate_type_names
[type
]))
1524 if (type
== Elements(tgsi_immediate_type_names
)) {
1525 report_error( ctx
, "Expected immediate type" );
1529 imm
= tgsi_default_full_immediate();
1530 imm
.Immediate
.NrTokens
+= 4;
1531 imm
.Immediate
.DataType
= type
;
1532 parse_immediate_data(ctx
, type
, imm
.u
);
1534 advance
= tgsi_build_full_immediate(
1538 (uint
) (ctx
->tokens_end
- ctx
->tokens_cur
) );
1541 ctx
->tokens_cur
+= advance
;
1543 ctx
->num_immediates
++;
1549 parse_primitive( const char **pcur
, uint
*primitive
)
1553 for (i
= 0; i
< PIPE_PRIM_MAX
; i
++) {
1554 const char *cur
= *pcur
;
1556 if (str_match_nocase_whole( &cur
, tgsi_primitive_names
[i
])) {
1566 parse_fs_coord_origin( const char **pcur
, uint
*fs_coord_origin
)
1570 for (i
= 0; i
< Elements(tgsi_fs_coord_origin_names
); i
++) {
1571 const char *cur
= *pcur
;
1573 if (str_match_nocase_whole( &cur
, tgsi_fs_coord_origin_names
[i
])) {
1574 *fs_coord_origin
= i
;
1583 parse_fs_coord_pixel_center( const char **pcur
, uint
*fs_coord_pixel_center
)
1587 for (i
= 0; i
< Elements(tgsi_fs_coord_pixel_center_names
); i
++) {
1588 const char *cur
= *pcur
;
1590 if (str_match_nocase_whole( &cur
, tgsi_fs_coord_pixel_center_names
[i
])) {
1591 *fs_coord_pixel_center
= i
;
1600 static boolean
parse_property( struct translate_ctx
*ctx
)
1602 struct tgsi_full_property prop
;
1608 if (!eat_white( &ctx
->cur
)) {
1609 report_error( ctx
, "Syntax error" );
1612 if (!parse_identifier( &ctx
->cur
, id
)) {
1613 report_error( ctx
, "Syntax error" );
1616 for (property_name
= 0; property_name
< TGSI_PROPERTY_COUNT
;
1618 if (streq_nocase_uprcase(tgsi_property_names
[property_name
], id
)) {
1622 if (property_name
>= TGSI_PROPERTY_COUNT
) {
1623 debug_printf( "\nError: Unknown property : '%s'", id
);
1627 eat_opt_white( &ctx
->cur
);
1628 switch(property_name
) {
1629 case TGSI_PROPERTY_GS_INPUT_PRIM
:
1630 case TGSI_PROPERTY_GS_OUTPUT_PRIM
:
1631 if (!parse_primitive(&ctx
->cur
, &values
[0] )) {
1632 report_error( ctx
, "Unknown primitive name as property!" );
1635 if (property_name
== TGSI_PROPERTY_GS_INPUT_PRIM
&&
1636 ctx
->processor
== TGSI_PROCESSOR_GEOMETRY
) {
1637 ctx
->implied_array_size
= u_vertices_per_prim(values
[0]);
1640 case TGSI_PROPERTY_FS_COORD_ORIGIN
:
1641 if (!parse_fs_coord_origin(&ctx
->cur
, &values
[0] )) {
1642 report_error( ctx
, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" );
1646 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER
:
1647 if (!parse_fs_coord_pixel_center(&ctx
->cur
, &values
[0] )) {
1648 report_error( ctx
, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" );
1652 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS
:
1654 if (!parse_uint(&ctx
->cur
, &values
[0] )) {
1655 report_error( ctx
, "Expected unsigned integer as property!" );
1660 prop
= tgsi_default_full_property();
1661 prop
.Property
.PropertyName
= property_name
;
1662 prop
.Property
.NrTokens
+= 1;
1663 prop
.u
[0].Data
= values
[0];
1665 advance
= tgsi_build_full_property(
1669 (uint
) (ctx
->tokens_end
- ctx
->tokens_cur
) );
1672 ctx
->tokens_cur
+= advance
;
1678 static boolean
translate( struct translate_ctx
*ctx
)
1680 eat_opt_white( &ctx
->cur
);
1681 if (!parse_header( ctx
))
1684 if (ctx
->processor
== TGSI_PROCESSOR_TESS_CTRL
||
1685 ctx
->processor
== TGSI_PROCESSOR_TESS_EVAL
)
1686 ctx
->implied_array_size
= 32;
1688 while (*ctx
->cur
!= '\0') {
1690 if (!eat_white( &ctx
->cur
)) {
1691 report_error( ctx
, "Syntax error" );
1695 if (*ctx
->cur
== '\0')
1697 if (parse_label( ctx
, &label_val
)) {
1698 if (!parse_instruction( ctx
, TRUE
))
1701 else if (str_match_nocase_whole( &ctx
->cur
, "DCL" )) {
1702 if (!parse_declaration( ctx
))
1705 else if (str_match_nocase_whole( &ctx
->cur
, "IMM" )) {
1706 if (!parse_immediate( ctx
))
1709 else if (str_match_nocase_whole( &ctx
->cur
, "PROPERTY" )) {
1710 if (!parse_property( ctx
))
1713 else if (!parse_instruction( ctx
, FALSE
)) {
1722 tgsi_text_translate(
1724 struct tgsi_token
*tokens
,
1727 struct translate_ctx ctx
= {0};
1731 ctx
.tokens
= tokens
;
1732 ctx
.tokens_cur
= tokens
;
1733 ctx
.tokens_end
= tokens
+ num_tokens
;
1735 if (!translate( &ctx
))
1738 return tgsi_sanity_check( tokens
);