tgsi_text.c revision dcf8543ab375dd9c128d1ca772b1e587cebbdc7c
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 "pipe/p_inlines.h" 33#include "tgsi_text.h" 34#include "tgsi_build.h" 35#include "tgsi_info.h" 36#include "tgsi_parse.h" 37#include "tgsi_sanity.h" 38#include "tgsi_util.h" 39 40static boolean is_alpha_underscore( const char *cur ) 41{ 42 return 43 (*cur >= 'a' && *cur <= 'z') || 44 (*cur >= 'A' && *cur <= 'Z') || 45 *cur == '_'; 46} 47 48static boolean is_digit( const char *cur ) 49{ 50 return *cur >= '0' && *cur <= '9'; 51} 52 53static boolean is_digit_alpha_underscore( const char *cur ) 54{ 55 return is_digit( cur ) || is_alpha_underscore( cur ); 56} 57 58static boolean uprcase( char c ) 59{ 60 if (c >= 'a' && c <= 'z') 61 return c += 'A' - 'a'; 62 return c; 63} 64 65/* 66 * Ignore case of str1 and assume str1 is already uppercase. 67 * Return TRUE iff str1 and str2 are equal. 68 */ 69static int 70streq_nocase_uprcase(const char *str1, 71 const char *str2) 72{ 73 while (*str1 && *str2) { 74 if (*str1 != uprcase(*str2)) 75 return FALSE; 76 str1++; 77 str2++; 78 } 79 return TRUE; 80} 81 82static boolean str_match_no_case( const char **pcur, const char *str ) 83{ 84 const char *cur = *pcur; 85 86 while (*str != '\0' && *str == uprcase( *cur )) { 87 str++; 88 cur++; 89 } 90 if (*str == '\0') { 91 *pcur = cur; 92 return TRUE; 93 } 94 return FALSE; 95} 96 97/* Eat zero or more whitespaces. 98 */ 99static void eat_opt_white( const char **pcur ) 100{ 101 while (**pcur == ' ' || **pcur == '\t' || **pcur == '\n') 102 (*pcur)++; 103} 104 105/* Eat one or more whitespaces. 106 * Return TRUE if at least one whitespace eaten. 107 */ 108static boolean eat_white( const char **pcur ) 109{ 110 const char *cur = *pcur; 111 112 eat_opt_white( pcur ); 113 return *pcur > cur; 114} 115 116/* Parse unsigned integer. 117 * No checks for overflow. 118 */ 119static boolean parse_uint( const char **pcur, uint *val ) 120{ 121 const char *cur = *pcur; 122 123 if (is_digit( cur )) { 124 *val = *cur++ - '0'; 125 while (is_digit( cur )) 126 *val = *val * 10 + *cur++ - '0'; 127 *pcur = cur; 128 return TRUE; 129 } 130 return FALSE; 131} 132 133static boolean parse_identifier( const char **pcur, char *ret ) 134{ 135 const char *cur = *pcur; 136 int i = 0; 137 if (is_alpha_underscore( cur )) { 138 ret[i++] = *cur++; 139 while (is_alpha_underscore( cur )) 140 ret[i++] = *cur++; 141 *pcur = cur; 142 return TRUE; 143 } 144 return FALSE; 145} 146 147/* Parse floating point. 148 */ 149static boolean parse_float( const char **pcur, float *val ) 150{ 151 const char *cur = *pcur; 152 boolean integral_part = FALSE; 153 boolean fractional_part = FALSE; 154 155 *val = (float) atof( cur ); 156 157 if (*cur == '-' || *cur == '+') 158 cur++; 159 if (is_digit( cur )) { 160 cur++; 161 integral_part = TRUE; 162 while (is_digit( cur )) 163 cur++; 164 } 165 if (*cur == '.') { 166 cur++; 167 if (is_digit( cur )) { 168 cur++; 169 fractional_part = TRUE; 170 while (is_digit( cur )) 171 cur++; 172 } 173 } 174 if (!integral_part && !fractional_part) 175 return FALSE; 176 if (uprcase( *cur ) == 'E') { 177 cur++; 178 if (*cur == '-' || *cur == '+') 179 cur++; 180 if (is_digit( cur )) { 181 cur++; 182 while (is_digit( cur )) 183 cur++; 184 } 185 else 186 return FALSE; 187 } 188 *pcur = cur; 189 return TRUE; 190} 191 192struct translate_ctx 193{ 194 const char *text; 195 const char *cur; 196 struct tgsi_token *tokens; 197 struct tgsi_token *tokens_cur; 198 struct tgsi_token *tokens_end; 199 struct tgsi_header *header; 200 unsigned processor : 4; 201 int implied_array_size : 5; 202}; 203 204static void report_error( struct translate_ctx *ctx, const char *msg ) 205{ 206 int line = 1; 207 int column = 1; 208 const char *itr = ctx->text; 209 210 while (itr != ctx->cur) { 211 if (*itr == '\n') { 212 column = 1; 213 ++line; 214 } 215 ++column; 216 ++itr; 217 } 218 219 debug_printf( "\nTGSI asm error: %s [%d : %d] \n", msg, line, column ); 220} 221 222/* Parse shader header. 223 * Return TRUE for one of the following headers. 224 * FRAG 225 * GEOM 226 * VERT 227 */ 228static boolean parse_header( struct translate_ctx *ctx ) 229{ 230 uint processor; 231 232 if (str_match_no_case( &ctx->cur, "FRAG" )) 233 processor = TGSI_PROCESSOR_FRAGMENT; 234 else if (str_match_no_case( &ctx->cur, "VERT" )) 235 processor = TGSI_PROCESSOR_VERTEX; 236 else if (str_match_no_case( &ctx->cur, "GEOM" )) 237 processor = TGSI_PROCESSOR_GEOMETRY; 238 else { 239 report_error( ctx, "Unknown header" ); 240 return FALSE; 241 } 242 243 if (ctx->tokens_cur >= ctx->tokens_end) 244 return FALSE; 245 ctx->header = (struct tgsi_header *) ctx->tokens_cur++; 246 *ctx->header = tgsi_build_header(); 247 248 if (ctx->tokens_cur >= ctx->tokens_end) 249 return FALSE; 250 *(struct tgsi_processor *) ctx->tokens_cur++ = tgsi_build_processor( processor, ctx->header ); 251 ctx->processor = processor; 252 253 return TRUE; 254} 255 256static boolean parse_label( struct translate_ctx *ctx, uint *val ) 257{ 258 const char *cur = ctx->cur; 259 260 if (parse_uint( &cur, val )) { 261 eat_opt_white( &cur ); 262 if (*cur == ':') { 263 cur++; 264 ctx->cur = cur; 265 return TRUE; 266 } 267 } 268 return FALSE; 269} 270 271static const char *file_names[TGSI_FILE_COUNT] = 272{ 273 "NULL", 274 "CONST", 275 "IN", 276 "OUT", 277 "TEMP", 278 "SAMP", 279 "ADDR", 280 "IMM", 281 "LOOP", 282 "PRED", 283 "SV" 284}; 285 286static boolean 287parse_file( const char **pcur, uint *file ) 288{ 289 uint i; 290 291 for (i = 0; i < TGSI_FILE_COUNT; i++) { 292 const char *cur = *pcur; 293 294 if (str_match_no_case( &cur, file_names[i] )) { 295 if (!is_digit_alpha_underscore( cur )) { 296 *pcur = cur; 297 *file = i; 298 return TRUE; 299 } 300 } 301 } 302 return FALSE; 303} 304 305static boolean 306parse_opt_writemask( 307 struct translate_ctx *ctx, 308 uint *writemask ) 309{ 310 const char *cur; 311 312 cur = ctx->cur; 313 eat_opt_white( &cur ); 314 if (*cur == '.') { 315 cur++; 316 *writemask = TGSI_WRITEMASK_NONE; 317 eat_opt_white( &cur ); 318 if (uprcase( *cur ) == 'X') { 319 cur++; 320 *writemask |= TGSI_WRITEMASK_X; 321 } 322 if (uprcase( *cur ) == 'Y') { 323 cur++; 324 *writemask |= TGSI_WRITEMASK_Y; 325 } 326 if (uprcase( *cur ) == 'Z') { 327 cur++; 328 *writemask |= TGSI_WRITEMASK_Z; 329 } 330 if (uprcase( *cur ) == 'W') { 331 cur++; 332 *writemask |= TGSI_WRITEMASK_W; 333 } 334 335 if (*writemask == TGSI_WRITEMASK_NONE) { 336 report_error( ctx, "Writemask expected" ); 337 return FALSE; 338 } 339 340 ctx->cur = cur; 341 } 342 else { 343 *writemask = TGSI_WRITEMASK_XYZW; 344 } 345 return TRUE; 346} 347 348static boolean 349parse_register_dst( struct translate_ctx *ctx, 350 uint *file, 351 int *index ); 352 353struct parsed_src_bracket { 354 int index; 355 356 uint ind_file; 357 int ind_index; 358 uint ind_comp; 359}; 360 361 362static boolean 363parse_register_src_bracket( 364 struct translate_ctx *ctx, 365 struct parsed_src_bracket *brackets) 366{ 367 const char *cur; 368 uint uindex; 369 370 memset(brackets, 0, sizeof(struct parsed_src_bracket)); 371 372 eat_opt_white( &ctx->cur ); 373 374 cur = ctx->cur; 375 if (parse_file( &cur, &brackets->ind_file )) { 376 if (!parse_register_dst( ctx, &brackets->ind_file, 377 &brackets->ind_index )) 378 return FALSE; 379 eat_opt_white( &ctx->cur ); 380 381 if (*ctx->cur == '.') { 382 ctx->cur++; 383 eat_opt_white(&ctx->cur); 384 385 switch (uprcase(*ctx->cur)) { 386 case 'X': 387 brackets->ind_comp = TGSI_SWIZZLE_X; 388 break; 389 case 'Y': 390 brackets->ind_comp = TGSI_SWIZZLE_Y; 391 break; 392 case 'Z': 393 brackets->ind_comp = TGSI_SWIZZLE_Z; 394 break; 395 case 'W': 396 brackets->ind_comp = TGSI_SWIZZLE_W; 397 break; 398 default: 399 report_error(ctx, "Expected indirect register swizzle component `x', `y', `z' or `w'"); 400 return FALSE; 401 } 402 ctx->cur++; 403 eat_opt_white(&ctx->cur); 404 } 405 406 if (*ctx->cur == '+' || *ctx->cur == '-') { 407 boolean negate; 408 409 negate = *ctx->cur == '-'; 410 ctx->cur++; 411 eat_opt_white( &ctx->cur ); 412 if (!parse_uint( &ctx->cur, &uindex )) { 413 report_error( ctx, "Expected literal unsigned integer" ); 414 return FALSE; 415 } 416 if (negate) 417 brackets->index = -(int) uindex; 418 else 419 brackets->index = (int) uindex; 420 } 421 else { 422 brackets->index = 0; 423 } 424 } 425 else { 426 if (!parse_uint( &ctx->cur, &uindex )) { 427 report_error( ctx, "Expected literal unsigned integer" ); 428 return FALSE; 429 } 430 brackets->index = (int) uindex; 431 brackets->ind_file = TGSI_FILE_NULL; 432 brackets->ind_index = 0; 433 } 434 eat_opt_white( &ctx->cur ); 435 if (*ctx->cur != ']') { 436 report_error( ctx, "Expected `]'" ); 437 return FALSE; 438 } 439 ctx->cur++; 440 return TRUE; 441} 442 443static boolean 444parse_opt_register_src_bracket( 445 struct translate_ctx *ctx, 446 struct parsed_src_bracket *brackets, 447 int *parsed_brackets) 448{ 449 const char *cur = ctx->cur; 450 451 *parsed_brackets = 0; 452 453 eat_opt_white( &cur ); 454 if (cur[0] == '[') { 455 ++cur; 456 ctx->cur = cur; 457 458 if (!parse_register_src_bracket(ctx, brackets)) 459 return FALSE; 460 461 *parsed_brackets = 1; 462 } 463 464 return TRUE; 465} 466 467/* <register_file_bracket> ::= <file> `[' 468 */ 469static boolean 470parse_register_file_bracket( 471 struct translate_ctx *ctx, 472 uint *file ) 473{ 474 if (!parse_file( &ctx->cur, file )) { 475 report_error( ctx, "Unknown register file" ); 476 return FALSE; 477 } 478 eat_opt_white( &ctx->cur ); 479 if (*ctx->cur != '[') { 480 report_error( ctx, "Expected `['" ); 481 return FALSE; 482 } 483 ctx->cur++; 484 return TRUE; 485} 486 487/* <register_file_bracket_index> ::= <register_file_bracket> <uint> 488 */ 489static boolean 490parse_register_file_bracket_index( 491 struct translate_ctx *ctx, 492 uint *file, 493 int *index ) 494{ 495 uint uindex; 496 497 if (!parse_register_file_bracket( ctx, file )) 498 return FALSE; 499 eat_opt_white( &ctx->cur ); 500 if (!parse_uint( &ctx->cur, &uindex )) { 501 report_error( ctx, "Expected literal unsigned integer" ); 502 return FALSE; 503 } 504 *index = (int) uindex; 505 return TRUE; 506} 507 508/* Parse source register operand. 509 * <register_src> ::= <register_file_bracket_index> `]' | 510 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `]' | 511 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `+' <uint> `]' | 512 * <register_file_bracket> <register_dst> [`.' (`x' | `y' | `z' | `w')] `-' <uint> `]' 513 */ 514static boolean 515parse_register_src( 516 struct translate_ctx *ctx, 517 uint *file, 518 struct parsed_src_bracket *brackets) 519{ 520 521 brackets->ind_comp = TGSI_SWIZZLE_X; 522 if (!parse_register_file_bracket( ctx, file )) 523 return FALSE; 524 if (!parse_register_src_bracket( ctx, brackets )) 525 return FALSE; 526 527 return TRUE; 528} 529 530struct parsed_dcl_bracket { 531 uint first; 532 uint last; 533}; 534 535static boolean 536parse_register_dcl_bracket( 537 struct translate_ctx *ctx, 538 struct parsed_dcl_bracket *bracket) 539{ 540 uint uindex; 541 memset(bracket, 0, sizeof(struct parsed_dcl_bracket)); 542 543 eat_opt_white( &ctx->cur ); 544 545 if (!parse_uint( &ctx->cur, &uindex )) { 546 /* it can be an empty bracket [] which means its range 547 * is from 0 to some implied size */ 548 if (ctx->cur[0] == ']' && ctx->implied_array_size != 0) { 549 bracket->first = 0; 550 bracket->last = ctx->implied_array_size - 1; 551 goto cleanup; 552 } 553 report_error( ctx, "Expected literal unsigned integer" ); 554 return FALSE; 555 } 556 bracket->first = uindex; 557 558 eat_opt_white( &ctx->cur ); 559 560 if (ctx->cur[0] == '.' && ctx->cur[1] == '.') { 561 uint uindex; 562 563 ctx->cur += 2; 564 eat_opt_white( &ctx->cur ); 565 if (!parse_uint( &ctx->cur, &uindex )) { 566 report_error( ctx, "Expected literal integer" ); 567 return FALSE; 568 } 569 bracket->last = (int) uindex; 570 eat_opt_white( &ctx->cur ); 571 } 572 else { 573 bracket->last = bracket->first; 574 } 575 576cleanup: 577 if (*ctx->cur != ']') { 578 report_error( ctx, "Expected `]' or `..'" ); 579 return FALSE; 580 } 581 ctx->cur++; 582 return TRUE; 583} 584 585/* Parse register declaration. 586 * <register_dcl> ::= <register_file_bracket_index> `]' | 587 * <register_file_bracket_index> `..' <index> `]' 588 */ 589static boolean 590parse_register_dcl( 591 struct translate_ctx *ctx, 592 uint *file, 593 struct parsed_dcl_bracket *brackets, 594 int *num_brackets) 595{ 596 const char *cur; 597 598 *num_brackets = 0; 599 600 if (!parse_register_file_bracket( ctx, file )) 601 return FALSE; 602 if (!parse_register_dcl_bracket( ctx, &brackets[0] )) 603 return FALSE; 604 605 *num_brackets = 1; 606 607 cur = ctx->cur; 608 eat_opt_white( &cur ); 609 610 if (cur[0] == '[') { 611 ++cur; 612 ctx->cur = cur; 613 if (!parse_register_dcl_bracket( ctx, &brackets[1] )) 614 return FALSE; 615 /* for geometry shader we don't really care about 616 * the first brackets it's always the size of the 617 * input primitive. so we want to declare just 618 * the index relevant to the semantics which is in 619 * the second bracket */ 620 if (ctx->processor == TGSI_PROCESSOR_GEOMETRY && *file == TGSI_FILE_INPUT) { 621 brackets[0] = brackets[1]; 622 *num_brackets = 1; 623 } else { 624 *num_brackets = 2; 625 } 626 } 627 628 return TRUE; 629} 630 631 632/* Parse destination register operand. 633 * <register_dst> ::= <register_file_bracket_index> `]' 634 */ 635static boolean 636parse_register_dst( 637 struct translate_ctx *ctx, 638 uint *file, 639 int *index ) 640{ 641 if (!parse_register_file_bracket_index( ctx, file, index )) 642 return FALSE; 643 eat_opt_white( &ctx->cur ); 644 if (*ctx->cur != ']') { 645 report_error( ctx, "Expected `]'" ); 646 return FALSE; 647 } 648 ctx->cur++; 649 return TRUE; 650} 651 652static boolean 653parse_dst_operand( 654 struct translate_ctx *ctx, 655 struct tgsi_full_dst_register *dst ) 656{ 657 uint file; 658 int index; 659 uint writemask; 660 const char *cur; 661 662 if (!parse_register_dst( ctx, &file, &index )) 663 return FALSE; 664 665 cur = ctx->cur; 666 eat_opt_white( &cur ); 667 668 if (!parse_opt_writemask( ctx, &writemask )) 669 return FALSE; 670 671 dst->Register.File = file; 672 dst->Register.Index = index; 673 dst->Register.WriteMask = writemask; 674 return TRUE; 675} 676 677static boolean 678parse_optional_swizzle( 679 struct translate_ctx *ctx, 680 uint swizzle[4], 681 boolean *parsed_swizzle ) 682{ 683 const char *cur = ctx->cur; 684 685 *parsed_swizzle = FALSE; 686 687 eat_opt_white( &cur ); 688 if (*cur == '.') { 689 uint i; 690 691 cur++; 692 eat_opt_white( &cur ); 693 for (i = 0; i < 4; i++) { 694 if (uprcase( *cur ) == 'X') 695 swizzle[i] = TGSI_SWIZZLE_X; 696 else if (uprcase( *cur ) == 'Y') 697 swizzle[i] = TGSI_SWIZZLE_Y; 698 else if (uprcase( *cur ) == 'Z') 699 swizzle[i] = TGSI_SWIZZLE_Z; 700 else if (uprcase( *cur ) == 'W') 701 swizzle[i] = TGSI_SWIZZLE_W; 702 else { 703 report_error( ctx, "Expected register swizzle component `x', `y', `z', `w', `0' or `1'" ); 704 return FALSE; 705 } 706 cur++; 707 } 708 *parsed_swizzle = TRUE; 709 ctx->cur = cur; 710 } 711 return TRUE; 712} 713 714static boolean 715parse_src_operand( 716 struct translate_ctx *ctx, 717 struct tgsi_full_src_register *src ) 718{ 719 uint file; 720 uint swizzle[4]; 721 boolean parsed_swizzle; 722 struct parsed_src_bracket bracket[2]; 723 int parsed_opt_brackets; 724 725 if (*ctx->cur == '-') { 726 ctx->cur++; 727 eat_opt_white( &ctx->cur ); 728 src->Register.Negate = 1; 729 } 730 731 if (*ctx->cur == '|') { 732 ctx->cur++; 733 eat_opt_white( &ctx->cur ); 734 src->Register.Absolute = 1; 735 } 736 737 if (!parse_register_src(ctx, &file, &bracket[0])) 738 return FALSE; 739 if (!parse_opt_register_src_bracket(ctx, &bracket[1], &parsed_opt_brackets)) 740 return FALSE; 741 742 src->Register.File = file; 743 if (parsed_opt_brackets) { 744 src->Register.Dimension = 1; 745 src->Dimension.Indirect = 0; 746 src->Dimension.Dimension = 0; 747 src->Dimension.Index = bracket[0].index; 748 bracket[0] = bracket[1]; 749 } 750 src->Register.Index = bracket[0].index; 751 if (bracket[0].ind_file != TGSI_FILE_NULL) { 752 src->Register.Indirect = 1; 753 src->Indirect.File = bracket[0].ind_file; 754 src->Indirect.Index = bracket[0].ind_index; 755 src->Indirect.SwizzleX = bracket[0].ind_comp; 756 src->Indirect.SwizzleY = bracket[0].ind_comp; 757 src->Indirect.SwizzleZ = bracket[0].ind_comp; 758 src->Indirect.SwizzleW = bracket[0].ind_comp; 759 } 760 761 /* Parse optional swizzle. 762 */ 763 if (parse_optional_swizzle( ctx, swizzle, &parsed_swizzle )) { 764 if (parsed_swizzle) { 765 src->Register.SwizzleX = swizzle[0]; 766 src->Register.SwizzleY = swizzle[1]; 767 src->Register.SwizzleZ = swizzle[2]; 768 src->Register.SwizzleW = swizzle[3]; 769 } 770 } 771 772 if (src->Register.Absolute) { 773 eat_opt_white( &ctx->cur ); 774 if (*ctx->cur != '|') { 775 report_error( ctx, "Expected `|'" ); 776 return FALSE; 777 } 778 ctx->cur++; 779 } 780 781 782 return TRUE; 783} 784 785static const char *texture_names[TGSI_TEXTURE_COUNT] = 786{ 787 "UNKNOWN", 788 "1D", 789 "2D", 790 "3D", 791 "CUBE", 792 "RECT", 793 "SHADOW1D", 794 "SHADOW2D", 795 "SHADOWRECT" 796}; 797 798static boolean 799match_inst_mnemonic(const char **pcur, 800 const struct tgsi_opcode_info *info) 801{ 802 if (str_match_no_case(pcur, info->mnemonic)) { 803 return TRUE; 804 } 805 return FALSE; 806} 807 808static boolean 809parse_instruction( 810 struct translate_ctx *ctx, 811 boolean has_label ) 812{ 813 uint i; 814 uint saturate = TGSI_SAT_NONE; 815 const struct tgsi_opcode_info *info; 816 struct tgsi_full_instruction inst; 817 uint advance; 818 819 /* Parse instruction name. 820 */ 821 eat_opt_white( &ctx->cur ); 822 for (i = 0; i < TGSI_OPCODE_LAST; i++) { 823 const char *cur = ctx->cur; 824 825 info = tgsi_get_opcode_info( i ); 826 if (match_inst_mnemonic(&cur, info)) { 827 if (str_match_no_case( &cur, "_SATNV" )) 828 saturate = TGSI_SAT_MINUS_PLUS_ONE; 829 else if (str_match_no_case( &cur, "_SAT" )) 830 saturate = TGSI_SAT_ZERO_ONE; 831 832 if (info->num_dst + info->num_src + info->is_tex == 0) { 833 if (!is_digit_alpha_underscore( cur )) { 834 ctx->cur = cur; 835 break; 836 } 837 } 838 else if (*cur == '\0' || eat_white( &cur )) { 839 ctx->cur = cur; 840 break; 841 } 842 } 843 } 844 if (i == TGSI_OPCODE_LAST) { 845 if (has_label) 846 report_error( ctx, "Unknown opcode" ); 847 else 848 report_error( ctx, "Expected `DCL', `IMM' or a label" ); 849 return FALSE; 850 } 851 852 inst = tgsi_default_full_instruction(); 853 inst.Instruction.Opcode = i; 854 inst.Instruction.Saturate = saturate; 855 inst.Instruction.NumDstRegs = info->num_dst; 856 inst.Instruction.NumSrcRegs = info->num_src; 857 858 /* Parse instruction operands. 859 */ 860 for (i = 0; i < info->num_dst + info->num_src + info->is_tex; i++) { 861 if (i > 0) { 862 eat_opt_white( &ctx->cur ); 863 if (*ctx->cur != ',') { 864 report_error( ctx, "Expected `,'" ); 865 return FALSE; 866 } 867 ctx->cur++; 868 eat_opt_white( &ctx->cur ); 869 } 870 871 if (i < info->num_dst) { 872 if (!parse_dst_operand( ctx, &inst.Dst[i] )) 873 return FALSE; 874 } 875 else if (i < info->num_dst + info->num_src) { 876 if (!parse_src_operand( ctx, &inst.Src[i - info->num_dst] )) 877 return FALSE; 878 } 879 else { 880 uint j; 881 882 for (j = 0; j < TGSI_TEXTURE_COUNT; j++) { 883 if (str_match_no_case( &ctx->cur, texture_names[j] )) { 884 if (!is_digit_alpha_underscore( ctx->cur )) { 885 inst.Instruction.Texture = 1; 886 inst.Texture.Texture = j; 887 break; 888 } 889 } 890 } 891 if (j == TGSI_TEXTURE_COUNT) { 892 report_error( ctx, "Expected texture target" ); 893 return FALSE; 894 } 895 } 896 } 897 898 if (info->is_branch) { 899 uint target; 900 901 eat_opt_white( &ctx->cur ); 902 if (*ctx->cur != ':') { 903 report_error( ctx, "Expected `:'" ); 904 return FALSE; 905 } 906 ctx->cur++; 907 eat_opt_white( &ctx->cur ); 908 if (!parse_uint( &ctx->cur, &target )) { 909 report_error( ctx, "Expected a label" ); 910 return FALSE; 911 } 912 inst.Instruction.Label = 1; 913 inst.Label.Label = target; 914 } 915 916 advance = tgsi_build_full_instruction( 917 &inst, 918 ctx->tokens_cur, 919 ctx->header, 920 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 921 if (advance == 0) 922 return FALSE; 923 ctx->tokens_cur += advance; 924 925 return TRUE; 926} 927 928static const char *semantic_names[TGSI_SEMANTIC_COUNT] = 929{ 930 "POSITION", 931 "COLOR", 932 "BCOLOR", 933 "FOG", 934 "PSIZE", 935 "GENERIC", 936 "NORMAL", 937 "FACE", 938 "EDGEFLAG", 939 "PRIM_ID", 940 "INSTANCEID" 941}; 942 943static const char *interpolate_names[TGSI_INTERPOLATE_COUNT] = 944{ 945 "CONSTANT", 946 "LINEAR", 947 "PERSPECTIVE" 948}; 949 950static boolean parse_declaration( struct translate_ctx *ctx ) 951{ 952 struct tgsi_full_declaration decl; 953 uint file; 954 struct parsed_dcl_bracket brackets[2]; 955 int num_brackets; 956 uint writemask; 957 const char *cur; 958 uint advance; 959 960 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT); 961 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT); 962 963 if (!eat_white( &ctx->cur )) { 964 report_error( ctx, "Syntax error" ); 965 return FALSE; 966 } 967 if (!parse_register_dcl( ctx, &file, brackets, &num_brackets)) 968 return FALSE; 969 if (!parse_opt_writemask( ctx, &writemask )) 970 return FALSE; 971 972 decl = tgsi_default_full_declaration(); 973 decl.Declaration.File = file; 974 decl.Declaration.UsageMask = writemask; 975 976 if (num_brackets == 1) { 977 decl.Range.First = brackets[0].first; 978 decl.Range.Last = brackets[0].last; 979 } else { 980 decl.Range.First = brackets[1].first; 981 decl.Range.Last = brackets[1].last; 982 983 decl.Declaration.Dimension = 1; 984 decl.Dim.Index2D = brackets[0].first; 985 } 986 987 cur = ctx->cur; 988 eat_opt_white( &cur ); 989 if (*cur == ',') { 990 uint i; 991 992 cur++; 993 eat_opt_white( &cur ); 994 for (i = 0; i < TGSI_SEMANTIC_COUNT; i++) { 995 if (str_match_no_case( &cur, semantic_names[i] )) { 996 const char *cur2 = cur; 997 uint index; 998 999 if (is_digit_alpha_underscore( cur )) 1000 continue; 1001 eat_opt_white( &cur2 ); 1002 if (*cur2 == '[') { 1003 cur2++; 1004 eat_opt_white( &cur2 ); 1005 if (!parse_uint( &cur2, &index )) { 1006 report_error( ctx, "Expected literal integer" ); 1007 return FALSE; 1008 } 1009 eat_opt_white( &cur2 ); 1010 if (*cur2 != ']') { 1011 report_error( ctx, "Expected `]'" ); 1012 return FALSE; 1013 } 1014 cur2++; 1015 1016 decl.Semantic.Index = index; 1017 1018 cur = cur2; 1019 } 1020 1021 decl.Declaration.Semantic = 1; 1022 decl.Semantic.Name = i; 1023 1024 ctx->cur = cur; 1025 break; 1026 } 1027 } 1028 } 1029 1030 cur = ctx->cur; 1031 eat_opt_white( &cur ); 1032 if (*cur == ',') { 1033 uint i; 1034 1035 cur++; 1036 eat_opt_white( &cur ); 1037 for (i = 0; i < TGSI_INTERPOLATE_COUNT; i++) { 1038 if (str_match_no_case( &cur, interpolate_names[i] )) { 1039 if (is_digit_alpha_underscore( cur )) 1040 continue; 1041 decl.Declaration.Interpolate = i; 1042 1043 ctx->cur = cur; 1044 break; 1045 } 1046 } 1047 if (i == TGSI_INTERPOLATE_COUNT) { 1048 report_error( ctx, "Expected semantic or interpolate attribute" ); 1049 return FALSE; 1050 } 1051 } 1052 1053 advance = tgsi_build_full_declaration( 1054 &decl, 1055 ctx->tokens_cur, 1056 ctx->header, 1057 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1058 if (advance == 0) 1059 return FALSE; 1060 ctx->tokens_cur += advance; 1061 1062 return TRUE; 1063} 1064 1065static boolean parse_immediate( struct translate_ctx *ctx ) 1066{ 1067 struct tgsi_full_immediate imm; 1068 uint i; 1069 float values[4]; 1070 uint advance; 1071 1072 if (!eat_white( &ctx->cur )) { 1073 report_error( ctx, "Syntax error" ); 1074 return FALSE; 1075 } 1076 if (!str_match_no_case( &ctx->cur, "FLT32" ) || is_digit_alpha_underscore( ctx->cur )) { 1077 report_error( ctx, "Expected `FLT32'" ); 1078 return FALSE; 1079 } 1080 eat_opt_white( &ctx->cur ); 1081 if (*ctx->cur != '{') { 1082 report_error( ctx, "Expected `{'" ); 1083 return FALSE; 1084 } 1085 ctx->cur++; 1086 for (i = 0; i < 4; i++) { 1087 eat_opt_white( &ctx->cur ); 1088 if (i > 0) { 1089 if (*ctx->cur != ',') { 1090 report_error( ctx, "Expected `,'" ); 1091 return FALSE; 1092 } 1093 ctx->cur++; 1094 eat_opt_white( &ctx->cur ); 1095 } 1096 if (!parse_float( &ctx->cur, &values[i] )) { 1097 report_error( ctx, "Expected literal floating point" ); 1098 return FALSE; 1099 } 1100 } 1101 eat_opt_white( &ctx->cur ); 1102 if (*ctx->cur != '}') { 1103 report_error( ctx, "Expected `}'" ); 1104 return FALSE; 1105 } 1106 ctx->cur++; 1107 1108 imm = tgsi_default_full_immediate(); 1109 imm.Immediate.NrTokens += 4; 1110 imm.Immediate.DataType = TGSI_IMM_FLOAT32; 1111 imm.u[0].Float = values[0]; 1112 imm.u[1].Float = values[1]; 1113 imm.u[2].Float = values[2]; 1114 imm.u[3].Float = values[3]; 1115 1116 advance = tgsi_build_full_immediate( 1117 &imm, 1118 ctx->tokens_cur, 1119 ctx->header, 1120 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1121 if (advance == 0) 1122 return FALSE; 1123 ctx->tokens_cur += advance; 1124 1125 return TRUE; 1126} 1127 1128static const char *property_names[] = 1129{ 1130 "GS_INPUT_PRIMITIVE", 1131 "GS_OUTPUT_PRIMITIVE", 1132 "GS_MAX_OUTPUT_VERTICES" 1133}; 1134 1135static const char *primitive_names[] = 1136{ 1137 "POINTS", 1138 "LINES", 1139 "LINE_LOOP", 1140 "LINE_STRIP", 1141 "TRIANGLES", 1142 "TRIANGLE_STRIP", 1143 "TRIANGLE_FAN", 1144 "QUADS", 1145 "QUAD_STRIP", 1146 "POLYGON" 1147}; 1148 1149static boolean 1150parse_primitive( const char **pcur, uint *primitive ) 1151{ 1152 uint i; 1153 1154 for (i = 0; i < PIPE_PRIM_MAX; i++) { 1155 const char *cur = *pcur; 1156 1157 if (str_match_no_case( &cur, primitive_names[i])) { 1158 *primitive = i; 1159 *pcur = cur; 1160 return TRUE; 1161 } 1162 } 1163 return FALSE; 1164} 1165 1166 1167static boolean parse_property( struct translate_ctx *ctx ) 1168{ 1169 struct tgsi_full_property prop; 1170 uint property_name; 1171 uint values[8]; 1172 uint advance; 1173 char id[64]; 1174 1175 if (!eat_white( &ctx->cur )) { 1176 report_error( ctx, "Syntax error" ); 1177 return FALSE; 1178 } 1179 if (!parse_identifier( &ctx->cur, id )) { 1180 report_error( ctx, "Syntax error" ); 1181 return FALSE; 1182 } 1183 for (property_name = 0; property_name < TGSI_PROPERTY_COUNT; 1184 ++property_name) { 1185 if (streq_nocase_uprcase(property_names[property_name], id)) { 1186 break; 1187 } 1188 } 1189 if (property_name >= TGSI_PROPERTY_COUNT) { 1190 debug_printf( "\nError: Unknown property : '%s'", id ); 1191 return FALSE; 1192 } 1193 1194 eat_opt_white( &ctx->cur ); 1195 switch(property_name) { 1196 case TGSI_PROPERTY_GS_INPUT_PRIM: 1197 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 1198 if (!parse_primitive(&ctx->cur, &values[0] )) { 1199 report_error( ctx, "Unknown primitive name as property!" ); 1200 return FALSE; 1201 } 1202 if (property_name == TGSI_PROPERTY_GS_INPUT_PRIM && 1203 ctx->processor == TGSI_PROCESSOR_GEOMETRY) { 1204 ctx->implied_array_size = u_vertices_per_prim(values[0]); 1205 } 1206 break; 1207 default: 1208 if (!parse_uint(&ctx->cur, &values[0] )) { 1209 report_error( ctx, "Expected unsigned integer as property!" ); 1210 return FALSE; 1211 } 1212 } 1213 1214 prop = tgsi_default_full_property(); 1215 prop.Property.PropertyName = property_name; 1216 prop.Property.NrTokens += 1; 1217 prop.u[0].Data = values[0]; 1218 1219 advance = tgsi_build_full_property( 1220 &prop, 1221 ctx->tokens_cur, 1222 ctx->header, 1223 (uint) (ctx->tokens_end - ctx->tokens_cur) ); 1224 if (advance == 0) 1225 return FALSE; 1226 ctx->tokens_cur += advance; 1227 1228 return TRUE; 1229} 1230 1231 1232static boolean translate( struct translate_ctx *ctx ) 1233{ 1234 eat_opt_white( &ctx->cur ); 1235 if (!parse_header( ctx )) 1236 return FALSE; 1237 1238 while (*ctx->cur != '\0') { 1239 uint label_val = 0; 1240 if (!eat_white( &ctx->cur )) { 1241 report_error( ctx, "Syntax error" ); 1242 return FALSE; 1243 } 1244 1245 if (*ctx->cur == '\0') 1246 break; 1247 if (parse_label( ctx, &label_val )) { 1248 if (!parse_instruction( ctx, TRUE )) 1249 return FALSE; 1250 } 1251 else if (str_match_no_case( &ctx->cur, "DCL" )) { 1252 if (!parse_declaration( ctx )) 1253 return FALSE; 1254 } 1255 else if (str_match_no_case( &ctx->cur, "IMM" )) { 1256 if (!parse_immediate( ctx )) 1257 return FALSE; 1258 } 1259 else if (str_match_no_case( &ctx->cur, "PROPERTY" )) { 1260 if (!parse_property( ctx )) 1261 return FALSE; 1262 } 1263 else if (!parse_instruction( ctx, FALSE )) { 1264 return FALSE; 1265 } 1266 } 1267 1268 return TRUE; 1269} 1270 1271boolean 1272tgsi_text_translate( 1273 const char *text, 1274 struct tgsi_token *tokens, 1275 uint num_tokens ) 1276{ 1277 struct translate_ctx ctx; 1278 1279 ctx.text = text; 1280 ctx.cur = text; 1281 ctx.tokens = tokens; 1282 ctx.tokens_cur = tokens; 1283 ctx.tokens_end = tokens + num_tokens; 1284 1285 if (!translate( &ctx )) 1286 return FALSE; 1287 1288 return tgsi_sanity_check( tokens ); 1289} 1290