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