tgsi_text.c revision 2faf01c8403514dda15ab8b1a2309d5529dd06ba
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 parse_int( &ctx->cur, &brackets->index ); 471 else 472 brackets->index = 0; 473 } 474 else { 475 if (!parse_uint( &ctx->cur, &uindex )) { 476 report_error( ctx, "Expected literal unsigned integer" ); 477 return FALSE; 478 } 479 brackets->index = (int) uindex; 480 brackets->ind_file = TGSI_FILE_NULL; 481 brackets->ind_index = 0; 482 } 483 eat_opt_white( &ctx->cur ); 484 if (*ctx->cur != ']') { 485 report_error( ctx, "Expected `]'" ); 486 return FALSE; 487 } 488 ctx->cur++; 489 return TRUE; 490} 491 492static boolean 493parse_opt_register_src_bracket( 494 struct translate_ctx *ctx, 495 struct parsed_bracket *brackets, 496 int *parsed_brackets) 497{ 498 const char *cur = ctx->cur; 499 500 *parsed_brackets = 0; 501 502 eat_opt_white( &cur ); 503 if (cur[0] == '[') { 504 ++cur; 505 ctx->cur = cur; 506 507 if (!parse_register_bracket(ctx, brackets)) 508 return FALSE; 509 510 *parsed_brackets = 1; 511 } 512 513 return TRUE; 514} 515 516 517/* Parse source register operand. 518 * <register_src> ::= <register_file_bracket_index> `]' | 519 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' | 520 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' | 521 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]' 522 */ 523static boolean 524parse_register_src( 525 struct translate_ctx *ctx, 526 uint *file, 527 struct parsed_bracket *brackets) 528{ 529 brackets->ind_comp = TGSI_SWIZZLE_X; 530 if (!parse_register_file_bracket( ctx, file )) 531 return FALSE; 532 if (!parse_register_bracket( ctx, brackets )) 533 return FALSE; 534 535 return TRUE; 536} 537 538struct parsed_dcl_bracket { 539 uint first; 540 uint last; 541}; 542 543static boolean 544parse_register_dcl_bracket( 545 struct translate_ctx *ctx, 546 struct parsed_dcl_bracket *bracket) 547{ 548 uint uindex; 549 memset(bracket, 0, sizeof(struct parsed_dcl_bracket)); 550 551 eat_opt_white( &ctx->cur ); 552 553 if (!parse_uint( &ctx->cur, &uindex )) { 554 /* it can be an empty bracket [] which means its range 555 * is from 0 to some implied size */ 556 if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) { 557 bracket->first = 0; 558 bracket->last = ctx->implied_array_size - 1; 559 goto cleanup; 560 } 561 report_error( ctx, "Expected literal unsigned integer" ); 562 return FALSE; 563 } 564 bracket->first = uindex; 565 566 eat_opt_white( &ctx->cur ); 567 568 if (ctx->cur[0] == '.' && ctx->cur[1] == '.') { 569 uint uindex; 570 571 ctx->cur += 2; 572 eat_opt_white( &ctx->cur ); 573 if (!parse_uint( &ctx->cur, &uindex )) { 574 report_error( ctx, "Expected literal integer" ); 575 return FALSE; 576 } 577 bracket->last = (int) uindex; 578 eat_opt_white( &ctx->cur ); 579 } 580 else { 581 bracket->last = bracket->first; 582 } 583 584cleanup: 585 if (*ctx->cur != ']') { 586 report_error( ctx, "Expected `]' or `..'" ); 587 return FALSE; 588 } 589 ctx->cur++; 590 return TRUE; 591} 592 593/* Parse register declaration. 594 * <register_dcl> ::= <register_file_bracket_index> `]' | 595 * <register_file_bracket_index> `..' <index> `]' 596 */ 597static boolean 598parse_register_dcl( 599 struct translate_ctx *ctx, 600 uint *file, 601 struct parsed_dcl_bracket *brackets, 602 int *num_brackets) 603{ 604 const char *cur; 605 606 *num_brackets = 0; 607 608 if (!parse_register_file_bracket( ctx, file )) 609 return FALSE; 610 if (!parse_register_dcl_bracket( ctx, &brackets[0] )) 611 return FALSE; 612 613 *num_brackets = 1; 614 615 cur = ctx->cur; 616 eat_opt_white( &cur ); 617 618 if (cur[0] == '[') { 619 ++cur; 620 ctx->cur = cur; 621 if (!parse_register_dcl_bracket( ctx, &brackets[1] )) 622 return FALSE; 623 /* for geometry shader we don't really care about 624 * the first brackets it's always the size of the 625 * input primitive. so we want to declare just 626 * the index relevant to the semantics which is in 627 * the second bracket */ 628 if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) { 629 brackets[0] = brackets[1]; 630 *num_brackets = 1; 631 } else { 632 *num_brackets = 2; 633 } 634 } 635 636 return TRUE; 637} 638 639 640/* Parse destination register operand.*/ 641static boolean 642parse_register_dst( 643 struct translate_ctx *ctx, 644 uint *file, 645 struct parsed_bracket *brackets) 646{ 647 brackets->ind_comp = TGSI_SWIZZLE_X; 648 if (!parse_register_file_bracket( ctx, file )) 649 return FALSE; 650 if (!parse_register_bracket( ctx, brackets )) 651 return FALSE; 652 653 return TRUE; 654} 655 656static boolean 657parse_dst_operand( 658 struct translate_ctx *ctx, 659 struct tgsi_full_dst_register *dst ) 660{ 661 uint file; 662 uint writemask; 663 const char *cur; 664 struct parsed_bracket bracket[2]; 665 int parsed_opt_brackets; 666 667 if (!parse_register_dst( ctx, &file, &bracket[0] )) 668 return FALSE; 669 if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets)) 670 return FALSE; 671 672 cur = ctx->cur; 673 eat_opt_white( &cur ); 674 675 if (!parse_opt_writemask( ctx, &writemask )) 676 return FALSE; 677 678 dst->Register.File = file; 679 if (parsed_opt_brackets) { 680 dst->Register.Dimension = 1; 681 dst->Dimension.Indirect = 0; 682 dst->Dimension.Dimension = 0; 683 dst->Dimension.Index = bracket[0].index; 684 bracket[0] = bracket[1]; 685 } 686 dst->Register.Index = bracket[0].index; 687 dst->Register.WriteMask = writemask; 688 if (bracket[0].ind_file != TGSI_FILE_NULL) { 689 dst->Register.Indirect = 1; 690 dst->Indirect.File = bracket[0].ind_file; 691 dst->Indirect.Index = bracket[0].ind_index; 692 dst->Indirect.SwizzleX = bracket[0].ind_comp; 693 dst->Indirect.SwizzleY = bracket[0].ind_comp; 694 dst->Indirect.SwizzleZ = bracket[0].ind_comp; 695 dst->Indirect.SwizzleW = bracket[0].ind_comp; 696 } 697 return TRUE; 698} 699 700static boolean 701parse_optional_swizzle( 702 struct translate_ctx *ctx, 703 uint swizzle[4], 704 boolean *parsed_swizzle ) 705{ 706 const char *cur = ctx->cur; 707 708 *parsed_swizzle = FALSE; 709 710 eat_opt_white( &cur ); 711 if (*cur == '.') { 712 uint i; 713 714 cur++; 715 eat_opt_white( &cur ); 716 for (i = 0; i < 4; i++) { 717 if (uprcase( *cur ) == 'X') 718 swizzle[i] = TGSI_SWIZZLE_X; 719 else if (uprcase( *cur ) == 'Y') 720 swizzle[i] = TGSI_SWIZZLE_Y; 721 else if (uprcase( *cur ) == 'Z') 722 swizzle[i] = TGSI_SWIZZLE_Z; 723 else if (uprcase( *cur ) == 'W') 724 swizzle[i] = TGSI_SWIZZLE_W; 725 else { 726 report_error( ctx, "Expected register swizzle component `x', `y', `z' or `w'" ); 727 return FALSE; 728 } 729 cur++; 730 } 731 *parsed_swizzle = TRUE; 732 ctx->cur = cur; 733 } 734 return TRUE; 735} 736 737static boolean 738parse_src_operand( 739 struct translate_ctx *ctx, 740 struct tgsi_full_src_register *src ) 741{ 742 uint file; 743 uint swizzle[4]; 744 boolean parsed_swizzle; 745 struct parsed_bracket bracket[2]; 746 int parsed_opt_brackets; 747 748 if (*ctx->cur == '-') { 749 ctx->cur++; 750 eat_opt_white( &ctx->cur ); 751 src->Register.Negate = 1; 752 } 753 754 if (*ctx->cur == '|') { 755 ctx->cur++; 756 eat_opt_white( &ctx->cur ); 757 src->Register.Absolute = 1; 758 } 759 760 if (!parse_register_src(ctx, &file, &bracket[0])) 761 return FALSE; 762 if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets)) 763 return FALSE; 764 765 src->Register.File = file; 766 if (parsed_opt_brackets) { 767 src->Register.Dimension = 1; 768 src->Dimension.Indirect = 0; 769 src->Dimension.Dimension = 0; 770 src->Dimension.Index = bracket[0].index; 771 bracket[0] = bracket[1]; 772 } 773 src->Register.Index = bracket[0].index; 774 if (bracket[0].ind_file != TGSI_FILE_NULL) { 775 src->Register.Indirect = 1; 776 src->Indirect.File = bracket[0].ind_file; 777 src->Indirect.Index = bracket[0].ind_index; 778 src->Indirect.SwizzleX = bracket[0].ind_comp; 779 src->Indirect.SwizzleY = bracket[0].ind_comp; 780 src->Indirect.SwizzleZ = bracket[0].ind_comp; 781 src->Indirect.SwizzleW = bracket[0].ind_comp; 782 } 783 784 /* Parse optional swizzle. 785 */ 786 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { 787 if (parsed_swizzle) { 788 src->Register.SwizzleX = swizzle[0]; 789 src->Register.SwizzleY = swizzle[1]; 790 src->Register.SwizzleZ = swizzle[2]; 791 src->Register.SwizzleW = swizzle[3]; 792 } 793 } 794 795 if (src->Register.Absolute) { 796 eat_opt_white( &ctx->cur ); 797 if (*ctx->cur != '|') { 798 report_error( ctx, "Expected `|'" ); 799 return FALSE; 800 } 801 ctx->cur++; 802 } 803 804 805 return TRUE; 806} 807 808static boolean 809match_inst_mnemonic(const char **pcur, 810 const struct tgsi_opcode_info *info) 811{ 812 if (str_match_no_case(pcur, info->mnemonic)) { 813 return TRUE; 814 } 815 return FALSE; 816} 817 818static boolean 819parse_instruction( 820 struct translate_ctx *ctx, 821 boolean has_label ) 822{ 823 uint i; 824 uint saturate = TGSI_SAT_NONE; 825 const struct tgsi_opcode_info *info; 826 struct tgsi_full_instruction inst; 827 const char *cur; 828 uint advance; 829 830 inst = tgsi_default_full_instruction(); 831 832 /* Parse predicate. 833 */ 834 eat_opt_white( &ctx->cur ); 835 if (*ctx->cur == '(') { 836 uint file; 837 int index; 838 uint swizzle[4]; 839 boolean parsed_swizzle; 840 841 inst.Instruction.Predicate = 1; 842 843 ctx->cur++; 844 if (*ctx->cur == '!') { 845 ctx->cur++; 846 inst.Predicate.Negate = 1; 847 } 848 849 if (!parse_register_1d( ctx, &file, &index )) 850 return FALSE; 851 852 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { 853 if (parsed_swizzle) { 854 inst.Predicate.SwizzleX = swizzle[0]; 855 inst.Predicate.SwizzleY = swizzle[1]; 856 inst.Predicate.SwizzleZ = swizzle[2]; 857 inst.Predicate.SwizzleW = swizzle[3]; 858 } 859 } 860 861 if (*ctx->cur != ')') { 862 report_error( ctx, "Expected `)'" ); 863 return FALSE; 864 } 865 866 ctx->cur++; 867 } 868 869 /* Parse instruction name. 870 */ 871 eat_opt_white( &ctx->cur ); 872 for (i = 0; i < TGSI_OPCODE_LAST; i++) { 873 cur = ctx->cur; 874 875 info = tgsi_get_opcode_info( i ); 876 if (match_inst_mnemonic(&cur, info)) { 877 if (str_match_no_case( &cur, "_SATNV" )) 878 saturate = TGSI_SAT_MINUS_PLUS_ONE; 879 else if (str_match_no_case( &cur, "_SAT" )) 880 saturate = TGSI_SAT_ZERO_ONE; 881 882 if (info->num_dst + info->num_src + info->is_tex == 0) { 883 if (!is_digit_alpha_underscore( cur )) { 884 ctx->cur = cur; 885 break; 886 } 887 } 888 else if (*cur == '\0' || eat_white( &cur )) { 889 ctx->cur = cur; 890 break; 891 } 892 } 893 } 894 if (i == TGSI_OPCODE_LAST) { 895 if (has_label) 896 report_error( ctx, "Unknown opcode" ); 897 else 898 report_error( ctx, "Expected `DCL', `IMM' or a label" ); 899 return FALSE; 900 } 901 902 inst.Instruction.Opcode = i; 903 inst.Instruction.Saturate = saturate; 904 inst.Instruction.NumDstRegs = info->num_dst; 905 inst.Instruction.NumSrcRegs = info->num_src; 906 907 /* Parse instruction operands. 908 */ 909 for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { 910 if (i > 0) { 911 eat_opt_white( &ctx->cur ); 912 if (*ctx->cur != ',') { 913 report_error( ctx, "Expected `,'" ); 914 return FALSE; 915 } 916 ctx->cur++; 917 eat_opt_white( &ctx->cur ); 918 } 919 920 if (i < info->num_dst) { 921 if (!parse_dst_operand( ctx, &inst.Dst[i] )) 922 return FALSE; 923 } 924 else if (i < info->num_dst + info->num_src) { 925 if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) 926 return FALSE; 927 } 928 else { 929 uint j; 930 931 for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { 932 if (str_match_no_case( &ctx->cur, tgsi_texture_names[j] )) { 933 if (!is_digit_alpha_underscore( ctx->cur )) { 934 inst.Instruction.Texture = 1; 935 inst.Texture.Texture = j; 936 break; 937 } 938 } 939 } 940 if (j == TGSI_TEXTURE_COUNT) { 941 report_error( ctx, "Expected texture target" ); 942 return FALSE; 943 } 944 } 945 } 946 947 cur = ctx->cur; 948 eat_opt_white( &cur ); 949 if (info->is_branch && *cur == ':') { 950 uint target; 951 952 cur++; 953 eat_opt_white( &cur ); 954 if (!parse_uint( &cur, &target )) { 955 report_error( ctx, "Expected a label" ); 956 return FALSE; 957 } 958 inst.Instruction.Label = 1; 959 inst.Label.Label = target; 960 ctx->cur = cur; 961 } 962 963 advance = tgsi_build_full_instruction( 964 &inst, 965 ctx->tokens_cur, 966 ctx->header, 967 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 968 if (advance == 0) 969 return FALSE; 970 ctx->tokens_cur += advance; 971 972 return TRUE; 973} 974 975/* parses a 4-touple of the form {x, y, z, w} 976 * where x, y, z, w are numbers */ 977static boolean parse_immediate_data(struct translate_ctx *ctx, unsigned type, 978 union tgsi_immediate_data *values) 979{ 980 unsigned i; 981 int ret; 982 983 eat_opt_white( &ctx->cur ); 984 if (*ctx->cur != '{') { 985 report_error( ctx, "Expected `{'" ); 986 return FALSE; 987 } 988 ctx->cur++; 989 for (i = 0; i < 4; i++) { 990 eat_opt_white( &ctx->cur ); 991 if (i > 0) { 992 if (*ctx->cur != ',') { 993 report_error( ctx, "Expected `,'" ); 994 return FALSE; 995 } 996 ctx->cur++; 997 eat_opt_white( &ctx->cur ); 998 } 999 1000 switch (type) { 1001 case TGSI_IMM_FLOAT32: 1002 ret = parse_float(&ctx->cur, &values[i].Float); 1003 break; 1004 case TGSI_IMM_UINT32: 1005 ret = parse_uint(&ctx->cur, &values[i].Uint); 1006 break; 1007 case TGSI_IMM_INT32: 1008 ret = parse_int(&ctx->cur, &values[i].Int); 1009 break; 1010 } 1011 1012 if (!ret) { 1013 report_error( ctx, "Expected immediate constant" ); 1014 return FALSE; 1015 } 1016 } 1017 eat_opt_white( &ctx->cur ); 1018 if (*ctx->cur != '}') { 1019 report_error( ctx, "Expected `}'" ); 1020 return FALSE; 1021 } 1022 ctx->cur++; 1023 1024 return TRUE; 1025} 1026 1027static boolean parse_declaration( struct translate_ctx *ctx ) 1028{ 1029 struct tgsi_full_declaration decl; 1030 uint file; 1031 struct parsed_dcl_bracket brackets[2]; 1032 int num_brackets; 1033 uint writemask; 1034 const char *cur, *cur2; 1035 uint advance; 1036 boolean is_vs_input; 1037 boolean is_imm_array; 1038 1039 if (!eat_white( &ctx->cur )) { 1040 report_error( ctx, "Syntax error" ); 1041 return FALSE; 1042 } 1043 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) 1044 return FALSE; 1045 if (!parse_opt_writemask( ctx, &writemask )) 1046 return FALSE; 1047 1048 decl = tgsi_default_full_declaration(); 1049 decl.Declaration.File = file; 1050 decl.Declaration.UsageMask = writemask; 1051 1052 if (num_brackets == 1) { 1053 decl.Range.First = brackets[0].first; 1054 decl.Range.Last = brackets[0].last; 1055 } else { 1056 decl.Range.First = brackets[1].first; 1057 decl.Range.Last = brackets[1].last; 1058 1059 decl.Declaration.Dimension = 1; 1060 decl.Dim.Index2D = brackets[0].first; 1061 } 1062 1063 is_vs_input = (file == TGSI_FILE_INPUT && 1064 ctx->processor == TGSI_PROCESSOR_VERTEX); 1065 is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY); 1066 1067 cur = ctx->cur; 1068 eat_opt_white( &cur ); 1069 if (*cur == ',' && !is_vs_input) { 1070 uint i, j; 1071 1072 cur++; 1073 eat_opt_white( &cur ); 1074 if (file == TGSI_FILE_RESOURCE) { 1075 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { 1076 if (str_match_no_case(&cur, tgsi_texture_names[i])) { 1077 if (!is_digit_alpha_underscore(cur)) { 1078 decl.Resource.Resource = i; 1079 break; 1080 } 1081 } 1082 } 1083 if (i == TGSI_TEXTURE_COUNT) { 1084 report_error(ctx, "Expected texture target"); 1085 return FALSE; 1086 } 1087 1088 cur2 = cur; 1089 eat_opt_white(&cur2); 1090 while (*cur2 == ',') { 1091 cur2++; 1092 eat_opt_white(&cur2); 1093 if (str_match_no_case(&cur2, "RAW") && 1094 !is_digit_alpha_underscore(cur2)) { 1095 decl.Resource.Raw = 1; 1096 1097 } else if (str_match_no_case(&cur2, "WR") && 1098 !is_digit_alpha_underscore(cur2)) { 1099 decl.Resource.Writable = 1; 1100 1101 } else { 1102 break; 1103 } 1104 cur = cur2; 1105 eat_opt_white(&cur2); 1106 } 1107 1108 ctx->cur = cur; 1109 1110 } else if (file == TGSI_FILE_SAMPLER_VIEW) { 1111 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { 1112 if (str_match_no_case(&cur, tgsi_texture_names[i])) { 1113 if (!is_digit_alpha_underscore(cur)) { 1114 decl.SamplerView.Resource = i; 1115 break; 1116 } 1117 } 1118 } 1119 if (i == TGSI_TEXTURE_COUNT) { 1120 report_error(ctx, "Expected texture target"); 1121 return FALSE; 1122 } 1123 eat_opt_white( &cur ); 1124 if (*cur != ',') { 1125 report_error( ctx, "Expected `,'" ); 1126 return FALSE; 1127 } 1128 ++cur; 1129 eat_opt_white( &cur ); 1130 for (j = 0; j < 4; ++j) { 1131 for (i = 0; i < PIPE_TYPE_COUNT; ++i) { 1132 if (str_match_no_case(&cur, tgsi_type_names[i])) { 1133 if (!is_digit_alpha_underscore(cur)) { 1134 switch (j) { 1135 case 0: 1136 decl.SamplerView.ReturnTypeX = i; 1137 break; 1138 case 1: 1139 decl.SamplerView.ReturnTypeY = i; 1140 break; 1141 case 2: 1142 decl.SamplerView.ReturnTypeZ = i; 1143 break; 1144 case 3: 1145 decl.SamplerView.ReturnTypeW = i; 1146 break; 1147 default: 1148 assert(0); 1149 } 1150 break; 1151 } 1152 } 1153 } 1154 if (i == PIPE_TYPE_COUNT) { 1155 if (j == 0 || j > 2) { 1156 report_error(ctx, "Expected type name"); 1157 return FALSE; 1158 } 1159 break; 1160 } else { 1161 cur2 = cur; 1162 eat_opt_white( &cur2 ); 1163 if (*cur2 == ',') { 1164 cur2++; 1165 eat_opt_white( &cur2 ); 1166 cur = cur2; 1167 continue; 1168 } else 1169 break; 1170 } 1171 } 1172 if (j < 4) { 1173 decl.SamplerView.ReturnTypeY = 1174 decl.SamplerView.ReturnTypeZ = 1175 decl.SamplerView.ReturnTypeW = 1176 decl.SamplerView.ReturnTypeX; 1177 } 1178 ctx->cur = cur; 1179 } else { 1180 if (str_match_no_case(&cur, "LOCAL") && 1181 !is_digit_alpha_underscore(cur)) { 1182 decl.Declaration.Local = 1; 1183 ctx->cur = cur; 1184 } 1185 1186 cur = ctx->cur; 1187 eat_opt_white( &cur ); 1188 if (*cur == ',') { 1189 cur++; 1190 eat_opt_white( &cur ); 1191 1192 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { 1193 if (str_match_no_case( &cur, tgsi_semantic_names[i] )) { 1194 uint index; 1195 1196 if (is_digit_alpha_underscore( cur )) 1197 continue; 1198 cur2 = cur; 1199 eat_opt_white( &cur2 ); 1200 if (*cur2 == '[') { 1201 cur2++; 1202 eat_opt_white( &cur2 ); 1203 if (!parse_uint( &cur2, &index )) { 1204 report_error( ctx, "Expected literal integer" ); 1205 return FALSE; 1206 } 1207 eat_opt_white( &cur2 ); 1208 if (*cur2 != ']') { 1209 report_error( ctx, "Expected `]'" ); 1210 return FALSE; 1211 } 1212 cur2++; 1213 1214 decl.Semantic.Index = index; 1215 1216 cur = cur2; 1217 } 1218 1219 decl.Declaration.Semantic = 1; 1220 decl.Semantic.Name = i; 1221 1222 ctx->cur = cur; 1223 break; 1224 } 1225 } 1226 } 1227 } 1228 } else if (is_imm_array) { 1229 unsigned i; 1230 union tgsi_immediate_data *vals_itr; 1231 /* we have our immediate data */ 1232 if (*cur != '{') { 1233 report_error( ctx, "Immediate array without data" ); 1234 return FALSE; 1235 } 1236 ++cur; 1237 ctx->cur = cur; 1238 1239 decl.ImmediateData.u = 1240 MALLOC(sizeof(union tgsi_immediate_data) * 4 * 1241 (decl.Range.Last + 1)); 1242 vals_itr = decl.ImmediateData.u; 1243 for (i = 0; i <= decl.Range.Last; ++i) { 1244 if (!parse_immediate_data(ctx, TGSI_IMM_FLOAT32, vals_itr)) { 1245 FREE(decl.ImmediateData.u); 1246 return FALSE; 1247 } 1248 vals_itr += 4; 1249 eat_opt_white( &ctx->cur ); 1250 if (*ctx->cur != ',') { 1251 if (i != decl.Range.Last) { 1252 report_error( ctx, "Not enough data in immediate array!" ); 1253 FREE(decl.ImmediateData.u); 1254 return FALSE; 1255 } 1256 } else 1257 ++ctx->cur; 1258 } 1259 eat_opt_white( &ctx->cur ); 1260 if (*ctx->cur != '}') { 1261 FREE(decl.ImmediateData.u); 1262 report_error( ctx, "Immediate array data missing closing '}'" ); 1263 return FALSE; 1264 } 1265 ++ctx->cur; 1266 } 1267 1268 cur = ctx->cur; 1269 eat_opt_white( &cur ); 1270 if (*cur == ',' && !is_vs_input) { 1271 uint i; 1272 1273 cur++; 1274 eat_opt_white( &cur ); 1275 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { 1276 if (str_match_no_case( &cur, tgsi_interpolate_names[i] )) { 1277 if (is_digit_alpha_underscore( cur )) 1278 continue; 1279 decl.Declaration.Interpolate = 1; 1280 decl.Interp.Interpolate = i; 1281 1282 ctx->cur = cur; 1283 break; 1284 } 1285 } 1286 if (i == TGSI_INTERPOLATE_COUNT) { 1287 report_error( ctx, "Expected semantic or interpolate attribute" ); 1288 return FALSE; 1289 } 1290 } 1291 1292 advance = tgsi_build_full_declaration( 1293 &decl, 1294 ctx->tokens_cur, 1295 ctx->header, 1296 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1297 1298 if (is_imm_array) 1299 FREE(decl.ImmediateData.u); 1300 1301 if (advance == 0) 1302 return FALSE; 1303 ctx->tokens_cur += advance; 1304 1305 return TRUE; 1306} 1307 1308static boolean parse_immediate( struct translate_ctx *ctx ) 1309{ 1310 struct tgsi_full_immediate imm; 1311 uint advance; 1312 int type; 1313 1314 if (!eat_white( &ctx->cur )) { 1315 report_error( ctx, "Syntax error" ); 1316 return FALSE; 1317 } 1318 for (type = 0; type < Elements(tgsi_immediate_type_names); ++type) { 1319 if (str_match_no_case(&ctx->cur, tgsi_immediate_type_names[type]) && 1320 !is_digit_alpha_underscore(ctx->cur)) 1321 break; 1322 } 1323 if (type == Elements(tgsi_immediate_type_names)) { 1324 report_error( ctx, "Expected immediate type" ); 1325 return FALSE; 1326 } 1327 1328 imm = tgsi_default_full_immediate(); 1329 imm.Immediate.NrTokens += 4; 1330 imm.Immediate.DataType = type; 1331 parse_immediate_data(ctx, type, imm.u); 1332 1333 advance = tgsi_build_full_immediate( 1334 &imm, 1335 ctx->tokens_cur, 1336 ctx->header, 1337 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1338 if (advance == 0) 1339 return FALSE; 1340 ctx->tokens_cur += advance; 1341 1342 return TRUE; 1343} 1344 1345static boolean 1346parse_primitive( const char **pcur, uint *primitive ) 1347{ 1348 uint i; 1349 1350 for (i = 0; i < PIPE_PRIM_MAX; i++) { 1351 const char *cur = *pcur; 1352 1353 if (str_match_no_case( &cur, tgsi_primitive_names[i])) { 1354 *primitive = i; 1355 *pcur = cur; 1356 return TRUE; 1357 } 1358 } 1359 return FALSE; 1360} 1361 1362static boolean 1363parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) 1364{ 1365 uint i; 1366 1367 for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) { 1368 const char *cur = *pcur; 1369 1370 if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) { 1371 *fs_coord_origin = i; 1372 *pcur = cur; 1373 return TRUE; 1374 } 1375 } 1376 return FALSE; 1377} 1378 1379static boolean 1380parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) 1381{ 1382 uint i; 1383 1384 for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) { 1385 const char *cur = *pcur; 1386 1387 if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) { 1388 *fs_coord_pixel_center = i; 1389 *pcur = cur; 1390 return TRUE; 1391 } 1392 } 1393 return FALSE; 1394} 1395 1396 1397static boolean parse_property( struct translate_ctx *ctx ) 1398{ 1399 struct tgsi_full_property prop; 1400 uint property_name; 1401 uint values[8]; 1402 uint advance; 1403 char id[64]; 1404 1405 if (!eat_white( &ctx->cur )) { 1406 report_error( ctx, "Syntax error" ); 1407 return FALSE; 1408 } 1409 if (!parse_identifier( &ctx->cur, id )) { 1410 report_error( ctx, "Syntax error" ); 1411 return FALSE; 1412 } 1413 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; 1414 ++property_name) { 1415 if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) { 1416 break; 1417 } 1418 } 1419 if (property_name >= TGSI_PROPERTY_COUNT) { 1420 debug_printf( "\nError: Unknown property : '%s'", id ); 1421 return FALSE; 1422 } 1423 1424 eat_opt_white( &ctx->cur ); 1425 switch(property_name) { 1426 case TGSI_PROPERTY_GS_INPUT_PRIM: 1427 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 1428 if (!parse_primitive(&ctx->cur, &values[0] )) { 1429 report_error( ctx, "Unknown primitive name as property!" ); 1430 return FALSE; 1431 } 1432 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && 1433 ctx->processor == TGSI_PROCESSOR_GEOMETRY) { 1434 ctx->implied_array_size = u_vertices_per_prim(values[0]); 1435 } 1436 break; 1437 case TGSI_PROPERTY_FS_COORD_ORIGIN: 1438 if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) { 1439 report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" ); 1440 return FALSE; 1441 } 1442 break; 1443 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 1444 if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) { 1445 report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" ); 1446 return FALSE; 1447 } 1448 break; 1449 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: 1450 default: 1451 if (!parse_uint(&ctx->cur, &values[0] )) { 1452 report_error( ctx, "Expected unsigned integer as property!" ); 1453 return FALSE; 1454 } 1455 } 1456 1457 prop = tgsi_default_full_property(); 1458 prop.Property.PropertyName = property_name; 1459 prop.Property.NrTokens += 1; 1460 prop.u[0].Data = values[0]; 1461 1462 advance = tgsi_build_full_property( 1463 &prop, 1464 ctx->tokens_cur, 1465 ctx->header, 1466 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1467 if (advance == 0) 1468 return FALSE; 1469 ctx->tokens_cur += advance; 1470 1471 return TRUE; 1472} 1473 1474 1475static boolean translate( struct translate_ctx *ctx ) 1476{ 1477 eat_opt_white( &ctx->cur ); 1478 if (!parse_header( ctx )) 1479 return FALSE; 1480 1481 while (*ctx->cur != '\0') { 1482 uint label_val = 0; 1483 if (!eat_white( &ctx->cur )) { 1484 report_error( ctx, "Syntax error" ); 1485 return FALSE; 1486 } 1487 1488 if (*ctx->cur == '\0') 1489 break; 1490 if (parse_label( ctx, &label_val )) { 1491 if (!parse_instruction( ctx, TRUE )) 1492 return FALSE; 1493 } 1494 else if (str_match_no_case( &ctx->cur, "DCL" )) { 1495 if (!parse_declaration( ctx )) 1496 return FALSE; 1497 } 1498 else if (str_match_no_case( &ctx->cur, "IMM" )) { 1499 if (!parse_immediate( ctx )) 1500 return FALSE; 1501 } 1502 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) { 1503 if (!parse_property( ctx )) 1504 return FALSE; 1505 } 1506 else if (!parse_instruction( ctx, FALSE )) { 1507 return FALSE; 1508 } 1509 } 1510 1511 return TRUE; 1512} 1513 1514boolean 1515tgsi_text_translate( 1516 const char *text, 1517 struct tgsi_token *tokens, 1518 uint num_tokens ) 1519{ 1520 struct translate_ctx ctx; 1521 1522 ctx.text = text; 1523 ctx.cur = text; 1524 ctx.tokens = tokens; 1525 ctx.tokens_cur = tokens; 1526 ctx.tokens_end = tokens + num_tokens; 1527 1528 if (!translate( &ctx )) 1529 return FALSE; 1530 1531 return tgsi_sanity_check( tokens ); 1532} 1533