ilo: fix a missing 'else'
[mesa.git] / src / gallium / drivers / ilo / shader / toy_compiler_disasm.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 LunarG, Inc.
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, sublicense,
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 shall be included
14 * in all copies or substantial portions of the 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
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include <stdio.h>
29 #include "genhw/genhw.h"
30 #include "toy_compiler.h"
31
32 #define DISASM_PRINTER_BUFFER_SIZE 256
33 #define DISASM_PRINTER_COLUMN_WIDTH 16
34
35 struct disasm_printer {
36 char buf[DISASM_PRINTER_BUFFER_SIZE];
37 int len;
38 };
39
40 struct disasm_operand {
41 unsigned file:2;
42 unsigned type:3;
43
44 unsigned addr_mode:1;
45 unsigned reg:8;
46 unsigned subreg:5;
47 unsigned addr_subreg:3;
48 unsigned addr_imm:10;
49 };
50
51 struct disasm_dst_operand {
52 struct disasm_operand base;
53
54 unsigned horz_stride:2;
55 unsigned writemask:4;
56 };
57
58 struct disasm_src_operand {
59 struct disasm_operand base;
60
61 unsigned vert_stride:4;
62 unsigned width:3;
63 unsigned horz_stride:2;
64 unsigned swizzle_x:2;
65 unsigned swizzle_y:2;
66 unsigned swizzle_z:2;
67 unsigned swizzle_w:2;
68 unsigned negate:1;
69 unsigned absolute:1;
70 };
71
72 struct disasm_inst {
73 const struct ilo_dev_info *dev;
74
75 unsigned has_jip:1;
76 unsigned has_uip:1;
77
78 unsigned opcode:7;
79 unsigned access_mode:1;
80 unsigned mask_ctrl:1;
81 unsigned dep_ctrl:2;
82 unsigned qtr_ctrl:2;
83 unsigned thread_ctrl:2;
84 unsigned pred_ctrl:4;
85 unsigned pred_inv:1;
86 unsigned exec_size:3;
87
88 unsigned cond_modifier:4;
89 unsigned sfid:4;
90 unsigned fc:4;
91
92 unsigned acc_wr_ctrl:1;
93 unsigned cmpt_ctrl:1;
94 unsigned debug_ctrl:1;
95 unsigned saturate:1;
96
97 unsigned nib_ctrl:1;
98
99 unsigned flag_reg:1;
100 unsigned flag_subreg:1;
101
102 struct disasm_dst_operand dst;
103 struct disasm_src_operand src0;
104 struct disasm_src_operand src1;
105 union {
106 struct disasm_src_operand src2;
107 uint32_t imm32;
108 } u;
109 };
110
111 static const struct {
112 const char *name;
113 int src_count;
114 } disasm_opcode_table[128] = {
115 [GEN6_OPCODE_ILLEGAL] = { "illegal", 0 },
116 [GEN6_OPCODE_MOV] = { "mov", 1 },
117 [GEN6_OPCODE_SEL] = { "sel", 2 },
118 [GEN6_OPCODE_MOVI] = { "movi", 1 },
119 [GEN6_OPCODE_NOT] = { "not", 1 },
120 [GEN6_OPCODE_AND] = { "and", 2 },
121 [GEN6_OPCODE_OR] = { "or", 2 },
122 [GEN6_OPCODE_XOR] = { "xor", 2 },
123 [GEN6_OPCODE_SHR] = { "shr", 2 },
124 [GEN6_OPCODE_SHL] = { "shl", 2 },
125 [GEN6_OPCODE_DIM] = { "dim", 1 },
126 [GEN6_OPCODE_ASR] = { "asr", 2 },
127 [GEN6_OPCODE_CMP] = { "cmp", 2 },
128 [GEN6_OPCODE_CMPN] = { "cmpn", 2 },
129 [GEN7_OPCODE_CSEL] = { "csel", 3 },
130 [GEN7_OPCODE_F32TO16] = { "f32to16", 1 },
131 [GEN7_OPCODE_F16TO32] = { "f16to32", 1 },
132 [GEN7_OPCODE_BFREV] = { "bfrev", 1 },
133 [GEN7_OPCODE_BFE] = { "bfe", 3 },
134 [GEN7_OPCODE_BFI1] = { "bfi1", 2 },
135 [GEN7_OPCODE_BFI2] = { "bfi2", 3 },
136 [GEN6_OPCODE_JMPI] = { "jmpi", 1 },
137 [GEN7_OPCODE_BRD] = { "brd", 1 },
138 [GEN6_OPCODE_IF] = { "if", 2 },
139 [GEN7_OPCODE_BRC] = { "brc", 1 },
140 [GEN6_OPCODE_ELSE] = { "else", 1 },
141 [GEN6_OPCODE_ENDIF] = { "endif", 0 },
142 [GEN6_OPCODE_CASE] = { "case", 2 },
143 [GEN6_OPCODE_WHILE] = { "while", 1 },
144 [GEN6_OPCODE_BREAK] = { "break", 1 },
145 [GEN6_OPCODE_CONT] = { "cont", 1 },
146 [GEN6_OPCODE_HALT] = { "halt", 1 },
147 [GEN75_OPCODE_CALLA] = { "calla", 1 },
148 [GEN6_OPCODE_CALL] = { "call", 1 },
149 [GEN6_OPCODE_RETURN] = { "return", 1 },
150 [GEN6_OPCODE_WAIT] = { "wait", 1 },
151 [GEN6_OPCODE_SEND] = { "send", 1 },
152 [GEN6_OPCODE_SENDC] = { "sendc", 1 },
153 [GEN6_OPCODE_MATH] = { "math", 2 },
154 [GEN6_OPCODE_ADD] = { "add", 2 },
155 [GEN6_OPCODE_MUL] = { "mul", 2 },
156 [GEN6_OPCODE_AVG] = { "avg", 2 },
157 [GEN6_OPCODE_FRC] = { "frc", 1 },
158 [GEN6_OPCODE_RNDU] = { "rndu", 1 },
159 [GEN6_OPCODE_RNDD] = { "rndd", 1 },
160 [GEN6_OPCODE_RNDE] = { "rnde", 1 },
161 [GEN6_OPCODE_RNDZ] = { "rndz", 1 },
162 [GEN6_OPCODE_MAC] = { "mac", 2 },
163 [GEN6_OPCODE_MACH] = { "mach", 2 },
164 [GEN6_OPCODE_LZD] = { "lzd", 1 },
165 [GEN7_OPCODE_FBH] = { "fbh", 1 },
166 [GEN7_OPCODE_FBL] = { "fbl", 1 },
167 [GEN7_OPCODE_CBIT] = { "cbit", 1 },
168 [GEN7_OPCODE_ADDC] = { "addc", 2 },
169 [GEN7_OPCODE_SUBB] = { "subb", 2 },
170 [GEN6_OPCODE_SAD2] = { "sad2", 2 },
171 [GEN6_OPCODE_SADA2] = { "sada2", 2 },
172 [GEN6_OPCODE_DP4] = { "dp4", 2 },
173 [GEN6_OPCODE_DPH] = { "dph", 2 },
174 [GEN6_OPCODE_DP3] = { "dp3", 2 },
175 [GEN6_OPCODE_DP2] = { "dp2", 2 },
176 [GEN6_OPCODE_LINE] = { "line", 2 },
177 [GEN6_OPCODE_PLN] = { "pln", 2 },
178 [GEN6_OPCODE_MAD] = { "mad", 3 },
179 [GEN6_OPCODE_LRP] = { "lrp", 3 },
180 [GEN6_OPCODE_NOP] = { "nop", 0 },
181 };
182
183 static void
184 disasm_inst_decode_dw0_gen6(struct disasm_inst *inst, uint32_t dw0)
185 {
186 inst->opcode = GEN_EXTRACT(dw0, GEN6_INST_OPCODE);
187
188 switch (inst->opcode) {
189 case GEN6_OPCODE_IF:
190 inst->has_jip = true;
191 inst->has_uip = (ilo_dev_gen(inst->dev) >= ILO_GEN(7));
192 break;
193 case GEN6_OPCODE_BREAK:
194 case GEN6_OPCODE_CONT:
195 case GEN6_OPCODE_HALT:
196 inst->has_uip = true;
197 /* fall through */
198 case GEN6_OPCODE_JMPI:
199 case GEN7_OPCODE_BRD:
200 case GEN7_OPCODE_BRC:
201 case GEN6_OPCODE_ELSE:
202 case GEN6_OPCODE_ENDIF:
203 case GEN6_OPCODE_CASE:
204 case GEN6_OPCODE_WHILE:
205 case GEN75_OPCODE_CALLA:
206 case GEN6_OPCODE_CALL:
207 case GEN6_OPCODE_RETURN:
208 inst->has_jip = true;
209 break;
210 default:
211 break;
212 }
213
214 inst->access_mode = GEN_EXTRACT(dw0, GEN6_INST_ACCESSMODE);
215 inst->mask_ctrl = GEN_EXTRACT(dw0, GEN6_INST_MASKCTRL);
216 inst->dep_ctrl = GEN_EXTRACT(dw0, GEN6_INST_DEPCTRL);
217 inst->qtr_ctrl = GEN_EXTRACT(dw0, GEN6_INST_QTRCTRL);
218 inst->thread_ctrl = GEN_EXTRACT(dw0, GEN6_INST_THREADCTRL);
219 inst->pred_ctrl = GEN_EXTRACT(dw0, GEN6_INST_PREDCTRL);
220
221 inst->pred_inv = (bool) (dw0 & GEN6_INST_PREDINV);
222
223 inst->exec_size = GEN_EXTRACT(dw0, GEN6_INST_EXECSIZE);
224
225 switch (inst->opcode) {
226 case GEN6_OPCODE_SEND:
227 case GEN6_OPCODE_SENDC:
228 inst->sfid = GEN_EXTRACT(dw0, GEN6_INST_SFID);
229 break;
230 case GEN6_OPCODE_MATH:
231 inst->fc = GEN_EXTRACT(dw0, GEN6_INST_FC);
232 break;
233 default:
234 inst->cond_modifier = GEN_EXTRACT(dw0, GEN6_INST_CONDMODIFIER);
235 break;
236 }
237
238 inst->acc_wr_ctrl = (bool) (dw0 & GEN6_INST_ACCWRCTRL);
239 inst->cmpt_ctrl = (bool) (dw0 & GEN6_INST_CMPTCTRL);
240 inst->debug_ctrl = (bool) (dw0 & GEN6_INST_DEBUGCTRL);
241 inst->saturate = (bool) (dw0 & GEN6_INST_SATURATE);
242 }
243
244 static bool
245 disasm_inst_jip_in_dw1_high_gen6(const struct disasm_inst *inst)
246 {
247 return (ilo_dev_gen(inst->dev) == ILO_GEN(6) &&
248 inst->has_jip && !inst->has_uip);
249 }
250
251 static void
252 disasm_inst_decode_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
253 {
254 inst->dst.base.file = GEN_EXTRACT(dw1, GEN6_INST_DST_FILE);
255 inst->dst.base.type = GEN_EXTRACT(dw1, GEN6_INST_DST_TYPE);
256 inst->src0.base.file = GEN_EXTRACT(dw1, GEN6_INST_SRC0_FILE);
257 inst->src0.base.type = GEN_EXTRACT(dw1, GEN6_INST_SRC0_TYPE);
258 inst->src1.base.file = GEN_EXTRACT(dw1, GEN6_INST_SRC1_FILE);
259 inst->src1.base.type = GEN_EXTRACT(dw1, GEN6_INST_SRC1_TYPE);
260
261 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7))
262 inst->nib_ctrl = (bool) (dw1 & GEN7_INST_NIBCTRL);
263
264 if (disasm_inst_jip_in_dw1_high_gen6(inst)) {
265 inst->u.imm32 = dw1 >> 16;
266 return;
267 }
268
269 inst->dst.base.addr_mode = GEN_EXTRACT(dw1, GEN6_INST_DST_ADDRMODE);
270
271 if (inst->dst.base.addr_mode == GEN6_ADDRMODE_DIRECT) {
272 inst->dst.base.reg = GEN_EXTRACT(dw1, GEN6_INST_DST_REG);
273
274 if (inst->access_mode == GEN6_ALIGN_1) {
275 inst->dst.base.subreg = GEN_EXTRACT(dw1, GEN6_INST_DST_SUBREG);
276 } else {
277 inst->dst.base.subreg =
278 GEN_EXTRACT(dw1, GEN6_INST_DST_SUBREG_ALIGN16) <<
279 GEN6_INST_DST_SUBREG_ALIGN16__SHR;
280 }
281 } else {
282 inst->dst.base.addr_subreg = GEN_EXTRACT(dw1, GEN6_INST_DST_ADDR_SUBREG);
283
284 if (inst->access_mode == GEN6_ALIGN_1) {
285 inst->dst.base.addr_imm = GEN_EXTRACT(dw1, GEN6_INST_DST_ADDR_IMM);
286 } else {
287 inst->dst.base.addr_imm = GEN_EXTRACT(dw1,
288 GEN6_INST_DST_ADDR_IMM_ALIGN16) <<
289 GEN6_INST_DST_ADDR_IMM_ALIGN16__SHR;
290 }
291 }
292
293 inst->dst.horz_stride = GEN_EXTRACT(dw1, GEN6_INST_DST_HORZSTRIDE);
294
295 if (inst->access_mode == GEN6_ALIGN_1)
296 inst->dst.writemask = 0xf;
297 else
298 inst->dst.writemask = GEN_EXTRACT(dw1, GEN6_INST_DST_WRITEMASK);
299 }
300
301 static void
302 disasm_inst_decode_dw2_dw3_gen6(struct disasm_inst *inst,
303 uint32_t dw2, uint32_t dw3)
304 {
305 int count, i;
306
307 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7))
308 inst->flag_reg = GEN_EXTRACT(dw2, GEN7_INST_FLAG_REG);
309
310 inst->flag_subreg = GEN_EXTRACT(dw2, GEN6_INST_FLAG_SUBREG);
311
312 if (inst->src0.base.file == GEN6_FILE_IMM ||
313 inst->src1.base.file == GEN6_FILE_IMM) {
314 count = 1;
315 if (!disasm_inst_jip_in_dw1_high_gen6(inst))
316 inst->u.imm32 = dw3;
317 } else {
318 count = 2;
319 }
320
321 for (i = 0; i < count; i++) {
322 struct disasm_src_operand *src = (i == 0) ? &inst->src0 : &inst->src1;
323 const uint32_t dw = (i == 0) ? dw2 : dw3;
324
325 src->base.addr_mode = GEN_EXTRACT(dw, GEN6_INST_SRC_ADDRMODE);
326
327 if (src->base.addr_mode == GEN6_ADDRMODE_DIRECT) {
328 src->base.reg = GEN_EXTRACT(dw, GEN6_INST_SRC_REG);
329
330 if (inst->access_mode == GEN6_ALIGN_1) {
331 src->base.subreg = GEN_EXTRACT(dw, GEN6_INST_SRC_SUBREG);
332 } else {
333 src->base.subreg = GEN_EXTRACT(dw, GEN6_INST_SRC_SUBREG_ALIGN16) <<
334 GEN6_INST_SRC_SUBREG_ALIGN16__SHR;
335 }
336 } else {
337 src->base.addr_subreg = GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_SUBREG);
338
339 if (inst->access_mode == GEN6_ALIGN_1) {
340 src->base.addr_imm = GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_IMM);
341 } else {
342 src->base.addr_imm =
343 GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_IMM_ALIGN16) <<
344 GEN6_INST_SRC_ADDR_IMM_ALIGN16__SHR;
345 }
346 }
347
348 src->vert_stride = GEN_EXTRACT(dw, GEN6_INST_SRC_VERTSTRIDE);
349
350 if (inst->access_mode == GEN6_ALIGN_1) {
351 src->width = GEN_EXTRACT(dw, GEN6_INST_SRC_WIDTH);
352 src->horz_stride = GEN_EXTRACT(dw, GEN6_INST_SRC_HORZSTRIDE);
353
354 src->swizzle_x = GEN6_SWIZZLE_X;
355 src->swizzle_y = GEN6_SWIZZLE_Y;
356 src->swizzle_z = GEN6_SWIZZLE_Z;
357 src->swizzle_w = GEN6_SWIZZLE_W;
358 } else {
359 src->width = GEN6_WIDTH_4;
360 src->horz_stride = GEN6_HORZSTRIDE_1;
361
362 src->swizzle_x = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_X);
363 src->swizzle_y = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_Y);
364 src->swizzle_z = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_Z);
365 src->swizzle_w = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_W);
366 }
367
368 src->negate = (bool) (dw & GEN6_INST_SRC_NEGATE);
369 src->absolute = (bool) (dw & GEN6_INST_SRC_ABSOLUTE);
370 }
371 }
372
373 static void
374 disasm_inst_decode_3src_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
375 {
376 static unsigned type_mapping[4] = {
377 [GEN7_TYPE_F_3SRC] = GEN6_TYPE_F,
378 [GEN7_TYPE_D_3SRC] = GEN6_TYPE_D,
379 [GEN7_TYPE_UD_3SRC] = GEN6_TYPE_UD,
380 [GEN7_TYPE_DF_3SRC] = GEN7_TYPE_DF,
381 };
382
383 inst->flag_subreg = GEN_EXTRACT(dw1, GEN6_3SRC_FLAG_SUBREG);
384
385 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
386 inst->nib_ctrl = (bool) (dw1 & GEN7_3SRC_NIBCTRL);
387 inst->flag_reg = GEN_EXTRACT(dw1, GEN7_3SRC_FLAG_REG);
388
389 inst->dst.base.file = GEN6_FILE_GRF;
390 inst->dst.base.type = GEN_EXTRACT(dw1, GEN7_3SRC_DST_TYPE);
391 inst->dst.base.type = type_mapping[inst->dst.base.type];
392
393 inst->src0.base.type = GEN_EXTRACT(dw1, GEN7_3SRC_SRC_TYPE);
394 inst->src0.base.type = type_mapping[inst->src0.base.type];
395
396 inst->src1.base.type = inst->src0.base.type;
397 inst->u.src2.base.type = inst->src0.base.type;
398 } else {
399 inst->dst.base.file = (dw1 & GEN6_3SRC_DST_FILE_MRF) ?
400 GEN6_FILE_MRF: GEN6_FILE_GRF;
401 inst->dst.base.type = GEN6_TYPE_F;
402
403 inst->src0.base.type = GEN6_TYPE_F;
404 inst->src1.base.type = GEN6_TYPE_F;
405 inst->u.src2.base.type = GEN6_TYPE_F;
406 }
407
408 inst->dst.base.addr_mode = GEN6_ADDRMODE_DIRECT;
409 inst->dst.base.reg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_REG);
410 inst->dst.base.subreg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_SUBREG) <<
411 GEN6_3SRC_DST_SUBREG__SHR;
412
413 inst->dst.horz_stride = GEN6_HORZSTRIDE_1;
414 inst->dst.writemask = GEN_EXTRACT(dw1, GEN6_3SRC_DST_WRITEMASK);
415
416 inst->src0.base.file = GEN6_FILE_GRF;
417 inst->src0.negate = (bool) (dw1 & GEN6_3SRC_SRC0_NEGATE);
418 inst->src0.absolute = (bool) (dw1 & GEN6_3SRC_SRC0_ABSOLUTE);
419 inst->src1.base.file = GEN6_FILE_GRF;
420 inst->src1.negate = (bool) (dw1 & GEN6_3SRC_SRC1_NEGATE);
421 inst->src1.absolute = (bool) (dw1 & GEN6_3SRC_SRC1_ABSOLUTE);
422 inst->u.src2.base.file = GEN6_FILE_GRF;
423 inst->u.src2.negate = (bool) (dw1 & GEN6_3SRC_SRC2_NEGATE);
424 inst->u.src2.absolute = (bool) (dw1 & GEN6_3SRC_SRC2_ABSOLUTE);
425 }
426
427 static void
428 disasm_inst_decode_3src_dw2_dw3_gen6(struct disasm_inst *inst,
429 uint32_t dw2, uint32_t dw3)
430 {
431 const uint64_t qw = (uint64_t) dw3 << 32 | dw2;
432 int i;
433
434 for (i = 0; i < 3; i++) {
435 struct disasm_src_operand *src = (i == 0) ? &inst->src0 :
436 (i == 1) ? &inst->src1 :
437 &inst->u.src2;
438 const uint32_t dw = (i == 0) ? GEN_EXTRACT(qw, GEN6_3SRC_SRC_0) :
439 (i == 1) ? GEN_EXTRACT(qw, GEN6_3SRC_SRC_1) :
440 GEN_EXTRACT(qw, GEN6_3SRC_SRC_2);
441
442 src->base.addr_mode = GEN6_ADDRMODE_DIRECT;
443 src->base.reg = GEN_EXTRACT(dw, GEN6_3SRC_SRC_REG);
444 src->base.subreg = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SUBREG) <<
445 GEN6_3SRC_SRC_SUBREG__SHR;
446
447 if (dw & GEN6_3SRC_SRC_REPCTRL) {
448 src->vert_stride = GEN6_VERTSTRIDE_0;
449 src->width = GEN6_WIDTH_1;
450 src->horz_stride = GEN6_HORZSTRIDE_0;
451 } else {
452 src->vert_stride = GEN6_VERTSTRIDE_4;
453 src->width = GEN6_WIDTH_4;
454 src->horz_stride = GEN6_HORZSTRIDE_1;
455 }
456
457 src->swizzle_x = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_X);
458 src->swizzle_y = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_Y);
459 src->swizzle_z = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_Z);
460 src->swizzle_w = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_W);
461 }
462 }
463
464 /*
465 * When GEN6_INST_CMPTCTRL of DW0 is set, the instruction has 64 bits and is
466 * in EU_INSTRUCTION_COMPACT_TWO_SRC form. We should have expanded it to its
467 * original form.
468 *
469 * Depending on the opcode, the 128-bits instruction is in one of the
470 * following forms
471 *
472 * - EU_INSTRUCTION_BASIC_ONE_SRC
473 * - EU_INSTRUCTION_BASIC_TWO_SRC
474 * - EU_INSTRUCTION_BASIC_THREE_SRC
475 * - EU_INSTRUCTION_BRANCH_CONDITIONAL
476 * - EU_INSTRUCTION_BRANCH_ONE_SRC
477 * - EU_INSTRUCTION_BRANCH_TWO_SRC
478 * - EU_INSTRUCTION_ILLEGAL
479 * - EU_INSTRUCTION_MATH
480 * - EU_INSTRUCTION_NOP
481 * - EU_INSTRUCTION_SEND
482 *
483 * In EU_INSTRUCTION_BASIC_ONE_SRC form,
484 *
485 * - DW0 is EU_INSTRUCTION_HEADER
486 * - DW1 is EU_INSTRUCTION_OPERAND_CONTROLS
487 * - DW2 is Source 0 and EU_INSTRUCTION_FLAGS
488 * - DW3 is reserved unless Source 0 is an immediate
489 *
490 * All other forms except EU_INSTRUCTION_BASIC_THREE_SRC are quite compatible
491 * with EU_INSTRUCTION_BASIC_ONE_SRC.
492 */
493 static void
494 disasm_inst_decode(struct disasm_inst *inst,
495 const uint32_t *dw)
496 {
497 assert(!(dw[0] & GEN6_INST_CMPTCTRL));
498
499 disasm_inst_decode_dw0_gen6(inst, dw[0]);
500
501 if (disasm_opcode_table[inst->opcode].src_count == 3) {
502 disasm_inst_decode_3src_dw1_gen6(inst, dw[1]);
503 disasm_inst_decode_3src_dw2_dw3_gen6(inst, dw[2], dw[3]);
504 } else {
505 disasm_inst_decode_dw1_gen6(inst, dw[1]);
506 disasm_inst_decode_dw2_dw3_gen6(inst, dw[2], dw[3]);
507 }
508 }
509
510 static const char *
511 disasm_inst_opcode(const struct disasm_inst *inst)
512 {
513 return (disasm_opcode_table[inst->opcode].name) ?
514 disasm_opcode_table[inst->opcode].name : "BAD";
515 }
516
517 static const char *
518 disasm_inst_pred_ctrl(const struct disasm_inst *inst)
519 {
520 if (inst->access_mode == GEN6_ALIGN_1) {
521 switch (inst->pred_ctrl) {
522 case GEN6_PREDCTRL_NORMAL: return "";
523 case GEN6_PREDCTRL_ANYV: return ".anyv";
524 case GEN6_PREDCTRL_ALLV: return ".allv";
525 case GEN6_PREDCTRL_ANY2H: return ".any2h";
526 case GEN6_PREDCTRL_ALL2H: return ".all2h";
527 case GEN6_PREDCTRL_ANY4H: return ".any4h";
528 case GEN6_PREDCTRL_ALL4H: return ".all4h";
529 case GEN6_PREDCTRL_ANY8H: return ".any8h";
530 case GEN6_PREDCTRL_ALL8H: return ".all8h";
531 case GEN6_PREDCTRL_ANY16H: return ".any16h";
532 case GEN6_PREDCTRL_ALL16H: return ".all16h";
533 case GEN7_PREDCTRL_ANY32H: return ".any32h";
534 case GEN7_PREDCTRL_ALL32H: return ".all32h";
535 default: return ".BAD";
536 }
537 } else {
538 switch (inst->pred_ctrl) {
539 case GEN6_PREDCTRL_NORMAL: return "";
540 case GEN6_PREDCTRL_X: return ".x";
541 case GEN6_PREDCTRL_Y: return ".y";
542 case GEN6_PREDCTRL_Z: return ".z";
543 case GEN6_PREDCTRL_W: return ".w";
544 default: return ".BAD";
545 }
546 }
547 }
548
549 static char
550 disasm_inst_pred_inv(const struct disasm_inst *inst)
551 {
552 return (inst->pred_inv) ? '-' : '+';
553 }
554
555 static const char *
556 disasm_inst_exec_size(const struct disasm_inst *inst)
557 {
558 switch (inst->exec_size) {
559 case GEN6_EXECSIZE_1: return "1";
560 case GEN6_EXECSIZE_2: return "2";
561 case GEN6_EXECSIZE_4: return "4";
562 case GEN6_EXECSIZE_8: return "8";
563 case GEN6_EXECSIZE_16: return "16";
564 case GEN6_EXECSIZE_32: return "32";
565 default: return "BAD";
566 }
567 }
568
569 static const char *
570 disasm_inst_fc(const struct disasm_inst *inst)
571 {
572 assert(inst->opcode == GEN6_OPCODE_MATH);
573
574 switch (inst->fc) {
575 case GEN6_MATH_INV: return "inv";
576 case GEN6_MATH_LOG: return "log";
577 case GEN6_MATH_EXP: return "exp";
578 case GEN6_MATH_SQRT: return "sqrt";
579 case GEN6_MATH_RSQ: return "rsq";
580 case GEN6_MATH_SIN: return "sin";
581 case GEN6_MATH_COS: return "cos";
582 case GEN6_MATH_FDIV: return "fdiv";
583 case GEN6_MATH_POW: return "pow";
584 case GEN6_MATH_INT_DIV: return "int_div";
585 case GEN6_MATH_INT_DIV_QUOTIENT: return "int_div_quotient";
586 case GEN6_MATH_INT_DIV_REMAINDER: return "int_div_remainder";
587 default: return "BAD";
588 }
589 }
590
591 static const char *
592 disasm_inst_sfid(const struct disasm_inst *inst)
593 {
594 assert(inst->opcode == GEN6_OPCODE_SEND ||
595 inst->opcode == GEN6_OPCODE_SENDC);
596
597 switch (inst->sfid) {
598 case GEN6_SFID_NULL: return "null";
599 case GEN6_SFID_SAMPLER: return "sampler";
600 case GEN6_SFID_GATEWAY: return "gateway";
601 case GEN6_SFID_DP_SAMPLER: return "dp sampler";
602 case GEN6_SFID_DP_RC: return "dp render";
603 case GEN6_SFID_URB: return "urb";
604 case GEN6_SFID_SPAWNER: return "spawner";
605 case GEN6_SFID_VME: return "vme";
606 case GEN6_SFID_DP_CC: return "dp const";
607 case GEN7_SFID_DP_DC0: return "dp data 0";
608 case GEN7_SFID_PI: return "pixel interp";
609 case GEN75_SFID_DP_DC1: return "dp data 1";
610 default: return "BAD";
611 }
612 }
613
614 static const char *
615 disasm_inst_cond_modifier(const struct disasm_inst *inst)
616 {
617 switch (inst->cond_modifier) {
618 case GEN6_COND_NONE: return "";
619 case GEN6_COND_Z: return ".z";
620 case GEN6_COND_NZ: return ".nz";
621 case GEN6_COND_G: return ".g";
622 case GEN6_COND_GE: return ".ge";
623 case GEN6_COND_L: return ".l";
624 case GEN6_COND_LE: return ".le";
625 case GEN6_COND_O: return ".o";
626 case GEN6_COND_U: return ".u";
627 default: return ".BAD";
628 }
629 }
630
631 static const char *
632 disasm_inst_debug_ctrl(const struct disasm_inst *inst)
633 {
634 return (inst->debug_ctrl) ? ".breakpoint" : "";
635 }
636
637 static const char *
638 disasm_inst_saturate(const struct disasm_inst *inst)
639 {
640 return (inst->saturate) ? ".sat" : "";
641 }
642
643 static const char *
644 disasm_inst_flag_reg(const struct disasm_inst *inst)
645 {
646 static const char *flag_names[2][2] = {
647 { "f0", "f0.1" },
648 { "f1.0", "f1.1" },
649 };
650
651 return (inst->flag_reg <= 1 && inst->flag_subreg <= 1) ?
652 flag_names[inst->flag_reg][inst->flag_subreg] : "fBAD";
653 }
654
655 static const char *
656 disasm_inst_access_mode(const struct disasm_inst *inst)
657 {
658 switch (inst->access_mode) {
659 case GEN6_ALIGN_1: return " align1";
660 case GEN6_ALIGN_16: return " align16";
661 default: return " alignBAD";
662 }
663 }
664
665 static const char *
666 disasm_inst_mask_ctrl(const struct disasm_inst *inst)
667 {
668 switch (inst->mask_ctrl) {
669 case GEN6_MASKCTRL_NORMAL: return "";
670 case GEN6_MASKCTRL_NOMASK: return " WE_all";
671 default: return " WE_BAD";
672 }
673 }
674
675 static const char *
676 disasm_inst_dep_ctrl(const struct disasm_inst *inst)
677 {
678 switch (inst->dep_ctrl) {
679 case GEN6_DEPCTRL_NORMAL: return "";
680 case GEN6_DEPCTRL_NODDCLR: return " NoDDClr";
681 case GEN6_DEPCTRL_NODDCHK: return " NoDDChk";
682 case GEN6_DEPCTRL_NEITHER: return " NoDDClr,NoDDChk";
683 default: return " NoDDBAD";
684 }
685 }
686
687 static const char *
688 disasm_inst_qtr_ctrl(const struct disasm_inst *inst)
689 {
690 switch (inst->exec_size) {
691 case GEN6_EXECSIZE_8:
692 switch (inst->qtr_ctrl) {
693 case GEN6_QTRCTRL_1Q: return " 1Q";
694 case GEN6_QTRCTRL_2Q: return " 2Q";
695 case GEN6_QTRCTRL_3Q: return " 3Q";
696 case GEN6_QTRCTRL_4Q: return " 4Q";
697 default: return " BADQ";
698 }
699 break;
700 case GEN6_EXECSIZE_16:
701 switch (inst->qtr_ctrl) {
702 case GEN6_QTRCTRL_1H: return " 1H";
703 case GEN6_QTRCTRL_2H: return " 2H";
704 default: return " BADH";
705 }
706 break;
707 default:
708 return "";
709 }
710
711 }
712
713 static const char *
714 disasm_inst_thread_ctrl(const struct disasm_inst *inst)
715 {
716 switch (inst->thread_ctrl) {
717 case GEN6_THREADCTRL_NORMAL: return "";
718 case GEN6_THREADCTRL_ATOMIC: return " atomic";
719 case GEN6_THREADCTRL_SWITCH: return " switch";
720 default: return " BAD";
721 }
722 }
723
724 static const char *
725 disasm_inst_acc_wr_ctrl(const struct disasm_inst *inst)
726 {
727 return (inst->acc_wr_ctrl) ? " AccWrEnable" : "";
728 }
729
730 static const char *
731 disasm_inst_cmpt_ctrl(const struct disasm_inst *inst)
732 {
733 return (inst->cmpt_ctrl) ? " compacted" : "";
734 }
735
736 static const char *
737 disasm_inst_eot(const struct disasm_inst *inst)
738 {
739 if (inst->opcode == GEN6_OPCODE_SEND ||
740 inst->opcode == GEN6_OPCODE_SENDC)
741 return (inst->u.imm32 & GEN6_MSG_EOT) ? " EOT" : "";
742 else
743 return "";
744 }
745
746 static const char *
747 disasm_inst_file(const struct disasm_inst *inst,
748 const struct disasm_operand *operand,
749 bool *multi_regs)
750 {
751 switch (operand->file) {
752 case GEN6_FILE_ARF:
753 switch (operand->reg & 0xf0) {
754 case GEN6_ARF_NULL: *multi_regs = false; return "null";
755 case GEN6_ARF_A0: *multi_regs = true; return "a";
756 case GEN6_ARF_ACC0: *multi_regs = true; return "acc";
757 case GEN6_ARF_F0: *multi_regs = true; return "f";
758 case GEN6_ARF_SR0: *multi_regs = true; return "sr";
759 case GEN6_ARF_CR0: *multi_regs = true; return "cr";
760 case GEN6_ARF_N0: *multi_regs = true; return "n";
761 case GEN6_ARF_IP: *multi_regs = false; return "ip";
762 case GEN6_ARF_TDR: *multi_regs = false; return "tdr";
763 case GEN7_ARF_TM0: *multi_regs = true; return "tm";
764 default: *multi_regs = false; return "BAD";
765 }
766 break;
767 case GEN6_FILE_GRF: *multi_regs = true; return "g";
768 case GEN6_FILE_MRF: *multi_regs = true; return "m";
769 case GEN6_FILE_IMM: *multi_regs = true; return "";
770 default: *multi_regs = false; return "BAD";
771 }
772 }
773
774 static const char *
775 disasm_inst_type(const struct disasm_inst *inst,
776 const struct disasm_operand *operand)
777 {
778 if (operand->file == GEN6_FILE_IMM) {
779 switch (operand->type) {
780 case GEN6_TYPE_UD: return "UD";
781 case GEN6_TYPE_D: return "D";
782 case GEN6_TYPE_UW: return "UW";
783 case GEN6_TYPE_W: return "W";
784 case GEN6_TYPE_UV_IMM: return "UV";
785 case GEN6_TYPE_VF_IMM: return "VF";
786 case GEN6_TYPE_V_IMM: return "V";
787 case GEN6_TYPE_F: return "F";
788 default: return "BAD";
789 }
790 } else {
791 switch (operand->type) {
792 case GEN6_TYPE_UD: return "UD";
793 case GEN6_TYPE_D: return "D";
794 case GEN6_TYPE_UW: return "UW";
795 case GEN6_TYPE_W: return "W";
796 case GEN6_TYPE_UB: return "UB";
797 case GEN6_TYPE_B: return "B";
798 case GEN7_TYPE_DF: return "DF";
799 case GEN6_TYPE_F: return "F";
800 default: return "BAD";
801 }
802 }
803 }
804
805 static const char *
806 disasm_inst_vert_stride(const struct disasm_inst *inst, unsigned vert_stride)
807 {
808 switch (vert_stride) {
809 case GEN6_VERTSTRIDE_0: return "0";
810 case GEN6_VERTSTRIDE_1: return "1";
811 case GEN6_VERTSTRIDE_2: return "2";
812 case GEN6_VERTSTRIDE_4: return "4";
813 case GEN6_VERTSTRIDE_8: return "8";
814 case GEN6_VERTSTRIDE_16: return "16";
815 case GEN6_VERTSTRIDE_32: return "32";
816 case GEN6_VERTSTRIDE_VXH: return "VxH";
817 default: return "BAD";
818 }
819 }
820
821 static const char *
822 disasm_inst_width(const struct disasm_inst *inst, unsigned width)
823 {
824 switch (width) {
825 case GEN6_WIDTH_1: return "1";
826 case GEN6_WIDTH_2: return "2";
827 case GEN6_WIDTH_4: return "4";
828 case GEN6_WIDTH_8: return "8";
829 case GEN6_WIDTH_16: return "16";
830 default: return "BAD";
831 }
832 }
833
834 static const char *
835 disasm_inst_horz_stride(const struct disasm_inst *inst, unsigned horz_stride)
836 {
837 switch (horz_stride) {
838 case GEN6_HORZSTRIDE_0: return "0";
839 case GEN6_HORZSTRIDE_1: return "1";
840 case GEN6_HORZSTRIDE_2: return "2";
841 case GEN6_HORZSTRIDE_4: return "4";
842 default: return "BAD";
843 }
844 }
845
846 static const char *
847 disasm_inst_writemask(const struct disasm_inst *inst, unsigned writemask)
848 {
849 switch (writemask) {
850 case 0x0: return ".";
851 case 0x1: return ".x";
852 case 0x2: return ".y";
853 case 0x3: return ".xy";
854 case 0x4: return ".z";
855 case 0x5: return ".xz";
856 case 0x6: return ".yz";
857 case 0x7: return ".xyz";
858 case 0x8: return ".w";
859 case 0x9: return ".xw";
860 case 0xa: return ".yw";
861 case 0xb: return ".xyw";
862 case 0xc: return ".zw";
863 case 0xd: return ".xzw";
864 case 0xe: return ".yzw";
865 case 0xf: return "";
866 default: return ".BAD";
867 }
868 }
869
870 static const char *
871 disasm_inst_negate(const struct disasm_inst *inst, bool negate)
872 {
873 return (negate) ? "-" : "";
874 }
875
876 static const char *
877 disasm_inst_absolute(const struct disasm_inst *inst, bool absolute)
878 {
879 return (absolute) ? "(abs)" : "";
880 }
881
882 static bool
883 disasm_inst_is_null(const struct disasm_inst *inst,
884 const struct disasm_operand *operand)
885 {
886 return (operand->file == GEN6_FILE_ARF && operand->reg == GEN6_ARF_NULL);
887 }
888
889 static int
890 disasm_inst_type_size(const struct disasm_inst *inst,
891 const struct disasm_operand *operand)
892 {
893 assert(operand->file != GEN6_FILE_IMM);
894
895 switch (operand->type) {
896 case GEN6_TYPE_UD: return 4;
897 case GEN6_TYPE_D: return 4;
898 case GEN6_TYPE_UW: return 2;
899 case GEN6_TYPE_W: return 2;
900 case GEN6_TYPE_UB: return 1;
901 case GEN6_TYPE_B: return 1;
902 case GEN7_TYPE_DF: return 8;
903 case GEN6_TYPE_F: return 4;
904 default: return 1;
905 }
906 }
907
908 static void
909 disasm_printer_reset(struct disasm_printer *printer)
910 {
911 printer->buf[0] = '\0';
912 printer->len = 0;
913 }
914
915 static const char *
916 disasm_printer_get_string(struct disasm_printer *printer)
917 {
918 return printer->buf;
919 }
920
921 static void _util_printf_format(2, 3)
922 disasm_printer_add(struct disasm_printer *printer, const char *format, ...)
923 {
924 const size_t avail = sizeof(printer->buf) - printer->len;
925 va_list ap;
926 int written;
927
928 va_start(ap, format);
929 written = vsnprintf(printer->buf + printer->len, avail, format, ap);
930 va_end(ap);
931
932 /* truncated */
933 if (written < 0 || written >= avail) {
934 memcpy(printer->buf + sizeof(printer->buf) - 4, "...", 4);
935 printer->len = sizeof(printer->buf) - 1;
936 } else {
937 printer->len += written;
938 }
939 }
940
941 /**
942 * Pad to the specified column.
943 */
944 static void
945 disasm_printer_column(struct disasm_printer *printer, int col)
946 {
947 int len = DISASM_PRINTER_COLUMN_WIDTH * col;
948
949 if (len <= printer->len) {
950 if (!printer->len)
951 return;
952
953 /* at least one space */
954 len = printer->len + 1;
955 }
956
957 if (len >= sizeof(printer->buf)) {
958 len = sizeof(printer->buf) - 1;
959
960 if (len <= printer->len)
961 return;
962 }
963
964 memset(printer->buf + printer->len, ' ', len - printer->len);
965 printer->len = len;
966 printer->buf[printer->len] = '\0';
967 }
968
969 static void
970 disasm_printer_add_op(struct disasm_printer *printer,
971 const struct disasm_inst *inst)
972 {
973 if (inst->pred_ctrl != GEN6_PREDCTRL_NONE) {
974 disasm_printer_add(printer, "(%c%s%s) ",
975 disasm_inst_pred_inv(inst),
976 disasm_inst_flag_reg(inst),
977 disasm_inst_pred_ctrl(inst));
978 }
979
980 disasm_printer_add(printer, "%s%s%s%s",
981 disasm_inst_opcode(inst),
982 disasm_inst_saturate(inst),
983 disasm_inst_debug_ctrl(inst),
984 disasm_inst_cond_modifier(inst));
985
986 if (inst->cond_modifier != GEN6_COND_NONE) {
987 switch (inst->opcode) {
988 case GEN6_OPCODE_SEL:
989 case GEN6_OPCODE_IF:
990 case GEN6_OPCODE_WHILE:
991 /* these do not update flag registers */
992 break;
993 default:
994 disasm_printer_add(printer, ".%s", disasm_inst_flag_reg(inst));
995 break;
996 }
997 }
998
999 if (inst->opcode == GEN6_OPCODE_MATH)
1000 disasm_printer_add(printer, " %s", disasm_inst_fc(inst));
1001 if (inst->opcode != GEN6_OPCODE_NOP)
1002 disasm_printer_add(printer, "(%s)", disasm_inst_exec_size(inst));
1003 }
1004
1005 static void
1006 disasm_printer_add_operand(struct disasm_printer *printer,
1007 const struct disasm_inst *inst,
1008 const struct disasm_operand *operand)
1009 {
1010 const char *name;
1011 bool multi_regs;
1012
1013 name = disasm_inst_file(inst, operand, &multi_regs);
1014 if (!multi_regs) {
1015 disasm_printer_add(printer, "%s", name);
1016 return;
1017 }
1018
1019 if (operand->file == GEN6_FILE_IMM) {
1020 switch (operand->type) {
1021 case GEN6_TYPE_UD:
1022 disasm_printer_add(printer, "0x%08xUD", inst->u.imm32);
1023 break;
1024 case GEN6_TYPE_D:
1025 disasm_printer_add(printer, "%dD", inst->u.imm32);
1026 break;
1027 case GEN6_TYPE_UW:
1028 disasm_printer_add(printer, "0x%04xUW", (uint16_t) inst->u.imm32);
1029 break;
1030 case GEN6_TYPE_W:
1031 disasm_printer_add(printer, "%dW", (int16_t) inst->u.imm32);
1032 break;
1033 case GEN6_TYPE_UV_IMM:
1034 disasm_printer_add(printer, "0x%08xUV", inst->u.imm32);
1035 break;
1036 case GEN6_TYPE_VF_IMM:
1037 disasm_printer_add(printer, "Vector Float");
1038 break;
1039 case GEN6_TYPE_V_IMM:
1040 disasm_printer_add(printer, "0x%08xV", inst->u.imm32);
1041 break;
1042 case GEN6_TYPE_F:
1043 disasm_printer_add(printer, "%-gF", uif(inst->u.imm32));
1044 break;
1045 default:
1046 disasm_printer_add(printer, "BAD");
1047 break;
1048 }
1049
1050 return;
1051 }
1052
1053 if (operand->addr_mode == GEN6_ADDRMODE_DIRECT) {
1054 unsigned reg, subreg;
1055
1056 reg = operand->reg;
1057 if (operand->file == GEN6_FILE_ARF)
1058 reg &= 0xf;
1059
1060 subreg = operand->subreg / disasm_inst_type_size(inst, operand);
1061
1062 if (subreg)
1063 disasm_printer_add(printer, "%s%d.%d", name, reg, subreg);
1064 else
1065 disasm_printer_add(printer, "%s%d", name, reg);
1066 } else {
1067 disasm_printer_add(printer, "%s[a0.%d %d]",
1068 name, operand->addr_subreg, operand->addr_imm);
1069 }
1070 }
1071
1072 static void
1073 disasm_printer_add_dst(struct disasm_printer *printer,
1074 const struct disasm_inst *inst,
1075 const struct disasm_dst_operand *dst)
1076 {
1077 disasm_printer_add_operand(printer, inst, &dst->base);
1078
1079 /* dst is an immediate when in EU_INSTRUCTION_BRANCH_CONDITIONAL form */
1080 if (disasm_inst_is_null(inst, &dst->base) ||
1081 dst->base.file == GEN6_FILE_IMM)
1082 return;
1083
1084 disasm_printer_add(printer, "<%s>%s%s",
1085 disasm_inst_horz_stride(inst, dst->horz_stride),
1086 disasm_inst_writemask(inst, dst->writemask),
1087 disasm_inst_type(inst, &dst->base));
1088 }
1089
1090 static void
1091 disasm_printer_add_src(struct disasm_printer *printer,
1092 const struct disasm_inst *inst,
1093 const struct disasm_src_operand *src)
1094 {
1095 static const char swizzle_chars[4] = { 'x', 'y', 'z', 'w' };
1096 char swizzle[5];
1097
1098 disasm_printer_add(printer, "%s%s",
1099 disasm_inst_negate(inst, src->negate),
1100 disasm_inst_absolute(inst, src->absolute));
1101
1102 disasm_printer_add_operand(printer, inst, &src->base);
1103
1104 if (disasm_inst_is_null(inst, &src->base) ||
1105 src->base.file == GEN6_FILE_IMM)
1106 return;
1107
1108 if (src->swizzle_x == 0 && src->swizzle_y == 1 &&
1109 src->swizzle_z == 2 && src->swizzle_w == 3) {
1110 swizzle[0] = '\0';
1111 } else if (src->swizzle_x == src->swizzle_y &&
1112 src->swizzle_x == src->swizzle_z &&
1113 src->swizzle_x == src->swizzle_w) {
1114 swizzle[0] = swizzle_chars[src->swizzle_x];
1115 swizzle[1] = '\0';
1116 } else {
1117 swizzle[0] = swizzle_chars[src->swizzle_x];
1118 swizzle[1] = swizzle_chars[src->swizzle_y];
1119 swizzle[2] = swizzle_chars[src->swizzle_z];
1120 swizzle[3] = swizzle_chars[src->swizzle_w];
1121 swizzle[4] = '\0';
1122 }
1123
1124 disasm_printer_add(printer, "<%s,%s,%s>%s%s",
1125 disasm_inst_vert_stride(inst, src->vert_stride),
1126 disasm_inst_width(inst, src->width),
1127 disasm_inst_horz_stride(inst, src->horz_stride),
1128 swizzle,
1129 disasm_inst_type(inst, &src->base));
1130 }
1131
1132 static void
1133 disasm_printer_add_ctrl(struct disasm_printer *printer,
1134 const struct disasm_inst *inst)
1135 {
1136 if (inst->opcode == GEN6_OPCODE_NOP) {
1137 disasm_printer_add(printer, ";");
1138 return;
1139 }
1140
1141 disasm_printer_add(printer, "{%s%s%s%s%s%s%s%s };",
1142 disasm_inst_access_mode(inst),
1143 disasm_inst_mask_ctrl(inst),
1144 disasm_inst_dep_ctrl(inst),
1145 disasm_inst_qtr_ctrl(inst),
1146 disasm_inst_cmpt_ctrl(inst),
1147 disasm_inst_thread_ctrl(inst),
1148 disasm_inst_acc_wr_ctrl(inst),
1149 disasm_inst_eot(inst));
1150 }
1151
1152 static void
1153 disasm_printer_add_mdesc_sampler(struct disasm_printer *printer,
1154 const struct disasm_inst *inst,
1155 uint32_t mdesc)
1156 {
1157 int op, simd;
1158
1159 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1160 op = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_OP);
1161 simd = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_SIMD);
1162 } else {
1163 op = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_OP);
1164 simd = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SIMD);
1165 }
1166
1167 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1168 GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SURFACE),
1169 GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_INDEX),
1170 op, simd);
1171 }
1172
1173 static void
1174 disasm_printer_add_mdesc_urb(struct disasm_printer *printer,
1175 const struct disasm_inst *inst,
1176 uint32_t mdesc)
1177 {
1178 const char *op;
1179 int offset;
1180 bool interleaved, complete, allocate, used;
1181
1182 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1183 switch (GEN_EXTRACT(mdesc, GEN7_MSG_URB_OP)) {
1184 case GEN7_MSG_URB_WRITE_HWORD: op = "write HWord"; break;
1185 case GEN7_MSG_URB_WRITE_OWORD: op = "write OWord"; break;
1186 case GEN7_MSG_URB_READ_HWORD: op = "read HWord"; break;
1187 case GEN7_MSG_URB_READ_OWORD: op = "read OWord"; break;
1188 case GEN7_MSG_URB_ATOMIC_MOV: op = "atomic mov"; break;
1189 case GEN7_MSG_URB_ATOMIC_INC: op = "atomic inc"; break;
1190 default: op = "BAD"; break;
1191 }
1192
1193 offset = GEN_EXTRACT(mdesc, GEN7_MSG_URB_GLOBAL_OFFSET);
1194 interleaved = mdesc & GEN7_MSG_URB_INTERLEAVED;
1195 complete = mdesc & GEN7_MSG_URB_COMPLETE;
1196
1197 allocate = false;
1198 used = false;
1199 } else {
1200 switch (GEN_EXTRACT(mdesc, GEN6_MSG_URB_OP)) {
1201 case GEN6_MSG_URB_WRITE: op = "urb_write"; break;
1202 case GEN6_MSG_URB_FF_SYNC: op = "ff_sync"; break;
1203 default: op = "BAD"; break;
1204 }
1205
1206 offset = GEN_EXTRACT(mdesc, GEN6_MSG_URB_OFFSET);
1207 interleaved = mdesc & GEN6_MSG_URB_INTERLEAVED;
1208 complete = mdesc & GEN6_MSG_URB_COMPLETE;
1209
1210 allocate = mdesc & GEN6_MSG_URB_ALLOCATE;
1211 used = mdesc & GEN6_MSG_URB_USED;
1212 }
1213
1214 disasm_printer_add(printer, " %d %s%s%s%s%s", offset, op,
1215 (interleaved) ? " interleave" : "",
1216 (allocate) ? " allocate" : "",
1217 (used) ? " used" : "",
1218 (complete) ? " complete" : "");
1219 }
1220
1221 static void
1222 disasm_printer_add_mdesc_dp_sampler(struct disasm_printer *printer,
1223 const struct disasm_inst *inst,
1224 uint32_t mdesc)
1225 {
1226 const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
1227 GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
1228 const bool write_commit = (ilo_dev_gen(inst->dev) == ILO_GEN(6)) ?
1229 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT) : 0;
1230
1231 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1232 GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE),
1233 GEN_EXTRACT(mdesc, GEN6_MSG_DP_OWORD_BLOCK_SIZE),
1234 op, write_commit);
1235 }
1236
1237 static void
1238 disasm_printer_add_mdesc_dp_rc(struct disasm_printer *printer,
1239 const struct disasm_inst *inst,
1240 uint32_t mdesc)
1241 {
1242 const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
1243 GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
1244 const char *str;
1245 bool is_rt_write;
1246
1247 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7.5)) {
1248 switch (op) {
1249 case GEN75_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1250 case GEN75_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1251 case GEN75_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1252 case GEN75_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1253 default: str = "BAD"; break;
1254 }
1255
1256 is_rt_write = (op == GEN75_MSG_DP_RC_RT_WRITE);
1257 } else if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1258 switch (op) {
1259 case GEN7_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1260 case GEN7_MSG_DP_RC_TYPED_SURFACE_READ: str = "typed surface read"; break;
1261 case GEN7_MSG_DP_RC_TYPED_ATOMIC_OP: str = "typed atomic op"; break;
1262 case GEN7_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1263 case GEN7_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1264 case GEN7_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1265 case GEN7_MSG_DP_RC_TYPED_SURFACE_WRITE: str = "typed surface write"; break;
1266 default: str = "BAD"; break;
1267 }
1268
1269 is_rt_write = (op == GEN7_MSG_DP_RC_RT_WRITE);
1270 } else {
1271 switch (op) {
1272 case GEN6_MSG_DP_OWORD_BLOCK_READ: str = "OWORD block read"; break;
1273 case GEN6_MSG_DP_RT_UNORM_READ: str = "RT UNORM read"; break;
1274 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_READ: str = "OWORD dual block read"; break;
1275 case GEN6_MSG_DP_MEDIA_BLOCK_READ: str = "media block read"; break;
1276 case GEN6_MSG_DP_UNALIGNED_OWORD_BLOCK_READ: str = "unaligned OWORD block read"; break;
1277 case GEN6_MSG_DP_DWORD_SCATTERED_READ: str = "DWORD scattered read"; break;
1278 case GEN6_MSG_DP_DWORD_ATOMIC_WRITE: str = "DWORD atomic write"; break;
1279 case GEN6_MSG_DP_OWORD_BLOCK_WRITE: str = "OWORD block write"; break;
1280 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_WRITE: str = "OWORD dual block_write"; break;
1281 case GEN6_MSG_DP_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1282 case GEN6_MSG_DP_DWORD_SCATTERED_WRITE: str = "DWORD scattered write"; break;
1283 case GEN6_MSG_DP_RT_WRITE: str = "RT write"; break;
1284 case GEN6_MSG_DP_SVB_WRITE: str = "SVB write"; break;
1285 case GEN6_MSG_DP_RT_UNORM_WRITE: str = "RT UNORM write"; break;
1286 default: str = "BAD"; break;
1287 }
1288
1289 is_rt_write = (op == GEN6_MSG_DP_RT_WRITE);
1290 }
1291
1292 disasm_printer_add(printer, " %s", str);
1293
1294 if (is_rt_write) {
1295 switch (mdesc & GEN6_MSG_DP_RT_MODE__MASK) {
1296 case GEN6_MSG_DP_RT_MODE_SIMD16: str = "SIMD16"; break;
1297 case GEN6_MSG_DP_RT_MODE_SIMD16_REPDATA: str = "SIMD16/RepData"; break;
1298 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_LO: str = "SIMD8/DualSrcLow"; break;
1299 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_HI: str = "SIMD8/DualSrcHigh"; break;
1300 case GEN6_MSG_DP_RT_MODE_SIMD8_LO: str = "SIMD8"; break;
1301 case GEN6_MSG_DP_RT_MODE_SIMD8_IMAGE_WR: str = "SIMD8/ImageWrite"; break;
1302 default: str = "BAD"; break;
1303 }
1304
1305 disasm_printer_add(printer, " %s%s%s%s", str,
1306 (mdesc & GEN6_MSG_DP_SLOTGRP_HI) ? " Hi" : "",
1307 (mdesc & GEN6_MSG_DP_RT_LAST) ? " LastRT" : "",
1308 (ilo_dev_gen(inst->dev) == ILO_GEN(6) &&
1309 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT)) ? " WriteCommit" : "");
1310 }
1311
1312 disasm_printer_add(printer, " Surface = %d",
1313 GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
1314 }
1315
1316 static void
1317 disasm_printer_add_mdesc(struct disasm_printer *printer,
1318 const struct disasm_inst *inst)
1319 {
1320 const uint32_t mdesc = inst->u.imm32;
1321
1322 assert(inst->opcode == GEN6_OPCODE_SEND ||
1323 inst->opcode == GEN6_OPCODE_SENDC);
1324 assert(inst->src1.base.file == GEN6_FILE_IMM);
1325
1326 disasm_printer_add(printer, " %s", disasm_inst_sfid(inst));
1327
1328 switch (inst->sfid) {
1329 case GEN6_SFID_SAMPLER:
1330 disasm_printer_add_mdesc_sampler(printer, inst, mdesc);
1331 break;
1332 case GEN6_SFID_DP_SAMPLER:
1333 disasm_printer_add_mdesc_dp_sampler(printer, inst, mdesc);
1334 break;
1335 case GEN6_SFID_DP_RC:
1336 disasm_printer_add_mdesc_dp_rc(printer, inst, mdesc);
1337 break;
1338 case GEN6_SFID_URB:
1339 disasm_printer_add_mdesc_urb(printer, inst, mdesc);
1340 break;
1341 case GEN6_SFID_DP_CC:
1342 case GEN7_SFID_DP_DC0:
1343 case GEN7_SFID_PI:
1344 case GEN75_SFID_DP_DC1:
1345 default:
1346 break;
1347 }
1348
1349 disasm_printer_add(printer, " mlen %d rlen %d",
1350 GEN_EXTRACT(mdesc, GEN6_MSG_MLEN),
1351 GEN_EXTRACT(mdesc, GEN6_MSG_RLEN));
1352 }
1353
1354 static void
1355 disasm_printer_print_inst(struct disasm_printer *printer,
1356 const struct disasm_inst *inst)
1357 {
1358 int col = 0;
1359
1360 disasm_printer_reset(printer);
1361
1362 disasm_printer_column(printer, col++);
1363 disasm_printer_add_op(printer, inst);
1364
1365 if (inst->has_jip || inst->has_uip) {
1366 if (inst->has_jip) {
1367 disasm_printer_column(printer, col++);
1368 disasm_printer_add(printer, "JIP: %d", (int16_t) inst->u.imm32);
1369 }
1370
1371 if (inst->has_uip) {
1372 disasm_printer_column(printer, col++);
1373 disasm_printer_add(printer, "UIP: %d",
1374 (int16_t) (inst->u.imm32 >> 16));
1375 }
1376 } else {
1377 const int src_count = disasm_opcode_table[inst->opcode].src_count;
1378
1379 if (src_count) {
1380 const struct disasm_src_operand *src[3] = {
1381 &inst->src0, &inst->src1, &inst->u.src2
1382 };
1383 int i;
1384
1385 disasm_printer_column(printer, col++);
1386 disasm_printer_add_dst(printer, inst, &inst->dst);
1387
1388 for (i = 0; i < src_count; i++) {
1389 disasm_printer_column(printer, col++);
1390 disasm_printer_add_src(printer, inst, src[i]);
1391 }
1392 }
1393 }
1394
1395 if (inst->opcode == GEN6_OPCODE_SEND ||
1396 inst->opcode == GEN6_OPCODE_SENDC) {
1397 /* start a new line */
1398 ilo_printf("%s\n", disasm_printer_get_string(printer));
1399 disasm_printer_reset(printer);
1400 col = 0;
1401
1402 disasm_printer_column(printer, col++);
1403
1404 disasm_printer_column(printer, col++);
1405 disasm_printer_add_mdesc(printer, inst);
1406 }
1407
1408 if (col < 4)
1409 col = 4;
1410
1411 disasm_printer_column(printer, col++);
1412 disasm_printer_add_ctrl(printer, inst);
1413
1414 ilo_printf("%s\n", disasm_printer_get_string(printer));
1415 }
1416
1417 void
1418 toy_compiler_disassemble(const struct ilo_dev_info *dev,
1419 const void *kernel, int size,
1420 bool dump_hex)
1421 {
1422 const uint32_t *cur = (const uint32_t *) kernel;
1423 const uint32_t *end = cur + size / sizeof(*cur);
1424 struct disasm_printer printer;
1425
1426 disasm_printer_reset(&printer);
1427
1428 while (cur < end) {
1429 struct disasm_inst inst;
1430 const bool compacted = (cur[0] & GEN6_INST_CMPTCTRL);
1431 const uint32_t *dw = cur;
1432 uint32_t temp[4];
1433
1434 cur += (compacted) ? 2 : 4;
1435 /* incomplete instruction */
1436 if (cur > end)
1437 break;
1438
1439 if (compacted) {
1440 /* no compaction support yet */
1441 memset(temp, 0, sizeof(temp));
1442 dw = temp;
1443 }
1444
1445 if (dump_hex) {
1446 ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ",
1447 dw[0], dw[1], dw[2], dw[3]);
1448 }
1449
1450 memset(&inst, 0, sizeof(inst));
1451 inst.dev = dev;
1452 disasm_inst_decode(&inst, dw);
1453 inst.cmpt_ctrl = compacted;
1454
1455 disasm_printer_print_inst(&printer, &inst);
1456 }
1457 }