tgsi_text.c revision e7ccd703a28e14431b90f29540cec0bf67be1e0f
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 "VERTEXID", 1027 "STENCIL" 1028}; 1029 1030static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] = 1031{ 1032 "CONSTANT", 1033 "LINEAR", 1034 "PERSPECTIVE" 1035}; 1036 1037 1038/* parses a 4-touple of the form {x, y, z, w} 1039 * where x, y, z, w are numbers */ 1040static boolean parse_immediate_data(struct translate_ctx *ctx, 1041 float *values) 1042{ 1043 unsigned i; 1044 1045 eat_opt_white( &ctx->cur ); 1046 if (*ctx->cur != '{') { 1047 report_error( ctx, "Expected `{'" ); 1048 return FALSE; 1049 } 1050 ctx->cur++; 1051 for (i = 0; i < 4; i++) { 1052 eat_opt_white( &ctx->cur ); 1053 if (i > 0) { 1054 if (*ctx->cur != ',') { 1055 report_error( ctx, "Expected `,'" ); 1056 return FALSE; 1057 } 1058 ctx->cur++; 1059 eat_opt_white( &ctx->cur ); 1060 } 1061 if (!parse_float( &ctx->cur, &values[i] )) { 1062 report_error( ctx, "Expected literal floating point" ); 1063 return FALSE; 1064 } 1065 } 1066 eat_opt_white( &ctx->cur ); 1067 if (*ctx->cur != '}') { 1068 report_error( ctx, "Expected `}'" ); 1069 return FALSE; 1070 } 1071 ctx->cur++; 1072 1073 return TRUE; 1074} 1075 1076static boolean parse_declaration( struct translate_ctx *ctx ) 1077{ 1078 struct tgsi_full_declaration decl; 1079 uint file; 1080 struct parsed_dcl_bracket brackets[2]; 1081 int num_brackets; 1082 uint writemask; 1083 const char *cur; 1084 uint advance; 1085 boolean is_vs_input; 1086 boolean is_imm_array; 1087 1088 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 1089 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 1090 1091 if (!eat_white( &ctx->cur )) { 1092 report_error( ctx, "Syntax error" ); 1093 return FALSE; 1094 } 1095 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) 1096 return FALSE; 1097 if (!parse_opt_writemask( ctx, &writemask )) 1098 return FALSE; 1099 1100 decl = tgsi_default_full_declaration(); 1101 decl.Declaration.File = file; 1102 decl.Declaration.UsageMask = writemask; 1103 1104 if (num_brackets == 1) { 1105 decl.Range.First = brackets[0].first; 1106 decl.Range.Last = brackets[0].last; 1107 } else { 1108 decl.Range.First = brackets[1].first; 1109 decl.Range.Last = brackets[1].last; 1110 1111 decl.Declaration.Dimension = 1; 1112 decl.Dim.Index2D = brackets[0].first; 1113 } 1114 1115 is_vs_input = (file == TGSI_FILE_INPUT && 1116 ctx->processor == TGSI_PROCESSOR_VERTEX); 1117 is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY); 1118 1119 cur = ctx->cur; 1120 eat_opt_white( &cur ); 1121 if (*cur == ',' && !is_vs_input) { 1122 uint i, j; 1123 1124 cur++; 1125 eat_opt_white( &cur ); 1126 if (file == TGSI_FILE_RESOURCE) { 1127 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { 1128 if (str_match_no_case(&cur, texture_names[i])) { 1129 if (!is_digit_alpha_underscore(cur)) { 1130 decl.Resource.Resource = i; 1131 break; 1132 } 1133 } 1134 } 1135 if (i == TGSI_TEXTURE_COUNT) { 1136 report_error(ctx, "Expected texture target"); 1137 return FALSE; 1138 } 1139 eat_opt_white( &cur ); 1140 if (*cur != ',') { 1141 report_error( ctx, "Expected `,'" ); 1142 return FALSE; 1143 } 1144 ++cur; 1145 eat_opt_white( &cur ); 1146 for (j = 0; j < 4; ++j) { 1147 for (i = 0; i < PIPE_TYPE_COUNT; ++i) { 1148 if (str_match_no_case(&cur, type_names[i])) { 1149 if (!is_digit_alpha_underscore(cur)) { 1150 switch (j) { 1151 case 0: 1152 decl.Resource.ReturnTypeX = i; 1153 break; 1154 case 1: 1155 decl.Resource.ReturnTypeY = i; 1156 break; 1157 case 2: 1158 decl.Resource.ReturnTypeZ = i; 1159 break; 1160 case 3: 1161 decl.Resource.ReturnTypeW = i; 1162 break; 1163 default: 1164 assert(0); 1165 } 1166 break; 1167 } 1168 } 1169 } 1170 if (i == PIPE_TYPE_COUNT) { 1171 if (j == 0 || j > 2) { 1172 report_error(ctx, "Expected type name"); 1173 return FALSE; 1174 } 1175 break; 1176 } else { 1177 const char *cur2 = cur; 1178 eat_opt_white( &cur2 ); 1179 if (*cur2 == ',') { 1180 cur2++; 1181 eat_opt_white( &cur2 ); 1182 cur = cur2; 1183 continue; 1184 } else 1185 break; 1186 } 1187 } 1188 if (j < 4) { 1189 decl.Resource.ReturnTypeY = 1190 decl.Resource.ReturnTypeZ = 1191 decl.Resource.ReturnTypeW = 1192 decl.Resource.ReturnTypeX; 1193 } 1194 ctx->cur = cur; 1195 } else { 1196 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { 1197 if (str_match_no_case( &cur, semantic_names[i] )) { 1198 const char *cur2 = cur; 1199 uint index; 1200 1201 if (is_digit_alpha_underscore( cur )) 1202 continue; 1203 eat_opt_white( &cur2 ); 1204 if (*cur2 == '[') { 1205 cur2++; 1206 eat_opt_white( &cur2 ); 1207 if (!parse_uint( &cur2, &index )) { 1208 report_error( ctx, "Expected literal integer" ); 1209 return FALSE; 1210 } 1211 eat_opt_white( &cur2 ); 1212 if (*cur2 != ']') { 1213 report_error( ctx, "Expected `]'" ); 1214 return FALSE; 1215 } 1216 cur2++; 1217 1218 decl.Semantic.Index = index; 1219 1220 cur = cur2; 1221 } 1222 1223 decl.Declaration.Semantic = 1; 1224 decl.Semantic.Name = i; 1225 1226 ctx->cur = cur; 1227 break; 1228 } 1229 } 1230 } 1231 } else if (is_imm_array) { 1232 unsigned i; 1233 float *vals_itr; 1234 /* we have our immediate data */ 1235 if (*cur != '{') { 1236 report_error( ctx, "Immediate array without data" ); 1237 return FALSE; 1238 } 1239 ++cur; 1240 ctx->cur = cur; 1241 1242 decl.ImmediateData.u = 1243 MALLOC(sizeof(union tgsi_immediate_data) * 4 * 1244 (decl.Range.Last + 1)); 1245 vals_itr = (float*)decl.ImmediateData.u; 1246 for (i = 0; i <= decl.Range.Last; ++i) { 1247 if (!parse_immediate_data(ctx, vals_itr)) { 1248 FREE(decl.ImmediateData.u); 1249 return FALSE; 1250 } 1251 vals_itr += 4; 1252 eat_opt_white( &ctx->cur ); 1253 if (*ctx->cur != ',') { 1254 if (i != decl.Range.Last) { 1255 report_error( ctx, "Not enough data in immediate array!" ); 1256 FREE(decl.ImmediateData.u); 1257 return FALSE; 1258 } 1259 } else 1260 ++ctx->cur; 1261 } 1262 eat_opt_white( &ctx->cur ); 1263 if (*ctx->cur != '}') { 1264 FREE(decl.ImmediateData.u); 1265 report_error( ctx, "Immediate array data missing closing '}'" ); 1266 return FALSE; 1267 } 1268 ++ctx->cur; 1269 } 1270 1271 cur = ctx->cur; 1272 eat_opt_white( &cur ); 1273 if (*cur == ',' && !is_vs_input) { 1274 uint i; 1275 1276 cur++; 1277 eat_opt_white( &cur ); 1278 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { 1279 if (str_match_no_case( &cur, interpolate_names[i] )) { 1280 if (is_digit_alpha_underscore( cur )) 1281 continue; 1282 decl.Declaration.Interpolate = i; 1283 1284 ctx->cur = cur; 1285 break; 1286 } 1287 } 1288 if (i == TGSI_INTERPOLATE_COUNT) { 1289 report_error( ctx, "Expected semantic or interpolate attribute" ); 1290 return FALSE; 1291 } 1292 } 1293 1294 advance = tgsi_build_full_declaration( 1295 &decl, 1296 ctx->tokens_cur, 1297 ctx->header, 1298 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1299 1300 if (is_imm_array) 1301 FREE(decl.ImmediateData.u); 1302 1303 if (advance == 0) 1304 return FALSE; 1305 ctx->tokens_cur += advance; 1306 1307 return TRUE; 1308} 1309 1310static boolean parse_immediate( struct translate_ctx *ctx ) 1311{ 1312 struct tgsi_full_immediate imm; 1313 float values[4]; 1314 uint advance; 1315 1316 if (!eat_white( &ctx->cur )) { 1317 report_error( ctx, "Syntax error" ); 1318 return FALSE; 1319 } 1320 if (!str_match_no_case( &ctx->cur, "FLT32" ) || 1321 is_digit_alpha_underscore( ctx->cur )) { 1322 report_error( ctx, "Expected `FLT32'" ); 1323 return FALSE; 1324 } 1325 1326 parse_immediate_data(ctx, values); 1327 1328 imm = tgsi_default_full_immediate(); 1329 imm.Immediate.NrTokens += 4; 1330 imm.Immediate.DataType = TGSI_IMM_FLOAT32; 1331 imm.u[0].Float = values[0]; 1332 imm.u[1].Float = values[1]; 1333 imm.u[2].Float = values[2]; 1334 imm.u[3].Float = values[3]; 1335 1336 advance = tgsi_build_full_immediate( 1337 &imm, 1338 ctx->tokens_cur, 1339 ctx->header, 1340 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1341 if (advance == 0) 1342 return FALSE; 1343 ctx->tokens_cur += advance; 1344 1345 return TRUE; 1346} 1347 1348static boolean 1349parse_primitive( const char **pcur, uint *primitive ) 1350{ 1351 uint i; 1352 1353 for (i = 0; i < PIPE_PRIM_MAX; i++) { 1354 const char *cur = *pcur; 1355 1356 if (str_match_no_case( &cur, tgsi_primitive_names[i])) { 1357 *primitive = i; 1358 *pcur = cur; 1359 return TRUE; 1360 } 1361 } 1362 return FALSE; 1363} 1364 1365static boolean 1366parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) 1367{ 1368 uint i; 1369 1370 for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) { 1371 const char *cur = *pcur; 1372 1373 if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) { 1374 *fs_coord_origin = i; 1375 *pcur = cur; 1376 return TRUE; 1377 } 1378 } 1379 return FALSE; 1380} 1381 1382static boolean 1383parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) 1384{ 1385 uint i; 1386 1387 for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) { 1388 const char *cur = *pcur; 1389 1390 if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) { 1391 *fs_coord_pixel_center = i; 1392 *pcur = cur; 1393 return TRUE; 1394 } 1395 } 1396 return FALSE; 1397} 1398 1399 1400static boolean parse_property( struct translate_ctx *ctx ) 1401{ 1402 struct tgsi_full_property prop; 1403 uint property_name; 1404 uint values[8]; 1405 uint advance; 1406 char id[64]; 1407 1408 if (!eat_white( &ctx->cur )) { 1409 report_error( ctx, "Syntax error" ); 1410 return FALSE; 1411 } 1412 if (!parse_identifier( &ctx->cur, id )) { 1413 report_error( ctx, "Syntax error" ); 1414 return FALSE; 1415 } 1416 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; 1417 ++property_name) { 1418 if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) { 1419 break; 1420 } 1421 } 1422 if (property_name >= TGSI_PROPERTY_COUNT) { 1423 debug_printf( "\nError: Unknown property : '%s'", id ); 1424 return FALSE; 1425 } 1426 1427 eat_opt_white( &ctx->cur ); 1428 switch(property_name) { 1429 case TGSI_PROPERTY_GS_INPUT_PRIM: 1430 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 1431 if (!parse_primitive(&ctx->cur, &values[0] )) { 1432 report_error( ctx, "Unknown primitive name as property!" ); 1433 return FALSE; 1434 } 1435 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && 1436 ctx->processor == TGSI_PROCESSOR_GEOMETRY) { 1437 ctx->implied_array_size = u_vertices_per_prim(values[0]); 1438 } 1439 break; 1440 case TGSI_PROPERTY_FS_COORD_ORIGIN: 1441 if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) { 1442 report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" ); 1443 return FALSE; 1444 } 1445 break; 1446 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 1447 if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) { 1448 report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" ); 1449 return FALSE; 1450 } 1451 break; 1452 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: 1453 default: 1454 if (!parse_uint(&ctx->cur, &values[0] )) { 1455 report_error( ctx, "Expected unsigned integer as property!" ); 1456 return FALSE; 1457 } 1458 } 1459 1460 prop = tgsi_default_full_property(); 1461 prop.Property.PropertyName = property_name; 1462 prop.Property.NrTokens += 1; 1463 prop.u[0].Data = values[0]; 1464 1465 advance = tgsi_build_full_property( 1466 &prop, 1467 ctx->tokens_cur, 1468 ctx->header, 1469 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1470 if (advance == 0) 1471 return FALSE; 1472 ctx->tokens_cur += advance; 1473 1474 return TRUE; 1475} 1476 1477 1478static boolean translate( struct translate_ctx *ctx ) 1479{ 1480 eat_opt_white( &ctx->cur ); 1481 if (!parse_header( ctx )) 1482 return FALSE; 1483 1484 while (*ctx->cur != '\0') { 1485 uint label_val = 0; 1486 if (!eat_white( &ctx->cur )) { 1487 report_error( ctx, "Syntax error" ); 1488 return FALSE; 1489 } 1490 1491 if (*ctx->cur == '\0') 1492 break; 1493 if (parse_label( ctx, &label_val )) { 1494 if (!parse_instruction( ctx, TRUE )) 1495 return FALSE; 1496 } 1497 else if (str_match_no_case( &ctx->cur, "DCL" )) { 1498 if (!parse_declaration( ctx )) 1499 return FALSE; 1500 } 1501 else if (str_match_no_case( &ctx->cur, "IMM" )) { 1502 if (!parse_immediate( ctx )) 1503 return FALSE; 1504 } 1505 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) { 1506 if (!parse_property( ctx )) 1507 return FALSE; 1508 } 1509 else if (!parse_instruction( ctx, FALSE )) { 1510 return FALSE; 1511 } 1512 } 1513 1514 return TRUE; 1515} 1516 1517boolean 1518tgsi_text_translate( 1519 const char *text, 1520 struct tgsi_token *tokens, 1521 uint num_tokens ) 1522{ 1523 struct translate_ctx ctx; 1524 1525 ctx.text = text; 1526 ctx.cur = text; 1527 ctx.tokens = tokens; 1528 ctx.tokens_cur = tokens; 1529 ctx.tokens_end = tokens + num_tokens; 1530 1531 if (!translate( &ctx )) 1532 return FALSE; 1533 1534 return tgsi_sanity_check( tokens ); 1535} 1536