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