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