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