1 /*
2  * Copyright (C) 2021 Alyssa Rosenzweig <alyssa@rosenzweig.io>
3  * Copyright (C) 2019-2020 Collabora, Ltd.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include "agx_compiler.h"
26 
27 static void
agx_print_sized(char prefix,unsigned value,enum agx_size size,FILE * fp)28 agx_print_sized(char prefix, unsigned value, enum agx_size size, FILE *fp)
29 {
30    switch (size) {
31    case AGX_SIZE_16:
32       fprintf(fp, "%c%u%c", prefix, value >> 1, (value & 1) ? 'h' : 'l');
33       return;
34    case AGX_SIZE_32:
35       assert((value & 1) == 0);
36       fprintf(fp, "%c%u", prefix, value >> 1);
37       return;
38    case AGX_SIZE_64:
39       assert((value & 1) == 0);
40       fprintf(fp, "%c%u:%c%u", prefix, value >> 1,
41             prefix, (value >> 1) + 1);
42       return;
43    }
44 
45    unreachable("Invalid size");
46 }
47 
48 static void
agx_print_index(agx_index index,FILE * fp)49 agx_print_index(agx_index index, FILE *fp)
50 {
51    switch (index.type) {
52    case AGX_INDEX_NULL:
53       fprintf(fp, "_");
54       return;
55 
56    case AGX_INDEX_NORMAL:
57       if (index.cache)
58          fprintf(fp, "$");
59 
60       if (index.discard)
61          fprintf(fp, "`");
62 
63       if (index.kill)
64          fprintf(fp, "*");
65 
66       fprintf(fp, "%u", index.value);
67       break;
68 
69    case AGX_INDEX_IMMEDIATE:
70       fprintf(fp, "#%u", index.value);
71       break;
72 
73    case AGX_INDEX_UNIFORM:
74       agx_print_sized('u', index.value, index.size, fp);
75       break;
76 
77    case AGX_INDEX_REGISTER:
78       agx_print_sized('r', index.value, index.size, fp);
79       break;
80 
81    default:
82       unreachable("Invalid index type");
83    }
84 
85    /* Print length suffixes if not implied */
86    if (index.type == AGX_INDEX_NORMAL || index.type == AGX_INDEX_IMMEDIATE) {
87       if (index.size == AGX_SIZE_16)
88          fprintf(fp, "h");
89       else if (index.size == AGX_SIZE_64)
90          fprintf(fp, "d");
91    }
92 
93    if (index.abs)
94       fprintf(fp, ".abs");
95 
96    if (index.neg)
97       fprintf(fp, ".neg");
98 }
99 
100 void
agx_print_instr(agx_instr * I,FILE * fp)101 agx_print_instr(agx_instr *I, FILE *fp)
102 {
103    assert(I->op < AGX_NUM_OPCODES);
104    struct agx_opcode_info info = agx_opcodes_info[I->op];
105 
106    fprintf(fp, "   %s", info.name);
107 
108    if (I->saturate)
109       fprintf(fp, ".sat");
110 
111    if (I->last)
112       fprintf(fp, ".last");
113 
114    fprintf(fp, " ");
115 
116    bool print_comma = false;
117 
118    for (unsigned d = 0; d < info.nr_dests; ++d) {
119       if (print_comma)
120          fprintf(fp, ", ");
121       else
122          print_comma = true;
123 
124       agx_print_index(I->dest[d], fp);
125    }
126 
127    for (unsigned s = 0; s < info.nr_srcs; ++s) {
128       if (print_comma)
129          fprintf(fp, ", ");
130       else
131          print_comma = true;
132 
133       agx_print_index(I->src[s], fp);
134    }
135 
136    if (I->mask) {
137       fprintf(fp, ", ");
138 
139       for (unsigned i = 0; i < 4; ++i) {
140          if (I->mask & (1 << i))
141             fprintf(fp, "%c", "xyzw"[i]);
142       }
143    }
144 
145    /* TODO: Do better for enums, truth tables, etc */
146    if (info.immediates) {
147       if (print_comma)
148          fprintf(fp, ", ");
149       else
150          print_comma = true;
151 
152       fprintf(fp, "#%X", I->imm);
153    }
154 
155    if (info.immediates & AGX_IMMEDIATE_DIM) {
156       if (print_comma)
157          fprintf(fp, ", ");
158       else
159          print_comma = true;
160 
161       fprintf(fp, "dim %u", I->dim); // TODO enumify
162    }
163 
164    if (info.immediates & AGX_IMMEDIATE_SCOREBOARD) {
165       if (print_comma)
166          fprintf(fp, ", ");
167       else
168          print_comma = true;
169 
170       fprintf(fp, "slot %u", I->scoreboard);
171    }
172 
173    if (info.immediates & AGX_IMMEDIATE_NEST) {
174       if (print_comma)
175          fprintf(fp, ", ");
176       else
177          print_comma = true;
178 
179       fprintf(fp, "n=%u", I->nest);
180    }
181 
182    if ((info.immediates & AGX_IMMEDIATE_INVERT_COND) && I->invert_cond) {
183       if (print_comma)
184          fprintf(fp, ", ");
185       else
186          print_comma = true;
187 
188       fprintf(fp, "inv");
189    }
190 
191    fprintf(fp, "\n");
192 }
193 
194 void
agx_print_block(agx_block * block,FILE * fp)195 agx_print_block(agx_block *block, FILE *fp)
196 {
197    fprintf(fp, "block%u {\n", block->name);
198 
199    agx_foreach_instr_in_block(block, ins)
200       agx_print_instr(ins, fp);
201 
202    fprintf(fp, "}");
203 
204    if (block->successors[0]) {
205       fprintf(fp, " -> ");
206 
207       agx_foreach_successor(block, succ)
208          fprintf(fp, "block%u ", succ->name);
209    }
210 
211    if (block->predecessors->entries) {
212       fprintf(fp, " from");
213 
214       agx_foreach_predecessor(block, pred)
215          fprintf(fp, " block%u", pred->name);
216    }
217 
218    fprintf(fp, "\n\n");
219 }
220 
221 void
agx_print_shader(agx_context * ctx,FILE * fp)222 agx_print_shader(agx_context *ctx, FILE *fp)
223 {
224    agx_foreach_block(ctx, block)
225       agx_print_block(block, fp);
226 }
227