1 /*
2  * Copyright (C) 2018-2019 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 <math.h>
26 
27 #include "util/bitscan.h"
28 #include "util/half_float.h"
29 #include "compiler.h"
30 #include "helpers.h"
31 #include "midgard_ops.h"
32 
33 /* Pretty printer for Midgard IR, for use debugging compiler-internal
34  * passes like register allocation. The output superficially resembles
35  * Midgard assembly, with the exception that unit information and such is
36  * (normally) omitted, and generic indices are usually used instead of
37  * registers */
38 
39 static void
mir_print_index(int source)40 mir_print_index(int source)
41 {
42         if (source == ~0) {
43                 printf("_");
44                 return;
45         }
46 
47         if (source >= SSA_FIXED_MINIMUM) {
48                 /* Specific register */
49                 int reg = SSA_REG_FROM_FIXED(source);
50 
51                 /* TODO: Moving threshold */
52                 if (reg > 16 && reg < 24)
53                         printf("u%d", 23 - reg);
54                 else
55                         printf("r%d", reg);
56         } else {
57                 printf("%d", source);
58         }
59 }
60 
61 static const char components[16] = "xyzwefghijklmnop";
62 
63 static void
mir_print_mask(unsigned mask)64 mir_print_mask(unsigned mask)
65 {
66         printf(".");
67 
68         for (unsigned i = 0; i < 16; ++i) {
69                 if (mask & (1 << i))
70                         putchar(components[i]);
71         }
72 }
73 
74 static void
mir_print_swizzle(unsigned * swizzle,nir_alu_type T)75 mir_print_swizzle(unsigned *swizzle, nir_alu_type T)
76 {
77         unsigned comps = mir_components_for_type(T);
78 
79         printf(".");
80 
81         for (unsigned i = 0; i < comps; ++i) {
82                 unsigned C = swizzle[i];
83                 assert(C < comps);
84                 putchar(components[C]);
85         }
86 }
87 
88 static const char *
mir_get_unit(unsigned unit)89 mir_get_unit(unsigned unit)
90 {
91         switch (unit) {
92         case ALU_ENAB_VEC_MUL:
93                 return "vmul";
94         case ALU_ENAB_SCAL_ADD:
95                 return "sadd";
96         case ALU_ENAB_VEC_ADD:
97                 return "vadd";
98         case ALU_ENAB_SCAL_MUL:
99                 return "smul";
100         case ALU_ENAB_VEC_LUT:
101                 return "lut";
102         case ALU_ENAB_BR_COMPACT:
103                 return "br";
104         case ALU_ENAB_BRANCH:
105                 return "brx";
106         default:
107                 return "???";
108         }
109 }
110 
111 static void
mir_print_embedded_constant(midgard_instruction * ins,unsigned src_idx)112 mir_print_embedded_constant(midgard_instruction *ins, unsigned src_idx)
113 {
114         assert(src_idx <= 1);
115 
116         unsigned base_size = max_bitsize_for_alu(ins);
117         unsigned sz = nir_alu_type_get_type_size(ins->src_types[src_idx]);
118         bool half = (sz == (base_size >> 1));
119         unsigned mod = mir_pack_mod(ins, src_idx, false);
120         unsigned *swizzle = ins->swizzle[src_idx];
121         midgard_reg_mode reg_mode = reg_mode_for_bitsize(max_bitsize_for_alu(ins));
122         unsigned comp_mask = effective_writemask(ins->op, ins->mask);
123         unsigned num_comp = util_bitcount(comp_mask);
124         unsigned max_comp = mir_components_for_type(ins->dest_type);
125         bool first = true;
126 
127         printf("#");
128 
129         if (num_comp > 1)
130                 printf("vec%d(", num_comp);
131 
132         for (unsigned comp = 0; comp < max_comp; comp++) {
133                 if (!(comp_mask & (1 << comp)))
134                         continue;
135 
136                 if (first)
137                         first = false;
138                 else
139                         printf(", ");
140 
141                 mir_print_constant_component(stdout, &ins->constants,
142                                              swizzle[comp], reg_mode,
143                                              half, mod, ins->op);
144         }
145 
146         if (num_comp > 1)
147                 printf(")");
148 }
149 
150 #define PRINT_SRC(ins, c) \
151         do { mir_print_index(ins->src[c]); \
152              if (ins->src[c] != ~0 && ins->src_types[c] != nir_type_invalid) { \
153                      pan_print_alu_type(ins->src_types[c], stdout); \
154                      mir_print_swizzle(ins->swizzle[c], ins->src_types[c]); \
155              } } while (0)
156 
157 void
mir_print_instruction(midgard_instruction * ins)158 mir_print_instruction(midgard_instruction *ins)
159 {
160         printf("\t");
161 
162         if (midgard_is_branch_unit(ins->unit)) {
163                 const char *branch_target_names[] = {
164                         "goto", "break", "continue", "discard"
165                 };
166 
167                 printf("%s.", mir_get_unit(ins->unit));
168                 if (ins->branch.target_type == TARGET_DISCARD)
169                         printf("discard.");
170                 else if (ins->writeout)
171                         printf("write.");
172                 else if (ins->unit == ALU_ENAB_BR_COMPACT &&
173                          !ins->branch.conditional)
174                         printf("uncond.");
175                 else
176                         printf("cond.");
177 
178                 if (!ins->branch.conditional)
179                         printf("always");
180                 else if (ins->branch.invert_conditional)
181                         printf("false");
182                 else
183                         printf("true");
184 
185                 if (ins->writeout) {
186                         printf(" (c: ");
187                         PRINT_SRC(ins, 0);
188                         printf(", z: ");
189                         PRINT_SRC(ins, 2);
190                         printf(", s: ");
191                         PRINT_SRC(ins, 3);
192                         printf(")");
193                 }
194 
195                 if (ins->branch.target_type != TARGET_DISCARD)
196                         printf(" %s -> block(%d)\n",
197                                ins->branch.target_type < 4 ?
198                                        branch_target_names[ins->branch.target_type] : "??",
199                                ins->branch.target_block);
200 
201                 return;
202         }
203 
204         switch (ins->type) {
205         case TAG_ALU_4: {
206                 midgard_alu_op op = ins->op;
207                 const char *name = alu_opcode_props[op].name;
208 
209                 if (ins->unit)
210                         printf("%s.", mir_get_unit(ins->unit));
211 
212                 printf("%s", name ? name : "??");
213                 break;
214         }
215 
216         case TAG_LOAD_STORE_4: {
217                 midgard_load_store_op op = ins->op;
218                 const char *name = load_store_opcode_props[op].name;
219 
220                 assert(name);
221                 printf("%s", name);
222                 break;
223         }
224 
225         case TAG_TEXTURE_4: {
226                 printf("TEX");
227 
228                 if (ins->helper_terminate)
229                         printf(".terminate");
230 
231                 if (ins->helper_execute)
232                         printf(".execute");
233 
234                 break;
235         }
236 
237         default:
238                 assert(0);
239         }
240 
241         if (ins->compact_branch && ins->branch.invert_conditional)
242                 printf(".not");
243 
244         printf(" ");
245         mir_print_index(ins->dest);
246 
247         if (ins->dest != ~0) {
248                 pan_print_alu_type(ins->dest_type, stdout);
249                 mir_print_mask(ins->mask);
250         }
251 
252         printf(", ");
253 
254         /* Only ALU can have an embedded constant, r26 as read on load/store is
255          * something else entirely */
256         bool is_alu = ins->type == TAG_ALU_4;
257         unsigned r_constant = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
258 
259         if (ins->src[0] == r_constant && is_alu)
260                 mir_print_embedded_constant(ins, 0);
261         else
262                 PRINT_SRC(ins, 0);
263 
264         printf(", ");
265 
266         if (ins->has_inline_constant)
267                 printf("#%d", ins->inline_constant);
268         else if (ins->src[1] == r_constant && is_alu)
269                 mir_print_embedded_constant(ins, 1);
270         else
271                 PRINT_SRC(ins, 1);
272 
273         for (unsigned c = 2; c <= 3; ++c) {
274                 printf(", ");
275                 PRINT_SRC(ins, c);
276         }
277 
278         if (ins->no_spill)
279                 printf(" /* no spill */");
280 
281         printf("\n");
282 }
283 
284 /* Dumps MIR for a block or entire shader respective */
285 
286 void
mir_print_block(midgard_block * block)287 mir_print_block(midgard_block *block)
288 {
289         printf("block%u: {\n", block->base.name);
290 
291         if (block->scheduled) {
292                 mir_foreach_bundle_in_block(block, bundle) {
293                         for (unsigned i = 0; i < bundle->instruction_count; ++i)
294                                 mir_print_instruction(bundle->instructions[i]);
295 
296                         printf("\n");
297                 }
298         } else {
299                 mir_foreach_instr_in_block(block, ins) {
300                         mir_print_instruction(ins);
301                 }
302         }
303 
304         printf("}");
305 
306         if (block->base.successors[0]) {
307                 printf(" -> ");
308                 pan_foreach_successor((&block->base), succ)
309                         printf(" block%u ", succ->name);
310         }
311 
312         printf(" from { ");
313         mir_foreach_predecessor(block, pred)
314                 printf("block%u ", pred->base.name);
315         printf("}");
316 
317         printf("\n\n");
318 }
319 
320 void
mir_print_shader(compiler_context * ctx)321 mir_print_shader(compiler_context *ctx)
322 {
323         mir_foreach_block(ctx, block) {
324                 mir_print_block((midgard_block *) block);
325         }
326 }
327