tgsi_ureg.c revision ad83f3bf0a633d5d7360c849010f01063afc1702
1/************************************************************************** 2 * 3 * Copyright 2009 VMware, Inc. 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 VMWARE, INC 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 29#include "pipe/p_context.h" 30#include "pipe/p_state.h" 31#include "tgsi/tgsi_ureg.h" 32#include "tgsi/tgsi_build.h" 33#include "tgsi/tgsi_info.h" 34#include "tgsi/tgsi_dump.h" 35#include "tgsi/tgsi_sanity.h" 36#include "util/u_memory.h" 37#include "util/u_math.h" 38 39union tgsi_any_token { 40 struct tgsi_header header; 41 struct tgsi_processor processor; 42 struct tgsi_token token; 43 struct tgsi_property prop; 44 struct tgsi_property_data prop_data; 45 struct tgsi_declaration decl; 46 struct tgsi_declaration_range decl_range; 47 struct tgsi_declaration_dimension decl_dim; 48 struct tgsi_declaration_semantic decl_semantic; 49 struct tgsi_immediate imm; 50 union tgsi_immediate_data imm_data; 51 struct tgsi_instruction insn; 52 struct tgsi_instruction_predicate insn_predicate; 53 struct tgsi_instruction_label insn_label; 54 struct tgsi_instruction_texture insn_texture; 55 struct tgsi_src_register src; 56 struct tgsi_dimension dim; 57 struct tgsi_dst_register dst; 58 unsigned value; 59}; 60 61 62struct ureg_tokens { 63 union tgsi_any_token *tokens; 64 unsigned size; 65 unsigned order; 66 unsigned count; 67}; 68 69#define UREG_MAX_INPUT PIPE_MAX_ATTRIBS 70#define UREG_MAX_SYSTEM_VALUE PIPE_MAX_ATTRIBS 71#define UREG_MAX_OUTPUT PIPE_MAX_ATTRIBS 72#define UREG_MAX_CONSTANT_RANGE 32 73#define UREG_MAX_IMMEDIATE 32 74#define UREG_MAX_TEMP 256 75#define UREG_MAX_ADDR 2 76#define UREG_MAX_LOOP 1 77#define UREG_MAX_PRED 1 78 79struct const_decl { 80 struct { 81 unsigned first; 82 unsigned last; 83 } constant_range[UREG_MAX_CONSTANT_RANGE]; 84 unsigned nr_constant_ranges; 85}; 86 87#define DOMAIN_DECL 0 88#define DOMAIN_INSN 1 89 90struct ureg_program 91{ 92 unsigned processor; 93 struct pipe_context *pipe; 94 95 struct { 96 unsigned semantic_name; 97 unsigned semantic_index; 98 unsigned interp; 99 } fs_input[UREG_MAX_INPUT]; 100 unsigned nr_fs_inputs; 101 102 unsigned vs_inputs[UREG_MAX_INPUT/32]; 103 104 struct { 105 unsigned index; 106 unsigned semantic_name; 107 unsigned semantic_index; 108 } gs_input[UREG_MAX_INPUT]; 109 unsigned nr_gs_inputs; 110 111 struct { 112 unsigned index; 113 unsigned semantic_name; 114 unsigned semantic_index; 115 } system_value[UREG_MAX_SYSTEM_VALUE]; 116 unsigned nr_system_values; 117 118 struct { 119 unsigned semantic_name; 120 unsigned semantic_index; 121 } output[UREG_MAX_OUTPUT]; 122 unsigned nr_outputs; 123 124 struct { 125 union { 126 float f[4]; 127 unsigned u[4]; 128 int i[4]; 129 } value; 130 unsigned nr; 131 unsigned type; 132 } immediate[UREG_MAX_IMMEDIATE]; 133 unsigned nr_immediates; 134 135 struct ureg_src sampler[PIPE_MAX_SAMPLERS]; 136 unsigned nr_samplers; 137 138 unsigned temps_active[UREG_MAX_TEMP / 32]; 139 unsigned nr_temps; 140 141 struct const_decl const_decls; 142 struct const_decl const_decls2D[PIPE_MAX_CONSTANT_BUFFERS]; 143 144 unsigned property_gs_input_prim; 145 unsigned property_gs_output_prim; 146 unsigned property_gs_max_vertices; 147 unsigned char property_fs_coord_origin; /* = TGSI_FS_COORD_ORIGIN_* */ 148 unsigned char property_fs_coord_pixel_center; /* = TGSI_FS_COORD_PIXEL_CENTER_* */ 149 150 unsigned nr_addrs; 151 unsigned nr_preds; 152 unsigned nr_loops; 153 unsigned nr_instructions; 154 155 struct ureg_tokens domain[2]; 156}; 157 158static union tgsi_any_token error_tokens[32]; 159 160static void tokens_error( struct ureg_tokens *tokens ) 161{ 162 if (tokens->tokens && tokens->tokens != error_tokens) 163 FREE(tokens->tokens); 164 165 tokens->tokens = error_tokens; 166 tokens->size = Elements(error_tokens); 167 tokens->count = 0; 168} 169 170 171static void tokens_expand( struct ureg_tokens *tokens, 172 unsigned count ) 173{ 174 unsigned old_size = tokens->size * sizeof(unsigned); 175 176 if (tokens->tokens == error_tokens) { 177 return; 178 } 179 180 while (tokens->count + count > tokens->size) { 181 tokens->size = (1 << ++tokens->order); 182 } 183 184 tokens->tokens = REALLOC(tokens->tokens, 185 old_size, 186 tokens->size * sizeof(unsigned)); 187 if (tokens->tokens == NULL) { 188 tokens_error(tokens); 189 } 190} 191 192static void set_bad( struct ureg_program *ureg ) 193{ 194 tokens_error(&ureg->domain[0]); 195} 196 197 198 199static union tgsi_any_token *get_tokens( struct ureg_program *ureg, 200 unsigned domain, 201 unsigned count ) 202{ 203 struct ureg_tokens *tokens = &ureg->domain[domain]; 204 union tgsi_any_token *result; 205 206 if (tokens->count + count > tokens->size) 207 tokens_expand(tokens, count); 208 209 result = &tokens->tokens[tokens->count]; 210 tokens->count += count; 211 return result; 212} 213 214 215static union tgsi_any_token *retrieve_token( struct ureg_program *ureg, 216 unsigned domain, 217 unsigned nr ) 218{ 219 if (ureg->domain[domain].tokens == error_tokens) 220 return &error_tokens[0]; 221 222 return &ureg->domain[domain].tokens[nr]; 223} 224 225 226 227static INLINE struct ureg_dst 228ureg_dst_register( unsigned file, 229 unsigned index ) 230{ 231 struct ureg_dst dst; 232 233 dst.File = file; 234 dst.WriteMask = TGSI_WRITEMASK_XYZW; 235 dst.Indirect = 0; 236 dst.IndirectIndex = 0; 237 dst.IndirectSwizzle = 0; 238 dst.Saturate = 0; 239 dst.Predicate = 0; 240 dst.PredNegate = 0; 241 dst.PredSwizzleX = TGSI_SWIZZLE_X; 242 dst.PredSwizzleY = TGSI_SWIZZLE_Y; 243 dst.PredSwizzleZ = TGSI_SWIZZLE_Z; 244 dst.PredSwizzleW = TGSI_SWIZZLE_W; 245 dst.Index = index; 246 247 return dst; 248} 249 250 251void 252ureg_property_gs_input_prim(struct ureg_program *ureg, 253 unsigned input_prim) 254{ 255 ureg->property_gs_input_prim = input_prim; 256} 257 258void 259ureg_property_gs_output_prim(struct ureg_program *ureg, 260 unsigned output_prim) 261{ 262 ureg->property_gs_output_prim = output_prim; 263} 264 265void 266ureg_property_gs_max_vertices(struct ureg_program *ureg, 267 unsigned max_vertices) 268{ 269 ureg->property_gs_max_vertices = max_vertices; 270} 271 272void 273ureg_property_fs_coord_origin(struct ureg_program *ureg, 274 unsigned fs_coord_origin) 275{ 276 ureg->property_fs_coord_origin = fs_coord_origin; 277} 278 279void 280ureg_property_fs_coord_pixel_center(struct ureg_program *ureg, 281 unsigned fs_coord_pixel_center) 282{ 283 ureg->property_fs_coord_pixel_center = fs_coord_pixel_center; 284} 285 286 287 288struct ureg_src 289ureg_DECL_fs_input( struct ureg_program *ureg, 290 unsigned name, 291 unsigned index, 292 unsigned interp_mode ) 293{ 294 unsigned i; 295 296 for (i = 0; i < ureg->nr_fs_inputs; i++) { 297 if (ureg->fs_input[i].semantic_name == name && 298 ureg->fs_input[i].semantic_index == index) 299 goto out; 300 } 301 302 if (ureg->nr_fs_inputs < UREG_MAX_INPUT) { 303 ureg->fs_input[i].semantic_name = name; 304 ureg->fs_input[i].semantic_index = index; 305 ureg->fs_input[i].interp = interp_mode; 306 ureg->nr_fs_inputs++; 307 } 308 else { 309 set_bad( ureg ); 310 } 311 312out: 313 return ureg_src_register( TGSI_FILE_INPUT, i ); 314} 315 316 317struct ureg_src 318ureg_DECL_vs_input( struct ureg_program *ureg, 319 unsigned index ) 320{ 321 assert(ureg->processor == TGSI_PROCESSOR_VERTEX); 322 323 ureg->vs_inputs[index/32] |= 1 << (index % 32); 324 return ureg_src_register( TGSI_FILE_INPUT, index ); 325} 326 327 328struct ureg_src 329ureg_DECL_gs_input(struct ureg_program *ureg, 330 unsigned index, 331 unsigned semantic_name, 332 unsigned semantic_index) 333{ 334 if (ureg->nr_gs_inputs < UREG_MAX_INPUT) { 335 ureg->gs_input[ureg->nr_gs_inputs].index = index; 336 ureg->gs_input[ureg->nr_gs_inputs].semantic_name = semantic_name; 337 ureg->gs_input[ureg->nr_gs_inputs].semantic_index = semantic_index; 338 ureg->nr_gs_inputs++; 339 } else { 340 set_bad(ureg); 341 } 342 343 /* XXX: Add suport for true 2D input registers. */ 344 return ureg_src_register(TGSI_FILE_INPUT, index); 345} 346 347 348struct ureg_src 349ureg_DECL_system_value(struct ureg_program *ureg, 350 unsigned index, 351 unsigned semantic_name, 352 unsigned semantic_index) 353{ 354 if (ureg->nr_system_values < UREG_MAX_SYSTEM_VALUE) { 355 ureg->system_value[ureg->nr_system_values].index = index; 356 ureg->system_value[ureg->nr_system_values].semantic_name = semantic_name; 357 ureg->system_value[ureg->nr_system_values].semantic_index = semantic_index; 358 ureg->nr_system_values++; 359 } else { 360 set_bad(ureg); 361 } 362 363 return ureg_src_register(TGSI_FILE_SYSTEM_VALUE, index); 364} 365 366 367struct ureg_dst 368ureg_DECL_output( struct ureg_program *ureg, 369 unsigned name, 370 unsigned index ) 371{ 372 unsigned i; 373 374 for (i = 0; i < ureg->nr_outputs; i++) { 375 if (ureg->output[i].semantic_name == name && 376 ureg->output[i].semantic_index == index) 377 goto out; 378 } 379 380 if (ureg->nr_outputs < UREG_MAX_OUTPUT) { 381 ureg->output[i].semantic_name = name; 382 ureg->output[i].semantic_index = index; 383 ureg->nr_outputs++; 384 } 385 else { 386 set_bad( ureg ); 387 } 388 389out: 390 return ureg_dst_register( TGSI_FILE_OUTPUT, i ); 391} 392 393 394/* Returns a new constant register. Keep track of which have been 395 * referred to so that we can emit decls later. 396 * 397 * Constant operands declared with this function must be addressed 398 * with a two-dimensional index. 399 * 400 * There is nothing in this code to bind this constant to any tracked 401 * value or manage any constant_buffer contents -- that's the 402 * resposibility of the calling code. 403 */ 404void 405ureg_DECL_constant2D(struct ureg_program *ureg, 406 unsigned first, 407 unsigned last, 408 unsigned index2D) 409{ 410 struct const_decl *decl = &ureg->const_decls2D[index2D]; 411 412 assert(index2D < PIPE_MAX_CONSTANT_BUFFERS); 413 414 if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { 415 uint i = decl->nr_constant_ranges++; 416 417 decl->constant_range[i].first = first; 418 decl->constant_range[i].last = last; 419 } 420} 421 422 423/* A one-dimensional, depricated version of ureg_DECL_constant2D(). 424 * 425 * Constant operands declared with this function must be addressed 426 * with a one-dimensional index. 427 */ 428struct ureg_src 429ureg_DECL_constant(struct ureg_program *ureg, 430 unsigned index) 431{ 432 struct const_decl *decl = &ureg->const_decls; 433 unsigned minconst = index, maxconst = index; 434 unsigned i; 435 436 /* Inside existing range? 437 */ 438 for (i = 0; i < decl->nr_constant_ranges; i++) { 439 if (decl->constant_range[i].first <= index && 440 decl->constant_range[i].last >= index) { 441 goto out; 442 } 443 } 444 445 /* Extend existing range? 446 */ 447 for (i = 0; i < decl->nr_constant_ranges; i++) { 448 if (decl->constant_range[i].last == index - 1) { 449 decl->constant_range[i].last = index; 450 goto out; 451 } 452 453 if (decl->constant_range[i].first == index + 1) { 454 decl->constant_range[i].first = index; 455 goto out; 456 } 457 458 minconst = MIN2(minconst, decl->constant_range[i].first); 459 maxconst = MAX2(maxconst, decl->constant_range[i].last); 460 } 461 462 /* Create new range? 463 */ 464 if (decl->nr_constant_ranges < UREG_MAX_CONSTANT_RANGE) { 465 i = decl->nr_constant_ranges++; 466 decl->constant_range[i].first = index; 467 decl->constant_range[i].last = index; 468 goto out; 469 } 470 471 /* Collapse all ranges down to one: 472 */ 473 i = 0; 474 decl->constant_range[0].first = minconst; 475 decl->constant_range[0].last = maxconst; 476 decl->nr_constant_ranges = 1; 477 478out: 479 assert(i < decl->nr_constant_ranges); 480 assert(decl->constant_range[i].first <= index); 481 assert(decl->constant_range[i].last >= index); 482 return ureg_src_register(TGSI_FILE_CONSTANT, index); 483} 484 485 486/* Allocate a new temporary. Temporaries greater than UREG_MAX_TEMP 487 * are legal, but will not be released. 488 */ 489struct ureg_dst ureg_DECL_temporary( struct ureg_program *ureg ) 490{ 491 unsigned i; 492 493 for (i = 0; i < UREG_MAX_TEMP; i += 32) { 494 int bit = ffs(~ureg->temps_active[i/32]); 495 if (bit != 0) { 496 i += bit - 1; 497 goto out; 498 } 499 } 500 501 /* No reusable temps, so allocate a new one: 502 */ 503 i = ureg->nr_temps++; 504 505out: 506 if (i < UREG_MAX_TEMP) 507 ureg->temps_active[i/32] |= 1 << (i % 32); 508 509 if (i >= ureg->nr_temps) 510 ureg->nr_temps = i + 1; 511 512 return ureg_dst_register( TGSI_FILE_TEMPORARY, i ); 513} 514 515 516void ureg_release_temporary( struct ureg_program *ureg, 517 struct ureg_dst tmp ) 518{ 519 if(tmp.File == TGSI_FILE_TEMPORARY) 520 if (tmp.Index < UREG_MAX_TEMP) 521 ureg->temps_active[tmp.Index/32] &= ~(1 << (tmp.Index % 32)); 522} 523 524 525/* Allocate a new address register. 526 */ 527struct ureg_dst ureg_DECL_address( struct ureg_program *ureg ) 528{ 529 if (ureg->nr_addrs < UREG_MAX_ADDR) 530 return ureg_dst_register( TGSI_FILE_ADDRESS, ureg->nr_addrs++ ); 531 532 assert( 0 ); 533 return ureg_dst_register( TGSI_FILE_ADDRESS, 0 ); 534} 535 536/* Allocate a new loop register. 537 */ 538struct ureg_dst 539ureg_DECL_loop(struct ureg_program *ureg) 540{ 541 if (ureg->nr_loops < UREG_MAX_LOOP) { 542 return ureg_dst_register(TGSI_FILE_LOOP, ureg->nr_loops++); 543 } 544 545 assert(0); 546 return ureg_dst_register(TGSI_FILE_LOOP, 0); 547} 548 549/* Allocate a new predicate register. 550 */ 551struct ureg_dst 552ureg_DECL_predicate(struct ureg_program *ureg) 553{ 554 if (ureg->nr_preds < UREG_MAX_PRED) { 555 return ureg_dst_register(TGSI_FILE_PREDICATE, ureg->nr_preds++); 556 } 557 558 assert(0); 559 return ureg_dst_register(TGSI_FILE_PREDICATE, 0); 560} 561 562/* Allocate a new sampler. 563 */ 564struct ureg_src ureg_DECL_sampler( struct ureg_program *ureg, 565 unsigned nr ) 566{ 567 unsigned i; 568 569 for (i = 0; i < ureg->nr_samplers; i++) 570 if (ureg->sampler[i].Index == nr) 571 return ureg->sampler[i]; 572 573 if (i < PIPE_MAX_SAMPLERS) { 574 ureg->sampler[i] = ureg_src_register( TGSI_FILE_SAMPLER, nr ); 575 ureg->nr_samplers++; 576 return ureg->sampler[i]; 577 } 578 579 assert( 0 ); 580 return ureg->sampler[0]; 581} 582 583 584static int 585match_or_expand_immediate( const unsigned *v, 586 unsigned nr, 587 unsigned *v2, 588 unsigned *pnr2, 589 unsigned *swizzle ) 590{ 591 unsigned nr2 = *pnr2; 592 unsigned i, j; 593 594 *swizzle = 0; 595 596 for (i = 0; i < nr; i++) { 597 boolean found = FALSE; 598 599 for (j = 0; j < nr2 && !found; j++) { 600 if (v[i] == v2[j]) { 601 *swizzle |= j << (i * 2); 602 found = TRUE; 603 } 604 } 605 606 if (!found) { 607 if (nr2 >= 4) { 608 return FALSE; 609 } 610 611 v2[nr2] = v[i]; 612 *swizzle |= nr2 << (i * 2); 613 nr2++; 614 } 615 } 616 617 /* Actually expand immediate only when fully succeeded. 618 */ 619 *pnr2 = nr2; 620 return TRUE; 621} 622 623 624static struct ureg_src 625decl_immediate( struct ureg_program *ureg, 626 const unsigned *v, 627 unsigned nr, 628 unsigned type ) 629{ 630 unsigned i, j; 631 unsigned swizzle = 0; 632 633 /* Could do a first pass where we examine all existing immediates 634 * without expanding. 635 */ 636 637 for (i = 0; i < ureg->nr_immediates; i++) { 638 if (ureg->immediate[i].type != type) { 639 continue; 640 } 641 if (match_or_expand_immediate(v, 642 nr, 643 ureg->immediate[i].value.u, 644 &ureg->immediate[i].nr, 645 &swizzle)) { 646 goto out; 647 } 648 } 649 650 if (ureg->nr_immediates < UREG_MAX_IMMEDIATE) { 651 i = ureg->nr_immediates++; 652 ureg->immediate[i].type = type; 653 if (match_or_expand_immediate(v, 654 nr, 655 ureg->immediate[i].value.u, 656 &ureg->immediate[i].nr, 657 &swizzle)) { 658 goto out; 659 } 660 } 661 662 set_bad(ureg); 663 664out: 665 /* Make sure that all referenced elements are from this immediate. 666 * Has the effect of making size-one immediates into scalars. 667 */ 668 for (j = nr; j < 4; j++) { 669 swizzle |= (swizzle & 0x3) << (j * 2); 670 } 671 672 return ureg_swizzle(ureg_src_register(TGSI_FILE_IMMEDIATE, i), 673 (swizzle >> 0) & 0x3, 674 (swizzle >> 2) & 0x3, 675 (swizzle >> 4) & 0x3, 676 (swizzle >> 6) & 0x3); 677} 678 679 680struct ureg_src 681ureg_DECL_immediate( struct ureg_program *ureg, 682 const float *v, 683 unsigned nr ) 684{ 685 union { 686 float f[4]; 687 unsigned u[4]; 688 } fu; 689 unsigned int i; 690 691 for (i = 0; i < nr; i++) { 692 fu.f[i] = v[i]; 693 } 694 695 return decl_immediate(ureg, fu.u, nr, TGSI_IMM_FLOAT32); 696} 697 698 699struct ureg_src 700ureg_DECL_immediate_uint( struct ureg_program *ureg, 701 const unsigned *v, 702 unsigned nr ) 703{ 704 return decl_immediate(ureg, v, nr, TGSI_IMM_UINT32); 705} 706 707 708struct ureg_src 709ureg_DECL_immediate_block_uint( struct ureg_program *ureg, 710 const unsigned *v, 711 unsigned nr ) 712{ 713 uint index; 714 uint i; 715 716 if (ureg->nr_immediates + (nr + 3) / 4 > UREG_MAX_IMMEDIATE) { 717 set_bad(ureg); 718 return ureg_src_register(TGSI_FILE_IMMEDIATE, 0); 719 } 720 721 index = ureg->nr_immediates; 722 ureg->nr_immediates += (nr + 3) / 4; 723 724 for (i = index; i < ureg->nr_immediates; i++) { 725 ureg->immediate[i].type = TGSI_IMM_UINT32; 726 ureg->immediate[i].nr = nr > 4 ? 4 : nr; 727 memcpy(ureg->immediate[i].value.u, 728 &v[(i - index) * 4], 729 ureg->immediate[i].nr * sizeof(uint)); 730 nr -= 4; 731 } 732 733 return ureg_src_register(TGSI_FILE_IMMEDIATE, index); 734} 735 736 737struct ureg_src 738ureg_DECL_immediate_int( struct ureg_program *ureg, 739 const int *v, 740 unsigned nr ) 741{ 742 return decl_immediate(ureg, (const unsigned *)v, nr, TGSI_IMM_INT32); 743} 744 745 746void 747ureg_emit_src( struct ureg_program *ureg, 748 struct ureg_src src ) 749{ 750 unsigned size = 1 + (src.Indirect ? 1 : 0) + (src.Dimension ? 1 : 0); 751 752 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 753 unsigned n = 0; 754 755 assert(src.File != TGSI_FILE_NULL); 756 assert(src.File != TGSI_FILE_OUTPUT); 757 assert(src.File < TGSI_FILE_COUNT); 758 759 out[n].value = 0; 760 out[n].src.File = src.File; 761 out[n].src.SwizzleX = src.SwizzleX; 762 out[n].src.SwizzleY = src.SwizzleY; 763 out[n].src.SwizzleZ = src.SwizzleZ; 764 out[n].src.SwizzleW = src.SwizzleW; 765 out[n].src.Index = src.Index; 766 out[n].src.Negate = src.Negate; 767 out[0].src.Absolute = src.Absolute; 768 n++; 769 770 if (src.Indirect) { 771 out[0].src.Indirect = 1; 772 out[n].value = 0; 773 out[n].src.File = src.IndirectFile; 774 out[n].src.SwizzleX = src.IndirectSwizzle; 775 out[n].src.SwizzleY = src.IndirectSwizzle; 776 out[n].src.SwizzleZ = src.IndirectSwizzle; 777 out[n].src.SwizzleW = src.IndirectSwizzle; 778 out[n].src.Index = src.IndirectIndex; 779 n++; 780 } 781 782 if (src.Dimension) { 783 out[0].src.Dimension = 1; 784 out[n].dim.Indirect = 0; 785 out[n].dim.Dimension = 0; 786 out[n].dim.Padding = 0; 787 out[n].dim.Index = src.DimensionIndex; 788 n++; 789 } 790 791 assert(n == size); 792} 793 794 795void 796ureg_emit_dst( struct ureg_program *ureg, 797 struct ureg_dst dst ) 798{ 799 unsigned size = (1 + 800 (dst.Indirect ? 1 : 0)); 801 802 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_INSN, size ); 803 unsigned n = 0; 804 805 assert(dst.File != TGSI_FILE_NULL); 806 assert(dst.File != TGSI_FILE_CONSTANT); 807 assert(dst.File != TGSI_FILE_INPUT); 808 assert(dst.File != TGSI_FILE_SAMPLER); 809 assert(dst.File != TGSI_FILE_IMMEDIATE); 810 assert(dst.File < TGSI_FILE_COUNT); 811 812 out[n].value = 0; 813 out[n].dst.File = dst.File; 814 out[n].dst.WriteMask = dst.WriteMask; 815 out[n].dst.Indirect = dst.Indirect; 816 out[n].dst.Index = dst.Index; 817 n++; 818 819 if (dst.Indirect) { 820 out[n].value = 0; 821 out[n].src.File = TGSI_FILE_ADDRESS; 822 out[n].src.SwizzleX = dst.IndirectSwizzle; 823 out[n].src.SwizzleY = dst.IndirectSwizzle; 824 out[n].src.SwizzleZ = dst.IndirectSwizzle; 825 out[n].src.SwizzleW = dst.IndirectSwizzle; 826 out[n].src.Index = dst.IndirectIndex; 827 n++; 828 } 829 830 assert(n == size); 831} 832 833 834static void validate( unsigned opcode, 835 unsigned nr_dst, 836 unsigned nr_src ) 837{ 838#ifdef DEBUG 839 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( opcode ); 840 assert(info); 841 if(info) { 842 assert(nr_dst == info->num_dst); 843 assert(nr_src == info->num_src); 844 } 845#endif 846} 847 848struct ureg_emit_insn_result 849ureg_emit_insn(struct ureg_program *ureg, 850 unsigned opcode, 851 boolean saturate, 852 boolean predicate, 853 boolean pred_negate, 854 unsigned pred_swizzle_x, 855 unsigned pred_swizzle_y, 856 unsigned pred_swizzle_z, 857 unsigned pred_swizzle_w, 858 unsigned num_dst, 859 unsigned num_src ) 860{ 861 union tgsi_any_token *out; 862 uint count = predicate ? 2 : 1; 863 struct ureg_emit_insn_result result; 864 865 validate( opcode, num_dst, num_src ); 866 867 out = get_tokens( ureg, DOMAIN_INSN, count ); 868 out[0].insn = tgsi_default_instruction(); 869 out[0].insn.Opcode = opcode; 870 out[0].insn.Saturate = saturate; 871 out[0].insn.NumDstRegs = num_dst; 872 out[0].insn.NumSrcRegs = num_src; 873 874 result.insn_token = ureg->domain[DOMAIN_INSN].count - count; 875 result.extended_token = result.insn_token; 876 877 if (predicate) { 878 out[0].insn.Predicate = 1; 879 out[1].insn_predicate = tgsi_default_instruction_predicate(); 880 out[1].insn_predicate.Negate = pred_negate; 881 out[1].insn_predicate.SwizzleX = pred_swizzle_x; 882 out[1].insn_predicate.SwizzleY = pred_swizzle_y; 883 out[1].insn_predicate.SwizzleZ = pred_swizzle_z; 884 out[1].insn_predicate.SwizzleW = pred_swizzle_w; 885 } 886 887 ureg->nr_instructions++; 888 889 return result; 890} 891 892 893void 894ureg_emit_label(struct ureg_program *ureg, 895 unsigned extended_token, 896 unsigned *label_token ) 897{ 898 union tgsi_any_token *out, *insn; 899 900 if(!label_token) 901 return; 902 903 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 904 out[0].value = 0; 905 906 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 907 insn->insn.Label = 1; 908 909 *label_token = ureg->domain[DOMAIN_INSN].count - 1; 910} 911 912/* Will return a number which can be used in a label to point to the 913 * next instruction to be emitted. 914 */ 915unsigned 916ureg_get_instruction_number( struct ureg_program *ureg ) 917{ 918 return ureg->nr_instructions; 919} 920 921/* Patch a given label (expressed as a token number) to point to a 922 * given instruction (expressed as an instruction number). 923 */ 924void 925ureg_fixup_label(struct ureg_program *ureg, 926 unsigned label_token, 927 unsigned instruction_number ) 928{ 929 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, label_token ); 930 931 out->insn_label.Label = instruction_number; 932} 933 934 935void 936ureg_emit_texture(struct ureg_program *ureg, 937 unsigned extended_token, 938 unsigned target ) 939{ 940 union tgsi_any_token *out, *insn; 941 942 out = get_tokens( ureg, DOMAIN_INSN, 1 ); 943 insn = retrieve_token( ureg, DOMAIN_INSN, extended_token ); 944 945 insn->insn.Texture = 1; 946 947 out[0].value = 0; 948 out[0].insn_texture.Texture = target; 949} 950 951 952void 953ureg_fixup_insn_size(struct ureg_program *ureg, 954 unsigned insn ) 955{ 956 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_INSN, insn ); 957 958 assert(out->insn.Type == TGSI_TOKEN_TYPE_INSTRUCTION); 959 out->insn.NrTokens = ureg->domain[DOMAIN_INSN].count - insn - 1; 960} 961 962 963void 964ureg_insn(struct ureg_program *ureg, 965 unsigned opcode, 966 const struct ureg_dst *dst, 967 unsigned nr_dst, 968 const struct ureg_src *src, 969 unsigned nr_src ) 970{ 971 struct ureg_emit_insn_result insn; 972 unsigned i; 973 boolean saturate; 974 boolean predicate; 975 boolean negate = FALSE; 976 unsigned swizzle[4] = { 0 }; 977 978 saturate = nr_dst ? dst[0].Saturate : FALSE; 979 predicate = nr_dst ? dst[0].Predicate : FALSE; 980 if (predicate) { 981 negate = dst[0].PredNegate; 982 swizzle[0] = dst[0].PredSwizzleX; 983 swizzle[1] = dst[0].PredSwizzleY; 984 swizzle[2] = dst[0].PredSwizzleZ; 985 swizzle[3] = dst[0].PredSwizzleW; 986 } 987 988 insn = ureg_emit_insn(ureg, 989 opcode, 990 saturate, 991 predicate, 992 negate, 993 swizzle[0], 994 swizzle[1], 995 swizzle[2], 996 swizzle[3], 997 nr_dst, 998 nr_src); 999 1000 for (i = 0; i < nr_dst; i++) 1001 ureg_emit_dst( ureg, dst[i] ); 1002 1003 for (i = 0; i < nr_src; i++) 1004 ureg_emit_src( ureg, src[i] ); 1005 1006 ureg_fixup_insn_size( ureg, insn.insn_token ); 1007} 1008 1009void 1010ureg_tex_insn(struct ureg_program *ureg, 1011 unsigned opcode, 1012 const struct ureg_dst *dst, 1013 unsigned nr_dst, 1014 unsigned target, 1015 const struct ureg_src *src, 1016 unsigned nr_src ) 1017{ 1018 struct ureg_emit_insn_result insn; 1019 unsigned i; 1020 boolean saturate; 1021 boolean predicate; 1022 boolean negate = FALSE; 1023 unsigned swizzle[4] = { 0 }; 1024 1025 saturate = nr_dst ? dst[0].Saturate : FALSE; 1026 predicate = nr_dst ? dst[0].Predicate : FALSE; 1027 if (predicate) { 1028 negate = dst[0].PredNegate; 1029 swizzle[0] = dst[0].PredSwizzleX; 1030 swizzle[1] = dst[0].PredSwizzleY; 1031 swizzle[2] = dst[0].PredSwizzleZ; 1032 swizzle[3] = dst[0].PredSwizzleW; 1033 } 1034 1035 insn = ureg_emit_insn(ureg, 1036 opcode, 1037 saturate, 1038 predicate, 1039 negate, 1040 swizzle[0], 1041 swizzle[1], 1042 swizzle[2], 1043 swizzle[3], 1044 nr_dst, 1045 nr_src); 1046 1047 ureg_emit_texture( ureg, insn.extended_token, target ); 1048 1049 for (i = 0; i < nr_dst; i++) 1050 ureg_emit_dst( ureg, dst[i] ); 1051 1052 for (i = 0; i < nr_src; i++) 1053 ureg_emit_src( ureg, src[i] ); 1054 1055 ureg_fixup_insn_size( ureg, insn.insn_token ); 1056} 1057 1058 1059void 1060ureg_label_insn(struct ureg_program *ureg, 1061 unsigned opcode, 1062 const struct ureg_src *src, 1063 unsigned nr_src, 1064 unsigned *label_token ) 1065{ 1066 struct ureg_emit_insn_result insn; 1067 unsigned i; 1068 1069 insn = ureg_emit_insn(ureg, 1070 opcode, 1071 FALSE, 1072 FALSE, 1073 FALSE, 1074 TGSI_SWIZZLE_X, 1075 TGSI_SWIZZLE_Y, 1076 TGSI_SWIZZLE_Z, 1077 TGSI_SWIZZLE_W, 1078 0, 1079 nr_src); 1080 1081 ureg_emit_label( ureg, insn.extended_token, label_token ); 1082 1083 for (i = 0; i < nr_src; i++) 1084 ureg_emit_src( ureg, src[i] ); 1085 1086 ureg_fixup_insn_size( ureg, insn.insn_token ); 1087} 1088 1089 1090 1091static void emit_decl( struct ureg_program *ureg, 1092 unsigned file, 1093 unsigned index, 1094 unsigned semantic_name, 1095 unsigned semantic_index, 1096 unsigned interp ) 1097{ 1098 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 3 ); 1099 1100 out[0].value = 0; 1101 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1102 out[0].decl.NrTokens = 3; 1103 out[0].decl.File = file; 1104 out[0].decl.UsageMask = TGSI_WRITEMASK_XYZW; /* FIXME! */ 1105 out[0].decl.Interpolate = interp; 1106 out[0].decl.Semantic = 1; 1107 1108 out[1].value = 0; 1109 out[1].decl_range.First = 1110 out[1].decl_range.Last = index; 1111 1112 out[2].value = 0; 1113 out[2].decl_semantic.Name = semantic_name; 1114 out[2].decl_semantic.Index = semantic_index; 1115 1116} 1117 1118 1119static void emit_decl_range( struct ureg_program *ureg, 1120 unsigned file, 1121 unsigned first, 1122 unsigned count ) 1123{ 1124 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 1125 1126 out[0].value = 0; 1127 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1128 out[0].decl.NrTokens = 2; 1129 out[0].decl.File = file; 1130 out[0].decl.UsageMask = 0xf; 1131 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 1132 out[0].decl.Semantic = 0; 1133 1134 out[1].value = 0; 1135 out[1].decl_range.First = first; 1136 out[1].decl_range.Last = first + count - 1; 1137} 1138 1139static void 1140emit_decl_range2D(struct ureg_program *ureg, 1141 unsigned file, 1142 unsigned first, 1143 unsigned last, 1144 unsigned index2D) 1145{ 1146 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 3); 1147 1148 out[0].value = 0; 1149 out[0].decl.Type = TGSI_TOKEN_TYPE_DECLARATION; 1150 out[0].decl.NrTokens = 3; 1151 out[0].decl.File = file; 1152 out[0].decl.UsageMask = 0xf; 1153 out[0].decl.Interpolate = TGSI_INTERPOLATE_CONSTANT; 1154 out[0].decl.Dimension = 1; 1155 1156 out[1].value = 0; 1157 out[1].decl_range.First = first; 1158 out[1].decl_range.Last = last; 1159 1160 out[2].value = 0; 1161 out[2].decl_dim.Index2D = index2D; 1162} 1163 1164static void 1165emit_immediate( struct ureg_program *ureg, 1166 const unsigned *v, 1167 unsigned type ) 1168{ 1169 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 5 ); 1170 1171 out[0].value = 0; 1172 out[0].imm.Type = TGSI_TOKEN_TYPE_IMMEDIATE; 1173 out[0].imm.NrTokens = 5; 1174 out[0].imm.DataType = type; 1175 out[0].imm.Padding = 0; 1176 1177 out[1].imm_data.Uint = v[0]; 1178 out[2].imm_data.Uint = v[1]; 1179 out[3].imm_data.Uint = v[2]; 1180 out[4].imm_data.Uint = v[3]; 1181} 1182 1183static void 1184emit_property(struct ureg_program *ureg, 1185 unsigned name, 1186 unsigned data) 1187{ 1188 union tgsi_any_token *out = get_tokens(ureg, DOMAIN_DECL, 2); 1189 1190 out[0].value = 0; 1191 out[0].prop.Type = TGSI_TOKEN_TYPE_PROPERTY; 1192 out[0].prop.NrTokens = 2; 1193 out[0].prop.PropertyName = name; 1194 1195 out[1].prop_data.Data = data; 1196} 1197 1198 1199static void emit_decls( struct ureg_program *ureg ) 1200{ 1201 unsigned i; 1202 1203 if (ureg->property_gs_input_prim != ~0) { 1204 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1205 1206 emit_property(ureg, 1207 TGSI_PROPERTY_GS_INPUT_PRIM, 1208 ureg->property_gs_input_prim); 1209 } 1210 1211 if (ureg->property_gs_output_prim != ~0) { 1212 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1213 1214 emit_property(ureg, 1215 TGSI_PROPERTY_GS_OUTPUT_PRIM, 1216 ureg->property_gs_output_prim); 1217 } 1218 1219 if (ureg->property_gs_max_vertices != ~0) { 1220 assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY); 1221 1222 emit_property(ureg, 1223 TGSI_PROPERTY_GS_MAX_VERTICES, 1224 ureg->property_gs_max_vertices); 1225 } 1226 1227 if (ureg->property_fs_coord_origin) { 1228 assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); 1229 1230 emit_property(ureg, 1231 TGSI_PROPERTY_FS_COORD_ORIGIN, 1232 ureg->property_fs_coord_origin); 1233 } 1234 1235 if (ureg->property_fs_coord_pixel_center) { 1236 assert(ureg->processor == TGSI_PROCESSOR_FRAGMENT); 1237 1238 emit_property(ureg, 1239 TGSI_PROPERTY_FS_COORD_PIXEL_CENTER, 1240 ureg->property_fs_coord_pixel_center); 1241 } 1242 1243 if (ureg->processor == TGSI_PROCESSOR_VERTEX) { 1244 for (i = 0; i < UREG_MAX_INPUT; i++) { 1245 if (ureg->vs_inputs[i/32] & (1 << (i%32))) { 1246 emit_decl_range( ureg, TGSI_FILE_INPUT, i, 1 ); 1247 } 1248 } 1249 } else if (ureg->processor == TGSI_PROCESSOR_FRAGMENT) { 1250 for (i = 0; i < ureg->nr_fs_inputs; i++) { 1251 emit_decl( ureg, 1252 TGSI_FILE_INPUT, 1253 i, 1254 ureg->fs_input[i].semantic_name, 1255 ureg->fs_input[i].semantic_index, 1256 ureg->fs_input[i].interp ); 1257 } 1258 } else { 1259 for (i = 0; i < ureg->nr_gs_inputs; i++) { 1260 emit_decl(ureg, 1261 TGSI_FILE_INPUT, 1262 ureg->gs_input[i].index, 1263 ureg->gs_input[i].semantic_name, 1264 ureg->gs_input[i].semantic_index, 1265 TGSI_INTERPOLATE_CONSTANT); 1266 } 1267 } 1268 1269 for (i = 0; i < ureg->nr_system_values; i++) { 1270 emit_decl(ureg, 1271 TGSI_FILE_SYSTEM_VALUE, 1272 ureg->system_value[i].index, 1273 ureg->system_value[i].semantic_name, 1274 ureg->system_value[i].semantic_index, 1275 TGSI_INTERPOLATE_CONSTANT); 1276 } 1277 1278 for (i = 0; i < ureg->nr_outputs; i++) { 1279 emit_decl( ureg, 1280 TGSI_FILE_OUTPUT, 1281 i, 1282 ureg->output[i].semantic_name, 1283 ureg->output[i].semantic_index, 1284 TGSI_INTERPOLATE_CONSTANT ); 1285 } 1286 1287 for (i = 0; i < ureg->nr_samplers; i++) { 1288 emit_decl_range( ureg, 1289 TGSI_FILE_SAMPLER, 1290 ureg->sampler[i].Index, 1 ); 1291 } 1292 1293 if (ureg->const_decls.nr_constant_ranges) { 1294 for (i = 0; i < ureg->const_decls.nr_constant_ranges; i++) { 1295 emit_decl_range(ureg, 1296 TGSI_FILE_CONSTANT, 1297 ureg->const_decls.constant_range[i].first, 1298 ureg->const_decls.constant_range[i].last - ureg->const_decls.constant_range[i].first + 1); 1299 } 1300 } 1301 1302 for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { 1303 struct const_decl *decl = &ureg->const_decls2D[i]; 1304 1305 if (decl->nr_constant_ranges) { 1306 uint j; 1307 1308 for (j = 0; j < decl->nr_constant_ranges; j++) { 1309 emit_decl_range2D(ureg, 1310 TGSI_FILE_CONSTANT, 1311 decl->constant_range[j].first, 1312 decl->constant_range[j].last, 1313 i); 1314 } 1315 } 1316 } 1317 1318 if (ureg->nr_temps) { 1319 emit_decl_range( ureg, 1320 TGSI_FILE_TEMPORARY, 1321 0, ureg->nr_temps ); 1322 } 1323 1324 if (ureg->nr_addrs) { 1325 emit_decl_range( ureg, 1326 TGSI_FILE_ADDRESS, 1327 0, ureg->nr_addrs ); 1328 } 1329 1330 if (ureg->nr_loops) { 1331 emit_decl_range(ureg, 1332 TGSI_FILE_LOOP, 1333 0, 1334 ureg->nr_loops); 1335 } 1336 1337 if (ureg->nr_preds) { 1338 emit_decl_range(ureg, 1339 TGSI_FILE_PREDICATE, 1340 0, 1341 ureg->nr_preds); 1342 } 1343 1344 for (i = 0; i < ureg->nr_immediates; i++) { 1345 emit_immediate( ureg, 1346 ureg->immediate[i].value.u, 1347 ureg->immediate[i].type ); 1348 } 1349} 1350 1351/* Append the instruction tokens onto the declarations to build a 1352 * contiguous stream suitable to send to the driver. 1353 */ 1354static void copy_instructions( struct ureg_program *ureg ) 1355{ 1356 unsigned nr_tokens = ureg->domain[DOMAIN_INSN].count; 1357 union tgsi_any_token *out = get_tokens( ureg, 1358 DOMAIN_DECL, 1359 nr_tokens ); 1360 1361 memcpy(out, 1362 ureg->domain[DOMAIN_INSN].tokens, 1363 nr_tokens * sizeof out[0] ); 1364} 1365 1366 1367static void 1368fixup_header_size(struct ureg_program *ureg) 1369{ 1370 union tgsi_any_token *out = retrieve_token( ureg, DOMAIN_DECL, 0 ); 1371 1372 out->header.BodySize = ureg->domain[DOMAIN_DECL].count - 2; 1373} 1374 1375 1376static void 1377emit_header( struct ureg_program *ureg ) 1378{ 1379 union tgsi_any_token *out = get_tokens( ureg, DOMAIN_DECL, 2 ); 1380 1381 out[0].header.HeaderSize = 2; 1382 out[0].header.BodySize = 0; 1383 1384 out[1].processor.Processor = ureg->processor; 1385 out[1].processor.Padding = 0; 1386} 1387 1388 1389const struct tgsi_token *ureg_finalize( struct ureg_program *ureg ) 1390{ 1391 const struct tgsi_token *tokens; 1392 1393 emit_header( ureg ); 1394 emit_decls( ureg ); 1395 copy_instructions( ureg ); 1396 fixup_header_size( ureg ); 1397 1398 if (ureg->domain[0].tokens == error_tokens || 1399 ureg->domain[1].tokens == error_tokens) { 1400 debug_printf("%s: error in generated shader\n", __FUNCTION__); 1401 assert(0); 1402 return NULL; 1403 } 1404 1405 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1406 1407 if (0) { 1408 debug_printf("%s: emitted shader %d tokens:\n", __FUNCTION__, 1409 ureg->domain[DOMAIN_DECL].count); 1410 tgsi_dump( tokens, 0 ); 1411 } 1412 1413#if DEBUG 1414 if (tokens && !tgsi_sanity_check(tokens)) { 1415 debug_printf("tgsi_ureg.c, sanity check failed on generated tokens:\n"); 1416 tgsi_dump(tokens, 0); 1417 assert(0); 1418 } 1419#endif 1420 1421 1422 return tokens; 1423} 1424 1425 1426void *ureg_create_shader( struct ureg_program *ureg, 1427 struct pipe_context *pipe ) 1428{ 1429 struct pipe_shader_state state; 1430 1431 state.tokens = ureg_finalize(ureg); 1432 if(!state.tokens) 1433 return NULL; 1434 1435 if (ureg->processor == TGSI_PROCESSOR_VERTEX) 1436 return pipe->create_vs_state( pipe, &state ); 1437 else 1438 return pipe->create_fs_state( pipe, &state ); 1439} 1440 1441 1442const struct tgsi_token *ureg_get_tokens( struct ureg_program *ureg, 1443 unsigned *nr_tokens ) 1444{ 1445 const struct tgsi_token *tokens; 1446 1447 ureg_finalize(ureg); 1448 1449 tokens = &ureg->domain[DOMAIN_DECL].tokens[0].token; 1450 1451 if (nr_tokens) 1452 *nr_tokens = ureg->domain[DOMAIN_DECL].size; 1453 1454 ureg->domain[DOMAIN_DECL].tokens = 0; 1455 ureg->domain[DOMAIN_DECL].size = 0; 1456 ureg->domain[DOMAIN_DECL].order = 0; 1457 ureg->domain[DOMAIN_DECL].count = 0; 1458 1459 return tokens; 1460} 1461 1462 1463struct ureg_program *ureg_create( unsigned processor ) 1464{ 1465 struct ureg_program *ureg = CALLOC_STRUCT( ureg_program ); 1466 if (ureg == NULL) 1467 return NULL; 1468 1469 ureg->processor = processor; 1470 ureg->property_gs_input_prim = ~0; 1471 ureg->property_gs_output_prim = ~0; 1472 ureg->property_gs_max_vertices = ~0; 1473 return ureg; 1474} 1475 1476 1477void ureg_destroy( struct ureg_program *ureg ) 1478{ 1479 unsigned i; 1480 1481 for (i = 0; i < Elements(ureg->domain); i++) { 1482 if (ureg->domain[i].tokens && 1483 ureg->domain[i].tokens != error_tokens) 1484 FREE(ureg->domain[i].tokens); 1485 } 1486 1487 FREE(ureg); 1488} 1489