tgsi: make sure that we print out the adjacency prims correctly
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_dump.c
1 /**************************************************************************
2 *
3 * Copyright 2007-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_string.h"
30 #include "util/u_math.h"
31 #include "util/u_memory.h"
32 #include "tgsi_dump.h"
33 #include "tgsi_info.h"
34 #include "tgsi_iterate.h"
35
36
37 /** Number of spaces to indent for IF/LOOP/etc */
38 static const int indent_spaces = 3;
39
40
41 struct dump_ctx
42 {
43 struct tgsi_iterate_context iter;
44
45 uint instno;
46 int indent;
47
48 uint indentation;
49
50 void (*printf)(struct dump_ctx *ctx, const char *format, ...);
51 };
52
53 static void
54 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
55 {
56 va_list ap;
57 (void)ctx;
58 va_start(ap, format);
59 _debug_vprintf(format, ap);
60 va_end(ap);
61 }
62
63 static void
64 dump_enum(
65 struct dump_ctx *ctx,
66 uint e,
67 const char **enums,
68 uint enum_count )
69 {
70 if (e >= enum_count)
71 ctx->printf( ctx, "%u", e );
72 else
73 ctx->printf( ctx, "%s", enums[e] );
74 }
75
76 #define EOL() ctx->printf( ctx, "\n" )
77 #define TXT(S) ctx->printf( ctx, "%s", S )
78 #define CHR(C) ctx->printf( ctx, "%c", C )
79 #define UIX(I) ctx->printf( ctx, "0x%x", I )
80 #define UID(I) ctx->printf( ctx, "%u", I )
81 #define INSTID(I) ctx->printf( ctx, "% 3u", I )
82 #define SID(I) ctx->printf( ctx, "%d", I )
83 #define FLT(F) ctx->printf( ctx, "%10.4f", F )
84 #define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) )
85
86 static const char *processor_type_names[] =
87 {
88 "FRAG",
89 "VERT",
90 "GEOM"
91 };
92
93 static const char *file_names[TGSI_FILE_COUNT] =
94 {
95 "NULL",
96 "CONST",
97 "IN",
98 "OUT",
99 "TEMP",
100 "SAMP",
101 "ADDR",
102 "IMM",
103 "PRED",
104 "SV",
105 "IMMX",
106 "TEMPX"
107 };
108
109 static const char *interpolate_names[] =
110 {
111 "CONSTANT",
112 "LINEAR",
113 "PERSPECTIVE"
114 };
115
116 static const char *semantic_names[] =
117 {
118 "POSITION",
119 "COLOR",
120 "BCOLOR",
121 "FOG",
122 "PSIZE",
123 "GENERIC",
124 "NORMAL",
125 "FACE",
126 "EDGEFLAG",
127 "PRIM_ID",
128 "INSTANCEID"
129 };
130
131 static const char *immediate_type_names[] =
132 {
133 "FLT32",
134 "UINT32",
135 "INT32"
136 };
137
138 static const char *swizzle_names[] =
139 {
140 "x",
141 "y",
142 "z",
143 "w"
144 };
145
146 static const char *texture_names[] =
147 {
148 "UNKNOWN",
149 "1D",
150 "2D",
151 "3D",
152 "CUBE",
153 "RECT",
154 "SHADOW1D",
155 "SHADOW2D",
156 "SHADOWRECT"
157 };
158
159 static const char *property_names[] =
160 {
161 "GS_INPUT_PRIMITIVE",
162 "GS_OUTPUT_PRIMITIVE",
163 "GS_MAX_OUTPUT_VERTICES",
164 "FS_COORD_ORIGIN",
165 "FS_COORD_PIXEL_CENTER"
166 };
167
168 static const char *primitive_names[] =
169 {
170 "POINTS",
171 "LINES",
172 "LINE_LOOP",
173 "LINE_STRIP",
174 "TRIANGLES",
175 "TRIANGLE_STRIP",
176 "TRIANGLE_FAN",
177 "QUADS",
178 "QUAD_STRIP",
179 "POLYGON",
180 "LINES_ADJACENCY",
181 "LINE_STRIP_ADJACENCY",
182 "TRIANGLES_ADJACENCY",
183 "TRIANGLE_STRIP_ADJACENCY"
184 };
185
186 static const char *fs_coord_origin_names[] =
187 {
188 "UPPER_LEFT",
189 "LOWER_LEFT"
190 };
191
192 static const char *fs_coord_pixel_center_names[] =
193 {
194 "HALF_INTEGER",
195 "INTEGER"
196 };
197
198
199 static void
200 _dump_register_src(
201 struct dump_ctx *ctx,
202 const struct tgsi_full_src_register *src )
203 {
204 ENM(src->Register.File, file_names);
205 if (src->Register.Dimension) {
206 if (src->Dimension.Indirect) {
207 CHR( '[' );
208 ENM( src->DimIndirect.File, file_names );
209 CHR( '[' );
210 SID( src->DimIndirect.Index );
211 TXT( "]." );
212 ENM( src->DimIndirect.SwizzleX, swizzle_names );
213 if (src->Dimension.Index != 0) {
214 if (src->Dimension.Index > 0)
215 CHR( '+' );
216 SID( src->Dimension.Index );
217 }
218 CHR( ']' );
219 } else {
220 CHR('[');
221 SID(src->Dimension.Index);
222 CHR(']');
223 }
224 }
225 if (src->Register.Indirect) {
226 CHR( '[' );
227 ENM( src->Indirect.File, file_names );
228 CHR( '[' );
229 SID( src->Indirect.Index );
230 TXT( "]." );
231 ENM( src->Indirect.SwizzleX, swizzle_names );
232 if (src->Register.Index != 0) {
233 if (src->Register.Index > 0)
234 CHR( '+' );
235 SID( src->Register.Index );
236 }
237 CHR( ']' );
238 } else {
239 CHR( '[' );
240 SID( src->Register.Index );
241 CHR( ']' );
242 }
243 }
244
245
246 static void
247 _dump_register_dst(
248 struct dump_ctx *ctx,
249 const struct tgsi_full_dst_register *dst )
250 {
251 ENM(dst->Register.File, file_names);
252 if (dst->Register.Dimension) {
253 if (dst->Dimension.Indirect) {
254 CHR( '[' );
255 ENM( dst->DimIndirect.File, file_names );
256 CHR( '[' );
257 SID( dst->DimIndirect.Index );
258 TXT( "]." );
259 ENM( dst->DimIndirect.SwizzleX, swizzle_names );
260 if (dst->Dimension.Index != 0) {
261 if (dst->Dimension.Index > 0)
262 CHR( '+' );
263 SID( dst->Dimension.Index );
264 }
265 CHR( ']' );
266 } else {
267 CHR('[');
268 SID(dst->Dimension.Index);
269 CHR(']');
270 }
271 }
272 if (dst->Register.Indirect) {
273 CHR( '[' );
274 ENM( dst->Indirect.File, file_names );
275 CHR( '[' );
276 SID( dst->Indirect.Index );
277 TXT( "]." );
278 ENM( dst->Indirect.SwizzleX, swizzle_names );
279 if (dst->Register.Index != 0) {
280 if (dst->Register.Index > 0)
281 CHR( '+' );
282 SID( dst->Register.Index );
283 }
284 CHR( ']' );
285 } else {
286 CHR( '[' );
287 SID( dst->Register.Index );
288 CHR( ']' );
289 }
290 }
291 static void
292 _dump_writemask(
293 struct dump_ctx *ctx,
294 uint writemask )
295 {
296 if (writemask != TGSI_WRITEMASK_XYZW) {
297 CHR( '.' );
298 if (writemask & TGSI_WRITEMASK_X)
299 CHR( 'x' );
300 if (writemask & TGSI_WRITEMASK_Y)
301 CHR( 'y' );
302 if (writemask & TGSI_WRITEMASK_Z)
303 CHR( 'z' );
304 if (writemask & TGSI_WRITEMASK_W)
305 CHR( 'w' );
306 }
307 }
308
309 static void
310 dump_imm_data(struct tgsi_iterate_context *iter,
311 union tgsi_immediate_data *data,
312 unsigned num_tokens,
313 unsigned data_type)
314 {
315 struct dump_ctx *ctx = (struct dump_ctx *)iter;
316 unsigned i ;
317
318 TXT( " {" );
319
320 assert( num_tokens <= 4 );
321 for (i = 0; i < num_tokens; i++) {
322 switch (data_type) {
323 case TGSI_IMM_FLOAT32:
324 FLT( data[i].Float );
325 break;
326 case TGSI_IMM_UINT32:
327 UID(data[i].Uint);
328 break;
329 case TGSI_IMM_INT32:
330 SID(data[i].Int);
331 break;
332 default:
333 assert( 0 );
334 }
335
336 if (i < num_tokens - 1)
337 TXT( ", " );
338 }
339 TXT( "}" );
340 }
341
342 static boolean
343 iter_declaration(
344 struct tgsi_iterate_context *iter,
345 struct tgsi_full_declaration *decl )
346 {
347 struct dump_ctx *ctx = (struct dump_ctx *)iter;
348
349 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
350 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
351
352 TXT( "DCL " );
353
354 ENM(decl->Declaration.File, file_names);
355
356 /* all geometry shader inputs are two dimensional */
357 if (decl->Declaration.File == TGSI_FILE_INPUT &&
358 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
359 TXT("[]");
360 }
361
362 if (decl->Declaration.Dimension) {
363 CHR('[');
364 SID(decl->Dim.Index2D);
365 CHR(']');
366 }
367
368 CHR('[');
369 SID(decl->Range.First);
370 if (decl->Range.First != decl->Range.Last) {
371 TXT("..");
372 SID(decl->Range.Last);
373 }
374 CHR(']');
375
376 _dump_writemask(
377 ctx,
378 decl->Declaration.UsageMask );
379
380 if (decl->Declaration.Semantic) {
381 TXT( ", " );
382 ENM( decl->Semantic.Name, semantic_names );
383 if (decl->Semantic.Index != 0 ||
384 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
385 CHR( '[' );
386 UID( decl->Semantic.Index );
387 CHR( ']' );
388 }
389 }
390
391 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
392 decl->Declaration.File == TGSI_FILE_INPUT)
393 {
394 TXT( ", " );
395 ENM( decl->Declaration.Interpolate, interpolate_names );
396 }
397
398 if (decl->Declaration.Centroid) {
399 TXT( ", CENTROID" );
400 }
401
402 if (decl->Declaration.Invariant) {
403 TXT( ", INVARIANT" );
404 }
405
406 if (decl->Declaration.CylindricalWrap) {
407 TXT(", CYLWRAP_");
408 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
409 CHR('X');
410 }
411 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
412 CHR('Y');
413 }
414 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
415 CHR('Z');
416 }
417 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
418 CHR('W');
419 }
420 }
421
422 if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) {
423 unsigned i;
424 char range_indent[4];
425
426 TXT(" {");
427
428 if (decl->Range.Last < 10)
429 range_indent[0] = '\0';
430 else if (decl->Range.Last < 100) {
431 range_indent[0] = ' ';
432 range_indent[1] = '\0';
433 } else if (decl->Range.Last < 1000) {
434 range_indent[0] = ' ';
435 range_indent[1] = ' ';
436 range_indent[2] = '\0';
437 } else {
438 range_indent[0] = ' ';
439 range_indent[1] = ' ';
440 range_indent[2] = ' ';
441 range_indent[3] = '\0';
442 }
443
444 dump_imm_data(iter, decl->ImmediateData.u,
445 4, TGSI_IMM_FLOAT32);
446 for(i = 1; i <= decl->Range.Last; ++i) {
447 /* indent by strlen of:
448 * "DCL IMMX[0..1] {" */
449 CHR('\n');
450 TXT( " " );
451 TXT( range_indent );
452 dump_imm_data(iter, decl->ImmediateData.u + i,
453 4, TGSI_IMM_FLOAT32);
454 }
455
456 TXT(" }");
457 }
458
459 EOL();
460
461 return TRUE;
462 }
463
464 void
465 tgsi_dump_declaration(
466 const struct tgsi_full_declaration *decl )
467 {
468 struct dump_ctx ctx;
469
470 ctx.printf = dump_ctx_printf;
471
472 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
473 }
474
475 static boolean
476 iter_property(
477 struct tgsi_iterate_context *iter,
478 struct tgsi_full_property *prop )
479 {
480 int i;
481 struct dump_ctx *ctx = (struct dump_ctx *)iter;
482
483 assert(Elements(property_names) == TGSI_PROPERTY_COUNT);
484
485 TXT( "PROPERTY " );
486 ENM(prop->Property.PropertyName, property_names);
487
488 if (prop->Property.NrTokens > 1)
489 TXT(" ");
490
491 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
492 switch (prop->Property.PropertyName) {
493 case TGSI_PROPERTY_GS_INPUT_PRIM:
494 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
495 ENM(prop->u[i].Data, primitive_names);
496 break;
497 case TGSI_PROPERTY_FS_COORD_ORIGIN:
498 ENM(prop->u[i].Data, fs_coord_origin_names);
499 break;
500 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
501 ENM(prop->u[i].Data, fs_coord_pixel_center_names);
502 break;
503 default:
504 SID( prop->u[i].Data );
505 break;
506 }
507 if (i < prop->Property.NrTokens - 2)
508 TXT( ", " );
509 }
510 EOL();
511
512 return TRUE;
513 }
514
515 void tgsi_dump_property(
516 const struct tgsi_full_property *prop )
517 {
518 struct dump_ctx ctx;
519
520 ctx.printf = dump_ctx_printf;
521
522 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
523 }
524
525 static boolean
526 iter_immediate(
527 struct tgsi_iterate_context *iter,
528 struct tgsi_full_immediate *imm )
529 {
530 struct dump_ctx *ctx = (struct dump_ctx *) iter;
531
532 TXT( "IMM " );
533 ENM( imm->Immediate.DataType, immediate_type_names );
534
535 dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
536 imm->Immediate.DataType);
537
538 EOL();
539
540 return TRUE;
541 }
542
543 void
544 tgsi_dump_immediate(
545 const struct tgsi_full_immediate *imm )
546 {
547 struct dump_ctx ctx;
548
549 ctx.printf = dump_ctx_printf;
550
551 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
552 }
553
554 static boolean
555 iter_instruction(
556 struct tgsi_iterate_context *iter,
557 struct tgsi_full_instruction *inst )
558 {
559 struct dump_ctx *ctx = (struct dump_ctx *) iter;
560 uint instno = ctx->instno++;
561 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
562 uint i;
563 boolean first_reg = TRUE;
564
565 INSTID( instno );
566 TXT( ": " );
567
568 ctx->indent -= info->pre_dedent;
569 for(i = 0; (int)i < ctx->indent; ++i)
570 TXT( " " );
571 ctx->indent += info->post_indent;
572
573 if (inst->Instruction.Predicate) {
574 CHR( '(' );
575
576 if (inst->Predicate.Negate)
577 CHR( '!' );
578
579 TXT( "PRED[" );
580 SID( inst->Predicate.Index );
581 CHR( ']' );
582
583 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
584 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
585 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
586 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
587 CHR( '.' );
588 ENM( inst->Predicate.SwizzleX, swizzle_names );
589 ENM( inst->Predicate.SwizzleY, swizzle_names );
590 ENM( inst->Predicate.SwizzleZ, swizzle_names );
591 ENM( inst->Predicate.SwizzleW, swizzle_names );
592 }
593
594 TXT( ") " );
595 }
596
597 TXT( info->mnemonic );
598
599 switch (inst->Instruction.Saturate) {
600 case TGSI_SAT_NONE:
601 break;
602 case TGSI_SAT_ZERO_ONE:
603 TXT( "_SAT" );
604 break;
605 case TGSI_SAT_MINUS_PLUS_ONE:
606 TXT( "_SATNV" );
607 break;
608 default:
609 assert( 0 );
610 }
611
612 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
613 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
614
615 if (!first_reg)
616 CHR( ',' );
617 CHR( ' ' );
618
619 _dump_register_dst( ctx, dst );
620 _dump_writemask( ctx, dst->Register.WriteMask );
621
622 first_reg = FALSE;
623 }
624
625 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
626 const struct tgsi_full_src_register *src = &inst->Src[i];
627
628 if (!first_reg)
629 CHR( ',' );
630 CHR( ' ' );
631
632 if (src->Register.Negate)
633 CHR( '-' );
634 if (src->Register.Absolute)
635 CHR( '|' );
636
637 _dump_register_src(ctx, src);
638
639 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
640 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
641 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
642 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
643 CHR( '.' );
644 ENM( src->Register.SwizzleX, swizzle_names );
645 ENM( src->Register.SwizzleY, swizzle_names );
646 ENM( src->Register.SwizzleZ, swizzle_names );
647 ENM( src->Register.SwizzleW, swizzle_names );
648 }
649
650 if (src->Register.Absolute)
651 CHR( '|' );
652
653 first_reg = FALSE;
654 }
655
656 if (inst->Instruction.Texture) {
657 TXT( ", " );
658 ENM( inst->Texture.Texture, texture_names );
659 }
660
661 switch (inst->Instruction.Opcode) {
662 case TGSI_OPCODE_IF:
663 case TGSI_OPCODE_ELSE:
664 case TGSI_OPCODE_BGNLOOP:
665 case TGSI_OPCODE_ENDLOOP:
666 case TGSI_OPCODE_CAL:
667 TXT( " :" );
668 UID( inst->Label.Label );
669 break;
670 }
671
672 /* update indentation */
673 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
674 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
675 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
676 ctx->indentation += indent_spaces;
677 }
678
679 EOL();
680
681 return TRUE;
682 }
683
684 void
685 tgsi_dump_instruction(
686 const struct tgsi_full_instruction *inst,
687 uint instno )
688 {
689 struct dump_ctx ctx;
690
691 ctx.instno = instno;
692 ctx.indent = 0;
693 ctx.printf = dump_ctx_printf;
694 ctx.indentation = 0;
695
696 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
697 }
698
699 static boolean
700 prolog(
701 struct tgsi_iterate_context *iter )
702 {
703 struct dump_ctx *ctx = (struct dump_ctx *) iter;
704 ENM( iter->processor.Processor, processor_type_names );
705 EOL();
706 return TRUE;
707 }
708
709 void
710 tgsi_dump(
711 const struct tgsi_token *tokens,
712 uint flags )
713 {
714 struct dump_ctx ctx;
715
716 ctx.iter.prolog = prolog;
717 ctx.iter.iterate_instruction = iter_instruction;
718 ctx.iter.iterate_declaration = iter_declaration;
719 ctx.iter.iterate_immediate = iter_immediate;
720 ctx.iter.iterate_property = iter_property;
721 ctx.iter.epilog = NULL;
722
723 ctx.instno = 0;
724 ctx.indent = 0;
725 ctx.printf = dump_ctx_printf;
726 ctx.indentation = 0;
727
728 tgsi_iterate_shader( tokens, &ctx.iter );
729 }
730
731 struct str_dump_ctx
732 {
733 struct dump_ctx base;
734 char *str;
735 char *ptr;
736 int left;
737 };
738
739 static void
740 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
741 {
742 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
743
744 if(sctx->left > 1) {
745 int written;
746 va_list ap;
747 va_start(ap, format);
748 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
749 va_end(ap);
750
751 /* Some complicated logic needed to handle the return value of
752 * vsnprintf:
753 */
754 if (written > 0) {
755 written = MIN2(sctx->left, written);
756 sctx->ptr += written;
757 sctx->left -= written;
758 }
759 }
760 }
761
762 void
763 tgsi_dump_str(
764 const struct tgsi_token *tokens,
765 uint flags,
766 char *str,
767 size_t size)
768 {
769 struct str_dump_ctx ctx;
770
771 ctx.base.iter.prolog = prolog;
772 ctx.base.iter.iterate_instruction = iter_instruction;
773 ctx.base.iter.iterate_declaration = iter_declaration;
774 ctx.base.iter.iterate_immediate = iter_immediate;
775 ctx.base.iter.iterate_property = iter_property;
776 ctx.base.iter.epilog = NULL;
777
778 ctx.base.instno = 0;
779 ctx.base.indent = 0;
780 ctx.base.printf = &str_dump_ctx_printf;
781 ctx.base.indentation = 0;
782
783 ctx.str = str;
784 ctx.str[0] = 0;
785 ctx.ptr = str;
786 ctx.left = (int)size;
787
788 tgsi_iterate_shader( tokens, &ctx.base.iter );
789 }