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