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