• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2018 Lima Project
3  *
4  * Copyright (c) 2013 Codethink (http://www.codethink.co.uk)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sub license,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include "util/half_float.h"
28 
29 #include "ppir.h"
30 #include "codegen.h"
31 
32 typedef struct {
33    char *name;
34    unsigned srcs;
35 } asm_op;
36 
37 static void
print_swizzle(uint8_t swizzle)38 print_swizzle(uint8_t swizzle)
39 {
40    if (swizzle == 0xE4)
41       return;
42 
43    printf(".");
44    for (unsigned i = 0; i < 4; i++, swizzle >>= 2)
45       printf("%c", "xyzw"[swizzle & 3]);
46 }
47 
48 static void
print_mask(uint8_t mask)49 print_mask(uint8_t mask)
50 {
51    if (mask == 0xF)
52       return;
53 
54    printf(".");
55    if (mask & 1) printf("x");
56    if (mask & 2) printf("y");
57    if (mask & 4) printf("z");
58    if (mask & 8) printf("w");
59 }
60 
61 static void
print_reg(ppir_codegen_vec4_reg reg,const char * special)62 print_reg(ppir_codegen_vec4_reg reg, const char *special)
63 {
64    if (special) {
65       printf("%s", special);
66    } else {
67       switch (reg)
68       {
69          case ppir_codegen_vec4_reg_constant0:
70             printf("^const0");
71             break;
72          case ppir_codegen_vec4_reg_constant1:
73             printf("^const1");
74             break;
75          case ppir_codegen_vec4_reg_texture:
76             printf("^texture");
77             break;
78          case ppir_codegen_vec4_reg_uniform:
79             printf("^uniform");
80             break;
81          default:
82             printf("$%u", reg);
83             break;
84       }
85    }
86 }
87 
88 static void
print_vector_source(ppir_codegen_vec4_reg reg,const char * special,uint8_t swizzle,bool abs,bool neg)89 print_vector_source(ppir_codegen_vec4_reg reg, const char *special,
90                     uint8_t swizzle, bool abs, bool neg)
91 {
92    if (neg)
93       printf("-");
94    if (abs)
95       printf("abs(");
96 
97    print_reg(reg, special);
98    print_swizzle(swizzle);
99 
100    if (abs)
101       printf(")");
102 }
103 
104 static void
print_source_scalar(unsigned reg,const char * special,bool abs,bool neg)105 print_source_scalar(unsigned reg, const char *special, bool abs, bool neg)
106 {
107    if (neg)
108       printf("-");
109    if (abs)
110       printf("abs(");
111 
112    print_reg(reg >> 2, special);
113    if (!special)
114       printf(".%c", "xyzw"[reg & 3]);
115 
116    if (abs)
117       printf(")");
118 }
119 
120 static void
print_varying_source(ppir_codegen_field_varying * varying)121 print_varying_source(ppir_codegen_field_varying *varying)
122 {
123    switch (varying->imm.alignment) {
124    case 0:
125       printf("%u.%c", varying->imm.index >> 2,
126              "xyzw"[varying->imm.index & 3]);
127       break;
128    case 1: {
129       const char *c[2] = {"xy", "zw"};
130       printf("%u.%s", varying->imm.index >> 1, c[varying->imm.index & 1]);
131       break;
132    }
133    default:
134       printf("%u", varying->imm.index);
135       break;
136    }
137 
138    if (varying->imm.offset_vector != 15) {
139       unsigned reg = (varying->imm.offset_vector << 2) +
140          varying->imm.offset_scalar;
141       printf("+");
142       print_source_scalar(reg, NULL, false, false);
143    }
144 }
145 
146 static void
print_outmod(ppir_codegen_outmod modifier)147 print_outmod(ppir_codegen_outmod modifier)
148 {
149    switch (modifier)
150    {
151       case ppir_codegen_outmod_clamp_fraction:
152          printf(".sat");
153          break;
154       case ppir_codegen_outmod_clamp_positive:
155          printf(".pos");
156          break;
157       case ppir_codegen_outmod_round:
158          printf(".int");
159          break;
160       default:
161          break;
162    }
163 }
164 
165 static void
print_dest_scalar(unsigned reg)166 print_dest_scalar(unsigned reg)
167 {
168    printf("$%u", reg >> 2);
169    printf(".%c ", "xyzw"[reg & 3]);
170 }
171 
172 static void
print_const(unsigned const_num,uint16_t * val)173 print_const(unsigned const_num, uint16_t *val)
174 {
175    printf("const%u", const_num);
176    for (unsigned i = 0; i < 4; i++)
177       printf(" %f", _mesa_half_to_float(val[i]));
178 }
179 
180 static void
print_const0(void * code,unsigned offset)181 print_const0(void *code, unsigned offset)
182 {
183    (void) offset;
184 
185    print_const(0, code);
186 }
187 
188 static void
print_const1(void * code,unsigned offset)189 print_const1(void *code, unsigned offset)
190 {
191    (void) offset;
192 
193    print_const(1, code);
194 }
195 
196 static void
print_varying(void * code,unsigned offset)197 print_varying(void *code, unsigned offset)
198 {
199    (void) offset;
200    ppir_codegen_field_varying *varying = code;
201 
202    printf("load");
203 
204    bool perspective = varying->imm.source_type < 2 && varying->imm.perspective;
205    if (perspective)
206    {
207       printf(".perspective");
208       switch (varying->imm.perspective)
209       {
210       case 2:
211          printf(".z");
212          break;
213       case 3:
214          printf(".w");
215          break;
216       default:
217          printf(".unknown");
218          break;
219       }
220    }
221 
222    printf(".v ");
223 
224    switch (varying->imm.dest)
225    {
226    case ppir_codegen_vec4_reg_discard:
227       printf("^discard");
228       break;
229    default:
230       printf("$%u", varying->imm.dest);
231       break;
232    }
233    print_mask(varying->imm.mask);
234    printf(" ");
235 
236    switch (varying->imm.source_type) {
237    case 1:
238       print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
239                           varying->reg.absolute, varying->reg.negate);
240       break;
241    case 2:
242       switch (varying->imm.perspective) {
243       case 0:
244          printf("cube(");
245          print_varying_source(varying);
246          printf(")");
247          break;
248       case 1:
249          printf("cube(");
250          print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
251                              varying->reg.absolute, varying->reg.negate);
252          printf(")");
253          break;
254       case 2:
255          printf("normalize(");
256          print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
257                              varying->reg.absolute, varying->reg.negate);
258          printf(")");
259          break;
260       default:
261          printf("gl_FragCoord");
262          break;
263       }
264       break;
265    case 3:
266       if (varying->imm.perspective)
267          printf("gl_FrontFacing");
268       else
269          printf("gl_PointCoord");
270       break;
271    default:
272       print_varying_source(varying);
273       break;
274    }
275 }
276 
277 static void
print_sampler(void * code,unsigned offset)278 print_sampler(void *code, unsigned offset)
279 {
280    (void) offset;
281    ppir_codegen_field_sampler *sampler = code;
282 
283    printf("texld");
284    if (sampler->lod_bias_en)
285       printf(".b");
286 
287    switch (sampler->type) {
288    case ppir_codegen_sampler_type_2d:
289       printf(".2d");
290       break;
291    case ppir_codegen_sampler_type_cube:
292       printf(".cube");
293       break;
294    default:
295       printf("_t%u", sampler->type);
296       break;
297    }
298 
299    printf(" %u", sampler->index);
300 
301    if (sampler->offset_en)
302    {
303       printf("+");
304       print_source_scalar(sampler->index_offset, NULL, false, false);
305    }
306 
307    if (sampler->lod_bias_en)
308    {
309       printf(" ");
310       print_source_scalar(sampler->lod_bias, NULL, false, false);
311    }
312 }
313 
314 static void
print_uniform(void * code,unsigned offset)315 print_uniform(void *code, unsigned offset)
316 {
317    (void) offset;
318    ppir_codegen_field_uniform *uniform = code;
319 
320    printf("load.");
321 
322    switch (uniform->source) {
323    case ppir_codegen_uniform_src_uniform:
324       printf("u");
325       break;
326    case ppir_codegen_uniform_src_temporary:
327       printf("t");
328       break;
329    default:
330       printf(".u%u", uniform->source);
331       break;
332    }
333 
334    int16_t index = uniform->index;
335    switch (uniform->alignment) {
336    case 2:
337       printf(" %d", index);
338       break;
339    case 1:
340       printf(" %d.%s", index / 2, (index & 1) ? "zw" : "xy");
341       break;
342    default:
343       printf(" %d.%c", index / 4, "xyzw"[index & 3]);
344       break;
345    }
346 
347    if (uniform->offset_en) {
348       printf("+");
349       print_source_scalar(uniform->offset_reg, NULL, false, false);
350    }
351 }
352 
353 #define CASE(_name, _srcs) \
354 [ppir_codegen_vec4_mul_op_##_name] = { \
355    .name = #_name, \
356    .srcs = _srcs \
357 }
358 
359 static const asm_op vec4_mul_ops[] = {
360    [0 ... 7] = {
361       .name = "mul",
362       .srcs = 2
363    },
364    CASE(not, 1),
365    CASE(and, 2),
366    CASE(or, 2),
367    CASE(xor, 2),
368    CASE(ne, 2),
369    CASE(gt, 2),
370    CASE(ge, 2),
371    CASE(eq, 2),
372    CASE(min, 2),
373    CASE(max, 2),
374    CASE(mov, 1),
375 };
376 
377 #undef CASE
378 
379 static void
print_vec4_mul(void * code,unsigned offset)380 print_vec4_mul(void *code, unsigned offset)
381 {
382    (void) offset;
383    ppir_codegen_field_vec4_mul *vec4_mul = code;
384 
385    asm_op op = vec4_mul_ops[vec4_mul->op];
386 
387    if (op.name)
388       printf("%s", op.name);
389    else
390       printf("op%u", vec4_mul->op);
391    print_outmod(vec4_mul->dest_modifier);
392    printf(".v0 ");
393 
394    if (vec4_mul->mask) {
395       printf("$%u", vec4_mul->dest);
396       print_mask(vec4_mul->mask);
397       printf(" ");
398    }
399 
400    print_vector_source(vec4_mul->arg0_source, NULL,
401                        vec4_mul->arg0_swizzle,
402                        vec4_mul->arg0_absolute,
403                        vec4_mul->arg0_negate);
404 
405    if (vec4_mul->op < 8 && vec4_mul->op != 0) {
406       printf("<<%u", vec4_mul->op);
407    }
408 
409    printf(" ");
410 
411    if (op.srcs > 1) {
412       print_vector_source(vec4_mul->arg1_source, NULL,
413                           vec4_mul->arg1_swizzle,
414                           vec4_mul->arg1_absolute,
415                           vec4_mul->arg1_negate);
416    }
417 }
418 
419 #define CASE(_name, _srcs) \
420 [ppir_codegen_vec4_acc_op_##_name] = { \
421    .name = #_name, \
422    .srcs = _srcs \
423 }
424 
425 static const asm_op vec4_acc_ops[] = {
426    CASE(add, 2),
427    CASE(fract, 1),
428    CASE(ne, 2),
429    CASE(gt, 2),
430    CASE(ge, 2),
431    CASE(eq, 2),
432    CASE(floor, 1),
433    CASE(ceil, 1),
434    CASE(min, 2),
435    CASE(max, 2),
436    CASE(sum3, 1),
437    CASE(sum4, 1),
438    CASE(dFdx, 2),
439    CASE(dFdy, 2),
440    CASE(sel, 2),
441    CASE(mov, 1),
442 };
443 
444 #undef CASE
445 
446 static void
print_vec4_acc(void * code,unsigned offset)447 print_vec4_acc(void *code, unsigned offset)
448 {
449    (void) offset;
450    ppir_codegen_field_vec4_acc *vec4_acc = code;
451 
452    asm_op op = vec4_acc_ops[vec4_acc->op];
453 
454    if (op.name)
455       printf("%s", op.name);
456    else
457       printf("op%u", vec4_acc->op);
458    print_outmod(vec4_acc->dest_modifier);
459    printf(".v1 ");
460 
461    if (vec4_acc->mask) {
462       printf("$%u", vec4_acc->dest);
463       print_mask(vec4_acc->mask);
464       printf(" ");
465    }
466 
467    print_vector_source(vec4_acc->arg0_source, vec4_acc->mul_in ? "^v0" : NULL,
468                        vec4_acc->arg0_swizzle,
469                        vec4_acc->arg0_absolute,
470                        vec4_acc->arg0_negate);
471 
472    if (op.srcs > 1) {
473       printf(" ");
474       print_vector_source(vec4_acc->arg1_source, NULL,
475                           vec4_acc->arg1_swizzle,
476                           vec4_acc->arg1_absolute,
477                           vec4_acc->arg1_negate);
478    }
479 }
480 
481 #define CASE(_name, _srcs) \
482 [ppir_codegen_float_mul_op_##_name] = { \
483    .name = #_name, \
484    .srcs = _srcs \
485 }
486 
487 static const asm_op float_mul_ops[] = {
488    [0 ... 7] = {
489       .name = "mul",
490       .srcs = 2
491    },
492    CASE(not, 1),
493    CASE(and, 2),
494    CASE(or, 2),
495    CASE(xor, 2),
496    CASE(ne, 2),
497    CASE(gt, 2),
498    CASE(ge, 2),
499    CASE(eq, 2),
500    CASE(min, 2),
501    CASE(max, 2),
502    CASE(mov, 1),
503 };
504 
505 #undef CASE
506 
507 static void
print_float_mul(void * code,unsigned offset)508 print_float_mul(void *code, unsigned offset)
509 {
510    (void) offset;
511    ppir_codegen_field_float_mul *float_mul = code;
512 
513    asm_op op = float_mul_ops[float_mul->op];
514 
515    if (op.name)
516       printf("%s", op.name);
517    else
518       printf("op%u", float_mul->op);
519    print_outmod(float_mul->dest_modifier);
520    printf(".s0 ");
521 
522    if (float_mul->output_en)
523       print_dest_scalar(float_mul->dest);
524 
525    print_source_scalar(float_mul->arg0_source, NULL,
526                        float_mul->arg0_absolute,
527                        float_mul->arg0_negate);
528 
529    if (float_mul->op < 8 && float_mul->op != 0) {
530       printf("<<%u", float_mul->op);
531    }
532 
533    if (op.srcs > 1) {
534       printf(" ");
535 
536       print_source_scalar(float_mul->arg1_source, NULL,
537                           float_mul->arg1_absolute,
538                           float_mul->arg1_negate);
539    }
540 }
541 
542 #define CASE(_name, _srcs) \
543 [ppir_codegen_float_acc_op_##_name] = { \
544    .name = #_name, \
545    .srcs = _srcs \
546 }
547 
548 static const asm_op float_acc_ops[] = {
549    CASE(add, 2),
550    CASE(fract, 1),
551    CASE(ne, 2),
552    CASE(gt, 2),
553    CASE(ge, 2),
554    CASE(eq, 2),
555    CASE(floor, 1),
556    CASE(ceil, 1),
557    CASE(min, 2),
558    CASE(max, 2),
559    CASE(dFdx, 2),
560    CASE(dFdy, 2),
561    CASE(sel, 2),
562    CASE(mov, 1),
563 };
564 
565 #undef CASE
566 
567 static void
print_float_acc(void * code,unsigned offset)568 print_float_acc(void *code, unsigned offset)
569 {
570    (void) offset;
571    ppir_codegen_field_float_acc *float_acc = code;
572 
573    asm_op op = float_acc_ops[float_acc->op];
574 
575    if (op.name)
576       printf("%s", op.name);
577    else
578       printf("op%u", float_acc->op);
579    print_outmod(float_acc->dest_modifier);
580    printf(".s1 ");
581 
582    if (float_acc->output_en)
583       print_dest_scalar(float_acc->dest);
584 
585    print_source_scalar(float_acc->arg0_source, float_acc->mul_in ? "^s0" : NULL,
586                        float_acc->arg0_absolute,
587                        float_acc->arg0_negate);
588 
589    if (op.srcs > 1) {
590       printf(" ");
591       print_source_scalar(float_acc->arg1_source, NULL,
592                           float_acc->arg1_absolute,
593                           float_acc->arg1_negate);
594    }
595 }
596 
597 #define CASE(_name, _srcs) \
598 [ppir_codegen_combine_scalar_op_##_name] = { \
599    .name = #_name, \
600    .srcs = _srcs \
601 }
602 
603 static const asm_op combine_ops[] = {
604    CASE(rcp, 1),
605    CASE(mov, 1),
606    CASE(sqrt, 1),
607    CASE(rsqrt, 1),
608    CASE(exp2, 1),
609    CASE(log2, 1),
610    CASE(sin, 1),
611    CASE(cos, 1),
612    CASE(atan, 1),
613    CASE(atan2, 1),
614 };
615 
616 #undef CASE
617 
618 static void
print_combine(void * code,unsigned offset)619 print_combine(void *code, unsigned offset)
620 {
621    (void) offset;
622    ppir_codegen_field_combine *combine = code;
623 
624    if (combine->scalar.dest_vec &&
625        combine->scalar.arg1_en) {
626       /* This particular combination can only be valid for scalar * vector
627        * multiplies, and the opcode field is reused for something else.
628        */
629       printf("mul");
630    } else {
631       asm_op op = combine_ops[combine->scalar.op];
632 
633       if (op.name)
634          printf("%s", op.name);
635       else
636          printf("op%u", combine->scalar.op);
637    }
638 
639    if (!combine->scalar.dest_vec)
640       print_outmod(combine->scalar.dest_modifier);
641    printf(".s2 ");
642 
643    if (combine->scalar.dest_vec) {
644       printf("$%u", combine->vector.dest);
645       print_mask(combine->vector.mask);
646    } else {
647       print_dest_scalar(combine->scalar.dest);
648    }
649    printf(" ");
650 
651    print_source_scalar(combine->scalar.arg0_src, NULL,
652                        combine->scalar.arg0_absolute,
653                        combine->scalar.arg0_negate);
654    printf(" ");
655 
656    if (combine->scalar.arg1_en) {
657       if (combine->scalar.dest_vec) {
658          print_vector_source(combine->vector.arg1_source, NULL,
659                              combine->vector.arg1_swizzle,
660                              false, false);
661       } else {
662          print_source_scalar(combine->scalar.arg1_src, NULL,
663                              combine->scalar.arg1_absolute,
664                              combine->scalar.arg1_negate);
665       }
666    }
667 }
668 
669 static void
print_temp_write(void * code,unsigned offset)670 print_temp_write(void *code, unsigned offset)
671 {
672    (void) offset;
673    ppir_codegen_field_temp_write *temp_write = code;
674 
675    if (temp_write->fb_read.unknown_0 == 0x7) {
676       if (temp_write->fb_read.source)
677          printf("fb_color");
678       else
679          printf("fb_depth");
680       printf(" $%u", temp_write->fb_read.dest);
681 
682       return;
683    }
684 
685    printf("store.t");
686 
687    int16_t index = temp_write->temp_write.index;
688    switch (temp_write->temp_write.alignment) {
689    case 2:
690       printf(" %d", index);
691       break;
692    case 1:
693       printf(" %d.%s", index / 2, (index & 1) ? "zw" : "xy");
694       break;
695    default:
696       printf(" %d.%c", index / 4, "xyzw"[index & 3]);
697       break;
698    }
699 
700    if (temp_write->temp_write.offset_en) {
701       printf("+");
702       print_source_scalar(temp_write->temp_write.offset_reg,
703                           NULL, false, false);
704    }
705 
706    printf(" ");
707 
708    if (temp_write->temp_write.alignment) {
709       print_reg(temp_write->temp_write.source >> 2, NULL);
710    } else {
711       print_source_scalar(temp_write->temp_write.source, NULL, false, false);
712    }
713 }
714 
715 static void
print_branch(void * code,unsigned offset)716 print_branch(void *code, unsigned offset)
717 {
718    ppir_codegen_field_branch *branch = code;
719 
720    if (branch->discard.word0 == PPIR_CODEGEN_DISCARD_WORD0 &&
721        branch->discard.word1 == PPIR_CODEGEN_DISCARD_WORD1 &&
722        branch->discard.word2 == PPIR_CODEGEN_DISCARD_WORD2) {
723       printf("discard");
724       return;
725    }
726 
727 
728    const char* cond[] = {
729       "nv", "lt", "eq", "le",
730       "gt", "ne", "ge", ""  ,
731    };
732 
733    unsigned cond_mask = 0;
734    cond_mask |= (branch->branch.cond_lt ? 1 : 0);
735    cond_mask |= (branch->branch.cond_eq ? 2 : 0);
736    cond_mask |= (branch->branch.cond_gt ? 4 : 0);
737    printf("branch");
738    if (cond_mask != 0x7) {
739       printf(".%s ", cond[cond_mask]);
740       print_source_scalar(branch->branch.arg0_source, NULL, false, false);
741       printf(" ");
742       print_source_scalar(branch->branch.arg1_source, NULL, false, false);
743    }
744 
745    printf(" %d", branch->branch.target + offset);
746 }
747 
748 typedef void (*print_field_func)(void *, unsigned);
749 
750 static const print_field_func print_field[ppir_codegen_field_shift_count] = {
751    [ppir_codegen_field_shift_varying] = print_varying,
752    [ppir_codegen_field_shift_sampler] = print_sampler,
753    [ppir_codegen_field_shift_uniform] = print_uniform,
754    [ppir_codegen_field_shift_vec4_mul] = print_vec4_mul,
755    [ppir_codegen_field_shift_float_mul] = print_float_mul,
756    [ppir_codegen_field_shift_vec4_acc] = print_vec4_acc,
757    [ppir_codegen_field_shift_float_acc] = print_float_acc,
758    [ppir_codegen_field_shift_combine] = print_combine,
759    [ppir_codegen_field_shift_temp_write] = print_temp_write,
760    [ppir_codegen_field_shift_branch] = print_branch,
761    [ppir_codegen_field_shift_vec4_const_0] = print_const0,
762    [ppir_codegen_field_shift_vec4_const_1] = print_const1,
763 };
764 
765 static const int ppir_codegen_field_size[] = {
766    34, 62, 41, 43, 30, 44, 31, 30, 41, 73, 64, 64
767 };
768 
769 static void
bitcopy(char * src,char * dst,unsigned bits,unsigned src_offset)770 bitcopy(char *src, char *dst, unsigned bits, unsigned src_offset)
771 {
772    src += src_offset / 8;
773    src_offset %= 8;
774 
775    for (int b = bits; b > 0; b -= 8, src++, dst++) {
776       unsigned char out = ((unsigned char) *src) >> src_offset;
777       if (src_offset > 0 && src_offset + b > 8)
778          out |= ((unsigned char) *(src + 1)) << (8 - src_offset);
779       *dst = (char) out;
780    }
781 }
782 
783 void
ppir_disassemble_instr(uint32_t * instr,unsigned offset)784 ppir_disassemble_instr(uint32_t *instr, unsigned offset)
785 {
786    ppir_codegen_ctrl *ctrl = (ppir_codegen_ctrl *) instr;
787 
788    char *instr_code = (char *) (instr + 1);
789    unsigned bit_offset = 0;
790    bool first = true;
791    for (unsigned i = 0; i < ppir_codegen_field_shift_count; i++) {
792       char code[12];
793 
794       if (!((ctrl->fields >> i) & 1))
795          continue;
796 
797       unsigned bits = ppir_codegen_field_size[i];
798       bitcopy(instr_code, code, bits, bit_offset);
799 
800       if (first)
801          first = false;
802       else
803          printf(", ");
804 
805       print_field[i](code, offset);
806 
807       bit_offset += bits;
808    }
809 
810    if (ctrl->sync)
811       printf(", sync");
812    if (ctrl->stop)
813       printf(", stop");
814 
815    printf("\n");
816 }
817 
818