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,FILE * fp)38 print_swizzle(uint8_t swizzle, FILE *fp)
39 {
40    if (swizzle == 0xE4)
41       return;
42 
43    fprintf(fp, ".");
44    for (unsigned i = 0; i < 4; i++, swizzle >>= 2)
45       fprintf(fp, "%c", "xyzw"[swizzle & 3]);
46 }
47 
48 static void
print_mask(uint8_t mask,FILE * fp)49 print_mask(uint8_t mask, FILE *fp)
50 {
51    if (mask == 0xF)
52       return;
53 
54    fprintf(fp, ".");
55    if (mask & 1) fprintf(fp, "x");
56    if (mask & 2) fprintf(fp, "y");
57    if (mask & 4) fprintf(fp, "z");
58    if (mask & 8) fprintf(fp, "w");
59 }
60 
61 static void
print_reg(ppir_codegen_vec4_reg reg,const char * special,FILE * fp)62 print_reg(ppir_codegen_vec4_reg reg, const char *special, FILE *fp)
63 {
64    if (special) {
65       fprintf(fp, "%s", special);
66    } else {
67       switch (reg)
68       {
69          case ppir_codegen_vec4_reg_constant0:
70             fprintf(fp, "^const0");
71             break;
72          case ppir_codegen_vec4_reg_constant1:
73             fprintf(fp, "^const1");
74             break;
75          case ppir_codegen_vec4_reg_texture:
76             fprintf(fp, "^texture");
77             break;
78          case ppir_codegen_vec4_reg_uniform:
79             fprintf(fp, "^uniform");
80             break;
81          default:
82             fprintf(fp, "$%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,FILE * fp)89 print_vector_source(ppir_codegen_vec4_reg reg, const char *special,
90                     uint8_t swizzle, bool abs, bool neg, FILE *fp)
91 {
92    if (neg)
93       fprintf(fp, "-");
94    if (abs)
95       fprintf(fp, "abs(");
96 
97    print_reg(reg, special, fp);
98    print_swizzle(swizzle, fp);
99 
100    if (abs)
101       fprintf(fp, ")");
102 }
103 
104 static void
print_source_scalar(unsigned reg,const char * special,bool abs,bool neg,FILE * fp)105 print_source_scalar(unsigned reg, const char *special, bool abs, bool neg, FILE *fp)
106 {
107    if (neg)
108       fprintf(fp, "-");
109    if (abs)
110       fprintf(fp, "abs(");
111 
112    print_reg(reg >> 2, special, fp);
113    if (!special)
114       fprintf(fp, ".%c", "xyzw"[reg & 3]);
115 
116    if (abs)
117       fprintf(fp, ")");
118 }
119 
120 static void
print_varying_source(ppir_codegen_field_varying * varying,FILE * fp)121 print_varying_source(ppir_codegen_field_varying *varying, FILE *fp)
122 {
123    switch (varying->imm.alignment) {
124    case 0:
125       fprintf(fp, "%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       fprintf(fp, "%u.%s", varying->imm.index >> 1, c[varying->imm.index & 1]);
131       break;
132    }
133    default:
134       fprintf(fp, "%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       fprintf(fp, "+");
142       print_source_scalar(reg, NULL, false, false, fp);
143    }
144 }
145 
146 static void
print_outmod(ppir_codegen_outmod modifier,FILE * fp)147 print_outmod(ppir_codegen_outmod modifier, FILE *fp)
148 {
149    switch (modifier)
150    {
151       case ppir_codegen_outmod_clamp_fraction:
152          fprintf(fp, ".sat");
153          break;
154       case ppir_codegen_outmod_clamp_positive:
155          fprintf(fp, ".pos");
156          break;
157       case ppir_codegen_outmod_round:
158          fprintf(fp, ".int");
159          break;
160       default:
161          break;
162    }
163 }
164 
165 static void
print_dest_scalar(unsigned reg,FILE * fp)166 print_dest_scalar(unsigned reg, FILE *fp)
167 {
168    fprintf(fp, "$%u", reg >> 2);
169    fprintf(fp, ".%c ", "xyzw"[reg & 3]);
170 }
171 
172 static void
print_const(unsigned const_num,uint16_t * val,FILE * fp)173 print_const(unsigned const_num, uint16_t *val, FILE *fp)
174 {
175    fprintf(fp, "const%u", const_num);
176    for (unsigned i = 0; i < 4; i++)
177       fprintf(fp, " %f", _mesa_half_to_float(val[i]));
178 }
179 
180 static void
print_const0(void * code,unsigned offset,FILE * fp)181 print_const0(void *code, unsigned offset, FILE *fp)
182 {
183    (void) offset;
184 
185    print_const(0, code, fp);
186 }
187 
188 static void
print_const1(void * code,unsigned offset,FILE * fp)189 print_const1(void *code, unsigned offset, FILE *fp)
190 {
191    (void) offset;
192 
193    print_const(1, code, fp);
194 }
195 
196 static void
print_varying(void * code,unsigned offset,FILE * fp)197 print_varying(void *code, unsigned offset, FILE *fp)
198 {
199    (void) offset;
200    ppir_codegen_field_varying *varying = code;
201 
202    fprintf(fp, "load");
203 
204    bool perspective = varying->imm.source_type < 2 && varying->imm.perspective;
205    if (perspective)
206    {
207       fprintf(fp, ".perspective");
208       switch (varying->imm.perspective)
209       {
210       case 2:
211          fprintf(fp, ".z");
212          break;
213       case 3:
214          fprintf(fp, ".w");
215          break;
216       default:
217          fprintf(fp, ".unknown");
218          break;
219       }
220    }
221 
222    fprintf(fp, ".v ");
223 
224    switch (varying->imm.dest)
225    {
226    case ppir_codegen_vec4_reg_discard:
227       fprintf(fp, "^discard");
228       break;
229    default:
230       fprintf(fp, "$%u", varying->imm.dest);
231       break;
232    }
233    print_mask(varying->imm.mask, fp);
234    fprintf(fp, " ");
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, fp);
240       break;
241    case 2:
242       switch (varying->imm.perspective) {
243       case 0:
244          fprintf(fp, "cube(");
245          print_varying_source(varying, fp);
246          fprintf(fp, ")");
247          break;
248       case 1:
249          fprintf(fp, "cube(");
250          print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
251                              varying->reg.absolute, varying->reg.negate, fp);
252          fprintf(fp, ")");
253          break;
254       case 2:
255          fprintf(fp, "normalize(");
256          print_vector_source(varying->reg.source, NULL, varying->reg.swizzle,
257                              varying->reg.absolute, varying->reg.negate, fp);
258          fprintf(fp, ")");
259          break;
260       default:
261          fprintf(fp, "gl_FragCoord");
262          break;
263       }
264       break;
265    case 3:
266       if (varying->imm.perspective)
267          fprintf(fp, "gl_FrontFacing");
268       else
269          fprintf(fp, "gl_PointCoord");
270       break;
271    default:
272       print_varying_source(varying, fp);
273       break;
274    }
275 }
276 
277 static void
print_sampler(void * code,unsigned offset,FILE * fp)278 print_sampler(void *code, unsigned offset, FILE *fp)
279 {
280    (void) offset;
281    ppir_codegen_field_sampler *sampler = code;
282 
283    fprintf(fp, "texld");
284    if (sampler->lod_bias_en)
285       fprintf(fp, ".b");
286 
287    switch (sampler->type) {
288    case ppir_codegen_sampler_type_2d:
289       fprintf(fp, ".2d");
290       break;
291    case ppir_codegen_sampler_type_cube:
292       fprintf(fp, ".cube");
293       break;
294    default:
295       fprintf(fp, "_t%u", sampler->type);
296       break;
297    }
298 
299    fprintf(fp, " %u", sampler->index);
300 
301    if (sampler->offset_en)
302    {
303       fprintf(fp, "+");
304       print_source_scalar(sampler->index_offset, NULL, false, false, fp);
305    }
306 
307    if (sampler->lod_bias_en)
308    {
309       fprintf(fp, " ");
310       print_source_scalar(sampler->lod_bias, NULL, false, false, fp);
311    }
312 }
313 
314 static void
print_uniform(void * code,unsigned offset,FILE * fp)315 print_uniform(void *code, unsigned offset, FILE *fp)
316 {
317    (void) offset;
318    ppir_codegen_field_uniform *uniform = code;
319 
320    fprintf(fp, "load.");
321 
322    switch (uniform->source) {
323    case ppir_codegen_uniform_src_uniform:
324       fprintf(fp, "u");
325       break;
326    case ppir_codegen_uniform_src_temporary:
327       fprintf(fp, "t");
328       break;
329    default:
330       fprintf(fp, ".u%u", uniform->source);
331       break;
332    }
333 
334    int16_t index = uniform->index;
335    switch (uniform->alignment) {
336    case 2:
337       fprintf(fp, " %d", index);
338       break;
339    case 1:
340       fprintf(fp, " %d.%s", index / 2, (index & 1) ? "zw" : "xy");
341       break;
342    default:
343       fprintf(fp, " %d.%c", index / 4, "xyzw"[index & 3]);
344       break;
345    }
346 
347    if (uniform->offset_en) {
348       fprintf(fp, "+");
349       print_source_scalar(uniform->offset_reg, NULL, false, false, fp);
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,FILE * fp)380 print_vec4_mul(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "%s", op.name);
389    else
390       fprintf(fp, "op%u", vec4_mul->op);
391    print_outmod(vec4_mul->dest_modifier, fp);
392    fprintf(fp, ".v0 ");
393 
394    if (vec4_mul->mask) {
395       fprintf(fp, "$%u", vec4_mul->dest);
396       print_mask(vec4_mul->mask, fp);
397       fprintf(fp, " ");
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, fp);
404 
405    if (vec4_mul->op < 8 && vec4_mul->op != 0) {
406       fprintf(fp, "<<%u", vec4_mul->op);
407    }
408 
409    fprintf(fp, " ");
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, fp);
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,FILE * fp)447 print_vec4_acc(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "%s", op.name);
456    else
457       fprintf(fp, "op%u", vec4_acc->op);
458    print_outmod(vec4_acc->dest_modifier, fp);
459    fprintf(fp, ".v1 ");
460 
461    if (vec4_acc->mask) {
462       fprintf(fp, "$%u", vec4_acc->dest);
463       print_mask(vec4_acc->mask, fp);
464       fprintf(fp, " ");
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, fp);
471 
472    if (op.srcs > 1) {
473       fprintf(fp, " ");
474       print_vector_source(vec4_acc->arg1_source, NULL,
475                           vec4_acc->arg1_swizzle,
476                           vec4_acc->arg1_absolute,
477                           vec4_acc->arg1_negate, fp);
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,FILE * fp)508 print_float_mul(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "%s", op.name);
517    else
518       fprintf(fp, "op%u", float_mul->op);
519    print_outmod(float_mul->dest_modifier, fp);
520    fprintf(fp, ".s0 ");
521 
522    if (float_mul->output_en)
523       print_dest_scalar(float_mul->dest, fp);
524 
525    print_source_scalar(float_mul->arg0_source, NULL,
526                        float_mul->arg0_absolute,
527                        float_mul->arg0_negate, fp);
528 
529    if (float_mul->op < 8 && float_mul->op != 0) {
530       fprintf(fp, "<<%u", float_mul->op);
531    }
532 
533    if (op.srcs > 1) {
534       fprintf(fp, " ");
535 
536       print_source_scalar(float_mul->arg1_source, NULL,
537                           float_mul->arg1_absolute,
538                           float_mul->arg1_negate, fp);
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,FILE * fp)568 print_float_acc(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "%s", op.name);
577    else
578       fprintf(fp, "op%u", float_acc->op);
579    print_outmod(float_acc->dest_modifier, fp);
580    fprintf(fp, ".s1 ");
581 
582    if (float_acc->output_en)
583       print_dest_scalar(float_acc->dest, fp);
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, fp);
588 
589    if (op.srcs > 1) {
590       fprintf(fp, " ");
591       print_source_scalar(float_acc->arg1_source, NULL,
592                           float_acc->arg1_absolute,
593                           float_acc->arg1_negate, fp);
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,FILE * fp)619 print_combine(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "mul");
630    } else {
631       asm_op op = combine_ops[combine->scalar.op];
632 
633       if (op.name)
634          fprintf(fp, "%s", op.name);
635       else
636          fprintf(fp, "op%u", combine->scalar.op);
637    }
638 
639    if (!combine->scalar.dest_vec)
640       print_outmod(combine->scalar.dest_modifier, fp);
641    fprintf(fp, ".s2 ");
642 
643    if (combine->scalar.dest_vec) {
644       fprintf(fp, "$%u", combine->vector.dest);
645       print_mask(combine->vector.mask, fp);
646    } else {
647       print_dest_scalar(combine->scalar.dest, fp);
648    }
649    fprintf(fp, " ");
650 
651    print_source_scalar(combine->scalar.arg0_src, NULL,
652                        combine->scalar.arg0_absolute,
653                        combine->scalar.arg0_negate, fp);
654    fprintf(fp, " ");
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, fp);
661       } else {
662          print_source_scalar(combine->scalar.arg1_src, NULL,
663                              combine->scalar.arg1_absolute,
664                              combine->scalar.arg1_negate, fp);
665       }
666    }
667 }
668 
669 static void
print_temp_write(void * code,unsigned offset,FILE * fp)670 print_temp_write(void *code, unsigned offset, FILE *fp)
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          fprintf(fp, "fb_color");
678       else
679          fprintf(fp, "fb_depth");
680       fprintf(fp, " $%u", temp_write->fb_read.dest);
681 
682       return;
683    }
684 
685    fprintf(fp, "store.t");
686 
687    int16_t index = temp_write->temp_write.index;
688    switch (temp_write->temp_write.alignment) {
689    case 2:
690       fprintf(fp, " %d", index);
691       break;
692    case 1:
693       fprintf(fp, " %d.%s", index / 2, (index & 1) ? "zw" : "xy");
694       break;
695    default:
696       fprintf(fp, " %d.%c", index / 4, "xyzw"[index & 3]);
697       break;
698    }
699 
700    if (temp_write->temp_write.offset_en) {
701       fprintf(fp, "+");
702       print_source_scalar(temp_write->temp_write.offset_reg,
703                           NULL, false, false, fp);
704    }
705 
706    fprintf(fp, " ");
707 
708    if (temp_write->temp_write.alignment) {
709       print_reg(temp_write->temp_write.source >> 2, NULL, fp);
710    } else {
711       print_source_scalar(temp_write->temp_write.source, NULL, false, false, fp);
712    }
713 }
714 
715 static void
print_branch(void * code,unsigned offset,FILE * fp)716 print_branch(void *code, unsigned offset, FILE *fp)
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       fprintf(fp, "discard");
724       return;
725    }
726 
727    const char* cond[] = {
728       "nv", "lt", "eq", "le",
729       "gt", "ne", "ge", ""  ,
730    };
731 
732    unsigned cond_mask = 0;
733    cond_mask |= (branch->branch.cond_lt ? 1 : 0);
734    cond_mask |= (branch->branch.cond_eq ? 2 : 0);
735    cond_mask |= (branch->branch.cond_gt ? 4 : 0);
736    fprintf(fp, "branch");
737    if (cond_mask != 0x7) {
738       fprintf(fp, ".%s ", cond[cond_mask]);
739       print_source_scalar(branch->branch.arg0_source, NULL, false, false, fp);
740       fprintf(fp, " ");
741       print_source_scalar(branch->branch.arg1_source, NULL, false, false, fp);
742    }
743 
744    fprintf(fp, " %d", branch->branch.target + offset);
745 }
746 
747 typedef void (*print_field_func)(void *, unsigned, FILE *);
748 
749 static const print_field_func print_field[ppir_codegen_field_shift_count] = {
750    [ppir_codegen_field_shift_varying] = print_varying,
751    [ppir_codegen_field_shift_sampler] = print_sampler,
752    [ppir_codegen_field_shift_uniform] = print_uniform,
753    [ppir_codegen_field_shift_vec4_mul] = print_vec4_mul,
754    [ppir_codegen_field_shift_float_mul] = print_float_mul,
755    [ppir_codegen_field_shift_vec4_acc] = print_vec4_acc,
756    [ppir_codegen_field_shift_float_acc] = print_float_acc,
757    [ppir_codegen_field_shift_combine] = print_combine,
758    [ppir_codegen_field_shift_temp_write] = print_temp_write,
759    [ppir_codegen_field_shift_branch] = print_branch,
760    [ppir_codegen_field_shift_vec4_const_0] = print_const0,
761    [ppir_codegen_field_shift_vec4_const_1] = print_const1,
762 };
763 
764 static const int ppir_codegen_field_size[] = {
765    34, 62, 41, 43, 30, 44, 31, 30, 41, 73, 64, 64
766 };
767 
768 static void
bitcopy(char * src,char * dst,unsigned bits,unsigned src_offset)769 bitcopy(char *src, char *dst, unsigned bits, unsigned src_offset)
770 {
771    src += src_offset / 8;
772    src_offset %= 8;
773 
774    for (int b = bits; b > 0; b -= 8, src++, dst++) {
775       unsigned char out = ((unsigned char) *src) >> src_offset;
776       if (src_offset > 0 && src_offset + b > 8)
777          out |= ((unsigned char) *(src + 1)) << (8 - src_offset);
778       *dst = (char) out;
779    }
780 }
781 
782 void
ppir_disassemble_instr(uint32_t * instr,unsigned offset,FILE * fp)783 ppir_disassemble_instr(uint32_t *instr, unsigned offset, FILE *fp)
784 {
785    ppir_codegen_ctrl *ctrl = (ppir_codegen_ctrl *) instr;
786 
787    char *instr_code = (char *) (instr + 1);
788    unsigned bit_offset = 0;
789    bool first = true;
790    for (unsigned i = 0; i < ppir_codegen_field_shift_count; i++) {
791       char code[12];
792 
793       if (!((ctrl->fields >> i) & 1))
794          continue;
795 
796       unsigned bits = ppir_codegen_field_size[i];
797       bitcopy(instr_code, code, bits, bit_offset);
798 
799       if (first)
800          first = false;
801       else
802          fprintf(fp, ", ");
803 
804       print_field[i](code, offset, fp);
805 
806       bit_offset += bits;
807    }
808 
809    if (ctrl->sync)
810       fprintf(fp, ", sync");
811    if (ctrl->stop)
812       fprintf(fp, ", stop");
813 
814    fprintf(fp, "\n");
815 }
816 
817