diff options
author | Chia-I Wu <[email protected]> | 2014-09-10 10:34:04 +0800 |
---|---|---|
committer | Chia-I Wu <[email protected]> | 2014-09-11 16:29:38 +0800 |
commit | 6816d853dbbfdc8b960b25496a9fe96a58053815 (patch) | |
tree | 2e17f2ba21ae5076c0af9f0dd3f28430f96ad12f /src/gallium/drivers/ilo/shader | |
parent | b51b349942ffd22a12d578bee6ba5db60d88d1bd (diff) |
ilo: add a new disassembler
The old disassembler was modified from i965's. It is as much work as doing a
new one to keep it up-to-date, which also requires copying more headers over.
The outputs of this new disassembler should match i965's as closely as
possible.
Diffstat (limited to 'src/gallium/drivers/ilo/shader')
-rw-r--r-- | src/gallium/drivers/ilo/shader/toy_compiler_disasm.c | 2617 |
1 files changed, 1352 insertions, 1265 deletions
diff --git a/src/gallium/drivers/ilo/shader/toy_compiler_disasm.c b/src/gallium/drivers/ilo/shader/toy_compiler_disasm.c index 1028940fbc4..a40d0cdb84f 100644 --- a/src/gallium/drivers/ilo/shader/toy_compiler_disasm.c +++ b/src/gallium/drivers/ilo/shader/toy_compiler_disasm.c @@ -1,1385 +1,1472 @@ /* - * Copyright © 2008 Keith Packard + * Mesa 3-D graphics library * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. + * Copyright (C) 2014 LunarG, Inc. * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Chia-I Wu <[email protected]> */ #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <unistd.h> -#include <stdarg.h> - -typedef short GLshort; -typedef int GLint; -typedef unsigned char GLubyte; -typedef unsigned int GLuint; -typedef float GLfloat; -#include <stdint.h> -#include "brw_defines.h" -#include "brw_structs.h" -static int brw_disasm (FILE *file, struct brw_instruction *inst, int gen); - +#include "genhw/genhw.h" #include "toy_compiler.h" -void -toy_compiler_disassemble(const struct ilo_dev_info *dev, - const void *kernel, int size, - bool dump_hex) -{ - const struct brw_instruction *instructions = kernel; - int i; - - for (i = 0; i < size / sizeof(*instructions); i++) { - if (dump_hex) { - const uint32_t *dwords = (const uint32_t *) &instructions[i]; - ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ", - dwords[3], dwords[2], dwords[1], dwords[0]); - } +#define DISASM_PRINTER_BUFFER_SIZE 256 +#define DISASM_PRINTER_COLUMN_WIDTH 16 - brw_disasm(stderr, (struct brw_instruction *) &instructions[i], - ILO_GEN_GET_MAJOR(dev->gen)); - } -} +#define READ(dw, field) (((dw) & field ## __MASK) >> field ## __SHIFT) -static const struct opcode_desc { - char *name; - int nsrc; - int ndst; -} opcode_descs[128] = { - [BRW_OPCODE_MOV] = { .name = "mov", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_FRC] = { .name = "frc", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_RNDU] = { .name = "rndu", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_RNDD] = { .name = "rndd", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_RNDE] = { .name = "rnde", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_RNDZ] = { .name = "rndz", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_NOT] = { .name = "not", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_LZD] = { .name = "lzd", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_F32TO16] = { .name = "f32to16", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_F16TO32] = { .name = "f16to32", .nsrc = 1, .ndst = 1 }, - - [BRW_OPCODE_MUL] = { .name = "mul", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_MAC] = { .name = "mac", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_MACH] = { .name = "mach", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_LINE] = { .name = "line", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_PLN] = { .name = "pln", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_MAD] = { .name = "mad", .nsrc = 3, .ndst = 1 }, - [BRW_OPCODE_LRP] = { .name = "lrp", .nsrc = 3, .ndst = 1 }, - [BRW_OPCODE_SAD2] = { .name = "sad2", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_SADA2] = { .name = "sada2", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_DP4] = { .name = "dp4", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_DPH] = { .name = "dph", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_DP3] = { .name = "dp3", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_DP2] = { .name = "dp2", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_MATH] = { .name = "math", .nsrc = 2, .ndst = 1 }, - - [BRW_OPCODE_AVG] = { .name = "avg", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_ADD] = { .name = "add", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_SEL] = { .name = "sel", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_AND] = { .name = "and", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_OR] = { .name = "or", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_XOR] = { .name = "xor", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_SHR] = { .name = "shr", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_SHL] = { .name = "shl", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_ASR] = { .name = "asr", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_CMP] = { .name = "cmp", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_CMPN] = { .name = "cmpn", .nsrc = 2, .ndst = 1 }, - - [BRW_OPCODE_SEND] = { .name = "send", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_SENDC] = { .name = "sendc", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_NOP] = { .name = "nop", .nsrc = 0, .ndst = 0 }, - [BRW_OPCODE_JMPI] = { .name = "jmpi", .nsrc = 0, .ndst = 0 }, - [BRW_OPCODE_IF] = { .name = "if", .nsrc = 2, .ndst = 0 }, - [BRW_OPCODE_IFF] = { .name = "iff", .nsrc = 2, .ndst = 1 }, - [BRW_OPCODE_WHILE] = { .name = "while", .nsrc = 2, .ndst = 0 }, - [BRW_OPCODE_ELSE] = { .name = "else", .nsrc = 2, .ndst = 0 }, - [BRW_OPCODE_BREAK] = { .name = "break", .nsrc = 2, .ndst = 0 }, - [BRW_OPCODE_CONTINUE] = { .name = "cont", .nsrc = 1, .ndst = 0 }, - [BRW_OPCODE_HALT] = { .name = "halt", .nsrc = 1, .ndst = 0 }, - [BRW_OPCODE_MSAVE] = { .name = "msave", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_PUSH] = { .name = "push", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_MRESTORE] = { .name = "mrest", .nsrc = 1, .ndst = 1 }, - [BRW_OPCODE_POP] = { .name = "pop", .nsrc = 2, .ndst = 0 }, - [BRW_OPCODE_WAIT] = { .name = "wait", .nsrc = 1, .ndst = 0 }, - [BRW_OPCODE_DO] = { .name = "do", .nsrc = 0, .ndst = 0 }, - [BRW_OPCODE_ENDIF] = { .name = "endif", .nsrc = 2, .ndst = 0 }, -}; -static const struct opcode_desc *opcode = opcode_descs; - -static const char * const conditional_modifier[16] = { - [BRW_CONDITIONAL_NONE] = "", - [BRW_CONDITIONAL_Z] = ".e", - [BRW_CONDITIONAL_NZ] = ".ne", - [BRW_CONDITIONAL_G] = ".g", - [BRW_CONDITIONAL_GE] = ".ge", - [BRW_CONDITIONAL_L] = ".l", - [BRW_CONDITIONAL_LE] = ".le", - [BRW_CONDITIONAL_R] = ".r", - [BRW_CONDITIONAL_O] = ".o", - [BRW_CONDITIONAL_U] = ".u", +struct disasm_printer { + char buf[DISASM_PRINTER_BUFFER_SIZE]; + int len; }; -static const char * const negate[2] = { - [0] = "", - [1] = "-", -}; +struct disasm_operand { + unsigned file:2; + unsigned type:3; -static const char * const _abs[2] = { - [0] = "", - [1] = "(abs)", + unsigned addr_mode:1; + unsigned reg:8; + unsigned subreg:5; + unsigned addr_subreg:3; + unsigned addr_imm:10; }; -static const char * const vert_stride[16] = { - [0] = "0", - [1] = "1", - [2] = "2", - [3] = "4", - [4] = "8", - [5] = "16", - [6] = "32", - [15] = "VxH", -}; +struct disasm_dst_operand { + struct disasm_operand base; -static const char * const width[8] = { - [0] = "1", - [1] = "2", - [2] = "4", - [3] = "8", - [4] = "16", + unsigned horz_stride:2; + unsigned writemask:4; }; -static const char * const horiz_stride[4] = { - [0] = "0", - [1] = "1", - [2] = "2", - [3] = "4" +struct disasm_src_operand { + struct disasm_operand base; + + unsigned vert_stride:4; + unsigned width:3; + unsigned horz_stride:2; + unsigned swizzle_x:2; + unsigned swizzle_y:2; + unsigned swizzle_z:2; + unsigned swizzle_w:2; + unsigned negate:1; + unsigned absolute:1; }; -static const char * const chan_sel[4] = { - [0] = "x", - [1] = "y", - [2] = "z", - [3] = "w", +struct disasm_inst { + const struct ilo_dev_info *dev; + + unsigned has_jip:1; + unsigned has_uip:1; + + unsigned opcode:7; + unsigned access_mode:1; + unsigned mask_ctrl:1; + unsigned dep_ctrl:2; + unsigned qtr_ctrl:2; + unsigned thread_ctrl:2; + unsigned pred_ctrl:4; + unsigned pred_inv:1; + unsigned exec_size:3; + + unsigned cond_modifier:4; + unsigned sfid:4; + unsigned fc:4; + + unsigned acc_wr_ctrl:1; + unsigned cmpt_ctrl:1; + unsigned debug_ctrl:1; + unsigned saturate:1; + + unsigned nib_ctrl:1; + + unsigned flag_reg:1; + unsigned flag_subreg:1; + + struct disasm_dst_operand dst; + struct disasm_src_operand src0; + struct disasm_src_operand src1; + union { + struct disasm_src_operand src2; + uint32_t imm32; + } u; }; -static const char * const debug_ctrl[2] = { - [0] = "", - [1] = ".breakpoint" +static const struct { + const char *name; + int src_count; +} disasm_opcode_table[128] = { + [GEN6_OPCODE_ILLEGAL] = { "illegal", 0 }, + [GEN6_OPCODE_MOV] = { "mov", 1 }, + [GEN6_OPCODE_SEL] = { "sel", 2 }, + [GEN6_OPCODE_MOVI] = { "movi", 1 }, + [GEN6_OPCODE_NOT] = { "not", 1 }, + [GEN6_OPCODE_AND] = { "and", 2 }, + [GEN6_OPCODE_OR] = { "or", 2 }, + [GEN6_OPCODE_XOR] = { "xor", 2 }, + [GEN6_OPCODE_SHR] = { "shr", 2 }, + [GEN6_OPCODE_SHL] = { "shl", 2 }, + [GEN6_OPCODE_DIM] = { "dim", 1 }, + [GEN6_OPCODE_ASR] = { "asr", 2 }, + [GEN6_OPCODE_CMP] = { "cmp", 2 }, + [GEN6_OPCODE_CMPN] = { "cmpn", 2 }, + [GEN7_OPCODE_CSEL] = { "csel", 3 }, + [GEN7_OPCODE_F32TO16] = { "f32to16", 1 }, + [GEN7_OPCODE_F16TO32] = { "f16to32", 1 }, + [GEN7_OPCODE_BFREV] = { "bfrev", 1 }, + [GEN7_OPCODE_BFE] = { "bfe", 3 }, + [GEN7_OPCODE_BFI1] = { "bfi1", 2 }, + [GEN7_OPCODE_BFI2] = { "bfi2", 3 }, + [GEN6_OPCODE_JMPI] = { "jmpi", 1 }, + [GEN7_OPCODE_BRD] = { "brd", 1 }, + [GEN6_OPCODE_IF] = { "if", 2 }, + [GEN7_OPCODE_BRC] = { "brc", 1 }, + [GEN6_OPCODE_ELSE] = { "else", 1 }, + [GEN6_OPCODE_ENDIF] = { "endif", 0 }, + [GEN6_OPCODE_CASE] = { "case", 2 }, + [GEN6_OPCODE_WHILE] = { "while", 1 }, + [GEN6_OPCODE_BREAK] = { "break", 1 }, + [GEN6_OPCODE_CONT] = { "cont", 1 }, + [GEN6_OPCODE_HALT] = { "halt", 1 }, + [GEN75_OPCODE_CALLA] = { "calla", 1 }, + [GEN6_OPCODE_CALL] = { "call", 1 }, + [GEN6_OPCODE_RETURN] = { "return", 1 }, + [GEN6_OPCODE_WAIT] = { "wait", 1 }, + [GEN6_OPCODE_SEND] = { "send", 1 }, + [GEN6_OPCODE_SENDC] = { "sendc", 1 }, + [GEN6_OPCODE_MATH] = { "math", 2 }, + [GEN6_OPCODE_ADD] = { "add", 2 }, + [GEN6_OPCODE_MUL] = { "mul", 2 }, + [GEN6_OPCODE_AVG] = { "avg", 2 }, + [GEN6_OPCODE_FRC] = { "frc", 1 }, + [GEN6_OPCODE_RNDU] = { "rndu", 1 }, + [GEN6_OPCODE_RNDD] = { "rndd", 1 }, + [GEN6_OPCODE_RNDE] = { "rnde", 1 }, + [GEN6_OPCODE_RNDZ] = { "rndz", 1 }, + [GEN6_OPCODE_MAC] = { "mac", 2 }, + [GEN6_OPCODE_MACH] = { "mach", 2 }, + [GEN6_OPCODE_LZD] = { "lzd", 1 }, + [GEN7_OPCODE_FBH] = { "fbh", 1 }, + [GEN7_OPCODE_FBL] = { "fbl", 1 }, + [GEN7_OPCODE_CBIT] = { "cbit", 1 }, + [GEN7_OPCODE_ADDC] = { "addc", 2 }, + [GEN7_OPCODE_SUBB] = { "subb", 2 }, + [GEN6_OPCODE_SAD2] = { "sad2", 2 }, + [GEN6_OPCODE_SADA2] = { "sada2", 2 }, + [GEN6_OPCODE_DP4] = { "dp4", 2 }, + [GEN6_OPCODE_DPH] = { "dph", 2 }, + [GEN6_OPCODE_DP3] = { "dp3", 2 }, + [GEN6_OPCODE_DP2] = { "dp2", 2 }, + [GEN6_OPCODE_LINE] = { "line", 2 }, + [GEN6_OPCODE_PLN] = { "pln", 2 }, + [GEN6_OPCODE_MAD] = { "mad", 3 }, + [GEN6_OPCODE_LRP] = { "lrp", 3 }, + [GEN6_OPCODE_NOP] = { "nop", 0 }, }; -static const char * const saturate[2] = { - [0] = "", - [1] = ".sat" -}; +static void +disasm_inst_decode_dw0_gen6(struct disasm_inst *inst, uint32_t dw0) +{ + inst->opcode = READ(dw0, GEN6_INST_OPCODE); + + switch (inst->opcode) { + case GEN6_OPCODE_IF: + inst->has_jip = true; + inst->has_uip = (inst->dev->gen >= ILO_GEN(7)); + break; + case GEN6_OPCODE_BREAK: + case GEN6_OPCODE_CONT: + case GEN6_OPCODE_HALT: + inst->has_uip = true; + /* fall through */ + case GEN6_OPCODE_JMPI: + case GEN7_OPCODE_BRD: + case GEN7_OPCODE_BRC: + case GEN6_OPCODE_ELSE: + case GEN6_OPCODE_ENDIF: + case GEN6_OPCODE_CASE: + case GEN6_OPCODE_WHILE: + case GEN75_OPCODE_CALLA: + case GEN6_OPCODE_CALL: + case GEN6_OPCODE_RETURN: + inst->has_jip = true; + break; + default: + break; + } -static const char * const accwr[2] = { - [0] = "", - [1] = "AccWrEnable" -}; + inst->access_mode = READ(dw0, GEN6_INST_ACCESSMODE); + inst->mask_ctrl = READ(dw0, GEN6_INST_MASKCTRL); + inst->dep_ctrl = READ(dw0, GEN6_INST_DEPCTRL); + inst->qtr_ctrl = READ(dw0, GEN6_INST_QTRCTRL); + inst->thread_ctrl = READ(dw0, GEN6_INST_THREADCTRL); + inst->pred_ctrl = READ(dw0, GEN6_INST_PREDCTRL); + + inst->pred_inv = (bool) (dw0 & GEN6_INST_PREDINV); + + inst->exec_size = READ(dw0, GEN6_INST_EXECSIZE); + + switch (inst->opcode) { + case GEN6_OPCODE_SEND: + case GEN6_OPCODE_SENDC: + inst->sfid = READ(dw0, GEN6_INST_SFID); + break; + case GEN6_OPCODE_MATH: + inst->fc = READ(dw0, GEN6_INST_FC); + break; + default: + inst->cond_modifier = READ(dw0, GEN6_INST_CONDMODIFIER); + break; + } -static const char * const wectrl[2] = { - [0] = "WE_normal", - [1] = "WE_all" -}; + inst->acc_wr_ctrl = (bool) (dw0 & GEN6_INST_ACCWRCTRL); + inst->cmpt_ctrl = (bool) (dw0 & GEN6_INST_CMPTCTRL); + inst->debug_ctrl = (bool) (dw0 & GEN6_INST_DEBUGCTRL); + inst->saturate = (bool) (dw0 & GEN6_INST_SATURATE); +} -static const char * const exec_size[8] = { - [0] = "1", - [1] = "2", - [2] = "4", - [3] = "8", - [4] = "16", - [5] = "32" -}; +static bool +disasm_inst_jip_in_dw1_high_gen6(const struct disasm_inst *inst) +{ + return (inst->dev->gen == ILO_GEN(6) && inst->has_jip && !inst->has_uip); +} -static const char * const pred_inv[2] = { - [0] = "+", - [1] = "-" -}; +static void +disasm_inst_decode_dw1_gen6(struct disasm_inst *inst, uint32_t dw1) +{ + inst->dst.base.file = READ(dw1, GEN6_INST_DST_FILE); + inst->dst.base.type = READ(dw1, GEN6_INST_DST_TYPE); + inst->src0.base.file = READ(dw1, GEN6_INST_SRC0_FILE); + inst->src0.base.type = READ(dw1, GEN6_INST_SRC0_TYPE); + inst->src1.base.file = READ(dw1, GEN6_INST_SRC1_FILE); + inst->src1.base.type = READ(dw1, GEN6_INST_SRC1_TYPE); + + if (inst->dev->gen >= ILO_GEN(7)) + inst->nib_ctrl = (bool) (dw1 & GEN7_INST_NIBCTRL); + + if (disasm_inst_jip_in_dw1_high_gen6(inst)) { + inst->u.imm32 = dw1 >> 16; + return; + } -static const char * const pred_ctrl_align16[16] = { - [1] = "", - [2] = ".x", - [3] = ".y", - [4] = ".z", - [5] = ".w", - [6] = ".any4h", - [7] = ".all4h", -}; + inst->dst.base.addr_mode = READ(dw1, GEN6_INST_DST_ADDRMODE); -static const char * const pred_ctrl_align1[16] = { - [1] = "", - [2] = ".anyv", - [3] = ".allv", - [4] = ".any2h", - [5] = ".all2h", - [6] = ".any4h", - [7] = ".all4h", - [8] = ".any8h", - [9] = ".all8h", - [10] = ".any16h", - [11] = ".all16h", -}; + if (inst->dst.base.addr_mode == GEN6_ADDRMODE_DIRECT) { + inst->dst.base.reg = READ(dw1, GEN6_INST_DST_REG); -static const char * const thread_ctrl[4] = { - [0] = "", - [2] = "switch" -}; + if (inst->access_mode == GEN6_ALIGN_1) { + inst->dst.base.subreg = READ(dw1, GEN6_INST_DST_SUBREG); + } else { + inst->dst.base.subreg = READ(dw1, GEN6_INST_DST_SUBREG_ALIGN16) << + GEN6_INST_DST_SUBREG_ALIGN16__SHR; + } + } else { + inst->dst.base.addr_subreg = READ(dw1, GEN6_INST_DST_ADDR_SUBREG); + + if (inst->access_mode == GEN6_ALIGN_1) { + inst->dst.base.addr_imm = READ(dw1, GEN6_INST_DST_ADDR_IMM); + } else { + inst->dst.base.addr_imm = READ(dw1, GEN6_INST_DST_ADDR_IMM_ALIGN16) << + GEN6_INST_DST_ADDR_IMM_ALIGN16__SHR; + } + } -static const char * const compr_ctrl[4] = { - [0] = "", - [1] = "sechalf", - [2] = "compr", - [3] = "compr4", -}; + inst->dst.horz_stride = READ(dw1, GEN6_INST_DST_HORZSTRIDE); -static const char * const dep_ctrl[4] = { - [0] = "", - [1] = "NoDDClr", - [2] = "NoDDChk", - [3] = "NoDDClr,NoDDChk", -}; + if (inst->access_mode == GEN6_ALIGN_1) + inst->dst.writemask = 0xf; + else + inst->dst.writemask = READ(dw1, GEN6_INST_DST_WRITEMASK); +} -static const char * const mask_ctrl[4] = { - [0] = "", - [1] = "nomask", -}; +static void +disasm_inst_decode_dw2_dw3_gen6(struct disasm_inst *inst, + uint32_t dw2, uint32_t dw3) +{ + int count, i; -static const char * const access_mode[2] = { - [0] = "align1", - [1] = "align16", -}; + if (inst->dev->gen >= ILO_GEN(7)) + inst->flag_reg = READ(dw2, GEN7_INST_FLAG_REG); -static const char * const reg_encoding[8] = { - [0] = "UD", - [1] = "D", - [2] = "UW", - [3] = "W", - [4] = "UB", - [5] = "B", - [7] = "F" -}; + inst->flag_subreg = READ(dw2, GEN6_INST_FLAG_SUBREG); -const int reg_type_size[8] = { - [0] = 4, - [1] = 4, - [2] = 2, - [3] = 2, - [4] = 1, - [5] = 1, - [7] = 4 -}; + if (inst->src0.base.file == GEN6_FILE_IMM || + inst->src1.base.file == GEN6_FILE_IMM) { + count = 1; + if (!disasm_inst_jip_in_dw1_high_gen6(inst)) + inst->u.imm32 = dw3; + } else { + count = 2; + } -static const char * const reg_file[4] = { - [0] = "A", - [1] = "g", - [2] = "m", - [3] = "imm", -}; + for (i = 0; i < count; i++) { + struct disasm_src_operand *src = (i == 0) ? &inst->src0 : &inst->src1; + const uint32_t dw = (i == 0) ? dw2 : dw3; + + src->base.addr_mode = READ(dw, GEN6_INST_SRC_ADDRMODE); + + if (src->base.addr_mode == GEN6_ADDRMODE_DIRECT) { + src->base.reg = READ(dw, GEN6_INST_SRC_REG); + + if (inst->access_mode == GEN6_ALIGN_1) { + src->base.subreg = READ(dw, GEN6_INST_SRC_SUBREG); + } else { + src->base.subreg = READ(dw, GEN6_INST_SRC_SUBREG_ALIGN16) << + GEN6_INST_SRC_SUBREG_ALIGN16__SHR; + } + } else { + src->base.addr_subreg = READ(dw, GEN6_INST_SRC_ADDR_SUBREG); + + if (inst->access_mode == GEN6_ALIGN_1) { + src->base.addr_imm = READ(dw, GEN6_INST_SRC_ADDR_IMM); + } else { + src->base.addr_imm = READ(dw, GEN6_INST_SRC_ADDR_IMM_ALIGN16) << + GEN6_INST_SRC_ADDR_IMM_ALIGN16__SHR; + } + } -static const char * const writemask[16] = { - [0x0] = ".", - [0x1] = ".x", - [0x2] = ".y", - [0x3] = ".xy", - [0x4] = ".z", - [0x5] = ".xz", - [0x6] = ".yz", - [0x7] = ".xyz", - [0x8] = ".w", - [0x9] = ".xw", - [0xa] = ".yw", - [0xb] = ".xyw", - [0xc] = ".zw", - [0xd] = ".xzw", - [0xe] = ".yzw", - [0xf] = "", -}; + src->vert_stride = READ(dw, GEN6_INST_SRC_VERTSTRIDE); -static const char * const end_of_thread[2] = { - [0] = "", - [1] = "EOT" -}; + if (inst->access_mode == GEN6_ALIGN_1) { + src->width = READ(dw, GEN6_INST_SRC_WIDTH); + src->horz_stride = READ(dw, GEN6_INST_SRC_HORZSTRIDE); -static const char * const target_function[16] = { - [BRW_SFID_NULL] = "null", - [BRW_SFID_MATH] = "math", - [BRW_SFID_SAMPLER] = "sampler", - [BRW_SFID_MESSAGE_GATEWAY] = "gateway", - [BRW_SFID_DATAPORT_READ] = "read", - [BRW_SFID_DATAPORT_WRITE] = "write", - [BRW_SFID_URB] = "urb", - [BRW_SFID_THREAD_SPAWNER] = "thread_spawner" -}; + src->swizzle_x = GEN6_SWIZZLE_X; + src->swizzle_y = GEN6_SWIZZLE_Y; + src->swizzle_z = GEN6_SWIZZLE_Z; + src->swizzle_w = GEN6_SWIZZLE_W; + } else { + src->width = GEN6_WIDTH_4; + src->horz_stride = GEN6_HORZSTRIDE_1; -static const char * const target_function_gen6[16] = { - [BRW_SFID_NULL] = "null", - [BRW_SFID_MATH] = "math", - [BRW_SFID_SAMPLER] = "sampler", - [BRW_SFID_MESSAGE_GATEWAY] = "gateway", - [BRW_SFID_URB] = "urb", - [BRW_SFID_THREAD_SPAWNER] = "thread_spawner", - [GEN6_SFID_DATAPORT_SAMPLER_CACHE] = "sampler", - [GEN6_SFID_DATAPORT_RENDER_CACHE] = "render", - [GEN6_SFID_DATAPORT_CONSTANT_CACHE] = "const", - [GEN7_SFID_DATAPORT_DATA_CACHE] = "data" -}; + src->swizzle_x = READ(dw, GEN6_INST_SRC_SWIZZLE_X); + src->swizzle_y = READ(dw, GEN6_INST_SRC_SWIZZLE_Y); + src->swizzle_z = READ(dw, GEN6_INST_SRC_SWIZZLE_Z); + src->swizzle_w = READ(dw, GEN6_INST_SRC_SWIZZLE_W); + } -static const char * const dp_rc_msg_type_gen6[16] = { - [BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ] = "OWORD block read", - [GEN6_DATAPORT_READ_MESSAGE_RENDER_UNORM_READ] = "RT UNORM read", - [GEN6_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ] = "OWORD dual block read", - [GEN6_DATAPORT_READ_MESSAGE_MEDIA_BLOCK_READ] = "media block read", - [GEN6_DATAPORT_READ_MESSAGE_OWORD_UNALIGN_BLOCK_READ] = "OWORD unaligned block read", - [GEN6_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ] = "DWORD scattered read", - [GEN6_DATAPORT_WRITE_MESSAGE_DWORD_ATOMIC_WRITE] = "DWORD atomic write", - [GEN6_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE] = "OWORD block write", - [GEN6_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE] = "OWORD dual block write", - [GEN6_DATAPORT_WRITE_MESSAGE_MEDIA_BLOCK_WRITE] = "media block write", - [GEN6_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE] = "DWORD scattered write", - [GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE] = "RT write", - [GEN6_DATAPORT_WRITE_MESSAGE_STREAMED_VB_WRITE] = "streamed VB write", - [GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_UNORM_WRITE] = "RT UNORMc write", -}; + src->negate = (bool) (dw & GEN6_INST_SRC_NEGATE); + src->absolute = (bool) (dw & GEN6_INST_SRC_ABSOLUTE); + } +} -static const char * const math_function[16] = { - [BRW_MATH_FUNCTION_INV] = "inv", - [BRW_MATH_FUNCTION_LOG] = "log", - [BRW_MATH_FUNCTION_EXP] = "exp", - [BRW_MATH_FUNCTION_SQRT] = "sqrt", - [BRW_MATH_FUNCTION_RSQ] = "rsq", - [BRW_MATH_FUNCTION_SIN] = "sin", - [BRW_MATH_FUNCTION_COS] = "cos", - [BRW_MATH_FUNCTION_SINCOS] = "sincos", - [BRW_MATH_FUNCTION_FDIV] = "fdiv", - [BRW_MATH_FUNCTION_POW] = "pow", - [BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER] = "intdivmod", - [BRW_MATH_FUNCTION_INT_DIV_QUOTIENT] = "intdiv", - [BRW_MATH_FUNCTION_INT_DIV_REMAINDER] = "intmod", -}; +static void +disasm_inst_decode_3src_dw1_gen6(struct disasm_inst *inst, uint32_t dw1) +{ + static unsigned type_mapping[4] = { + [GEN7_TYPE_F_3SRC] = GEN6_TYPE_F, + [GEN7_TYPE_D_3SRC] = GEN6_TYPE_D, + [GEN7_TYPE_UD_3SRC] = GEN6_TYPE_UD, + [GEN7_TYPE_DF_3SRC] = GEN7_TYPE_DF, + }; + + inst->flag_subreg = READ(dw1, GEN6_3SRC_FLAG_SUBREG); + + if (inst->dev->gen >= ILO_GEN(7)) { + inst->nib_ctrl = (bool) (dw1 & GEN7_3SRC_NIBCTRL); + inst->flag_reg = READ(dw1, GEN7_3SRC_FLAG_REG); + + inst->dst.base.file = GEN6_FILE_GRF; + inst->dst.base.type = READ(dw1, GEN7_3SRC_DST_TYPE); + inst->dst.base.type = type_mapping[inst->dst.base.type]; + + inst->src0.base.type = READ(dw1, GEN7_3SRC_SRC_TYPE); + inst->src0.base.type = type_mapping[inst->src0.base.type]; + + inst->src1.base.type = inst->src0.base.type; + inst->u.src2.base.type = inst->src0.base.type; + } else { + inst->dst.base.file = (dw1 & GEN6_3SRC_DST_FILE_MRF) ? + GEN6_FILE_MRF: GEN6_FILE_GRF; + inst->dst.base.type = GEN6_TYPE_F; + + inst->src0.base.type = GEN6_TYPE_F; + inst->src1.base.type = GEN6_TYPE_F; + inst->u.src2.base.type = GEN6_TYPE_F; + } -static const char * const math_saturate[2] = { - [0] = "", - [1] = "sat" -}; + inst->dst.base.addr_mode = GEN6_ADDRMODE_DIRECT; + inst->dst.base.reg = READ(dw1, GEN6_3SRC_DST_REG); + inst->dst.base.subreg = READ(dw1, GEN6_3SRC_DST_SUBREG) << + GEN6_3SRC_DST_SUBREG__SHR; + + inst->dst.horz_stride = GEN6_HORZSTRIDE_1; + inst->dst.writemask = READ(dw1, GEN6_3SRC_DST_WRITEMASK); + + inst->src0.base.file = GEN6_FILE_GRF; + inst->src0.negate = (bool) (dw1 & GEN6_3SRC_SRC0_NEGATE); + inst->src0.absolute = (bool) (dw1 & GEN6_3SRC_SRC0_ABSOLUTE); + inst->src1.base.file = GEN6_FILE_GRF; + inst->src1.negate = (bool) (dw1 & GEN6_3SRC_SRC1_NEGATE); + inst->src1.absolute = (bool) (dw1 & GEN6_3SRC_SRC1_ABSOLUTE); + inst->u.src2.base.file = GEN6_FILE_GRF; + inst->u.src2.negate = (bool) (dw1 & GEN6_3SRC_SRC2_NEGATE); + inst->u.src2.absolute = (bool) (dw1 & GEN6_3SRC_SRC2_ABSOLUTE); +} -static const char * const math_signed[2] = { - [0] = "", - [1] = "signed" -}; +static void +disasm_inst_decode_3src_dw2_dw3_gen6(struct disasm_inst *inst, + uint32_t dw2, uint32_t dw3) +{ + const uint64_t qw = (uint64_t) dw3 << 32 | dw2; + int i; -static const char * const math_scalar[2] = { - [0] = "", - [1] = "scalar" -}; + for (i = 0; i < 3; i++) { + struct disasm_src_operand *src = (i == 0) ? &inst->src0 : + (i == 1) ? &inst->src1 : + &inst->u.src2; + const uint32_t dw = (i == 0) ? READ(qw, GEN6_3SRC_SRC_0) : + (i == 1) ? READ(qw, GEN6_3SRC_SRC_1) : + READ(qw, GEN6_3SRC_SRC_2); + + src->base.addr_mode = GEN6_ADDRMODE_DIRECT; + src->base.reg = READ(dw, GEN6_3SRC_SRC_REG); + src->base.subreg = READ(dw, GEN6_3SRC_SRC_SUBREG) << + GEN6_3SRC_SRC_SUBREG__SHR; + + if (dw & GEN6_3SRC_SRC_REPCTRL) { + src->vert_stride = GEN6_VERTSTRIDE_0; + src->width = GEN6_WIDTH_1; + src->horz_stride = GEN6_HORZSTRIDE_0; + } else { + src->vert_stride = GEN6_VERTSTRIDE_4; + src->width = GEN6_WIDTH_4; + src->horz_stride = GEN6_HORZSTRIDE_1; + } -static const char * const math_precision[2] = { - [0] = "", - [1] = "partial_precision" -}; + src->swizzle_x = READ(dw, GEN6_3SRC_SRC_SWIZZLE_X); + src->swizzle_y = READ(dw, GEN6_3SRC_SRC_SWIZZLE_Y); + src->swizzle_z = READ(dw, GEN6_3SRC_SRC_SWIZZLE_Z); + src->swizzle_w = READ(dw, GEN6_3SRC_SRC_SWIZZLE_W); + } +} -static const char * const urb_opcode[2] = { - [0] = "urb_write", - [1] = "ff_sync", -}; +/* + * When GEN6_INST_CMPTCTRL of DW0 is set, the instruction has 64 bits and is + * in EU_INSTRUCTION_COMPACT_TWO_SRC form. We should have expanded it to its + * original form. + * + * Depending on the opcode, the 128-bits instruction is in one of the + * following forms + * + * - EU_INSTRUCTION_BASIC_ONE_SRC + * - EU_INSTRUCTION_BASIC_TWO_SRC + * - EU_INSTRUCTION_BASIC_THREE_SRC + * - EU_INSTRUCTION_BRANCH_CONDITIONAL + * - EU_INSTRUCTION_BRANCH_ONE_SRC + * - EU_INSTRUCTION_BRANCH_TWO_SRC + * - EU_INSTRUCTION_ILLEGAL + * - EU_INSTRUCTION_MATH + * - EU_INSTRUCTION_NOP + * - EU_INSTRUCTION_SEND + * + * In EU_INSTRUCTION_BASIC_ONE_SRC form, + * + * - DW0 is EU_INSTRUCTION_HEADER + * - DW1 is EU_INSTRUCTION_OPERAND_CONTROLS + * - DW2 is Source 0 and EU_INSTRUCTION_FLAGS + * - DW3 is reserved unless Source 0 is an immediate + * + * All other forms except EU_INSTRUCTION_BASIC_THREE_SRC are quite compatible + * with EU_INSTRUCTION_BASIC_ONE_SRC. + */ +static void +disasm_inst_decode(struct disasm_inst *inst, + const uint32_t *dw) +{ + assert(!(dw[0] & GEN6_INST_CMPTCTRL)); + + disasm_inst_decode_dw0_gen6(inst, dw[0]); + + switch (inst->opcode) { + case GEN7_OPCODE_CSEL: + case GEN7_OPCODE_BFE: + case GEN7_OPCODE_BFI2: + case GEN6_OPCODE_MAD: + case GEN6_OPCODE_LRP: + disasm_inst_decode_3src_dw1_gen6(inst, dw[1]); + disasm_inst_decode_3src_dw2_dw3_gen6(inst, dw[2], dw[3]); + break; + default: + disasm_inst_decode_dw1_gen6(inst, dw[1]); + disasm_inst_decode_dw2_dw3_gen6(inst, dw[2], dw[3]); + break; + } +} -static const char * const urb_swizzle[4] = { - [BRW_URB_SWIZZLE_NONE] = "", - [BRW_URB_SWIZZLE_INTERLEAVE] = "interleave", - [BRW_URB_SWIZZLE_TRANSPOSE] = "transpose", -}; +static const char * +disasm_inst_opcode(const struct disasm_inst *inst) +{ + return (disasm_opcode_table[inst->opcode].name) ? + disasm_opcode_table[inst->opcode].name : "BAD"; +} -static const char * const urb_allocate[2] = { - [0] = "", - [1] = "allocate" -}; +static const char * +disasm_inst_pred_ctrl(const struct disasm_inst *inst) +{ + if (inst->access_mode == GEN6_ALIGN_1) { + switch (inst->pred_ctrl) { + case GEN6_PREDCTRL_NORMAL: return ""; + case GEN6_PREDCTRL_ANYV: return ".anyv"; + case GEN6_PREDCTRL_ALLV: return ".allv"; + case GEN6_PREDCTRL_ANY2H: return ".any2h"; + case GEN6_PREDCTRL_ALL2H: return ".all2h"; + case GEN6_PREDCTRL_ANY4H: return ".any4h"; + case GEN6_PREDCTRL_ALL4H: return ".all4h"; + case GEN6_PREDCTRL_ANY8H: return ".any8h"; + case GEN6_PREDCTRL_ALL8H: return ".all8h"; + case GEN6_PREDCTRL_ANY16H: return ".any16h"; + case GEN6_PREDCTRL_ALL16H: return ".all16h"; + case GEN7_PREDCTRL_ANY32H: return ".any32h"; + case GEN7_PREDCTRL_ALL32H: return ".all32h"; + default: return ".BAD"; + } + } else { + switch (inst->pred_ctrl) { + case GEN6_PREDCTRL_NORMAL: return ""; + case GEN6_PREDCTRL_X: return ".x"; + case GEN6_PREDCTRL_Y: return ".y"; + case GEN6_PREDCTRL_Z: return ".z"; + case GEN6_PREDCTRL_W: return ".w"; + default: return ".BAD"; + } + } +} -static const char * const urb_used[2] = { - [0] = "", - [1] = "used" -}; +static char +disasm_inst_pred_inv(const struct disasm_inst *inst) +{ + return (inst->pred_inv) ? '-' : '+'; +} -static const char * const urb_complete[2] = { - [0] = "", - [1] = "complete" -}; +static const char * +disasm_inst_exec_size(const struct disasm_inst *inst) +{ + switch (inst->exec_size) { + case GEN6_EXECSIZE_1: return "1"; + case GEN6_EXECSIZE_2: return "2"; + case GEN6_EXECSIZE_4: return "4"; + case GEN6_EXECSIZE_8: return "8"; + case GEN6_EXECSIZE_16: return "16"; + case GEN6_EXECSIZE_32: return "32"; + default: return "BAD"; + } +} -static const char * const sampler_target_format[4] = { - [0] = "F", - [2] = "UD", - [3] = "D" -}; +static const char * +disasm_inst_fc(const struct disasm_inst *inst) +{ + assert(inst->opcode == GEN6_OPCODE_MATH); + + switch (inst->fc) { + case GEN6_MATH_INV: return "inv"; + case GEN6_MATH_LOG: return "log"; + case GEN6_MATH_EXP: return "exp"; + case GEN6_MATH_SQRT: return "sqrt"; + case GEN6_MATH_RSQ: return "rsq"; + case GEN6_MATH_SIN: return "sin"; + case GEN6_MATH_COS: return "cos"; + case GEN6_MATH_FDIV: return "fdiv"; + case GEN6_MATH_POW: return "pow"; + case GEN6_MATH_INT_DIV: return "int_div"; + case GEN6_MATH_INT_DIV_QUOTIENT: return "int_div_quotient"; + case GEN6_MATH_INT_DIV_REMAINDER: return "int_div_remainder"; + default: return "BAD"; + } +} +static const char * +disasm_inst_sfid(const struct disasm_inst *inst) +{ + assert(inst->opcode == GEN6_OPCODE_SEND || + inst->opcode == GEN6_OPCODE_SENDC); + + switch (inst->sfid) { + case GEN6_SFID_NULL: return "null"; + case GEN6_SFID_SAMPLER: return "sampler"; + case GEN6_SFID_GATEWAY: return "gateway"; + case GEN6_SFID_DP_SAMPLER: return "dp sampler"; + case GEN6_SFID_DP_RC: return "dp render"; + case GEN6_SFID_URB: return "urb"; + case GEN6_SFID_SPAWNER: return "spawner"; + case GEN6_SFID_VME: return "vme"; + case GEN6_SFID_DP_CC: return "dp const"; + case GEN7_SFID_DP_DC0: return "dp data 0"; + case GEN7_SFID_PI: return "pixel interp"; + case GEN75_SFID_DP_DC1: return "dp data 1"; + default: return "BAD"; + } +} -static int column; +static const char * +disasm_inst_cond_modifier(const struct disasm_inst *inst) +{ + switch (inst->cond_modifier) { + case GEN6_COND_NONE: return ""; + case GEN6_COND_Z: return ".z"; + case GEN6_COND_NZ: return ".nz"; + case GEN6_COND_G: return ".g"; + case GEN6_COND_GE: return ".ge"; + case GEN6_COND_L: return ".l"; + case GEN6_COND_LE: return ".le"; + case GEN6_COND_O: return ".o"; + case GEN6_COND_U: return ".u"; + default: return ".BAD"; + } +} -static int string (FILE *file, const char *string) +static const char * +disasm_inst_debug_ctrl(const struct disasm_inst *inst) { - fputs (string, file); - column += strlen (string); - return 0; + return (inst->debug_ctrl) ? ".breakpoint" : ""; } -static int format (FILE *f, const char *format, ...) +static const char * +disasm_inst_saturate(const struct disasm_inst *inst) { - char buf[1024]; - va_list args; - va_start (args, format); - - vsnprintf (buf, sizeof (buf) - 1, format, args); - va_end (args); - string (f, buf); - return 0; + return (inst->saturate) ? ".sat" : ""; } -static int newline (FILE *f) +static const char * +disasm_inst_flag_reg(const struct disasm_inst *inst) { - putc ('\n', f); - column = 0; - return 0; + static const char *flag_names[2][2] = { + { "f0", "f0.1" }, + { "f1.0", "f1.1" }, + }; + + return (inst->flag_reg <= 1 && inst->flag_subreg <= 1) ? + flag_names[inst->flag_reg][inst->flag_subreg] : "fBAD"; } -static int pad (FILE *f, int c) +static const char * +disasm_inst_access_mode(const struct disasm_inst *inst) { - do - string (f, " "); - while (column < c); - return 0; + switch (inst->access_mode) { + case GEN6_ALIGN_1: return " align1"; + case GEN6_ALIGN_16: return " align16"; + default: return " alignBAD"; + } } -static int control (FILE *file, const char *name, const char * const ctrl[], - GLuint id, int *space) +static const char * +disasm_inst_mask_ctrl(const struct disasm_inst *inst) { - if (!ctrl[id]) { - fprintf (file, "*** invalid %s value %d ", - name, id); - return 1; - } - if (ctrl[id][0]) - { - if (space && *space) - string (file, " "); - string (file, ctrl[id]); - if (space) - *space = 1; - } - return 0; + switch (inst->mask_ctrl) { + case GEN6_MASKCTRL_NORMAL: return ""; + case GEN6_MASKCTRL_NOMASK: return " WE_all"; + default: return " WE_BAD"; + } } -static int print_opcode (FILE *file, int id) +static const char * +disasm_inst_dep_ctrl(const struct disasm_inst *inst) { - if (!opcode[id].name) { - format (file, "*** invalid opcode value %d ", id); - return 1; - } - string (file, opcode[id].name); - return 0; + switch (inst->dep_ctrl) { + case GEN6_DEPCTRL_NORMAL: return ""; + case GEN6_DEPCTRL_NODDCLR: return " NoDDClr"; + case GEN6_DEPCTRL_NODDCHK: return " NoDDChk"; + case GEN6_DEPCTRL_NEITHER: return " NoDDClr,NoDDChk"; + default: return " NoDDBAD"; + } } -static int reg (FILE *file, GLuint _reg_file, GLuint _reg_nr) +static const char * +disasm_inst_qtr_ctrl(const struct disasm_inst *inst) { - int err = 0; - - /* Clear the Compr4 instruction compression bit. */ - if (_reg_file == BRW_MESSAGE_REGISTER_FILE) - _reg_nr &= ~(1 << 7); - - if (_reg_file == BRW_ARCHITECTURE_REGISTER_FILE) { - switch (_reg_nr & 0xf0) { - case BRW_ARF_NULL: - string (file, "null"); - return -1; - case BRW_ARF_ADDRESS: - format (file, "a%d", _reg_nr & 0x0f); - break; - case BRW_ARF_ACCUMULATOR: - format (file, "acc%d", _reg_nr & 0x0f); - break; - case BRW_ARF_FLAG: - format (file, "f%d", _reg_nr & 0x0f); - break; - case BRW_ARF_MASK: - format (file, "mask%d", _reg_nr & 0x0f); - break; - case BRW_ARF_MASK_STACK: - format (file, "msd%d", _reg_nr & 0x0f); - break; - case BRW_ARF_STATE: - format (file, "sr%d", _reg_nr & 0x0f); - break; - case BRW_ARF_CONTROL: - format (file, "cr%d", _reg_nr & 0x0f); - break; - case BRW_ARF_NOTIFICATION_COUNT: - format (file, "n%d", _reg_nr & 0x0f); - break; - case BRW_ARF_IP: - string (file, "ip"); - return -1; - break; - default: - format (file, "ARF%d", _reg_nr); - break; - } - } else { - err |= control (file, "src reg file", reg_file, _reg_file, NULL); - format (file, "%d", _reg_nr); - } - return err; + switch (inst->exec_size) { + case GEN6_EXECSIZE_8: + switch (inst->qtr_ctrl) { + case GEN6_QTRCTRL_1Q: return " 1Q"; + case GEN6_QTRCTRL_2Q: return " 2Q"; + case GEN6_QTRCTRL_3Q: return " 3Q"; + case GEN6_QTRCTRL_4Q: return " 4Q"; + default: return " BADQ"; + } + break; + case GEN6_EXECSIZE_16: + switch (inst->qtr_ctrl) { + case GEN6_QTRCTRL_1H: return " 1H"; + case GEN6_QTRCTRL_2H: return " 2H"; + default: return " BADH"; + } + break; + default: + return ""; + } + } -static int dest (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_thread_ctrl(const struct disasm_inst *inst) { - int err = 0; - - if (inst->header.access_mode == BRW_ALIGN_1) - { - if (inst->bits1.da1.dest_address_mode == BRW_ADDRESS_DIRECT) - { - err |= reg (file, inst->bits1.da1.dest_reg_file, inst->bits1.da1.dest_reg_nr); - if (err == -1) - return 0; - if (inst->bits1.da1.dest_subreg_nr) - format (file, ".%d", inst->bits1.da1.dest_subreg_nr / - reg_type_size[inst->bits1.da1.dest_reg_type]); - string (file, "<"); - err |= control (file, "horiz stride", horiz_stride, inst->bits1.da1.dest_horiz_stride, NULL); - string (file, ">"); - err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da1.dest_reg_type, NULL); - } - else - { - string (file, "g[a0"); - if (inst->bits1.ia1.dest_subreg_nr) - format (file, ".%d", inst->bits1.ia1.dest_subreg_nr / - reg_type_size[inst->bits1.ia1.dest_reg_type]); - if (inst->bits1.ia1.dest_indirect_offset) - format (file, " %d", inst->bits1.ia1.dest_indirect_offset); - string (file, "]<"); - err |= control (file, "horiz stride", horiz_stride, inst->bits1.ia1.dest_horiz_stride, NULL); - string (file, ">"); - err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.ia1.dest_reg_type, NULL); - } - } - else - { - if (inst->bits1.da16.dest_address_mode == BRW_ADDRESS_DIRECT) - { - err |= reg (file, inst->bits1.da16.dest_reg_file, inst->bits1.da16.dest_reg_nr); - if (err == -1) - return 0; - if (inst->bits1.da16.dest_subreg_nr) - format (file, ".%d", inst->bits1.da16.dest_subreg_nr / - reg_type_size[inst->bits1.da16.dest_reg_type]); - string (file, "<1>"); - err |= control (file, "writemask", writemask, inst->bits1.da16.dest_writemask, NULL); - err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da16.dest_reg_type, NULL); - } - else - { - err = 1; - string (file, "Indirect align16 address mode not supported"); - } - } - - return 0; + switch (inst->thread_ctrl) { + case GEN6_THREADCTRL_NORMAL: return ""; + case GEN6_THREADCTRL_ATOMIC: return " atomic"; + case GEN6_THREADCTRL_SWITCH: return " switch"; + default: return " BAD"; + } } -static int dest_3src (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_acc_wr_ctrl(const struct disasm_inst *inst) { - int err = 0; - uint32_t reg_file; - - if (inst->bits1.da3src.dest_reg_file) - reg_file = BRW_MESSAGE_REGISTER_FILE; - else - reg_file = BRW_GENERAL_REGISTER_FILE; - - err |= reg (file, reg_file, inst->bits1.da3src.dest_reg_nr); - if (err == -1) - return 0; - if (inst->bits1.da3src.dest_subreg_nr) - format (file, ".%d", inst->bits1.da3src.dest_subreg_nr); - string (file, "<1>"); - err |= control (file, "writemask", writemask, inst->bits1.da3src.dest_writemask, NULL); - err |= control (file, "dest reg encoding", reg_encoding, BRW_REGISTER_TYPE_F, NULL); - - return 0; + return (inst->acc_wr_ctrl) ? " AccWrEnable" : ""; } -static int src_align1_region (FILE *file, - GLuint _vert_stride, GLuint _width, GLuint _horiz_stride) +static const char * +disasm_inst_cmpt_ctrl(const struct disasm_inst *inst) { - int err = 0; - string (file, "<"); - err |= control (file, "vert stride", vert_stride, _vert_stride, NULL); - string (file, ","); - err |= control (file, "width", width, _width, NULL); - string (file, ","); - err |= control (file, "horiz_stride", horiz_stride, _horiz_stride, NULL); - string (file, ">"); - return err; + return (inst->cmpt_ctrl) ? " compacted" : ""; } -static int src_da1 (FILE *file, GLuint type, GLuint _reg_file, - GLuint _vert_stride, GLuint _width, GLuint _horiz_stride, - GLuint reg_num, GLuint sub_reg_num, GLuint __abs, GLuint _negate) +static const char * +disasm_inst_eot(const struct disasm_inst *inst) { - int err = 0; - err |= control (file, "negate", negate, _negate, NULL); - err |= control (file, "abs", _abs, __abs, NULL); - - err |= reg (file, _reg_file, reg_num); - if (err == -1) - return 0; - if (sub_reg_num) - format (file, ".%d", sub_reg_num / reg_type_size[type]); /* use formal style like spec */ - src_align1_region (file, _vert_stride, _width, _horiz_stride); - err |= control (file, "src reg encoding", reg_encoding, type, NULL); - return err; + if (inst->opcode == GEN6_OPCODE_SEND || + inst->opcode == GEN6_OPCODE_SENDC) + return (inst->u.imm32 & GEN6_MSG_EOT) ? " EOT" : ""; + else + return ""; } -static int src_ia1 (FILE *file, - GLuint type, - GLuint _reg_file, - GLint _addr_imm, - GLuint _addr_subreg_nr, - GLuint _negate, - GLuint __abs, - GLuint _addr_mode, - GLuint _horiz_stride, - GLuint _width, - GLuint _vert_stride) +static const char * +disasm_inst_file(const struct disasm_inst *inst, + const struct disasm_operand *operand, + bool *multi_regs) { - int err = 0; - err |= control (file, "negate", negate, _negate, NULL); - err |= control (file, "abs", _abs, __abs, NULL); - - string (file, "g[a0"); - if (_addr_subreg_nr) - format (file, ".%d", _addr_subreg_nr); - if (_addr_imm) - format (file, " %d", _addr_imm); - string (file, "]"); - src_align1_region (file, _vert_stride, _width, _horiz_stride); - err |= control (file, "src reg encoding", reg_encoding, type, NULL); - return err; + switch (operand->file) { + case GEN6_FILE_ARF: + switch (operand->reg & 0xf0) { + case GEN6_ARF_NULL: *multi_regs = false; return "null"; + case GEN6_ARF_A0: *multi_regs = true; return "a"; + case GEN6_ARF_ACC0: *multi_regs = true; return "acc"; + case GEN6_ARF_F0: *multi_regs = true; return "f"; + case GEN6_ARF_SR0: *multi_regs = true; return "sr"; + case GEN6_ARF_CR0: *multi_regs = true; return "cr"; + case GEN6_ARF_N0: *multi_regs = true; return "n"; + case GEN6_ARF_IP: *multi_regs = false; return "ip"; + case GEN6_ARF_TDR: *multi_regs = false; return "tdr"; + case GEN7_ARF_TM0: *multi_regs = true; return "tm"; + default: *multi_regs = false; return "BAD"; + } + break; + case GEN6_FILE_GRF: *multi_regs = true; return "g"; + case GEN6_FILE_MRF: *multi_regs = true; return "m"; + case GEN6_FILE_IMM: *multi_regs = true; return ""; + default: *multi_regs = false; return "BAD"; + } } -static int src_da16 (FILE *file, - GLuint _reg_type, - GLuint _reg_file, - GLuint _vert_stride, - GLuint _reg_nr, - GLuint _subreg_nr, - GLuint __abs, - GLuint _negate, - GLuint swz_x, - GLuint swz_y, - GLuint swz_z, - GLuint swz_w) +static const char * +disasm_inst_type(const struct disasm_inst *inst, + const struct disasm_operand *operand) { - int err = 0; - err |= control (file, "negate", negate, _negate, NULL); - err |= control (file, "abs", _abs, __abs, NULL); - - err |= reg (file, _reg_file, _reg_nr); - if (err == -1) - return 0; - if (_subreg_nr) - /* bit4 for subreg number byte addressing. Make this same meaning as - in da1 case, so output looks consistent. */ - format (file, ".%d", 16 / reg_type_size[_reg_type]); - string (file, "<"); - err |= control (file, "vert stride", vert_stride, _vert_stride, NULL); - string (file, ",4,1>"); - /* - * Three kinds of swizzle display: - * identity - nothing printed - * 1->all - print the single channel - * 1->1 - print the mapping - */ - if (swz_x == BRW_CHANNEL_X && - swz_y == BRW_CHANNEL_Y && - swz_z == BRW_CHANNEL_Z && - swz_w == BRW_CHANNEL_W) - { - ; - } - else if (swz_x == swz_y && swz_x == swz_z && swz_x == swz_w) - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - } - else - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - err |= control (file, "channel select", chan_sel, swz_y, NULL); - err |= control (file, "channel select", chan_sel, swz_z, NULL); - err |= control (file, "channel select", chan_sel, swz_w, NULL); - } - err |= control (file, "src da16 reg type", reg_encoding, _reg_type, NULL); - return err; + if (operand->file == GEN6_FILE_IMM) { + switch (operand->type) { + case GEN6_TYPE_UD: return "UD"; + case GEN6_TYPE_D: return "D"; + case GEN6_TYPE_UW: return "UW"; + case GEN6_TYPE_W: return "W"; + case GEN6_TYPE_UV_IMM: return "UV"; + case GEN6_TYPE_VF_IMM: return "VF"; + case GEN6_TYPE_V_IMM: return "V"; + case GEN6_TYPE_F: return "F"; + default: return "BAD"; + } + } else { + switch (operand->type) { + case GEN6_TYPE_UD: return "UD"; + case GEN6_TYPE_D: return "D"; + case GEN6_TYPE_UW: return "UW"; + case GEN6_TYPE_W: return "W"; + case GEN6_TYPE_UB: return "UB"; + case GEN6_TYPE_B: return "B"; + case GEN7_TYPE_DF: return "DF"; + case GEN6_TYPE_F: return "F"; + default: return "BAD"; + } + } } -static int src0_3src (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_vert_stride(const struct disasm_inst *inst, unsigned vert_stride) { - int err = 0; - GLuint swz_x = (inst->bits2.da3src.src0_swizzle >> 0) & 0x3; - GLuint swz_y = (inst->bits2.da3src.src0_swizzle >> 2) & 0x3; - GLuint swz_z = (inst->bits2.da3src.src0_swizzle >> 4) & 0x3; - GLuint swz_w = (inst->bits2.da3src.src0_swizzle >> 6) & 0x3; - - err |= control (file, "negate", negate, inst->bits1.da3src.src0_negate, NULL); - err |= control (file, "abs", _abs, inst->bits1.da3src.src0_abs, NULL); - - err |= reg (file, BRW_GENERAL_REGISTER_FILE, inst->bits2.da3src.src0_reg_nr); - if (err == -1) - return 0; - if (inst->bits2.da3src.src0_subreg_nr) - format (file, ".%d", inst->bits2.da3src.src0_subreg_nr); - string (file, "<4,1,1>"); - err |= control (file, "src da16 reg type", reg_encoding, - BRW_REGISTER_TYPE_F, NULL); - /* - * Three kinds of swizzle display: - * identity - nothing printed - * 1->all - print the single channel - * 1->1 - print the mapping - */ - if (swz_x == BRW_CHANNEL_X && - swz_y == BRW_CHANNEL_Y && - swz_z == BRW_CHANNEL_Z && - swz_w == BRW_CHANNEL_W) - { - ; - } - else if (swz_x == swz_y && swz_x == swz_z && swz_x == swz_w) - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - } - else - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - err |= control (file, "channel select", chan_sel, swz_y, NULL); - err |= control (file, "channel select", chan_sel, swz_z, NULL); - err |= control (file, "channel select", chan_sel, swz_w, NULL); - } - return err; + switch (vert_stride) { + case GEN6_VERTSTRIDE_0: return "0"; + case GEN6_VERTSTRIDE_1: return "1"; + case GEN6_VERTSTRIDE_2: return "2"; + case GEN6_VERTSTRIDE_4: return "4"; + case GEN6_VERTSTRIDE_8: return "8"; + case GEN6_VERTSTRIDE_16: return "16"; + case GEN6_VERTSTRIDE_32: return "32"; + case GEN6_VERTSTRIDE_VXH: return "VxH"; + default: return "BAD"; + } } -static int src1_3src (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_width(const struct disasm_inst *inst, unsigned width) { - int err = 0; - GLuint swz_x = (inst->bits2.da3src.src1_swizzle >> 0) & 0x3; - GLuint swz_y = (inst->bits2.da3src.src1_swizzle >> 2) & 0x3; - GLuint swz_z = (inst->bits2.da3src.src1_swizzle >> 4) & 0x3; - GLuint swz_w = (inst->bits2.da3src.src1_swizzle >> 6) & 0x3; - GLuint src1_subreg_nr = (inst->bits2.da3src.src1_subreg_nr_low | - (inst->bits3.da3src.src1_subreg_nr_high << 2)); - - err |= control (file, "negate", negate, inst->bits1.da3src.src1_negate, - NULL); - err |= control (file, "abs", _abs, inst->bits1.da3src.src1_abs, NULL); - - err |= reg (file, BRW_GENERAL_REGISTER_FILE, - inst->bits3.da3src.src1_reg_nr); - if (err == -1) - return 0; - if (src1_subreg_nr) - format (file, ".%d", src1_subreg_nr); - string (file, "<4,1,1>"); - err |= control (file, "src da16 reg type", reg_encoding, - BRW_REGISTER_TYPE_F, NULL); - /* - * Three kinds of swizzle display: - * identity - nothing printed - * 1->all - print the single channel - * 1->1 - print the mapping - */ - if (swz_x == BRW_CHANNEL_X && - swz_y == BRW_CHANNEL_Y && - swz_z == BRW_CHANNEL_Z && - swz_w == BRW_CHANNEL_W) - { - ; - } - else if (swz_x == swz_y && swz_x == swz_z && swz_x == swz_w) - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - } - else - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - err |= control (file, "channel select", chan_sel, swz_y, NULL); - err |= control (file, "channel select", chan_sel, swz_z, NULL); - err |= control (file, "channel select", chan_sel, swz_w, NULL); - } - return err; + switch (width) { + case GEN6_WIDTH_1: return "1"; + case GEN6_WIDTH_2: return "2"; + case GEN6_WIDTH_4: return "4"; + case GEN6_WIDTH_8: return "8"; + case GEN6_WIDTH_16: return "16"; + default: return "BAD"; + } } +static const char * +disasm_inst_horz_stride(const struct disasm_inst *inst, unsigned horz_stride) +{ + switch (horz_stride) { + case GEN6_HORZSTRIDE_0: return "0"; + case GEN6_HORZSTRIDE_1: return "1"; + case GEN6_HORZSTRIDE_2: return "2"; + case GEN6_HORZSTRIDE_4: return "4"; + default: return "BAD"; + } +} -static int src2_3src (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_writemask(const struct disasm_inst *inst, unsigned writemask) { - int err = 0; - GLuint swz_x = (inst->bits3.da3src.src2_swizzle >> 0) & 0x3; - GLuint swz_y = (inst->bits3.da3src.src2_swizzle >> 2) & 0x3; - GLuint swz_z = (inst->bits3.da3src.src2_swizzle >> 4) & 0x3; - GLuint swz_w = (inst->bits3.da3src.src2_swizzle >> 6) & 0x3; - - err |= control (file, "negate", negate, inst->bits1.da3src.src2_negate, - NULL); - err |= control (file, "abs", _abs, inst->bits1.da3src.src2_abs, NULL); - - err |= reg (file, BRW_GENERAL_REGISTER_FILE, - inst->bits3.da3src.src2_reg_nr); - if (err == -1) - return 0; - if (inst->bits3.da3src.src2_subreg_nr) - format (file, ".%d", inst->bits3.da3src.src2_subreg_nr); - string (file, "<4,1,1>"); - err |= control (file, "src da16 reg type", reg_encoding, - BRW_REGISTER_TYPE_F, NULL); - /* - * Three kinds of swizzle display: - * identity - nothing printed - * 1->all - print the single channel - * 1->1 - print the mapping - */ - if (swz_x == BRW_CHANNEL_X && - swz_y == BRW_CHANNEL_Y && - swz_z == BRW_CHANNEL_Z && - swz_w == BRW_CHANNEL_W) - { - ; - } - else if (swz_x == swz_y && swz_x == swz_z && swz_x == swz_w) - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - } - else - { - string (file, "."); - err |= control (file, "channel select", chan_sel, swz_x, NULL); - err |= control (file, "channel select", chan_sel, swz_y, NULL); - err |= control (file, "channel select", chan_sel, swz_z, NULL); - err |= control (file, "channel select", chan_sel, swz_w, NULL); - } - return err; + switch (writemask) { + case 0x0: return "."; + case 0x1: return ".x"; + case 0x2: return ".y"; + case 0x3: return ".xy"; + case 0x4: return ".z"; + case 0x5: return ".xz"; + case 0x6: return ".yz"; + case 0x7: return ".xyz"; + case 0x8: return ".w"; + case 0x9: return ".xw"; + case 0xa: return ".yw"; + case 0xb: return ".xyw"; + case 0xc: return ".zw"; + case 0xd: return ".xzw"; + case 0xe: return ".yzw"; + case 0xf: return ""; + default: return ".BAD"; + } } -static int imm (FILE *file, GLuint type, struct brw_instruction *inst) { - switch (type) { - case BRW_REGISTER_TYPE_UD: - format (file, "0x%08xUD", inst->bits3.ud); - break; - case BRW_REGISTER_TYPE_D: - format (file, "%dD", inst->bits3.d); - break; - case BRW_REGISTER_TYPE_UW: - format (file, "0x%04xUW", (uint16_t) inst->bits3.ud); - break; - case BRW_REGISTER_TYPE_W: - format (file, "%dW", (int16_t) inst->bits3.d); - break; - case BRW_REGISTER_TYPE_UB: - format (file, "0x%02xUB", (int8_t) inst->bits3.ud); - break; - case BRW_REGISTER_TYPE_VF: - format (file, "Vector Float"); - break; - case BRW_REGISTER_TYPE_V: - format (file, "0x%08xV", inst->bits3.ud); - break; - case BRW_REGISTER_TYPE_F: - format (file, "%-gF", inst->bits3.f); - } - return 0; +static const char * +disasm_inst_negate(const struct disasm_inst *inst, bool negate) +{ + return (negate) ? "-" : ""; } -static int src0 (FILE *file, struct brw_instruction *inst) +static const char * +disasm_inst_absolute(const struct disasm_inst *inst, bool absolute) { - if (inst->bits1.da1.src0_reg_file == BRW_IMMEDIATE_VALUE) - return imm (file, inst->bits1.da1.src0_reg_type, - inst); - else if (inst->header.access_mode == BRW_ALIGN_1) - { - if (inst->bits2.da1.src0_address_mode == BRW_ADDRESS_DIRECT) - { - return src_da1 (file, - inst->bits1.da1.src0_reg_type, - inst->bits1.da1.src0_reg_file, - inst->bits2.da1.src0_vert_stride, - inst->bits2.da1.src0_width, - inst->bits2.da1.src0_horiz_stride, - inst->bits2.da1.src0_reg_nr, - inst->bits2.da1.src0_subreg_nr, - inst->bits2.da1.src0_abs, - inst->bits2.da1.src0_negate); - } - else - { - return src_ia1 (file, - inst->bits1.ia1.src0_reg_type, - inst->bits1.ia1.src0_reg_file, - inst->bits2.ia1.src0_indirect_offset, - inst->bits2.ia1.src0_subreg_nr, - inst->bits2.ia1.src0_negate, - inst->bits2.ia1.src0_abs, - inst->bits2.ia1.src0_address_mode, - inst->bits2.ia1.src0_horiz_stride, - inst->bits2.ia1.src0_width, - inst->bits2.ia1.src0_vert_stride); - } - } - else - { - if (inst->bits2.da16.src0_address_mode == BRW_ADDRESS_DIRECT) - { - return src_da16 (file, - inst->bits1.da16.src0_reg_type, - inst->bits1.da16.src0_reg_file, - inst->bits2.da16.src0_vert_stride, - inst->bits2.da16.src0_reg_nr, - inst->bits2.da16.src0_subreg_nr, - inst->bits2.da16.src0_abs, - inst->bits2.da16.src0_negate, - inst->bits2.da16.src0_swz_x, - inst->bits2.da16.src0_swz_y, - inst->bits2.da16.src0_swz_z, - inst->bits2.da16.src0_swz_w); - } - else - { - string (file, "Indirect align16 address mode not supported"); - return 1; - } - } + return (absolute) ? "(abs)" : ""; } -static int src1 (FILE *file, struct brw_instruction *inst) +static bool +disasm_inst_is_null(const struct disasm_inst *inst, + const struct disasm_operand *operand) { - if (inst->bits1.da1.src1_reg_file == BRW_IMMEDIATE_VALUE) - return imm (file, inst->bits1.da1.src1_reg_type, - inst); - else if (inst->header.access_mode == BRW_ALIGN_1) - { - if (inst->bits3.da1.src1_address_mode == BRW_ADDRESS_DIRECT) - { - return src_da1 (file, - inst->bits1.da1.src1_reg_type, - inst->bits1.da1.src1_reg_file, - inst->bits3.da1.src1_vert_stride, - inst->bits3.da1.src1_width, - inst->bits3.da1.src1_horiz_stride, - inst->bits3.da1.src1_reg_nr, - inst->bits3.da1.src1_subreg_nr, - inst->bits3.da1.src1_abs, - inst->bits3.da1.src1_negate); - } - else - { - return src_ia1 (file, - inst->bits1.ia1.src1_reg_type, - inst->bits1.ia1.src1_reg_file, - inst->bits3.ia1.src1_indirect_offset, - inst->bits3.ia1.src1_subreg_nr, - inst->bits3.ia1.src1_negate, - inst->bits3.ia1.src1_abs, - inst->bits3.ia1.src1_address_mode, - inst->bits3.ia1.src1_horiz_stride, - inst->bits3.ia1.src1_width, - inst->bits3.ia1.src1_vert_stride); - } - } - else - { - if (inst->bits3.da16.src1_address_mode == BRW_ADDRESS_DIRECT) - { - return src_da16 (file, - inst->bits1.da16.src1_reg_type, - inst->bits1.da16.src1_reg_file, - inst->bits3.da16.src1_vert_stride, - inst->bits3.da16.src1_reg_nr, - inst->bits3.da16.src1_subreg_nr, - inst->bits3.da16.src1_abs, - inst->bits3.da16.src1_negate, - inst->bits3.da16.src1_swz_x, - inst->bits3.da16.src1_swz_y, - inst->bits3.da16.src1_swz_z, - inst->bits3.da16.src1_swz_w); - } - else - { - string (file, "Indirect align16 address mode not supported"); - return 1; - } - } + return (operand->file == GEN6_FILE_ARF && operand->reg == GEN6_ARF_NULL); } -int esize[6] = { - [0] = 1, - [1] = 2, - [2] = 4, - [3] = 8, - [4] = 16, - [5] = 32, -}; +static int +disasm_inst_type_size(const struct disasm_inst *inst, + const struct disasm_operand *operand) +{ + assert(operand->file != GEN6_FILE_IMM); + + switch (operand->type) { + case GEN6_TYPE_UD: return 4; + case GEN6_TYPE_D: return 4; + case GEN6_TYPE_UW: return 2; + case GEN6_TYPE_W: return 2; + case GEN6_TYPE_UB: return 1; + case GEN6_TYPE_B: return 1; + case GEN7_TYPE_DF: return 8; + case GEN6_TYPE_F: return 4; + default: return 1; + } +} -static int qtr_ctrl(FILE *file, struct brw_instruction *inst) +static void +disasm_printer_reset(struct disasm_printer *printer) { - int qtr_ctl = inst->header.compression_control; - int exec_size = esize[inst->header.execution_size]; - - if (exec_size == 8) { - switch (qtr_ctl) { - case 0: - string (file, " 1Q"); - break; - case 1: - string (file, " 2Q"); - break; - case 2: - string (file, " 3Q"); - break; - case 3: - string (file, " 4Q"); - break; - } - } else if (exec_size == 16){ - if (qtr_ctl < 2) - string (file, " 1H"); - else - string (file, " 2H"); - } - return 0; + printer->buf[0] = '\0'; + printer->len = 0; } -int brw_disasm (FILE *file, struct brw_instruction *inst, int gen) +static const char * +disasm_printer_get_string(struct disasm_printer *printer) { - int err = 0; - int space = 0; - - if (inst->header.predicate_control) { - string (file, "("); - err |= control (file, "predicate inverse", pred_inv, inst->header.predicate_inverse, NULL); - format (file, "f%d", gen >= 7 ? inst->bits2.da1.flag_reg_nr : 0); - if (inst->bits2.da1.flag_subreg_nr) - format (file, ".%d", inst->bits2.da1.flag_subreg_nr); - if (inst->header.access_mode == BRW_ALIGN_1) - err |= control (file, "predicate control align1", pred_ctrl_align1, - inst->header.predicate_control, NULL); - else - err |= control (file, "predicate control align16", pred_ctrl_align16, - inst->header.predicate_control, NULL); - string (file, ") "); - } - - err |= print_opcode (file, inst->header.opcode); - err |= control (file, "saturate", saturate, inst->header.saturate, NULL); - err |= control (file, "debug control", debug_ctrl, inst->header.debug_control, NULL); - - if (inst->header.opcode == BRW_OPCODE_MATH) { - string (file, " "); - err |= control (file, "function", math_function, - inst->header.destreg__conditionalmod, NULL); - } else if (inst->header.opcode != BRW_OPCODE_SEND && - inst->header.opcode != BRW_OPCODE_SENDC) { - err |= control (file, "conditional modifier", conditional_modifier, - inst->header.destreg__conditionalmod, NULL); - - /* If we're using the conditional modifier, print which flags reg is - * used for it. Note that on gen6+, the embedded-condition SEL and - * control flow doesn't update flags. - */ - if (inst->header.destreg__conditionalmod && - (gen < 6 || (inst->header.opcode != BRW_OPCODE_SEL && - inst->header.opcode != BRW_OPCODE_IF && - inst->header.opcode != BRW_OPCODE_WHILE))) { - format (file, ".f%d", gen >= 7 ? inst->bits2.da1.flag_reg_nr : 0); - if (inst->bits2.da1.flag_subreg_nr) - format (file, ".%d", inst->bits2.da1.flag_subreg_nr); - } - } - - if (inst->header.opcode != BRW_OPCODE_NOP) { - string (file, "("); - err |= control (file, "execution size", exec_size, inst->header.execution_size, NULL); - string (file, ")"); - } - - if (inst->header.opcode == BRW_OPCODE_SEND && gen < 6) - format (file, " %d", inst->header.destreg__conditionalmod); - - if (opcode[inst->header.opcode].nsrc == 3) { - pad (file, 16); - err |= dest_3src (file, inst); - - pad (file, 32); - err |= src0_3src (file, inst); - - pad (file, 48); - err |= src1_3src (file, inst); - - pad (file, 64); - err |= src2_3src (file, inst); - } else { - if (opcode[inst->header.opcode].ndst > 0) { - pad (file, 16); - err |= dest (file, inst); - } else if (gen == 7 && (inst->header.opcode == BRW_OPCODE_ELSE || - inst->header.opcode == BRW_OPCODE_ENDIF || - inst->header.opcode == BRW_OPCODE_WHILE)) { - format (file, " %d", inst->bits3.break_cont.jip); - } else if (gen == 6 && (inst->header.opcode == BRW_OPCODE_IF || - inst->header.opcode == BRW_OPCODE_ELSE || - inst->header.opcode == BRW_OPCODE_ENDIF || - inst->header.opcode == BRW_OPCODE_WHILE)) { - format (file, " %d", inst->bits1.branch_gen6.jump_count); - } else if ((gen >= 6 && (inst->header.opcode == BRW_OPCODE_BREAK || - inst->header.opcode == BRW_OPCODE_CONTINUE || - inst->header.opcode == BRW_OPCODE_HALT)) || - (gen == 7 && inst->header.opcode == BRW_OPCODE_IF)) { - format (file, " %d %d", inst->bits3.break_cont.uip, inst->bits3.break_cont.jip); - } else if (inst->header.opcode == BRW_OPCODE_JMPI) { - format (file, " %d", inst->bits3.d); - } - - if (opcode[inst->header.opcode].nsrc > 0) { - pad (file, 32); - err |= src0 (file, inst); - } - if (opcode[inst->header.opcode].nsrc > 1) { - pad (file, 48); - err |= src1 (file, inst); - } - } - - if (inst->header.opcode == BRW_OPCODE_SEND || - inst->header.opcode == BRW_OPCODE_SENDC) { - enum brw_message_target target; - - if (gen >= 6) - target = inst->header.destreg__conditionalmod; - else if (gen == 5) - target = inst->bits2.send_gen5.sfid; - else - target = inst->bits3.generic.msg_target; - - newline (file); - pad (file, 16); - space = 0; - - if (gen >= 6) { - err |= control (file, "target function", target_function_gen6, - target, &space); - } else { - err |= control (file, "target function", target_function, - target, &space); - } - - switch (target) { - case BRW_SFID_MATH: - err |= control (file, "math function", math_function, - inst->bits3.math.function, &space); - err |= control (file, "math saturate", math_saturate, - inst->bits3.math.saturate, &space); - err |= control (file, "math signed", math_signed, - inst->bits3.math.int_type, &space); - err |= control (file, "math scalar", math_scalar, - inst->bits3.math.data_type, &space); - err |= control (file, "math precision", math_precision, - inst->bits3.math.precision, &space); - break; - case BRW_SFID_SAMPLER: - if (gen >= 7) { - format (file, " (%d, %d, %d, %d)", - inst->bits3.sampler_gen7.binding_table_index, - inst->bits3.sampler_gen7.sampler, - inst->bits3.sampler_gen7.msg_type, - inst->bits3.sampler_gen7.simd_mode); - } else if (gen >= 5) { - format (file, " (%d, %d, %d, %d)", - inst->bits3.sampler_gen5.binding_table_index, - inst->bits3.sampler_gen5.sampler, - inst->bits3.sampler_gen5.msg_type, - inst->bits3.sampler_gen5.simd_mode); - } else if (0 /* FINISHME: is_g4x */) { - format (file, " (%d, %d)", - inst->bits3.sampler_g4x.binding_table_index, - inst->bits3.sampler_g4x.sampler); - } else { - format (file, " (%d, %d, ", - inst->bits3.sampler.binding_table_index, - inst->bits3.sampler.sampler); - err |= control (file, "sampler target format", - sampler_target_format, - inst->bits3.sampler.return_format, NULL); - string (file, ")"); - } - break; - case BRW_SFID_DATAPORT_READ: - if (gen >= 6) { - format (file, " (%d, %d, %d, %d)", - inst->bits3.gen6_dp.binding_table_index, - inst->bits3.gen6_dp.msg_control, - inst->bits3.gen6_dp.msg_type, - inst->bits3.gen6_dp.send_commit_msg); - } else if (gen >= 5 /* FINISHME: || is_g4x */) { - format (file, " (%d, %d, %d)", - inst->bits3.dp_read_gen5.binding_table_index, - inst->bits3.dp_read_gen5.msg_control, - inst->bits3.dp_read_gen5.msg_type); - } else { - format (file, " (%d, %d, %d)", - inst->bits3.dp_read.binding_table_index, - inst->bits3.dp_read.msg_control, - inst->bits3.dp_read.msg_type); - } - break; - - case BRW_SFID_DATAPORT_WRITE: - if (gen >= 7) { - format (file, " ("); - - err |= control (file, "DP rc message type", - dp_rc_msg_type_gen6, - inst->bits3.gen7_dp.msg_type, &space); - - format (file, ", %d, %d, %d)", - inst->bits3.gen7_dp.binding_table_index, - inst->bits3.gen7_dp.msg_control, - inst->bits3.gen7_dp.msg_type); - } else if (gen == 6) { - format (file, " ("); - - err |= control (file, "DP rc message type", - dp_rc_msg_type_gen6, - inst->bits3.gen6_dp.msg_type, &space); - - format (file, ", %d, %d, %d, %d)", - inst->bits3.gen6_dp.binding_table_index, - inst->bits3.gen6_dp.msg_control, - inst->bits3.gen6_dp.msg_type, - inst->bits3.gen6_dp.send_commit_msg); - } else { - format (file, " (%d, %d, %d, %d)", - inst->bits3.dp_write.binding_table_index, - (inst->bits3.dp_write.last_render_target << 3) | - inst->bits3.dp_write.msg_control, - inst->bits3.dp_write.msg_type, - inst->bits3.dp_write.send_commit_msg); - } - break; - - case BRW_SFID_URB: - if (gen >= 5) { - format (file, " %d", inst->bits3.urb_gen5.offset); - } else { - format (file, " %d", inst->bits3.urb.offset); - } - - space = 1; - if (gen >= 5) { - err |= control (file, "urb opcode", urb_opcode, - inst->bits3.urb_gen5.opcode, &space); - } - err |= control (file, "urb swizzle", urb_swizzle, - inst->bits3.urb.swizzle_control, &space); - err |= control (file, "urb allocate", urb_allocate, - inst->bits3.urb.allocate, &space); - err |= control (file, "urb used", urb_used, - inst->bits3.urb.used, &space); - err |= control (file, "urb complete", urb_complete, - inst->bits3.urb.complete, &space); - break; - case BRW_SFID_THREAD_SPAWNER: - break; - case GEN7_SFID_DATAPORT_DATA_CACHE: - format (file, " (%d, %d, %d)", - inst->bits3.gen7_dp.binding_table_index, - inst->bits3.gen7_dp.msg_control, - inst->bits3.gen7_dp.msg_type); - break; - - - default: - format (file, "unsupported target %d", target); - break; - } - if (space) - string (file, " "); - if (gen >= 5) { - format (file, "mlen %d", - inst->bits3.generic_gen5.msg_length); - format (file, " rlen %d", - inst->bits3.generic_gen5.response_length); - } else { - format (file, "mlen %d", - inst->bits3.generic.msg_length); - format (file, " rlen %d", - inst->bits3.generic.response_length); - } - } - pad (file, 64); - if (inst->header.opcode != BRW_OPCODE_NOP) { - string (file, "{"); - space = 1; - err |= control(file, "access mode", access_mode, inst->header.access_mode, &space); - if (gen >= 6) - err |= control (file, "write enable control", wectrl, inst->header.mask_control, &space); - else - err |= control (file, "mask control", mask_ctrl, inst->header.mask_control, &space); - err |= control (file, "dependency control", dep_ctrl, inst->header.dependency_control, &space); - - if (gen >= 6) - err |= qtr_ctrl (file, inst); - else { - if (inst->header.compression_control == BRW_COMPRESSION_COMPRESSED && - opcode[inst->header.opcode].ndst > 0 && - inst->bits1.da1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE && - inst->bits1.da1.dest_reg_nr & (1 << 7)) { - format (file, " compr4"); - } else { - err |= control (file, "compression control", compr_ctrl, - inst->header.compression_control, &space); - } - } - - err |= control (file, "thread control", thread_ctrl, inst->header.thread_control, &space); - if (gen >= 6) - err |= control (file, "acc write control", accwr, inst->header.acc_wr_control, &space); - if (inst->header.opcode == BRW_OPCODE_SEND || - inst->header.opcode == BRW_OPCODE_SENDC) - err |= control (file, "end of thread", end_of_thread, - inst->bits3.generic.end_of_thread, &space); - if (space) - string (file, " "); - string (file, "}"); - } - string (file, ";"); - newline (file); - return err; + return printer->buf; +} + +static void _util_printf_format(2, 3) +disasm_printer_add(struct disasm_printer *printer, const char *format, ...) +{ + const size_t avail = sizeof(printer->buf) - printer->len; + va_list ap; + int written; + + va_start(ap, format); + written = vsnprintf(printer->buf + printer->len, avail, format, ap); + va_end(ap); + + /* truncated */ + if (written < 0 || written >= avail) { + memcpy(printer->buf + sizeof(printer->buf) - 4, "...", 4); + printer->len = sizeof(printer->buf) - 1; + } else { + printer->len += written; + } +} + +/** + * Pad to the specified column. + */ +static void +disasm_printer_column(struct disasm_printer *printer, int col) +{ + int len = DISASM_PRINTER_COLUMN_WIDTH * col; + + if (len <= printer->len) { + if (!printer->len) + return; + + /* at least one space */ + len = printer->len + 1; + } + + if (len >= sizeof(printer->buf)) { + len = sizeof(printer->buf) - 1; + + if (len <= printer->len) + return; + } + + memset(printer->buf + printer->len, ' ', len - printer->len); + printer->len = len; + printer->buf[printer->len] = '\0'; +} + +static void +disasm_printer_add_op(struct disasm_printer *printer, + const struct disasm_inst *inst) +{ + if (inst->pred_ctrl != GEN6_PREDCTRL_NONE) { + disasm_printer_add(printer, "(%c%s%s) ", + disasm_inst_pred_inv(inst), + disasm_inst_flag_reg(inst), + disasm_inst_pred_ctrl(inst)); + } + + disasm_printer_add(printer, "%s%s%s%s", + disasm_inst_opcode(inst), + disasm_inst_saturate(inst), + disasm_inst_debug_ctrl(inst), + disasm_inst_cond_modifier(inst)); + + if (inst->cond_modifier != GEN6_COND_NONE) { + switch (inst->opcode) { + case GEN6_OPCODE_SEL: + case GEN6_OPCODE_IF: + case GEN6_OPCODE_WHILE: + /* these do not update flag registers */ + break; + default: + disasm_printer_add(printer, ".%s", disasm_inst_flag_reg(inst)); + break; + } + } + + if (inst->opcode == GEN6_OPCODE_MATH) + disasm_printer_add(printer, " %s", disasm_inst_fc(inst)); + if (inst->opcode != GEN6_OPCODE_NOP) + disasm_printer_add(printer, "(%s)", disasm_inst_exec_size(inst)); +} + +static void +disasm_printer_add_operand(struct disasm_printer *printer, + const struct disasm_inst *inst, + const struct disasm_operand *operand) +{ + const char *name; + bool multi_regs; + + name = disasm_inst_file(inst, operand, &multi_regs); + if (!multi_regs) { + disasm_printer_add(printer, name); + return; + } + + if (operand->file == GEN6_FILE_IMM) { + switch (operand->type) { + case GEN6_TYPE_UD: + disasm_printer_add(printer, "0x%08xUD", inst->u.imm32); + break; + case GEN6_TYPE_D: + disasm_printer_add(printer, "%dD", inst->u.imm32); + break; + case GEN6_TYPE_UW: + disasm_printer_add(printer, "0x%04xUW", (uint16_t) inst->u.imm32); + break; + case GEN6_TYPE_W: + disasm_printer_add(printer, "%dW", (int16_t) inst->u.imm32); + break; + case GEN6_TYPE_UV_IMM: + disasm_printer_add(printer, "0x%08xUV", inst->u.imm32); + break; + case GEN6_TYPE_VF_IMM: + disasm_printer_add(printer, "Vector Float"); + break; + case GEN6_TYPE_V_IMM: + disasm_printer_add(printer, "0x%08xV", inst->u.imm32); + break; + case GEN6_TYPE_F: + disasm_printer_add(printer, "%-gF", uif(inst->u.imm32)); + break; + default: + disasm_printer_add(printer, "BAD"); + break; + } + + return; + } + + if (operand->addr_mode == GEN6_ADDRMODE_DIRECT) { + unsigned reg, subreg; + + reg = operand->reg; + if (operand->file == GEN6_FILE_ARF) + reg &= 0xf; + + subreg = operand->subreg / disasm_inst_type_size(inst, operand); + + if (subreg) + disasm_printer_add(printer, "%s%d.%d", name, reg, subreg); + else + disasm_printer_add(printer, "%s%d", name, reg); + } else { + disasm_printer_add(printer, "%s[a0.%d %d]", + name, operand->addr_subreg, operand->addr_imm); + } +} + +static void +disasm_printer_add_dst(struct disasm_printer *printer, + const struct disasm_inst *inst, + const struct disasm_dst_operand *dst) +{ + disasm_printer_add_operand(printer, inst, &dst->base); + + /* dst is an immediate when in EU_INSTRUCTION_BRANCH_CONDITIONAL form */ + if (disasm_inst_is_null(inst, &dst->base) || + dst->base.file == GEN6_FILE_IMM) + return; + + disasm_printer_add(printer, "<%s>%s%s", + disasm_inst_horz_stride(inst, dst->horz_stride), + disasm_inst_writemask(inst, dst->writemask), + disasm_inst_type(inst, &dst->base)); +} + +static void +disasm_printer_add_src(struct disasm_printer *printer, + const struct disasm_inst *inst, + const struct disasm_src_operand *src) +{ + static const char swizzle_chars[4] = { 'x', 'y', 'z', 'w' }; + char swizzle[5]; + + disasm_printer_add(printer, "%s%s", + disasm_inst_negate(inst, src->negate), + disasm_inst_absolute(inst, src->absolute)); + + disasm_printer_add_operand(printer, inst, &src->base); + + if (disasm_inst_is_null(inst, &src->base) || + src->base.file == GEN6_FILE_IMM) + return; + + if (src->swizzle_x == 0 && src->swizzle_y == 1 && + src->swizzle_z == 2 && src->swizzle_w == 3) { + swizzle[0] = '\0'; + } else if (src->swizzle_x == src->swizzle_y && + src->swizzle_x == src->swizzle_z && + src->swizzle_x == src->swizzle_w) { + swizzle[0] = swizzle_chars[src->swizzle_x]; + swizzle[1] = '\0'; + } else { + swizzle[0] = swizzle_chars[src->swizzle_x]; + swizzle[1] = swizzle_chars[src->swizzle_y]; + swizzle[2] = swizzle_chars[src->swizzle_z]; + swizzle[3] = swizzle_chars[src->swizzle_w]; + swizzle[4] = '\0'; + } + + disasm_printer_add(printer, "<%s,%s,%s>%s%s", + disasm_inst_vert_stride(inst, src->vert_stride), + disasm_inst_width(inst, src->width), + disasm_inst_horz_stride(inst, src->horz_stride), + swizzle, + disasm_inst_type(inst, &src->base)); +} + +static void +disasm_printer_add_ctrl(struct disasm_printer *printer, + const struct disasm_inst *inst) +{ + if (inst->opcode == GEN6_OPCODE_NOP) { + disasm_printer_add(printer, ";"); + return; + } + + disasm_printer_add(printer, "{%s%s%s%s%s%s%s%s };", + disasm_inst_access_mode(inst), + disasm_inst_mask_ctrl(inst), + disasm_inst_dep_ctrl(inst), + disasm_inst_qtr_ctrl(inst), + disasm_inst_cmpt_ctrl(inst), + disasm_inst_thread_ctrl(inst), + disasm_inst_acc_wr_ctrl(inst), + disasm_inst_eot(inst)); +} + +static void +disasm_printer_add_mdesc_sampler(struct disasm_printer *printer, + const struct disasm_inst *inst, + uint32_t mdesc) +{ + int op, simd; + + if (inst->dev->gen >= ILO_GEN(7)) { + op = READ(mdesc, GEN7_MSG_SAMPLER_OP); + simd = READ(mdesc, GEN7_MSG_SAMPLER_SIMD); + } { + op = READ(mdesc, GEN6_MSG_SAMPLER_OP); + simd = READ(mdesc, GEN6_MSG_SAMPLER_SIMD); + } + + disasm_printer_add(printer, " (%d, %d, %d, %d)", + READ(mdesc, GEN6_MSG_SAMPLER_SURFACE), + READ(mdesc, GEN6_MSG_SAMPLER_INDEX), + op, simd); +} + +static void +disasm_printer_add_mdesc_urb(struct disasm_printer *printer, + const struct disasm_inst *inst, + uint32_t mdesc) +{ + const char *op; + int offset; + bool interleaved, complete, allocate, used; + + if (inst->dev->gen >= ILO_GEN(7)) { + switch (READ(mdesc, GEN7_MSG_URB_OP)) { + case GEN7_MSG_URB_WRITE_HWORD: op = "write HWord"; break; + case GEN7_MSG_URB_WRITE_OWORD: op = "write OWord"; break; + case GEN7_MSG_URB_READ_HWORD: op = "read HWord"; break; + case GEN7_MSG_URB_READ_OWORD: op = "read OWord"; break; + case GEN7_MSG_URB_ATOMIC_MOV: op = "atomic mov"; break; + case GEN7_MSG_URB_ATOMIC_INC: op = "atomic inc"; break; + default: op = "BAD"; break; + } + + offset = READ(mdesc, GEN7_MSG_URB_GLOBAL_OFFSET); + interleaved = mdesc & GEN7_MSG_URB_INTERLEAVED; + complete = mdesc & GEN7_MSG_URB_COMPLETE; + + allocate = false; + used = false; + } else { + switch (READ(mdesc, GEN6_MSG_URB_OP)) { + case GEN6_MSG_URB_WRITE: op = "urb_write"; break; + case GEN6_MSG_URB_FF_SYNC: op = "ff_sync"; break; + default: op = "BAD"; break; + } + + offset = READ(mdesc, GEN6_MSG_URB_OFFSET); + interleaved = mdesc & GEN6_MSG_URB_INTERLEAVED; + complete = mdesc & GEN6_MSG_URB_COMPLETE; + + allocate = mdesc & GEN6_MSG_URB_ALLOCATE; + used = mdesc & GEN6_MSG_URB_USED; + } + + disasm_printer_add(printer, " %d %s%s%s%s%s", offset, op, + (interleaved) ? " interleave" : "", + (allocate) ? " allocate" : "", + (used) ? " used" : "", + (complete) ? " complete" : ""); +} + +static void +disasm_printer_add_mdesc_dp_sampler(struct disasm_printer *printer, + const struct disasm_inst *inst, + uint32_t mdesc) +{ + const int op = (inst->dev->gen >= ILO_GEN(7)) ? + READ(mdesc, GEN7_MSG_DP_OP) : READ(mdesc, GEN6_MSG_DP_OP); + const bool write_commit = (inst->dev->gen == ILO_GEN(6)) ? + (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT) : 0; + + disasm_printer_add(printer, " (%d, %d, %d, %d)", + READ(mdesc, GEN6_MSG_DP_SURFACE), + READ(mdesc, GEN6_MSG_DP_OWORD_BLOCK_SIZE), + op, write_commit); +} + +static void +disasm_printer_add_mdesc_dp_rc(struct disasm_printer *printer, + const struct disasm_inst *inst, + uint32_t mdesc) +{ + const int op = (inst->dev->gen >= ILO_GEN(7)) ? + READ(mdesc, GEN7_MSG_DP_OP) : READ(mdesc, GEN6_MSG_DP_OP); + const char *str; + bool is_rt_write; + + if (inst->dev->gen >= ILO_GEN(7.5)) { + switch (op) { + case GEN75_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break; + case GEN75_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break; + case GEN75_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break; + case GEN75_MSG_DP_RC_RT_WRITE: str = "RT write"; break; + default: str = "BAD"; break; + } + + is_rt_write = (op == GEN75_MSG_DP_RC_RT_WRITE); + } else if (inst->dev->gen >= ILO_GEN(7)) { + switch (op) { + case GEN7_MSG_DP_RC_MEDIA_BLOCK_READ: str = "media block read"; break; + case GEN7_MSG_DP_RC_TYPED_SURFACE_READ: str = "typed surface read"; break; + case GEN7_MSG_DP_RC_TYPED_ATOMIC_OP: str = "typed atomic op"; break; + case GEN7_MSG_DP_RC_MEMORY_FENCE: str = "memory fence"; break; + case GEN7_MSG_DP_RC_MEDIA_BLOCK_WRITE: str = "media block write"; break; + case GEN7_MSG_DP_RC_RT_WRITE: str = "RT write"; break; + case GEN7_MSG_DP_RC_TYPED_SURFACE_WRITE: str = "typed surface write"; break; + default: str = "BAD"; break; + } + + is_rt_write = (op == GEN7_MSG_DP_RC_RT_WRITE); + } else { + switch (op) { + case GEN6_MSG_DP_OWORD_BLOCK_READ: str = "OWORD block read"; break; + case GEN6_MSG_DP_RT_UNORM_READ: str = "RT UNORM read"; break; + case GEN6_MSG_DP_OWORD_DUAL_BLOCK_READ: str = "OWORD dual block read"; break; + case GEN6_MSG_DP_MEDIA_BLOCK_READ: str = "media block read"; break; + case GEN6_MSG_DP_UNALIGNED_OWORD_BLOCK_READ: str = "unaligned OWORD block read"; break; + case GEN6_MSG_DP_DWORD_SCATTERED_READ: str = "DWORD scattered read"; break; + case GEN6_MSG_DP_DWORD_ATOMIC_WRITE: str = "DWORD atomic write"; break; + case GEN6_MSG_DP_OWORD_BLOCK_WRITE: str = "OWORD block write"; break; + case GEN6_MSG_DP_OWORD_DUAL_BLOCK_WRITE: str = "OWORD dual block_write"; break; + case GEN6_MSG_DP_MEDIA_BLOCK_WRITE: str = "media block write"; break; + case GEN6_MSG_DP_DWORD_SCATTERED_WRITE: str = "DWORD scattered write"; break; + case GEN6_MSG_DP_RT_WRITE: str = "RT write"; break; + case GEN6_MSG_DP_SVB_WRITE: str = "SVB write"; break; + case GEN6_MSG_DP_RT_UNORM_WRITE: str = "RT UNORM write"; break; + default: str = "BAD"; break; + } + + is_rt_write = (op == GEN6_MSG_DP_RT_WRITE); + } + + disasm_printer_add(printer, " %s", str); + + if (is_rt_write) { + switch (mdesc & GEN6_MSG_DP_RT_MODE__MASK) { + case GEN6_MSG_DP_RT_MODE_SIMD16: str = "SIMD16"; break; + case GEN6_MSG_DP_RT_MODE_SIMD16_REPDATA: str = "SIMD16/RepData"; break; + case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_LO: str = "SIMD8/DualSrcLow"; break; + case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_HI: str = "SIMD8/DualSrcHigh"; break; + case GEN6_MSG_DP_RT_MODE_SIMD8_LO: str = "SIMD8"; break; + case GEN6_MSG_DP_RT_MODE_SIMD8_IMAGE_WR: str = "SIMD8/ImageWrite"; break; + default: str = "BAD"; break; + } + + disasm_printer_add(printer, " %s%s%s%s", str, + (mdesc & GEN6_MSG_DP_SLOTGRP_HI) ? " Hi" : "", + (mdesc & GEN6_MSG_DP_RT_LAST) ? " LastRT" : "", + (inst->dev->gen == ILO_GEN(6) && + (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT)) ? " WriteCommit" : ""); + } + + disasm_printer_add(printer, " Surface = %d", + READ(mdesc, GEN6_MSG_DP_SURFACE)); +} + +static void +disasm_printer_add_mdesc(struct disasm_printer *printer, + const struct disasm_inst *inst) +{ + const uint32_t mdesc = inst->u.imm32; + + assert(inst->opcode == GEN6_OPCODE_SEND || + inst->opcode == GEN6_OPCODE_SENDC); + assert(inst->src1.base.file == GEN6_FILE_IMM); + + disasm_printer_add(printer, " %s", disasm_inst_sfid(inst)); + + switch (inst->sfid) { + case GEN6_SFID_SAMPLER: + disasm_printer_add_mdesc_sampler(printer, inst, mdesc); + break; + case GEN6_SFID_DP_SAMPLER: + disasm_printer_add_mdesc_dp_sampler(printer, inst, mdesc); + break; + case GEN6_SFID_DP_RC: + disasm_printer_add_mdesc_dp_rc(printer, inst, mdesc); + break; + case GEN6_SFID_URB: + disasm_printer_add_mdesc_urb(printer, inst, mdesc); + break; + case GEN6_SFID_DP_CC: + case GEN7_SFID_DP_DC0: + case GEN7_SFID_PI: + case GEN75_SFID_DP_DC1: + default: + break; + } + + disasm_printer_add(printer, " mlen %d rlen %d", + READ(mdesc, GEN6_MSG_MLEN), + READ(mdesc, GEN6_MSG_RLEN)); +} + +static void +disasm_printer_print_inst(struct disasm_printer *printer, + const struct disasm_inst *inst) +{ + int col = 0; + + disasm_printer_reset(printer); + + disasm_printer_column(printer, col++); + disasm_printer_add_op(printer, inst); + + if (inst->has_jip || inst->has_uip) { + if (inst->has_jip) { + disasm_printer_column(printer, col++); + disasm_printer_add(printer, "JIP: %d", (int16_t) inst->u.imm32); + } + + if (inst->has_uip) { + disasm_printer_column(printer, col++); + disasm_printer_add(printer, "UIP: %d", + (int16_t) (inst->u.imm32 >> 16)); + } + } else { + const int src_count = disasm_opcode_table[inst->opcode].src_count; + const struct disasm_src_operand *src[3]; + int i; + + /* get src operands */ + switch (src_count) { + case 3: + src[2] = &inst->u.src2; + case 2: + src[1] = &inst->src1; + case 1: + src[0] = &inst->src0; + case 0: + default: + break; + } + + if (src_count) { + disasm_printer_column(printer, col++); + disasm_printer_add_dst(printer, inst, &inst->dst); + + for (i = 0; i < src_count; i++) { + disasm_printer_column(printer, col++); + disasm_printer_add_src(printer, inst, src[i]); + } + } + } + + if (inst->opcode == GEN6_OPCODE_SEND || + inst->opcode == GEN6_OPCODE_SENDC) { + /* start a new line */ + ilo_printf("%s\n", disasm_printer_get_string(printer)); + disasm_printer_reset(printer); + col = 0; + + disasm_printer_column(printer, col++); + + disasm_printer_column(printer, col++); + disasm_printer_add_mdesc(printer, inst); + } + + if (col < 4) + col = 4; + + disasm_printer_column(printer, col++); + disasm_printer_add_ctrl(printer, inst); + + ilo_printf("%s\n", disasm_printer_get_string(printer)); +} + +void +toy_compiler_disassemble(const struct ilo_dev_info *dev, + const void *kernel, int size, + bool dump_hex) +{ + const uint32_t *cur = (const uint32_t *) kernel; + const uint32_t *end = cur + size / sizeof(*cur); + struct disasm_printer printer; + + disasm_printer_reset(&printer); + + while (cur < end) { + struct disasm_inst inst; + const bool compacted = (cur[0] & GEN6_INST_CMPTCTRL); + const uint32_t *dw = cur; + uint32_t temp[4]; + + cur += (compacted) ? 2 : 4; + /* incomplete instruction */ + if (cur > end) + break; + + if (compacted) { + /* no compaction support yet */ + memset(temp, 0, sizeof(temp)); + dw = temp; + } + + if (dump_hex) { + ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ", + dw[0], dw[1], dw[2], dw[3]); + } + + memset(&inst, 0, sizeof(inst)); + inst.dev = dev; + disasm_inst_decode(&inst, dw); + inst.cmpt_ctrl = compacted; + + disasm_printer_print_inst(&printer, &inst); + } } |