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