ilo: use an accessor for dev->gen
[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 switch (inst->opcode) {
502 case GEN7_OPCODE_CSEL:
503 case GEN7_OPCODE_BFE:
504 case GEN7_OPCODE_BFI2:
505 case GEN6_OPCODE_MAD:
506 case GEN6_OPCODE_LRP:
507 disasm_inst_decode_3src_dw1_gen6(inst, dw[1]);
508 disasm_inst_decode_3src_dw2_dw3_gen6(inst, dw[2], dw[3]);
509 break;
510 default:
511 disasm_inst_decode_dw1_gen6(inst, dw[1]);
512 disasm_inst_decode_dw2_dw3_gen6(inst, dw[2], dw[3]);
513 break;
514 }
515 }
516
517 static const char *
518 disasm_inst_opcode(const struct disasm_inst *inst)
519 {
520 return (disasm_opcode_table[inst->opcode].name) ?
521 disasm_opcode_table[inst->opcode].name : "BAD";
522 }
523
524 static const char *
525 disasm_inst_pred_ctrl(const struct disasm_inst *inst)
526 {
527 if (inst->access_mode == GEN6_ALIGN_1) {
528 switch (inst->pred_ctrl) {
529 case GEN6_PREDCTRL_NORMAL: return "";
530 case GEN6_PREDCTRL_ANYV: return ".anyv";
531 case GEN6_PREDCTRL_ALLV: return ".allv";
532 case GEN6_PREDCTRL_ANY2H: return ".any2h";
533 case GEN6_PREDCTRL_ALL2H: return ".all2h";
534 case GEN6_PREDCTRL_ANY4H: return ".any4h";
535 case GEN6_PREDCTRL_ALL4H: return ".all4h";
536 case GEN6_PREDCTRL_ANY8H: return ".any8h";
537 case GEN6_PREDCTRL_ALL8H: return ".all8h";
538 case GEN6_PREDCTRL_ANY16H: return ".any16h";
539 case GEN6_PREDCTRL_ALL16H: return ".all16h";
540 case GEN7_PREDCTRL_ANY32H: return ".any32h";
541 case GEN7_PREDCTRL_ALL32H: return ".all32h";
542 default: return ".BAD";
543 }
544 } else {
545 switch (inst->pred_ctrl) {
546 case GEN6_PREDCTRL_NORMAL: return "";
547 case GEN6_PREDCTRL_X: return ".x";
548 case GEN6_PREDCTRL_Y: return ".y";
549 case GEN6_PREDCTRL_Z: return ".z";
550 case GEN6_PREDCTRL_W: return ".w";
551 default: return ".BAD";
552 }
553 }
554 }
555
556 static char
557 disasm_inst_pred_inv(const struct disasm_inst *inst)
558 {
559 return (inst->pred_inv) ? '-' : '+';
560 }
561
562 static const char *
563 disasm_inst_exec_size(const struct disasm_inst *inst)
564 {
565 switch (inst->exec_size) {
566 case GEN6_EXECSIZE_1: return "1";
567 case GEN6_EXECSIZE_2: return "2";
568 case GEN6_EXECSIZE_4: return "4";
569 case GEN6_EXECSIZE_8: return "8";
570 case GEN6_EXECSIZE_16: return "16";
571 case GEN6_EXECSIZE_32: return "32";
572 default: return "BAD";
573 }
574 }
575
576 static const char *
577 disasm_inst_fc(const struct disasm_inst *inst)
578 {
579 assert(inst->opcode == GEN6_OPCODE_MATH);
580
581 switch (inst->fc) {
582 case GEN6_MATH_INV: return "inv";
583 case GEN6_MATH_LOG: return "log";
584 case GEN6_MATH_EXP: return "exp";
585 case GEN6_MATH_SQRT: return "sqrt";
586 case GEN6_MATH_RSQ: return "rsq";
587 case GEN6_MATH_SIN: return "sin";
588 case GEN6_MATH_COS: return "cos";
589 case GEN6_MATH_FDIV: return "fdiv";
590 case GEN6_MATH_POW: return "pow";
591 case GEN6_MATH_INT_DIV: return "int_div";
592 case GEN6_MATH_INT_DIV_QUOTIENT: return "int_div_quotient";
593 case GEN6_MATH_INT_DIV_REMAINDER: return "int_div_remainder";
594 default: return "BAD";
595 }
596 }
597
598 static const char *
599 disasm_inst_sfid(const struct disasm_inst *inst)
600 {
601 assert(inst->opcode == GEN6_OPCODE_SEND ||
602 inst->opcode == GEN6_OPCODE_SENDC);
603
604 switch (inst->sfid) {
605 case GEN6_SFID_NULL: return "null";
606 case GEN6_SFID_SAMPLER: return "sampler";
607 case GEN6_SFID_GATEWAY: return "gateway";
608 case GEN6_SFID_DP_SAMPLER: return "dp sampler";
609 case GEN6_SFID_DP_RC: return "dp render";
610 case GEN6_SFID_URB: return "urb";
611 case GEN6_SFID_SPAWNER: return "spawner";
612 case GEN6_SFID_VME: return "vme";
613 case GEN6_SFID_DP_CC: return "dp const";
614 case GEN7_SFID_DP_DC0: return "dp data 0";
615 case GEN7_SFID_PI: return "pixel interp";
616 case GEN75_SFID_DP_DC1: return "dp data 1";
617 default: return "BAD";
618 }
619 }
620
621 static const char *
622 disasm_inst_cond_modifier(const struct disasm_inst *inst)
623 {
624 switch (inst->cond_modifier) {
625 case GEN6_COND_NONE: return "";
626 case GEN6_COND_Z: return ".z";
627 case GEN6_COND_NZ: return ".nz";
628 case GEN6_COND_G: return ".g";
629 case GEN6_COND_GE: return ".ge";
630 case GEN6_COND_L: return ".l";
631 case GEN6_COND_LE: return ".le";
632 case GEN6_COND_O: return ".o";
633 case GEN6_COND_U: return ".u";
634 default: return ".BAD";
635 }
636 }
637
638 static const char *
639 disasm_inst_debug_ctrl(const struct disasm_inst *inst)
640 {
641 return (inst->debug_ctrl) ? ".breakpoint" : "";
642 }
643
644 static const char *
645 disasm_inst_saturate(const struct disasm_inst *inst)
646 {
647 return (inst->saturate) ? ".sat" : "";
648 }
649
650 static const char *
651 disasm_inst_flag_reg(const struct disasm_inst *inst)
652 {
653 static const char *flag_names[2][2] = {
654 { "f0", "f0.1" },
655 { "f1.0", "f1.1" },
656 };
657
658 return (inst->flag_reg <= 1 && inst->flag_subreg <= 1) ?
659 flag_names[inst->flag_reg][inst->flag_subreg] : "fBAD";
660 }
661
662 static const char *
663 disasm_inst_access_mode(const struct disasm_inst *inst)
664 {
665 switch (inst->access_mode) {
666 case GEN6_ALIGN_1: return " align1";
667 case GEN6_ALIGN_16: return " align16";
668 default: return " alignBAD";
669 }
670 }
671
672 static const char *
673 disasm_inst_mask_ctrl(const struct disasm_inst *inst)
674 {
675 switch (inst->mask_ctrl) {
676 case GEN6_MASKCTRL_NORMAL: return "";
677 case GEN6_MASKCTRL_NOMASK: return " WE_all";
678 default: return " WE_BAD";
679 }
680 }
681
682 static const char *
683 disasm_inst_dep_ctrl(const struct disasm_inst *inst)
684 {
685 switch (inst->dep_ctrl) {
686 case GEN6_DEPCTRL_NORMAL: return "";
687 case GEN6_DEPCTRL_NODDCLR: return " NoDDClr";
688 case GEN6_DEPCTRL_NODDCHK: return " NoDDChk";
689 case GEN6_DEPCTRL_NEITHER: return " NoDDClr,NoDDChk";
690 default: return " NoDDBAD";
691 }
692 }
693
694 static const char *
695 disasm_inst_qtr_ctrl(const struct disasm_inst *inst)
696 {
697 switch (inst->exec_size) {
698 case GEN6_EXECSIZE_8:
699 switch (inst->qtr_ctrl) {
700 case GEN6_QTRCTRL_1Q: return " 1Q";
701 case GEN6_QTRCTRL_2Q: return " 2Q";
702 case GEN6_QTRCTRL_3Q: return " 3Q";
703 case GEN6_QTRCTRL_4Q: return " 4Q";
704 default: return " BADQ";
705 }
706 break;
707 case GEN6_EXECSIZE_16:
708 switch (inst->qtr_ctrl) {
709 case GEN6_QTRCTRL_1H: return " 1H";
710 case GEN6_QTRCTRL_2H: return " 2H";
711 default: return " BADH";
712 }
713 break;
714 default:
715 return "";
716 }
717
718 }
719
720 static const char *
721 disasm_inst_thread_ctrl(const struct disasm_inst *inst)
722 {
723 switch (inst->thread_ctrl) {
724 case GEN6_THREADCTRL_NORMAL: return "";
725 case GEN6_THREADCTRL_ATOMIC: return " atomic";
726 case GEN6_THREADCTRL_SWITCH: return " switch";
727 default: return " BAD";
728 }
729 }
730
731 static const char *
732 disasm_inst_acc_wr_ctrl(const struct disasm_inst *inst)
733 {
734 return (inst->acc_wr_ctrl) ? " AccWrEnable" : "";
735 }
736
737 static const char *
738 disasm_inst_cmpt_ctrl(const struct disasm_inst *inst)
739 {
740 return (inst->cmpt_ctrl) ? " compacted" : "";
741 }
742
743 static const char *
744 disasm_inst_eot(const struct disasm_inst *inst)
745 {
746 if (inst->opcode == GEN6_OPCODE_SEND ||
747 inst->opcode == GEN6_OPCODE_SENDC)
748 return (inst->u.imm32 & GEN6_MSG_EOT) ? " EOT" : "";
749 else
750 return "";
751 }
752
753 static const char *
754 disasm_inst_file(const struct disasm_inst *inst,
755 const struct disasm_operand *operand,
756 bool *multi_regs)
757 {
758 switch (operand->file) {
759 case GEN6_FILE_ARF:
760 switch (operand->reg & 0xf0) {
761 case GEN6_ARF_NULL: *multi_regs = false; return "null";
762 case GEN6_ARF_A0: *multi_regs = true; return "a";
763 case GEN6_ARF_ACC0: *multi_regs = true; return "acc";
764 case GEN6_ARF_F0: *multi_regs = true; return "f";
765 case GEN6_ARF_SR0: *multi_regs = true; return "sr";
766 case GEN6_ARF_CR0: *multi_regs = true; return "cr";
767 case GEN6_ARF_N0: *multi_regs = true; return "n";
768 case GEN6_ARF_IP: *multi_regs = false; return "ip";
769 case GEN6_ARF_TDR: *multi_regs = false; return "tdr";
770 case GEN7_ARF_TM0: *multi_regs = true; return "tm";
771 default: *multi_regs = false; return "BAD";
772 }
773 break;
774 case GEN6_FILE_GRF: *multi_regs = true; return "g";
775 case GEN6_FILE_MRF: *multi_regs = true; return "m";
776 case GEN6_FILE_IMM: *multi_regs = true; return "";
777 default: *multi_regs = false; return "BAD";
778 }
779 }
780
781 static const char *
782 disasm_inst_type(const struct disasm_inst *inst,
783 const struct disasm_operand *operand)
784 {
785 if (operand->file == GEN6_FILE_IMM) {
786 switch (operand->type) {
787 case GEN6_TYPE_UD: return "UD";
788 case GEN6_TYPE_D: return "D";
789 case GEN6_TYPE_UW: return "UW";
790 case GEN6_TYPE_W: return "W";
791 case GEN6_TYPE_UV_IMM: return "UV";
792 case GEN6_TYPE_VF_IMM: return "VF";
793 case GEN6_TYPE_V_IMM: return "V";
794 case GEN6_TYPE_F: return "F";
795 default: return "BAD";
796 }
797 } else {
798 switch (operand->type) {
799 case GEN6_TYPE_UD: return "UD";
800 case GEN6_TYPE_D: return "D";
801 case GEN6_TYPE_UW: return "UW";
802 case GEN6_TYPE_W: return "W";
803 case GEN6_TYPE_UB: return "UB";
804 case GEN6_TYPE_B: return "B";
805 case GEN7_TYPE_DF: return "DF";
806 case GEN6_TYPE_F: return "F";
807 default: return "BAD";
808 }
809 }
810 }
811
812 static const char *
813 disasm_inst_vert_stride(const struct disasm_inst *inst, unsigned vert_stride)
814 {
815 switch (vert_stride) {
816 case GEN6_VERTSTRIDE_0: return "0";
817 case GEN6_VERTSTRIDE_1: return "1";
818 case GEN6_VERTSTRIDE_2: return "2";
819 case GEN6_VERTSTRIDE_4: return "4";
820 case GEN6_VERTSTRIDE_8: return "8";
821 case GEN6_VERTSTRIDE_16: return "16";
822 case GEN6_VERTSTRIDE_32: return "32";
823 case GEN6_VERTSTRIDE_VXH: return "VxH";
824 default: return "BAD";
825 }
826 }
827
828 static const char *
829 disasm_inst_width(const struct disasm_inst *inst, unsigned width)
830 {
831 switch (width) {
832 case GEN6_WIDTH_1: return "1";
833 case GEN6_WIDTH_2: return "2";
834 case GEN6_WIDTH_4: return "4";
835 case GEN6_WIDTH_8: return "8";
836 case GEN6_WIDTH_16: return "16";
837 default: return "BAD";
838 }
839 }
840
841 static const char *
842 disasm_inst_horz_stride(const struct disasm_inst *inst, unsigned horz_stride)
843 {
844 switch (horz_stride) {
845 case GEN6_HORZSTRIDE_0: return "0";
846 case GEN6_HORZSTRIDE_1: return "1";
847 case GEN6_HORZSTRIDE_2: return "2";
848 case GEN6_HORZSTRIDE_4: return "4";
849 default: return "BAD";
850 }
851 }
852
853 static const char *
854 disasm_inst_writemask(const struct disasm_inst *inst, unsigned writemask)
855 {
856 switch (writemask) {
857 case 0x0: return ".";
858 case 0x1: return ".x";
859 case 0x2: return ".y";
860 case 0x3: return ".xy";
861 case 0x4: return ".z";
862 case 0x5: return ".xz";
863 case 0x6: return ".yz";
864 case 0x7: return ".xyz";
865 case 0x8: return ".w";
866 case 0x9: return ".xw";
867 case 0xa: return ".yw";
868 case 0xb: return ".xyw";
869 case 0xc: return ".zw";
870 case 0xd: return ".xzw";
871 case 0xe: return ".yzw";
872 case 0xf: return "";
873 default: return ".BAD";
874 }
875 }
876
877 static const char *
878 disasm_inst_negate(const struct disasm_inst *inst, bool negate)
879 {
880 return (negate) ? "-" : "";
881 }
882
883 static const char *
884 disasm_inst_absolute(const struct disasm_inst *inst, bool absolute)
885 {
886 return (absolute) ? "(abs)" : "";
887 }
888
889 static bool
890 disasm_inst_is_null(const struct disasm_inst *inst,
891 const struct disasm_operand *operand)
892 {
893 return (operand->file == GEN6_FILE_ARF && operand->reg == GEN6_ARF_NULL);
894 }
895
896 static int
897 disasm_inst_type_size(const struct disasm_inst *inst,
898 const struct disasm_operand *operand)
899 {
900 assert(operand->file != GEN6_FILE_IMM);
901
902 switch (operand->type) {
903 case GEN6_TYPE_UD: return 4;
904 case GEN6_TYPE_D: return 4;
905 case GEN6_TYPE_UW: return 2;
906 case GEN6_TYPE_W: return 2;
907 case GEN6_TYPE_UB: return 1;
908 case GEN6_TYPE_B: return 1;
909 case GEN7_TYPE_DF: return 8;
910 case GEN6_TYPE_F: return 4;
911 default: return 1;
912 }
913 }
914
915 static void
916 disasm_printer_reset(struct disasm_printer *printer)
917 {
918 printer->buf[0] = '\0';
919 printer->len = 0;
920 }
921
922 static const char *
923 disasm_printer_get_string(struct disasm_printer *printer)
924 {
925 return printer->buf;
926 }
927
928 static void _util_printf_format(2, 3)
929 disasm_printer_add(struct disasm_printer *printer, const char *format, ...)
930 {
931 const size_t avail = sizeof(printer->buf) - printer->len;
932 va_list ap;
933 int written;
934
935 va_start(ap, format);
936 written = vsnprintf(printer->buf + printer->len, avail, format, ap);
937 va_end(ap);
938
939 /* truncated */
940 if (written < 0 || written >= avail) {
941 memcpy(printer->buf + sizeof(printer->buf) - 4, "...", 4);
942 printer->len = sizeof(printer->buf) - 1;
943 } else {
944 printer->len += written;
945 }
946 }
947
948 /**
949 * Pad to the specified column.
950 */
951 static void
952 disasm_printer_column(struct disasm_printer *printer, int col)
953 {
954 int len = DISASM_PRINTER_COLUMN_WIDTH * col;
955
956 if (len <= printer->len) {
957 if (!printer->len)
958 return;
959
960 /* at least one space */
961 len = printer->len + 1;
962 }
963
964 if (len >= sizeof(printer->buf)) {
965 len = sizeof(printer->buf) - 1;
966
967 if (len <= printer->len)
968 return;
969 }
970
971 memset(printer->buf + printer->len, ' ', len - printer->len);
972 printer->len = len;
973 printer->buf[printer->len] = '\0';
974 }
975
976 static void
977 disasm_printer_add_op(struct disasm_printer *printer,
978 const struct disasm_inst *inst)
979 {
980 if (inst->pred_ctrl != GEN6_PREDCTRL_NONE) {
981 disasm_printer_add(printer, "(%c%s%s) ",
982 disasm_inst_pred_inv(inst),
983 disasm_inst_flag_reg(inst),
984 disasm_inst_pred_ctrl(inst));
985 }
986
987 disasm_printer_add(printer, "%s%s%s%s",
988 disasm_inst_opcode(inst),
989 disasm_inst_saturate(inst),
990 disasm_inst_debug_ctrl(inst),
991 disasm_inst_cond_modifier(inst));
992
993 if (inst->cond_modifier != GEN6_COND_NONE) {
994 switch (inst->opcode) {
995 case GEN6_OPCODE_SEL:
996 case GEN6_OPCODE_IF:
997 case GEN6_OPCODE_WHILE:
998 /* these do not update flag registers */
999 break;
1000 default:
1001 disasm_printer_add(printer, ".%s", disasm_inst_flag_reg(inst));
1002 break;
1003 }
1004 }
1005
1006 if (inst->opcode == GEN6_OPCODE_MATH)
1007 disasm_printer_add(printer, " %s", disasm_inst_fc(inst));
1008 if (inst->opcode != GEN6_OPCODE_NOP)
1009 disasm_printer_add(printer, "(%s)", disasm_inst_exec_size(inst));
1010 }
1011
1012 static void
1013 disasm_printer_add_operand(struct disasm_printer *printer,
1014 const struct disasm_inst *inst,
1015 const struct disasm_operand *operand)
1016 {
1017 const char *name;
1018 bool multi_regs;
1019
1020 name = disasm_inst_file(inst, operand, &multi_regs);
1021 if (!multi_regs) {
1022 disasm_printer_add(printer, "%s", name);
1023 return;
1024 }
1025
1026 if (operand->file == GEN6_FILE_IMM) {
1027 switch (operand->type) {
1028 case GEN6_TYPE_UD:
1029 disasm_printer_add(printer, "0x%08xUD", inst->u.imm32);
1030 break;
1031 case GEN6_TYPE_D:
1032 disasm_printer_add(printer, "%dD", inst->u.imm32);
1033 break;
1034 case GEN6_TYPE_UW:
1035 disasm_printer_add(printer, "0x%04xUW", (uint16_t) inst->u.imm32);
1036 break;
1037 case GEN6_TYPE_W:
1038 disasm_printer_add(printer, "%dW", (int16_t) inst->u.imm32);
1039 break;
1040 case GEN6_TYPE_UV_IMM:
1041 disasm_printer_add(printer, "0x%08xUV", inst->u.imm32);
1042 break;
1043 case GEN6_TYPE_VF_IMM:
1044 disasm_printer_add(printer, "Vector Float");
1045 break;
1046 case GEN6_TYPE_V_IMM:
1047 disasm_printer_add(printer, "0x%08xV", inst->u.imm32);
1048 break;
1049 case GEN6_TYPE_F:
1050 disasm_printer_add(printer, "%-gF", uif(inst->u.imm32));
1051 break;
1052 default:
1053 disasm_printer_add(printer, "BAD");
1054 break;
1055 }
1056
1057 return;
1058 }
1059
1060 if (operand->addr_mode == GEN6_ADDRMODE_DIRECT) {
1061 unsigned reg, subreg;
1062
1063 reg = operand->reg;
1064 if (operand->file == GEN6_FILE_ARF)
1065 reg &= 0xf;
1066
1067 subreg = operand->subreg / disasm_inst_type_size(inst, operand);
1068
1069 if (subreg)
1070 disasm_printer_add(printer, "%s%d.%d", name, reg, subreg);
1071 else
1072 disasm_printer_add(printer, "%s%d", name, reg);
1073 } else {
1074 disasm_printer_add(printer, "%s[a0.%d %d]",
1075 name, operand->addr_subreg, operand->addr_imm);
1076 }
1077 }
1078
1079 static void
1080 disasm_printer_add_dst(struct disasm_printer *printer,
1081 const struct disasm_inst *inst,
1082 const struct disasm_dst_operand *dst)
1083 {
1084 disasm_printer_add_operand(printer, inst, &dst->base);
1085
1086 /* dst is an immediate when in EU_INSTRUCTION_BRANCH_CONDITIONAL form */
1087 if (disasm_inst_is_null(inst, &dst->base) ||
1088 dst->base.file == GEN6_FILE_IMM)
1089 return;
1090
1091 disasm_printer_add(printer, "<%s>%s%s",
1092 disasm_inst_horz_stride(inst, dst->horz_stride),
1093 disasm_inst_writemask(inst, dst->writemask),
1094 disasm_inst_type(inst, &dst->base));
1095 }
1096
1097 static void
1098 disasm_printer_add_src(struct disasm_printer *printer,
1099 const struct disasm_inst *inst,
1100 const struct disasm_src_operand *src)
1101 {
1102 static const char swizzle_chars[4] = { 'x', 'y', 'z', 'w' };
1103 char swizzle[5];
1104
1105 disasm_printer_add(printer, "%s%s",
1106 disasm_inst_negate(inst, src->negate),
1107 disasm_inst_absolute(inst, src->absolute));
1108
1109 disasm_printer_add_operand(printer, inst, &src->base);
1110
1111 if (disasm_inst_is_null(inst, &src->base) ||
1112 src->base.file == GEN6_FILE_IMM)
1113 return;
1114
1115 if (src->swizzle_x == 0 && src->swizzle_y == 1 &&
1116 src->swizzle_z == 2 && src->swizzle_w == 3) {
1117 swizzle[0] = '\0';
1118 } else if (src->swizzle_x == src->swizzle_y &&
1119 src->swizzle_x == src->swizzle_z &&
1120 src->swizzle_x == src->swizzle_w) {
1121 swizzle[0] = swizzle_chars[src->swizzle_x];
1122 swizzle[1] = '\0';
1123 } else {
1124 swizzle[0] = swizzle_chars[src->swizzle_x];
1125 swizzle[1] = swizzle_chars[src->swizzle_y];
1126 swizzle[2] = swizzle_chars[src->swizzle_z];
1127 swizzle[3] = swizzle_chars[src->swizzle_w];
1128 swizzle[4] = '\0';
1129 }
1130
1131 disasm_printer_add(printer, "<%s,%s,%s>%s%s",
1132 disasm_inst_vert_stride(inst, src->vert_stride),
1133 disasm_inst_width(inst, src->width),
1134 disasm_inst_horz_stride(inst, src->horz_stride),
1135 swizzle,
1136 disasm_inst_type(inst, &src->base));
1137 }
1138
1139 static void
1140 disasm_printer_add_ctrl(struct disasm_printer *printer,
1141 const struct disasm_inst *inst)
1142 {
1143 if (inst->opcode == GEN6_OPCODE_NOP) {
1144 disasm_printer_add(printer, ";");
1145 return;
1146 }
1147
1148 disasm_printer_add(printer, "{%s%s%s%s%s%s%s%s };",
1149 disasm_inst_access_mode(inst),
1150 disasm_inst_mask_ctrl(inst),
1151 disasm_inst_dep_ctrl(inst),
1152 disasm_inst_qtr_ctrl(inst),
1153 disasm_inst_cmpt_ctrl(inst),
1154 disasm_inst_thread_ctrl(inst),
1155 disasm_inst_acc_wr_ctrl(inst),
1156 disasm_inst_eot(inst));
1157 }
1158
1159 static void
1160 disasm_printer_add_mdesc_sampler(struct disasm_printer *printer,
1161 const struct disasm_inst *inst,
1162 uint32_t mdesc)
1163 {
1164 int op, simd;
1165
1166 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1167 op = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_OP);
1168 simd = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_SIMD);
1169 } {
1170 op = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_OP);
1171 simd = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SIMD);
1172 }
1173
1174 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1175 GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SURFACE),
1176 GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_INDEX),
1177 op, simd);
1178 }
1179
1180 static void
1181 disasm_printer_add_mdesc_urb(struct disasm_printer *printer,
1182 const struct disasm_inst *inst,
1183 uint32_t mdesc)
1184 {
1185 const char *op;
1186 int offset;
1187 bool interleaved, complete, allocate, used;
1188
1189 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1190 switch (GEN_EXTRACT(mdesc, GEN7_MSG_URB_OP)) {
1191 case GEN7_MSG_URB_WRITE_HWORD: op = "write HWord"; break;
1192 case GEN7_MSG_URB_WRITE_OWORD: op = "write OWord"; break;
1193 case GEN7_MSG_URB_READ_HWORD: op = "read HWord"; break;
1194 case GEN7_MSG_URB_READ_OWORD: op = "read OWord"; break;
1195 case GEN7_MSG_URB_ATOMIC_MOV: op = "atomic mov"; break;
1196 case GEN7_MSG_URB_ATOMIC_INC: op = "atomic inc"; break;
1197 default: op = "BAD"; break;
1198 }
1199
1200 offset = GEN_EXTRACT(mdesc, GEN7_MSG_URB_GLOBAL_OFFSET);
1201 interleaved = mdesc & GEN7_MSG_URB_INTERLEAVED;
1202 complete = mdesc & GEN7_MSG_URB_COMPLETE;
1203
1204 allocate = false;
1205 used = false;
1206 } else {
1207 switch (GEN_EXTRACT(mdesc, GEN6_MSG_URB_OP)) {
1208 case GEN6_MSG_URB_WRITE: op = "urb_write"; break;
1209 case GEN6_MSG_URB_FF_SYNC: op = "ff_sync"; break;
1210 default: op = "BAD"; break;
1211 }
1212
1213 offset = GEN_EXTRACT(mdesc, GEN6_MSG_URB_OFFSET);
1214 interleaved = mdesc & GEN6_MSG_URB_INTERLEAVED;
1215 complete = mdesc & GEN6_MSG_URB_COMPLETE;
1216
1217 allocate = mdesc & GEN6_MSG_URB_ALLOCATE;
1218 used = mdesc & GEN6_MSG_URB_USED;
1219 }
1220
1221 disasm_printer_add(printer, " %d %s%s%s%s%s", offset, op,
1222 (interleaved) ? " interleave" : "",
1223 (allocate) ? " allocate" : "",
1224 (used) ? " used" : "",
1225 (complete) ? " complete" : "");
1226 }
1227
1228 static void
1229 disasm_printer_add_mdesc_dp_sampler(struct disasm_printer *printer,
1230 const struct disasm_inst *inst,
1231 uint32_t mdesc)
1232 {
1233 const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
1234 GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
1235 const bool write_commit = (ilo_dev_gen(inst->dev) == ILO_GEN(6)) ?
1236 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT) : 0;
1237
1238 disasm_printer_add(printer, " (%d, %d, %d, %d)",
1239 GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE),
1240 GEN_EXTRACT(mdesc, GEN6_MSG_DP_OWORD_BLOCK_SIZE),
1241 op, write_commit);
1242 }
1243
1244 static void
1245 disasm_printer_add_mdesc_dp_rc(struct disasm_printer *printer,
1246 const struct disasm_inst *inst,
1247 uint32_t mdesc)
1248 {
1249 const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
1250 GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
1251 const char *str;
1252 bool is_rt_write;
1253
1254 if (ilo_dev_gen(inst->dev) >= ILO_GEN(7.5)) {
1255 switch (op) {
1256 case GEN75_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1257 case GEN75_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1258 case GEN75_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1259 case GEN75_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1260 default: str = "BAD"; break;
1261 }
1262
1263 is_rt_write = (op == GEN75_MSG_DP_RC_RT_WRITE);
1264 } else if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
1265 switch (op) {
1266 case GEN7_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break;
1267 case GEN7_MSG_DP_RC_TYPED_SURFACE_READ: str = "typed surface read"; break;
1268 case GEN7_MSG_DP_RC_TYPED_ATOMIC_OP: str = "typed atomic op"; break;
1269 case GEN7_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break;
1270 case GEN7_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1271 case GEN7_MSG_DP_RC_RT_WRITE: str = "RT write"; break;
1272 case GEN7_MSG_DP_RC_TYPED_SURFACE_WRITE: str = "typed surface write"; break;
1273 default: str = "BAD"; break;
1274 }
1275
1276 is_rt_write = (op == GEN7_MSG_DP_RC_RT_WRITE);
1277 } else {
1278 switch (op) {
1279 case GEN6_MSG_DP_OWORD_BLOCK_READ: str = "OWORD block read"; break;
1280 case GEN6_MSG_DP_RT_UNORM_READ: str = "RT UNORM read"; break;
1281 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_READ: str = "OWORD dual block read"; break;
1282 case GEN6_MSG_DP_MEDIA_BLOCK_READ: str = "media block read"; break;
1283 case GEN6_MSG_DP_UNALIGNED_OWORD_BLOCK_READ: str = "unaligned OWORD block read"; break;
1284 case GEN6_MSG_DP_DWORD_SCATTERED_READ: str = "DWORD scattered read"; break;
1285 case GEN6_MSG_DP_DWORD_ATOMIC_WRITE: str = "DWORD atomic write"; break;
1286 case GEN6_MSG_DP_OWORD_BLOCK_WRITE: str = "OWORD block write"; break;
1287 case GEN6_MSG_DP_OWORD_DUAL_BLOCK_WRITE: str = "OWORD dual block_write"; break;
1288 case GEN6_MSG_DP_MEDIA_BLOCK_WRITE: str = "media block write"; break;
1289 case GEN6_MSG_DP_DWORD_SCATTERED_WRITE: str = "DWORD scattered write"; break;
1290 case GEN6_MSG_DP_RT_WRITE: str = "RT write"; break;
1291 case GEN6_MSG_DP_SVB_WRITE: str = "SVB write"; break;
1292 case GEN6_MSG_DP_RT_UNORM_WRITE: str = "RT UNORM write"; break;
1293 default: str = "BAD"; break;
1294 }
1295
1296 is_rt_write = (op == GEN6_MSG_DP_RT_WRITE);
1297 }
1298
1299 disasm_printer_add(printer, " %s", str);
1300
1301 if (is_rt_write) {
1302 switch (mdesc & GEN6_MSG_DP_RT_MODE__MASK) {
1303 case GEN6_MSG_DP_RT_MODE_SIMD16: str = "SIMD16"; break;
1304 case GEN6_MSG_DP_RT_MODE_SIMD16_REPDATA: str = "SIMD16/RepData"; break;
1305 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_LO: str = "SIMD8/DualSrcLow"; break;
1306 case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_HI: str = "SIMD8/DualSrcHigh"; break;
1307 case GEN6_MSG_DP_RT_MODE_SIMD8_LO: str = "SIMD8"; break;
1308 case GEN6_MSG_DP_RT_MODE_SIMD8_IMAGE_WR: str = "SIMD8/ImageWrite"; break;
1309 default: str = "BAD"; break;
1310 }
1311
1312 disasm_printer_add(printer, " %s%s%s%s", str,
1313 (mdesc & GEN6_MSG_DP_SLOTGRP_HI) ? " Hi" : "",
1314 (mdesc & GEN6_MSG_DP_RT_LAST) ? " LastRT" : "",
1315 (ilo_dev_gen(inst->dev) == ILO_GEN(6) &&
1316 (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT)) ? " WriteCommit" : "");
1317 }
1318
1319 disasm_printer_add(printer, " Surface = %d",
1320 GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
1321 }
1322
1323 static void
1324 disasm_printer_add_mdesc(struct disasm_printer *printer,
1325 const struct disasm_inst *inst)
1326 {
1327 const uint32_t mdesc = inst->u.imm32;
1328
1329 assert(inst->opcode == GEN6_OPCODE_SEND ||
1330 inst->opcode == GEN6_OPCODE_SENDC);
1331 assert(inst->src1.base.file == GEN6_FILE_IMM);
1332
1333 disasm_printer_add(printer, " %s", disasm_inst_sfid(inst));
1334
1335 switch (inst->sfid) {
1336 case GEN6_SFID_SAMPLER:
1337 disasm_printer_add_mdesc_sampler(printer, inst, mdesc);
1338 break;
1339 case GEN6_SFID_DP_SAMPLER:
1340 disasm_printer_add_mdesc_dp_sampler(printer, inst, mdesc);
1341 break;
1342 case GEN6_SFID_DP_RC:
1343 disasm_printer_add_mdesc_dp_rc(printer, inst, mdesc);
1344 break;
1345 case GEN6_SFID_URB:
1346 disasm_printer_add_mdesc_urb(printer, inst, mdesc);
1347 break;
1348 case GEN6_SFID_DP_CC:
1349 case GEN7_SFID_DP_DC0:
1350 case GEN7_SFID_PI:
1351 case GEN75_SFID_DP_DC1:
1352 default:
1353 break;
1354 }
1355
1356 disasm_printer_add(printer, " mlen %d rlen %d",
1357 GEN_EXTRACT(mdesc, GEN6_MSG_MLEN),
1358 GEN_EXTRACT(mdesc, GEN6_MSG_RLEN));
1359 }
1360
1361 static void
1362 disasm_printer_print_inst(struct disasm_printer *printer,
1363 const struct disasm_inst *inst)
1364 {
1365 int col = 0;
1366
1367 disasm_printer_reset(printer);
1368
1369 disasm_printer_column(printer, col++);
1370 disasm_printer_add_op(printer, inst);
1371
1372 if (inst->has_jip || inst->has_uip) {
1373 if (inst->has_jip) {
1374 disasm_printer_column(printer, col++);
1375 disasm_printer_add(printer, "JIP: %d", (int16_t) inst->u.imm32);
1376 }
1377
1378 if (inst->has_uip) {
1379 disasm_printer_column(printer, col++);
1380 disasm_printer_add(printer, "UIP: %d",
1381 (int16_t) (inst->u.imm32 >> 16));
1382 }
1383 } else {
1384 const int src_count = disasm_opcode_table[inst->opcode].src_count;
1385 const struct disasm_src_operand *src[3];
1386 int i;
1387
1388 /* get src operands */
1389 switch (src_count) {
1390 case 3:
1391 src[2] = &inst->u.src2;
1392 case 2:
1393 src[1] = &inst->src1;
1394 case 1:
1395 src[0] = &inst->src0;
1396 case 0:
1397 default:
1398 break;
1399 }
1400
1401 if (src_count) {
1402 disasm_printer_column(printer, col++);
1403 disasm_printer_add_dst(printer, inst, &inst->dst);
1404
1405 for (i = 0; i < src_count; i++) {
1406 disasm_printer_column(printer, col++);
1407 disasm_printer_add_src(printer, inst, src[i]);
1408 }
1409 }
1410 }
1411
1412 if (inst->opcode == GEN6_OPCODE_SEND ||
1413 inst->opcode == GEN6_OPCODE_SENDC) {
1414 /* start a new line */
1415 ilo_printf("%s\n", disasm_printer_get_string(printer));
1416 disasm_printer_reset(printer);
1417 col = 0;
1418
1419 disasm_printer_column(printer, col++);
1420
1421 disasm_printer_column(printer, col++);
1422 disasm_printer_add_mdesc(printer, inst);
1423 }
1424
1425 if (col < 4)
1426 col = 4;
1427
1428 disasm_printer_column(printer, col++);
1429 disasm_printer_add_ctrl(printer, inst);
1430
1431 ilo_printf("%s\n", disasm_printer_get_string(printer));
1432 }
1433
1434 void
1435 toy_compiler_disassemble(const struct ilo_dev_info *dev,
1436 const void *kernel, int size,
1437 bool dump_hex)
1438 {
1439 const uint32_t *cur = (const uint32_t *) kernel;
1440 const uint32_t *end = cur + size / sizeof(*cur);
1441 struct disasm_printer printer;
1442
1443 disasm_printer_reset(&printer);
1444
1445 while (cur < end) {
1446 struct disasm_inst inst;
1447 const bool compacted = (cur[0] & GEN6_INST_CMPTCTRL);
1448 const uint32_t *dw = cur;
1449 uint32_t temp[4];
1450
1451 cur += (compacted) ? 2 : 4;
1452 /* incomplete instruction */
1453 if (cur > end)
1454 break;
1455
1456 if (compacted) {
1457 /* no compaction support yet */
1458 memset(temp, 0, sizeof(temp));
1459 dw = temp;
1460 }
1461
1462 if (dump_hex) {
1463 ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ",
1464 dw[0], dw[1], dw[2], dw[3]);
1465 }
1466
1467 memset(&inst, 0, sizeof(inst));
1468 inst.dev = dev;
1469 disasm_inst_decode(&inst, dw);
1470 inst.cmpt_ctrl = compacted;
1471
1472 disasm_printer_print_inst(&printer, &inst);
1473 }
1474 }