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