tgsi_text.c revision a426b0d5bce24659a19c72af27a5aa4871782f9d
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 const char *cur; 825 uint advance; 826 827 inst = tgsi_default_full_instruction(); 828 829 /* Parse predicate. 830 */ 831 eat_opt_white( &ctx->cur ); 832 if (*ctx->cur == '(') { 833 uint file; 834 int index; 835 uint swizzle[4]; 836 boolean parsed_swizzle; 837 838 inst.Instruction.Predicate = 1; 839 840 ctx->cur++; 841 if (*ctx->cur == '!') { 842 ctx->cur++; 843 inst.Predicate.Negate = 1; 844 } 845 846 if (!parse_register_1d( ctx, &file, &index )) 847 return FALSE; 848 849 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { 850 if (parsed_swizzle) { 851 inst.Predicate.SwizzleX = swizzle[0]; 852 inst.Predicate.SwizzleY = swizzle[1]; 853 inst.Predicate.SwizzleZ = swizzle[2]; 854 inst.Predicate.SwizzleW = swizzle[3]; 855 } 856 } 857 858 if (*ctx->cur != ')') { 859 report_error( ctx, "Expected `)'" ); 860 return FALSE; 861 } 862 863 ctx->cur++; 864 } 865 866 /* Parse instruction name. 867 */ 868 eat_opt_white( &ctx->cur ); 869 for (i = 0; i < TGSI_OPCODE_LAST; i++) { 870 cur = ctx->cur; 871 872 info = tgsi_get_opcode_info( i ); 873 if (match_inst_mnemonic(&cur, info)) { 874 if (str_match_no_case( &cur, "_SATNV" )) 875 saturate = TGSI_SAT_MINUS_PLUS_ONE; 876 else if (str_match_no_case( &cur, "_SAT" )) 877 saturate = TGSI_SAT_ZERO_ONE; 878 879 if (info->num_dst + info->num_src + info->is_tex == 0) { 880 if (!is_digit_alpha_underscore( cur )) { 881 ctx->cur = cur; 882 break; 883 } 884 } 885 else if (*cur == '\0' || eat_white( &cur )) { 886 ctx->cur = cur; 887 break; 888 } 889 } 890 } 891 if (i == TGSI_OPCODE_LAST) { 892 if (has_label) 893 report_error( ctx, "Unknown opcode" ); 894 else 895 report_error( ctx, "Expected `DCL', `IMM' or a label" ); 896 return FALSE; 897 } 898 899 inst.Instruction.Opcode = i; 900 inst.Instruction.Saturate = saturate; 901 inst.Instruction.NumDstRegs = info->num_dst; 902 inst.Instruction.NumSrcRegs = info->num_src; 903 904 /* Parse instruction operands. 905 */ 906 for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { 907 if (i > 0) { 908 eat_opt_white( &ctx->cur ); 909 if (*ctx->cur != ',') { 910 report_error( ctx, "Expected `,'" ); 911 return FALSE; 912 } 913 ctx->cur++; 914 eat_opt_white( &ctx->cur ); 915 } 916 917 if (i < info->num_dst) { 918 if (!parse_dst_operand( ctx, &inst.Dst[i] )) 919 return FALSE; 920 } 921 else if (i < info->num_dst + info->num_src) { 922 if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) 923 return FALSE; 924 } 925 else { 926 uint j; 927 928 for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { 929 if (str_match_no_case( &ctx->cur, tgsi_texture_names[j] )) { 930 if (!is_digit_alpha_underscore( ctx->cur )) { 931 inst.Instruction.Texture = 1; 932 inst.Texture.Texture = j; 933 break; 934 } 935 } 936 } 937 if (j == TGSI_TEXTURE_COUNT) { 938 report_error( ctx, "Expected texture target" ); 939 return FALSE; 940 } 941 } 942 } 943 944 cur = ctx->cur; 945 eat_opt_white( &cur ); 946 if (info->is_branch && *cur == ':') { 947 uint target; 948 949 cur++; 950 eat_opt_white( &cur ); 951 if (!parse_uint( &cur, &target )) { 952 report_error( ctx, "Expected a label" ); 953 return FALSE; 954 } 955 inst.Instruction.Label = 1; 956 inst.Label.Label = target; 957 ctx->cur = cur; 958 } 959 960 advance = tgsi_build_full_instruction( 961 &inst, 962 ctx->tokens_cur, 963 ctx->header, 964 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 965 if (advance == 0) 966 return FALSE; 967 ctx->tokens_cur += advance; 968 969 return TRUE; 970} 971 972/* parses a 4-touple of the form {x, y, z, w} 973 * where x, y, z, w are numbers */ 974static boolean parse_immediate_data(struct translate_ctx *ctx, 975 float *values) 976{ 977 unsigned i; 978 979 eat_opt_white( &ctx->cur ); 980 if (*ctx->cur != '{') { 981 report_error( ctx, "Expected `{'" ); 982 return FALSE; 983 } 984 ctx->cur++; 985 for (i = 0; i < 4; i++) { 986 eat_opt_white( &ctx->cur ); 987 if (i > 0) { 988 if (*ctx->cur != ',') { 989 report_error( ctx, "Expected `,'" ); 990 return FALSE; 991 } 992 ctx->cur++; 993 eat_opt_white( &ctx->cur ); 994 } 995 if (!parse_float( &ctx->cur, &values[i] )) { 996 report_error( ctx, "Expected literal floating point" ); 997 return FALSE; 998 } 999 } 1000 eat_opt_white( &ctx->cur ); 1001 if (*ctx->cur != '}') { 1002 report_error( ctx, "Expected `}'" ); 1003 return FALSE; 1004 } 1005 ctx->cur++; 1006 1007 return TRUE; 1008} 1009 1010static boolean parse_declaration( struct translate_ctx *ctx ) 1011{ 1012 struct tgsi_full_declaration decl; 1013 uint file; 1014 struct parsed_dcl_bracket brackets[2]; 1015 int num_brackets; 1016 uint writemask; 1017 const char *cur, *cur2; 1018 uint advance; 1019 boolean is_vs_input; 1020 boolean is_imm_array; 1021 1022 if (!eat_white( &ctx->cur )) { 1023 report_error( ctx, "Syntax error" ); 1024 return FALSE; 1025 } 1026 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) 1027 return FALSE; 1028 if (!parse_opt_writemask( ctx, &writemask )) 1029 return FALSE; 1030 1031 decl = tgsi_default_full_declaration(); 1032 decl.Declaration.File = file; 1033 decl.Declaration.UsageMask = writemask; 1034 1035 if (num_brackets == 1) { 1036 decl.Range.First = brackets[0].first; 1037 decl.Range.Last = brackets[0].last; 1038 } else { 1039 decl.Range.First = brackets[1].first; 1040 decl.Range.Last = brackets[1].last; 1041 1042 decl.Declaration.Dimension = 1; 1043 decl.Dim.Index2D = brackets[0].first; 1044 } 1045 1046 is_vs_input = (file == TGSI_FILE_INPUT && 1047 ctx->processor == TGSI_PROCESSOR_VERTEX); 1048 is_imm_array = (file == TGSI_FILE_IMMEDIATE_ARRAY); 1049 1050 cur = ctx->cur; 1051 eat_opt_white( &cur ); 1052 if (*cur == ',' && !is_vs_input) { 1053 uint i, j; 1054 1055 cur++; 1056 eat_opt_white( &cur ); 1057 if (file == TGSI_FILE_RESOURCE) { 1058 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { 1059 if (str_match_no_case(&cur, tgsi_texture_names[i])) { 1060 if (!is_digit_alpha_underscore(cur)) { 1061 decl.Resource.Resource = i; 1062 break; 1063 } 1064 } 1065 } 1066 if (i == TGSI_TEXTURE_COUNT) { 1067 report_error(ctx, "Expected texture target"); 1068 return FALSE; 1069 } 1070 1071 cur2 = cur; 1072 eat_opt_white(&cur2); 1073 while (*cur2 == ',') { 1074 cur2++; 1075 eat_opt_white(&cur2); 1076 if (str_match_no_case(&cur2, "RAW") && 1077 !is_digit_alpha_underscore(cur2)) { 1078 decl.Resource.Raw = 1; 1079 1080 } else if (str_match_no_case(&cur2, "WR") && 1081 !is_digit_alpha_underscore(cur2)) { 1082 decl.Resource.Writable = 1; 1083 1084 } else { 1085 break; 1086 } 1087 cur = cur2; 1088 eat_opt_white(&cur2); 1089 } 1090 1091 ctx->cur = cur; 1092 1093 } else if (file == TGSI_FILE_SAMPLER_VIEW) { 1094 for (i = 0; i < TGSI_TEXTURE_COUNT; i++) { 1095 if (str_match_no_case(&cur, tgsi_texture_names[i])) { 1096 if (!is_digit_alpha_underscore(cur)) { 1097 decl.SamplerView.Resource = i; 1098 break; 1099 } 1100 } 1101 } 1102 if (i == TGSI_TEXTURE_COUNT) { 1103 report_error(ctx, "Expected texture target"); 1104 return FALSE; 1105 } 1106 eat_opt_white( &cur ); 1107 if (*cur != ',') { 1108 report_error( ctx, "Expected `,'" ); 1109 return FALSE; 1110 } 1111 ++cur; 1112 eat_opt_white( &cur ); 1113 for (j = 0; j < 4; ++j) { 1114 for (i = 0; i < PIPE_TYPE_COUNT; ++i) { 1115 if (str_match_no_case(&cur, tgsi_type_names[i])) { 1116 if (!is_digit_alpha_underscore(cur)) { 1117 switch (j) { 1118 case 0: 1119 decl.SamplerView.ReturnTypeX = i; 1120 break; 1121 case 1: 1122 decl.SamplerView.ReturnTypeY = i; 1123 break; 1124 case 2: 1125 decl.SamplerView.ReturnTypeZ = i; 1126 break; 1127 case 3: 1128 decl.SamplerView.ReturnTypeW = i; 1129 break; 1130 default: 1131 assert(0); 1132 } 1133 break; 1134 } 1135 } 1136 } 1137 if (i == PIPE_TYPE_COUNT) { 1138 if (j == 0 || j > 2) { 1139 report_error(ctx, "Expected type name"); 1140 return FALSE; 1141 } 1142 break; 1143 } else { 1144 cur2 = cur; 1145 eat_opt_white( &cur2 ); 1146 if (*cur2 == ',') { 1147 cur2++; 1148 eat_opt_white( &cur2 ); 1149 cur = cur2; 1150 continue; 1151 } else 1152 break; 1153 } 1154 } 1155 if (j < 4) { 1156 decl.SamplerView.ReturnTypeY = 1157 decl.SamplerView.ReturnTypeZ = 1158 decl.SamplerView.ReturnTypeW = 1159 decl.SamplerView.ReturnTypeX; 1160 } 1161 ctx->cur = cur; 1162 } else { 1163 if (str_match_no_case(&cur, "LOCAL") && 1164 !is_digit_alpha_underscore(cur)) { 1165 decl.Declaration.Local = 1; 1166 ctx->cur = cur; 1167 } 1168 1169 cur = ctx->cur; 1170 eat_opt_white( &cur ); 1171 if (*cur == ',') { 1172 cur++; 1173 eat_opt_white( &cur ); 1174 1175 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { 1176 if (str_match_no_case( &cur, tgsi_semantic_names[i] )) { 1177 uint index; 1178 1179 if (is_digit_alpha_underscore( cur )) 1180 continue; 1181 cur2 = cur; 1182 eat_opt_white( &cur2 ); 1183 if (*cur2 == '[') { 1184 cur2++; 1185 eat_opt_white( &cur2 ); 1186 if (!parse_uint( &cur2, &index )) { 1187 report_error( ctx, "Expected literal integer" ); 1188 return FALSE; 1189 } 1190 eat_opt_white( &cur2 ); 1191 if (*cur2 != ']') { 1192 report_error( ctx, "Expected `]'" ); 1193 return FALSE; 1194 } 1195 cur2++; 1196 1197 decl.Semantic.Index = index; 1198 1199 cur = cur2; 1200 } 1201 1202 decl.Declaration.Semantic = 1; 1203 decl.Semantic.Name = i; 1204 1205 ctx->cur = cur; 1206 break; 1207 } 1208 } 1209 } 1210 } 1211 } else if (is_imm_array) { 1212 unsigned i; 1213 float *vals_itr; 1214 /* we have our immediate data */ 1215 if (*cur != '{') { 1216 report_error( ctx, "Immediate array without data" ); 1217 return FALSE; 1218 } 1219 ++cur; 1220 ctx->cur = cur; 1221 1222 decl.ImmediateData.u = 1223 MALLOC(sizeof(union tgsi_immediate_data) * 4 * 1224 (decl.Range.Last + 1)); 1225 vals_itr = (float*)decl.ImmediateData.u; 1226 for (i = 0; i <= decl.Range.Last; ++i) { 1227 if (!parse_immediate_data(ctx, vals_itr)) { 1228 FREE(decl.ImmediateData.u); 1229 return FALSE; 1230 } 1231 vals_itr += 4; 1232 eat_opt_white( &ctx->cur ); 1233 if (*ctx->cur != ',') { 1234 if (i != decl.Range.Last) { 1235 report_error( ctx, "Not enough data in immediate array!" ); 1236 FREE(decl.ImmediateData.u); 1237 return FALSE; 1238 } 1239 } else 1240 ++ctx->cur; 1241 } 1242 eat_opt_white( &ctx->cur ); 1243 if (*ctx->cur != '}') { 1244 FREE(decl.ImmediateData.u); 1245 report_error( ctx, "Immediate array data missing closing '}'" ); 1246 return FALSE; 1247 } 1248 ++ctx->cur; 1249 } 1250 1251 cur = ctx->cur; 1252 eat_opt_white( &cur ); 1253 if (*cur == ',' && !is_vs_input) { 1254 uint i; 1255 1256 cur++; 1257 eat_opt_white( &cur ); 1258 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { 1259 if (str_match_no_case( &cur, tgsi_interpolate_names[i] )) { 1260 if (is_digit_alpha_underscore( cur )) 1261 continue; 1262 decl.Declaration.Interpolate = 1; 1263 decl.Interp.Interpolate = i; 1264 1265 ctx->cur = cur; 1266 break; 1267 } 1268 } 1269 if (i == TGSI_INTERPOLATE_COUNT) { 1270 report_error( ctx, "Expected semantic or interpolate attribute" ); 1271 return FALSE; 1272 } 1273 } 1274 1275 advance = tgsi_build_full_declaration( 1276 &decl, 1277 ctx->tokens_cur, 1278 ctx->header, 1279 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1280 1281 if (is_imm_array) 1282 FREE(decl.ImmediateData.u); 1283 1284 if (advance == 0) 1285 return FALSE; 1286 ctx->tokens_cur += advance; 1287 1288 return TRUE; 1289} 1290 1291static boolean parse_immediate( struct translate_ctx *ctx ) 1292{ 1293 struct tgsi_full_immediate imm; 1294 float values[4]; 1295 uint advance; 1296 1297 if (!eat_white( &ctx->cur )) { 1298 report_error( ctx, "Syntax error" ); 1299 return FALSE; 1300 } 1301 if (!str_match_no_case( &ctx->cur, "FLT32" ) || 1302 is_digit_alpha_underscore( ctx->cur )) { 1303 report_error( ctx, "Expected `FLT32'" ); 1304 return FALSE; 1305 } 1306 1307 parse_immediate_data(ctx, values); 1308 1309 imm = tgsi_default_full_immediate(); 1310 imm.Immediate.NrTokens += 4; 1311 imm.Immediate.DataType = TGSI_IMM_FLOAT32; 1312 imm.u[0].Float = values[0]; 1313 imm.u[1].Float = values[1]; 1314 imm.u[2].Float = values[2]; 1315 imm.u[3].Float = values[3]; 1316 1317 advance = tgsi_build_full_immediate( 1318 &imm, 1319 ctx->tokens_cur, 1320 ctx->header, 1321 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1322 if (advance == 0) 1323 return FALSE; 1324 ctx->tokens_cur += advance; 1325 1326 return TRUE; 1327} 1328 1329static boolean 1330parse_primitive( const char **pcur, uint *primitive ) 1331{ 1332 uint i; 1333 1334 for (i = 0; i < PIPE_PRIM_MAX; i++) { 1335 const char *cur = *pcur; 1336 1337 if (str_match_no_case( &cur, tgsi_primitive_names[i])) { 1338 *primitive = i; 1339 *pcur = cur; 1340 return TRUE; 1341 } 1342 } 1343 return FALSE; 1344} 1345 1346static boolean 1347parse_fs_coord_origin( const char **pcur, uint *fs_coord_origin ) 1348{ 1349 uint i; 1350 1351 for (i = 0; i < Elements(tgsi_fs_coord_origin_names); i++) { 1352 const char *cur = *pcur; 1353 1354 if (str_match_no_case( &cur, tgsi_fs_coord_origin_names[i])) { 1355 *fs_coord_origin = i; 1356 *pcur = cur; 1357 return TRUE; 1358 } 1359 } 1360 return FALSE; 1361} 1362 1363static boolean 1364parse_fs_coord_pixel_center( const char **pcur, uint *fs_coord_pixel_center ) 1365{ 1366 uint i; 1367 1368 for (i = 0; i < Elements(tgsi_fs_coord_pixel_center_names); i++) { 1369 const char *cur = *pcur; 1370 1371 if (str_match_no_case( &cur, tgsi_fs_coord_pixel_center_names[i])) { 1372 *fs_coord_pixel_center = i; 1373 *pcur = cur; 1374 return TRUE; 1375 } 1376 } 1377 return FALSE; 1378} 1379 1380 1381static boolean parse_property( struct translate_ctx *ctx ) 1382{ 1383 struct tgsi_full_property prop; 1384 uint property_name; 1385 uint values[8]; 1386 uint advance; 1387 char id[64]; 1388 1389 if (!eat_white( &ctx->cur )) { 1390 report_error( ctx, "Syntax error" ); 1391 return FALSE; 1392 } 1393 if (!parse_identifier( &ctx->cur, id )) { 1394 report_error( ctx, "Syntax error" ); 1395 return FALSE; 1396 } 1397 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; 1398 ++property_name) { 1399 if (streq_nocase_uprcase(tgsi_property_names[property_name], id)) { 1400 break; 1401 } 1402 } 1403 if (property_name >= TGSI_PROPERTY_COUNT) { 1404 debug_printf( "\nError: Unknown property : '%s'", id ); 1405 return FALSE; 1406 } 1407 1408 eat_opt_white( &ctx->cur ); 1409 switch(property_name) { 1410 case TGSI_PROPERTY_GS_INPUT_PRIM: 1411 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 1412 if (!parse_primitive(&ctx->cur, &values[0] )) { 1413 report_error( ctx, "Unknown primitive name as property!" ); 1414 return FALSE; 1415 } 1416 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && 1417 ctx->processor == TGSI_PROCESSOR_GEOMETRY) { 1418 ctx->implied_array_size = u_vertices_per_prim(values[0]); 1419 } 1420 break; 1421 case TGSI_PROPERTY_FS_COORD_ORIGIN: 1422 if (!parse_fs_coord_origin(&ctx->cur, &values[0] )) { 1423 report_error( ctx, "Unknown coord origin as property: must be UPPER_LEFT or LOWER_LEFT!" ); 1424 return FALSE; 1425 } 1426 break; 1427 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: 1428 if (!parse_fs_coord_pixel_center(&ctx->cur, &values[0] )) { 1429 report_error( ctx, "Unknown coord pixel center as property: must be HALF_INTEGER or INTEGER!" ); 1430 return FALSE; 1431 } 1432 break; 1433 case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: 1434 default: 1435 if (!parse_uint(&ctx->cur, &values[0] )) { 1436 report_error( ctx, "Expected unsigned integer as property!" ); 1437 return FALSE; 1438 } 1439 } 1440 1441 prop = tgsi_default_full_property(); 1442 prop.Property.PropertyName = property_name; 1443 prop.Property.NrTokens += 1; 1444 prop.u[0].Data = values[0]; 1445 1446 advance = tgsi_build_full_property( 1447 &prop, 1448 ctx->tokens_cur, 1449 ctx->header, 1450 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1451 if (advance == 0) 1452 return FALSE; 1453 ctx->tokens_cur += advance; 1454 1455 return TRUE; 1456} 1457 1458 1459static boolean translate( struct translate_ctx *ctx ) 1460{ 1461 eat_opt_white( &ctx->cur ); 1462 if (!parse_header( ctx )) 1463 return FALSE; 1464 1465 while (*ctx->cur != '\0') { 1466 uint label_val = 0; 1467 if (!eat_white( &ctx->cur )) { 1468 report_error( ctx, "Syntax error" ); 1469 return FALSE; 1470 } 1471 1472 if (*ctx->cur == '\0') 1473 break; 1474 if (parse_label( ctx, &label_val )) { 1475 if (!parse_instruction( ctx, TRUE )) 1476 return FALSE; 1477 } 1478 else if (str_match_no_case( &ctx->cur, "DCL" )) { 1479 if (!parse_declaration( ctx )) 1480 return FALSE; 1481 } 1482 else if (str_match_no_case( &ctx->cur, "IMM" )) { 1483 if (!parse_immediate( ctx )) 1484 return FALSE; 1485 } 1486 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) { 1487 if (!parse_property( ctx )) 1488 return FALSE; 1489 } 1490 else if (!parse_instruction( ctx, FALSE )) { 1491 return FALSE; 1492 } 1493 } 1494 1495 return TRUE; 1496} 1497 1498boolean 1499tgsi_text_translate( 1500 const char *text, 1501 struct tgsi_token *tokens, 1502 uint num_tokens ) 1503{ 1504 struct translate_ctx ctx; 1505 1506 ctx.text = text; 1507 ctx.cur = text; 1508 ctx.tokens = tokens; 1509 ctx.tokens_cur = tokens; 1510 ctx.tokens_end = tokens + num_tokens; 1511 1512 if (!translate( &ctx )) 1513 return FALSE; 1514 1515 return tgsi_sanity_check( tokens ); 1516} 1517