tgsi_text.c revision 69faf5b48fde9d89b554c75fba7b431ddcd591da
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 40static boolean is_alpha_underscore( const char *cur ) 41{ 42 return 43 (*cur >= 'a' && *cur <= 'z') || 44 (*cur >= 'A' && *cur <= 'Z') || 45 *cur == '_'; 46} 47 48static boolean is_digit( const char *cur ) 49{ 50 return *cur >= '0' && *cur <= '9'; 51} 52 53static boolean is_digit_alpha_underscore( const char *cur ) 54{ 55 return is_digit( cur ) || is_alpha_underscore( cur ); 56} 57 58static 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 */ 69static int 70streq_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 82static 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 */ 99static 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 */ 108static 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 */ 119static 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 133static 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 */ 149static 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 192struct 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 204static 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 */ 228static 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 256static 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 271static 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 285static boolean 286parse_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 304static boolean 305parse_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 347static boolean 348parse_register_dst( struct translate_ctx *ctx, 349 uint *file, 350 int *index ); 351 352struct parsed_src_bracket { 353 int index; 354 355 uint ind_file; 356 int ind_index; 357 uint ind_comp; 358}; 359 360 361static boolean 362parse_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 442static boolean 443parse_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 */ 468static boolean 469parse_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 */ 488static boolean 489parse_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 */ 513static boolean 514parse_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 529struct parsed_dcl_bracket { 530 uint first; 531 uint last; 532}; 533 534static boolean 535parse_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 575cleanup: 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 */ 588static boolean 589parse_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 */ 634static boolean 635parse_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 651static boolean 652parse_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 676static boolean 677parse_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 713static boolean 714parse_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 784static 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 797static boolean 798match_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 807static boolean 808parse_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 965static 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 980static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] = 981{ 982 "CONSTANT", 983 "LINEAR", 984 "PERSPECTIVE" 985}; 986 987static 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 boolean is_vs_input; 997 998 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 999 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 1000 1001 if (!eat_white( &ctx->cur )) { 1002 report_error( ctx, "Syntax error" ); 1003 return FALSE; 1004 } 1005 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) 1006 return FALSE; 1007 if (!parse_opt_writemask( ctx, &writemask )) 1008 return FALSE; 1009 1010 decl = tgsi_default_full_declaration(); 1011 decl.Declaration.File = file; 1012 decl.Declaration.UsageMask = writemask; 1013 1014 if (num_brackets == 1) { 1015 decl.Range.First = brackets[0].first; 1016 decl.Range.Last = brackets[0].last; 1017 } else { 1018 decl.Range.First = brackets[1].first; 1019 decl.Range.Last = brackets[1].last; 1020 1021 decl.Declaration.Dimension = 1; 1022 decl.Dim.Index2D = brackets[0].first; 1023 } 1024 1025 is_vs_input = (file == TGSI_FILE_INPUT && 1026 ctx->processor == TGSI_PROCESSOR_VERTEX); 1027 1028 cur = ctx->cur; 1029 eat_opt_white( &cur ); 1030 if (*cur == ',' && !is_vs_input) { 1031 uint i; 1032 1033 cur++; 1034 eat_opt_white( &cur ); 1035 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { 1036 if (str_match_no_case( &cur, semantic_names[i] )) { 1037 const char *cur2 = cur; 1038 uint index; 1039 1040 if (is_digit_alpha_underscore( cur )) 1041 continue; 1042 eat_opt_white( &cur2 ); 1043 if (*cur2 == '[') { 1044 cur2++; 1045 eat_opt_white( &cur2 ); 1046 if (!parse_uint( &cur2, &index )) { 1047 report_error( ctx, "Expected literal integer" ); 1048 return FALSE; 1049 } 1050 eat_opt_white( &cur2 ); 1051 if (*cur2 != ']') { 1052 report_error( ctx, "Expected `]'" ); 1053 return FALSE; 1054 } 1055 cur2++; 1056 1057 decl.Semantic.Index = index; 1058 1059 cur = cur2; 1060 } 1061 1062 decl.Declaration.Semantic = 1; 1063 decl.Semantic.Name = i; 1064 1065 ctx->cur = cur; 1066 break; 1067 } 1068 } 1069 } 1070 1071 cur = ctx->cur; 1072 eat_opt_white( &cur ); 1073 if (*cur == ',' && !is_vs_input) { 1074 uint i; 1075 1076 cur++; 1077 eat_opt_white( &cur ); 1078 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { 1079 if (str_match_no_case( &cur, interpolate_names[i] )) { 1080 if (is_digit_alpha_underscore( cur )) 1081 continue; 1082 decl.Declaration.Interpolate = i; 1083 1084 ctx->cur = cur; 1085 break; 1086 } 1087 } 1088 if (i == TGSI_INTERPOLATE_COUNT) { 1089 report_error( ctx, "Expected semantic or interpolate attribute" ); 1090 return FALSE; 1091 } 1092 } 1093 1094 advance = tgsi_build_full_declaration( 1095 &decl, 1096 ctx->tokens_cur, 1097 ctx->header, 1098 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1099 if (advance == 0) 1100 return FALSE; 1101 ctx->tokens_cur += advance; 1102 1103 return TRUE; 1104} 1105 1106static boolean parse_immediate( struct translate_ctx *ctx ) 1107{ 1108 struct tgsi_full_immediate imm; 1109 uint i; 1110 float values[4]; 1111 uint advance; 1112 1113 if (!eat_white( &ctx->cur )) { 1114 report_error( ctx, "Syntax error" ); 1115 return FALSE; 1116 } 1117 if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) { 1118 report_error( ctx, "Expected `FLT32'" ); 1119 return FALSE; 1120 } 1121 eat_opt_white( &ctx->cur ); 1122 if (*ctx->cur != '{') { 1123 report_error( ctx, "Expected `{'" ); 1124 return FALSE; 1125 } 1126 ctx->cur++; 1127 for (i = 0; i < 4; i++) { 1128 eat_opt_white( &ctx->cur ); 1129 if (i > 0) { 1130 if (*ctx->cur != ',') { 1131 report_error( ctx, "Expected `,'" ); 1132 return FALSE; 1133 } 1134 ctx->cur++; 1135 eat_opt_white( &ctx->cur ); 1136 } 1137 if (!parse_float( &ctx->cur, &values[i] )) { 1138 report_error( ctx, "Expected literal floating point" ); 1139 return FALSE; 1140 } 1141 } 1142 eat_opt_white( &ctx->cur ); 1143 if (*ctx->cur != '}') { 1144 report_error( ctx, "Expected `}'" ); 1145 return FALSE; 1146 } 1147 ctx->cur++; 1148 1149 imm = tgsi_default_full_immediate(); 1150 imm.Immediate.NrTokens += 4; 1151 imm.Immediate.DataType = TGSI_IMM_FLOAT32; 1152 imm.u[0].Float = values[0]; 1153 imm.u[1].Float = values[1]; 1154 imm.u[2].Float = values[2]; 1155 imm.u[3].Float = values[3]; 1156 1157 advance = tgsi_build_full_immediate( 1158 &imm, 1159 ctx->tokens_cur, 1160 ctx->header, 1161 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1162 if (advance == 0) 1163 return FALSE; 1164 ctx->tokens_cur += advance; 1165 1166 return TRUE; 1167} 1168 1169static const char *property_names[] = 1170{ 1171 "GS_INPUT_PRIMITIVE", 1172 "GS_OUTPUT_PRIMITIVE", 1173 "GS_MAX_OUTPUT_VERTICES", 1174 "FS_COORD_ORIGIN", 1175 "FS_COORD_PIXEL_CENTER" 1176}; 1177 1178static const char *primitive_names[] = 1179{ 1180 "POINTS", 1181 "LINES", 1182 "LINE_LOOP", 1183 "LINE_STRIP", 1184 "TRIANGLES", 1185 "TRIANGLE_STRIP", 1186 "TRIANGLE_FAN", 1187 "QUADS", 1188 "QUAD_STRIP", 1189 "POLYGON" 1190}; 1191 1192static const char *fs_coord_origin_names[] = 1193{ 1194 "UPPER_LEFT", 1195 "LOWER_LEFT" 1196}; 1197 1198static const char *fs_coord_pixel_center_names[] = 1199{ 1200 "HALF_INTEGER", 1201 "INTEGER" 1202}; 1203 1204 1205static boolean 1206parse_primitive( const char **pcur, uint *primitive ) 1207{ 1208 uint i; 1209 1210 for (i = 0; i < PIPE_PRIM_MAX; i++) { 1211 const char *cur = *pcur; 1212 1213 if (str_match_no_case( &cur, primitive_names[i])) { 1214 *primitive = i; 1215 *pcur = cur; 1216 return TRUE; 1217 } 1218 } 1219 return FALSE; 1220} 1221 1222static boolean 1223parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) 1224{ 1225 uint i; 1226 1227 for (i = 0; i < sizeof(fs_coord_origin_names) / sizeof(fs_coord_origin_names[0]); i++) { 1228 const char *cur = *pcur; 1229 1230 if (str_match_no_case( &cur, fs_coord_origin_names[i])) { 1231 *fs_coord_origin = i; 1232 *pcur = cur; 1233 return TRUE; 1234 } 1235 } 1236 return FALSE; 1237} 1238 1239static boolean 1240parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) 1241{ 1242 uint i; 1243 1244 for (i = 0; i < sizeof(fs_coord_pixel_center_names) / sizeof(fs_coord_pixel_center_names[0]); i++) { 1245 const char *cur = *pcur; 1246 1247 if (str_match_no_case( &cur, fs_coord_pixel_center_names[i])) { 1248 *fs_coord_pixel_center = i; 1249 *pcur = cur; 1250 return TRUE; 1251 } 1252 } 1253 return FALSE; 1254} 1255 1256 1257static boolean parse_property( struct translate_ctx *ctx ) 1258{ 1259 struct tgsi_full_property prop; 1260 uint property_name; 1261 uint values[8]; 1262 uint advance; 1263 char id[64]; 1264 1265 if (!eat_white( &ctx->cur )) { 1266 report_error( ctx, "Syntax error" ); 1267 return FALSE; 1268 } 1269 if (!parse_identifier( &ctx->cur, id )) { 1270 report_error( ctx, "Syntax error" ); 1271 return FALSE; 1272 } 1273 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; 1274 ++property_name) { 1275 if (streq_nocase_uprcase(property_names[property_name], id)) { 1276 break; 1277 } 1278 } 1279 if (property_name >= TGSI_PROPERTY_COUNT) { 1280 debug_printf( "\nError: Unknown property : '%s'", id ); 1281 return FALSE; 1282 } 1283 1284 eat_opt_white( &ctx->cur ); 1285 switch(property_name) { 1286 case TGSI_PROPERTY_GS_INPUT_PRIM: 1287 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 1288 if (!parse_primitive(&ctx->cur, &values[0] )) { 1289 report_error( ctx, "Unknown primitive name as property!" ); 1290 return FALSE; 1291 } 1292 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && 1293 ctx->processor == TGSI_PROCESSOR_GEOMETRY) { 1294 ctx->implied_array_size = u_vertices_per_prim(values[0]); 1295 } 1296 break; 1297 case TGSI_PROPERTY_FS_COORD_ORIGIN: 1298 if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) { 1299 report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" ); 1300 return FALSE; 1301 } 1302 break; 1303 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 1304 if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) { 1305 report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" ); 1306 return FALSE; 1307 } 1308 break; 1309 default: 1310 if (!parse_uint(&ctx->cur, &values[0] )) { 1311 report_error( ctx, "Expected unsigned integer as property!" ); 1312 return FALSE; 1313 } 1314 } 1315 1316 prop = tgsi_default_full_property(); 1317 prop.Property.PropertyName = property_name; 1318 prop.Property.NrTokens += 1; 1319 prop.u[0].Data = values[0]; 1320 1321 advance = tgsi_build_full_property( 1322 &prop, 1323 ctx->tokens_cur, 1324 ctx->header, 1325 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1326 if (advance == 0) 1327 return FALSE; 1328 ctx->tokens_cur += advance; 1329 1330 return TRUE; 1331} 1332 1333 1334static boolean translate( struct translate_ctx *ctx ) 1335{ 1336 eat_opt_white( &ctx->cur ); 1337 if (!parse_header( ctx )) 1338 return FALSE; 1339 1340 while (*ctx->cur != '\0') { 1341 uint label_val = 0; 1342 if (!eat_white( &ctx->cur )) { 1343 report_error( ctx, "Syntax error" ); 1344 return FALSE; 1345 } 1346 1347 if (*ctx->cur == '\0') 1348 break; 1349 if (parse_label( ctx, &label_val )) { 1350 if (!parse_instruction( ctx, TRUE )) 1351 return FALSE; 1352 } 1353 else if (str_match_no_case( &ctx->cur, "DCL" )) { 1354 if (!parse_declaration( ctx )) 1355 return FALSE; 1356 } 1357 else if (str_match_no_case( &ctx->cur, "IMM" )) { 1358 if (!parse_immediate( ctx )) 1359 return FALSE; 1360 } 1361 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) { 1362 if (!parse_property( ctx )) 1363 return FALSE; 1364 } 1365 else if (!parse_instruction( ctx, FALSE )) { 1366 return FALSE; 1367 } 1368 } 1369 1370 return TRUE; 1371} 1372 1373boolean 1374tgsi_text_translate( 1375 const char *text, 1376 struct tgsi_token *tokens, 1377 uint num_tokens ) 1378{ 1379 struct translate_ctx ctx; 1380 1381 ctx.text = text; 1382 ctx.cur = text; 1383 ctx.tokens = tokens; 1384 ctx.tokens_cur = tokens; 1385 ctx.tokens_end = tokens + num_tokens; 1386 1387 if (!translate( &ctx )) 1388 return FALSE; 1389 1390 return tgsi_sanity_check( tokens ); 1391} 1392