Home | History | Annotate | Download | only in shader
      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 (at) 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:4;
     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 *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 branch_ctrl:1;
     94 
     95    unsigned cmpt_ctrl:1;
     96    unsigned debug_ctrl:1;
     97    unsigned saturate:1;
     98 
     99    unsigned nib_ctrl:1;
    100 
    101    unsigned flag_reg:1;
    102    unsigned flag_subreg:1;
    103 
    104    struct disasm_dst_operand dst;
    105    struct disasm_src_operand src0;
    106    struct disasm_src_operand src1;
    107    union {
    108       struct disasm_src_operand src2;
    109       uint64_t imm64;
    110 
    111       uint32_t ud;
    112       int32_t d;
    113       uint16_t uw;
    114       int16_t w;
    115       float f;
    116 
    117       struct {
    118          int16_t jip;
    119          int16_t uip;
    120       } ip16;
    121 
    122       struct {
    123          int32_t jip;
    124          int32_t uip;
    125       } ip32;
    126    } u;
    127 };
    128 
    129 static const struct {
    130    const char *name;
    131    int src_count;
    132 } disasm_opcode_table[128] = {
    133    [GEN6_OPCODE_ILLEGAL]     = { "illegal",  0 },
    134    [GEN6_OPCODE_MOV]         = { "mov",      1 },
    135    [GEN6_OPCODE_SEL]         = { "sel",      2 },
    136    [GEN6_OPCODE_MOVI]        = { "movi",     1 },
    137    [GEN6_OPCODE_NOT]         = { "not",      1 },
    138    [GEN6_OPCODE_AND]         = { "and",      2 },
    139    [GEN6_OPCODE_OR]          = { "or",       2 },
    140    [GEN6_OPCODE_XOR]         = { "xor",      2 },
    141    [GEN6_OPCODE_SHR]         = { "shr",      2 },
    142    [GEN6_OPCODE_SHL]         = { "shl",      2 },
    143    [GEN6_OPCODE_DIM]         = { "dim",      1 },
    144    [GEN6_OPCODE_ASR]         = { "asr",      2 },
    145    [GEN6_OPCODE_CMP]         = { "cmp",      2 },
    146    [GEN6_OPCODE_CMPN]        = { "cmpn",     2 },
    147    [GEN7_OPCODE_CSEL]        = { "csel",     3 },
    148    [GEN7_OPCODE_F32TO16]     = { "f32to16",  1 },
    149    [GEN7_OPCODE_F16TO32]     = { "f16to32",  1 },
    150    [GEN7_OPCODE_BFREV]       = { "bfrev",    1 },
    151    [GEN7_OPCODE_BFE]         = { "bfe",      3 },
    152    [GEN7_OPCODE_BFI1]        = { "bfi1",     2 },
    153    [GEN7_OPCODE_BFI2]        = { "bfi2",     3 },
    154    [GEN6_OPCODE_JMPI]        = { "jmpi",     1 },
    155    [GEN7_OPCODE_BRD]         = { "brd",      1 },
    156    [GEN6_OPCODE_IF]          = { "if",       2 },
    157    [GEN7_OPCODE_BRC]         = { "brc",      1 },
    158    [GEN6_OPCODE_ELSE]        = { "else",     1 },
    159    [GEN6_OPCODE_ENDIF]       = { "endif",    0 },
    160    [GEN6_OPCODE_CASE]        = { "case",     2 },
    161    [GEN6_OPCODE_WHILE]       = { "while",    1 },
    162    [GEN6_OPCODE_BREAK]       = { "break",    1 },
    163    [GEN6_OPCODE_CONT]        = { "cont",     1 },
    164    [GEN6_OPCODE_HALT]        = { "halt",     1 },
    165    [GEN75_OPCODE_CALLA]      = { "calla",    1 },
    166    [GEN6_OPCODE_CALL]        = { "call",     1 },
    167    [GEN6_OPCODE_RETURN]      = { "return",   1 },
    168    [GEN8_OPCODE_GOTO]        = { "goto",     1 },
    169    [GEN6_OPCODE_WAIT]        = { "wait",     1 },
    170    [GEN6_OPCODE_SEND]        = { "send",     1 },
    171    [GEN6_OPCODE_SENDC]       = { "sendc",    1 },
    172    [GEN6_OPCODE_MATH]        = { "math",     2 },
    173    [GEN6_OPCODE_ADD]         = { "add",      2 },
    174    [GEN6_OPCODE_MUL]         = { "mul",      2 },
    175    [GEN6_OPCODE_AVG]         = { "avg",      2 },
    176    [GEN6_OPCODE_FRC]         = { "frc",      1 },
    177    [GEN6_OPCODE_RNDU]        = { "rndu",     1 },
    178    [GEN6_OPCODE_RNDD]        = { "rndd",     1 },
    179    [GEN6_OPCODE_RNDE]        = { "rnde",     1 },
    180    [GEN6_OPCODE_RNDZ]        = { "rndz",     1 },
    181    [GEN6_OPCODE_MAC]         = { "mac",      2 },
    182    [GEN6_OPCODE_MACH]        = { "mach",     2 },
    183    [GEN6_OPCODE_LZD]         = { "lzd",      1 },
    184    [GEN7_OPCODE_FBH]         = { "fbh",      1 },
    185    [GEN7_OPCODE_FBL]         = { "fbl",      1 },
    186    [GEN7_OPCODE_CBIT]        = { "cbit",     1 },
    187    [GEN7_OPCODE_ADDC]        = { "addc",     2 },
    188    [GEN7_OPCODE_SUBB]        = { "subb",     2 },
    189    [GEN6_OPCODE_SAD2]        = { "sad2",     2 },
    190    [GEN6_OPCODE_SADA2]       = { "sada2",    2 },
    191    [GEN6_OPCODE_DP4]         = { "dp4",      2 },
    192    [GEN6_OPCODE_DPH]         = { "dph",      2 },
    193    [GEN6_OPCODE_DP3]         = { "dp3",      2 },
    194    [GEN6_OPCODE_DP2]         = { "dp2",      2 },
    195    [GEN6_OPCODE_LINE]        = { "line",     2 },
    196    [GEN6_OPCODE_PLN]         = { "pln",      2 },
    197    [GEN6_OPCODE_MAD]         = { "mad",      3 },
    198    [GEN6_OPCODE_LRP]         = { "lrp",      3 },
    199    [GEN6_OPCODE_NOP]         = { "nop",      0 },
    200 };
    201 
    202 static void
    203 disasm_inst_decode_dw0_opcode_gen6(struct disasm_inst *inst, uint32_t dw0)
    204 {
    205    ILO_DEV_ASSERT(inst->dev, 6, 8);
    206 
    207    inst->opcode = GEN_EXTRACT(dw0, GEN6_INST_OPCODE);
    208 
    209    switch (inst->opcode) {
    210    case GEN6_OPCODE_IF:
    211       inst->has_jip = true;
    212       inst->has_uip = (ilo_dev_gen(inst->dev) >= ILO_GEN(7));
    213       break;
    214    case GEN6_OPCODE_ELSE:
    215       inst->has_jip = true;
    216       inst->has_uip = (ilo_dev_gen(inst->dev) >= ILO_GEN(8));
    217       break;
    218    case GEN6_OPCODE_BREAK:
    219    case GEN6_OPCODE_CONT:
    220    case GEN6_OPCODE_HALT:
    221       inst->has_uip = true;
    222       /* fall through */
    223    case GEN6_OPCODE_JMPI:
    224    case GEN7_OPCODE_BRD:
    225    case GEN7_OPCODE_BRC:
    226    case GEN6_OPCODE_ENDIF:
    227    case GEN6_OPCODE_CASE:
    228    case GEN6_OPCODE_WHILE:
    229    case GEN75_OPCODE_CALLA:
    230    case GEN6_OPCODE_CALL:
    231    case GEN6_OPCODE_RETURN:
    232       inst->has_jip = true;
    233       break;
    234    default:
    235       break;
    236    }
    237 }
    238 
    239 static void
    240 disasm_inst_decode_dw0_gen6(struct disasm_inst *inst, uint32_t dw0)
    241 {
    242    ILO_DEV_ASSERT(inst->dev, 6, 8);
    243 
    244    disasm_inst_decode_dw0_opcode_gen6(inst, dw0);
    245 
    246    inst->access_mode = GEN_EXTRACT(dw0, GEN6_INST_ACCESSMODE);
    247 
    248    if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
    249       inst->dep_ctrl = GEN_EXTRACT(dw0, GEN8_INST_DEPCTRL);
    250       inst->nib_ctrl = (bool) (dw0 & GEN8_INST_NIBCTRL);
    251    } else {
    252       inst->mask_ctrl = GEN_EXTRACT(dw0, GEN6_INST_MASKCTRL);
    253       inst->dep_ctrl = GEN_EXTRACT(dw0, GEN6_INST_DEPCTRL);
    254    }
    255 
    256    inst->qtr_ctrl = GEN_EXTRACT(dw0, GEN6_INST_QTRCTRL);
    257    inst->thread_ctrl = GEN_EXTRACT(dw0, GEN6_INST_THREADCTRL);
    258    inst->pred_ctrl = GEN_EXTRACT(dw0, GEN6_INST_PREDCTRL);
    259 
    260    inst->pred_inv = (bool) (dw0 & GEN6_INST_PREDINV);
    261 
    262    inst->exec_size = GEN_EXTRACT(dw0, GEN6_INST_EXECSIZE);
    263 
    264    switch (inst->opcode) {
    265    case GEN6_OPCODE_SEND:
    266    case GEN6_OPCODE_SENDC:
    267       inst->sfid = GEN_EXTRACT(dw0, GEN6_INST_SFID);
    268       break;
    269    case GEN6_OPCODE_MATH:
    270       inst->fc = GEN_EXTRACT(dw0, GEN6_INST_FC);
    271       break;
    272    default:
    273       inst->cond_modifier = GEN_EXTRACT(dw0, GEN6_INST_CONDMODIFIER);
    274       break;
    275    }
    276 
    277    switch (inst->opcode) {
    278    case GEN6_OPCODE_IF:
    279    case GEN6_OPCODE_ELSE:
    280    case GEN8_OPCODE_GOTO:
    281       if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
    282          inst->branch_ctrl = (bool) (dw0 & GEN8_INST_BRANCHCTRL);
    283          break;
    284       }
    285    default:
    286       inst->acc_wr_ctrl = (bool) (dw0 & GEN6_INST_ACCWRCTRL);
    287       break;
    288    }
    289 
    290    inst->cmpt_ctrl = (bool) (dw0 & GEN6_INST_CMPTCTRL);
    291    inst->debug_ctrl = (bool) (dw0 & GEN6_INST_DEBUGCTRL);
    292    inst->saturate = (bool) (dw0 & GEN6_INST_SATURATE);
    293 }
    294 
    295 static void
    296 disasm_inst_decode_dw1_low_gen6(struct disasm_inst *inst, uint32_t dw1)
    297 {
    298    ILO_DEV_ASSERT(inst->dev, 6, 7.5);
    299 
    300    inst->dst.base.file = GEN_EXTRACT(dw1, GEN6_INST_DST_FILE);
    301    inst->dst.base.type = GEN_EXTRACT(dw1, GEN6_INST_DST_TYPE);
    302    inst->src0.base.file = GEN_EXTRACT(dw1, GEN6_INST_SRC0_FILE);
    303    inst->src0.base.type = GEN_EXTRACT(dw1, GEN6_INST_SRC0_TYPE);
    304    inst->src1.base.file = GEN_EXTRACT(dw1, GEN6_INST_SRC1_FILE);
    305    inst->src1.base.type = GEN_EXTRACT(dw1, GEN6_INST_SRC1_TYPE);
    306 
    307    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7))
    308       inst->nib_ctrl = (bool) (dw1 & GEN7_INST_NIBCTRL);
    309 }
    310 
    311 static void
    312 disasm_inst_decode_dw1_low_gen8(struct disasm_inst *inst, uint32_t dw1)
    313 {
    314    ILO_DEV_ASSERT(inst->dev, 8, 8);
    315 
    316    inst->flag_subreg = GEN_EXTRACT(dw1, GEN8_INST_FLAG_SUBREG);
    317    inst->flag_reg = GEN_EXTRACT(dw1, GEN8_INST_FLAG_REG);
    318    inst->mask_ctrl = GEN_EXTRACT(dw1, GEN8_INST_MASKCTRL);
    319 
    320    inst->dst.base.file = GEN_EXTRACT(dw1, GEN8_INST_DST_FILE);
    321    inst->dst.base.type = GEN_EXTRACT(dw1, GEN8_INST_DST_TYPE);
    322    inst->src0.base.file = GEN_EXTRACT(dw1, GEN8_INST_SRC0_FILE);
    323    inst->src0.base.type = GEN_EXTRACT(dw1, GEN8_INST_SRC0_TYPE);
    324 
    325    inst->dst.base.addr_imm = GEN_EXTRACT(dw1, GEN8_INST_DST_ADDR_IMM_BIT9) <<
    326       GEN8_INST_DST_ADDR_IMM_BIT9__SHR;
    327 }
    328 
    329 static void
    330 disasm_inst_decode_dw1_high_gen6(struct disasm_inst *inst, uint32_t dw1)
    331 {
    332    ILO_DEV_ASSERT(inst->dev, 6, 8);
    333 
    334    inst->dst.base.addr_mode = GEN_EXTRACT(dw1, GEN6_INST_DST_ADDRMODE);
    335 
    336    if (inst->dst.base.addr_mode == GEN6_ADDRMODE_DIRECT) {
    337       inst->dst.base.reg = GEN_EXTRACT(dw1, GEN6_INST_DST_REG);
    338 
    339       if (inst->access_mode == GEN6_ALIGN_1) {
    340          inst->dst.base.subreg = GEN_EXTRACT(dw1, GEN6_INST_DST_SUBREG);
    341       } else {
    342          inst->dst.base.subreg =
    343             GEN_EXTRACT(dw1, GEN6_INST_DST_SUBREG_ALIGN16) <<
    344             GEN6_INST_DST_SUBREG_ALIGN16__SHR;
    345       }
    346    } else {
    347       if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
    348          inst->dst.base.addr_subreg =
    349             GEN_EXTRACT(dw1, GEN8_INST_DST_ADDR_SUBREG);
    350 
    351          /* bit 9 is already set in disasm_inst_decode_dw1_low_gen8() */
    352          if (inst->access_mode == GEN6_ALIGN_1) {
    353             inst->dst.base.addr_imm |=
    354                GEN_EXTRACT(dw1, GEN8_INST_DST_ADDR_IMM);
    355          } else {
    356             inst->dst.base.addr_imm |=
    357                GEN_EXTRACT(dw1, GEN8_INST_DST_ADDR_IMM_ALIGN16) <<
    358                GEN8_INST_DST_ADDR_IMM_ALIGN16__SHR;
    359          }
    360       } else {
    361          inst->dst.base.addr_subreg =
    362             GEN_EXTRACT(dw1, GEN6_INST_DST_ADDR_SUBREG);
    363 
    364          if (inst->access_mode == GEN6_ALIGN_1) {
    365             inst->dst.base.addr_imm =
    366                GEN_EXTRACT(dw1, GEN6_INST_DST_ADDR_IMM);
    367          } else {
    368             inst->dst.base.addr_imm =
    369                GEN_EXTRACT(dw1, GEN6_INST_DST_ADDR_IMM_ALIGN16) <<
    370                GEN6_INST_DST_ADDR_IMM_ALIGN16__SHR;
    371          }
    372       }
    373    }
    374 
    375    inst->dst.horz_stride = GEN_EXTRACT(dw1, GEN6_INST_DST_HORZSTRIDE);
    376 
    377    if (inst->access_mode == GEN6_ALIGN_1)
    378       inst->dst.writemask = 0xf;
    379    else
    380       inst->dst.writemask = GEN_EXTRACT(dw1, GEN6_INST_DST_WRITEMASK);
    381 }
    382 
    383 static void
    384 disasm_inst_decode_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
    385 {
    386    ILO_DEV_ASSERT(inst->dev, 6, 8);
    387 
    388    if (ilo_dev_gen(inst->dev) >= ILO_GEN(8))
    389       disasm_inst_decode_dw1_low_gen8(inst, dw1);
    390    else
    391       disasm_inst_decode_dw1_low_gen6(inst, dw1);
    392 
    393    if (ilo_dev_gen(inst->dev) == ILO_GEN(6) &&
    394        inst->has_jip && !inst->has_uip)
    395       inst->u.imm64 = dw1 >> 16;
    396    else
    397       disasm_inst_decode_dw1_high_gen6(inst, dw1);
    398 }
    399 
    400 static void
    401 disasm_inst_decode_dw2_dw3_gen6(struct disasm_inst *inst,
    402                                 uint32_t dw2, uint32_t dw3)
    403 {
    404    int imm_bits = 0, count, i;
    405 
    406    ILO_DEV_ASSERT(inst->dev, 6, 8);
    407 
    408    if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
    409       /* how about real 64-bit immediates? */
    410       if (inst->has_uip) {
    411          imm_bits = 64;
    412          inst->src1.base.file = GEN6_FILE_IMM;
    413          inst->src1.base.type = GEN6_TYPE_D;
    414       } else {
    415          inst->src1.base.file = GEN_EXTRACT(dw2, GEN8_INST_SRC1_FILE);
    416          inst->src1.base.type = GEN_EXTRACT(dw2, GEN8_INST_SRC1_TYPE);
    417 
    418          if (inst->src0.base.file == GEN6_FILE_IMM ||
    419              inst->src1.base.file == GEN6_FILE_IMM)
    420             imm_bits = 32;
    421       }
    422    } else {
    423       if (ilo_dev_gen(inst->dev) >= ILO_GEN(7))
    424          inst->flag_reg = GEN_EXTRACT(dw2, GEN7_INST_FLAG_REG);
    425       inst->flag_subreg = GEN_EXTRACT(dw2, GEN6_INST_FLAG_SUBREG);
    426 
    427       if (inst->src0.base.file == GEN6_FILE_IMM ||
    428           inst->src1.base.file == GEN6_FILE_IMM)
    429          imm_bits = 32;
    430    }
    431 
    432    switch (imm_bits) {
    433    case 32:
    434       inst->u.imm64 = dw3;
    435       count = 1;
    436       break;
    437    case 64:
    438       inst->u.imm64 = (uint64_t) dw2 << 32 | dw3;
    439       count = 0;
    440       break;
    441    default:
    442       count = 2;
    443       break;
    444    }
    445 
    446    for (i = 0; i < count; i++) {
    447       struct disasm_src_operand *src = (i == 0) ? &inst->src0 : &inst->src1;
    448       const uint32_t dw = (i == 0) ? dw2 : dw3;
    449 
    450       src->base.addr_mode = GEN_EXTRACT(dw, GEN6_INST_SRC_ADDRMODE);
    451 
    452       if (src->base.addr_mode == GEN6_ADDRMODE_DIRECT) {
    453          src->base.reg = GEN_EXTRACT(dw, GEN6_INST_SRC_REG);
    454 
    455          if (inst->access_mode == GEN6_ALIGN_1) {
    456             src->base.subreg = GEN_EXTRACT(dw, GEN6_INST_SRC_SUBREG);
    457          } else {
    458             src->base.subreg = GEN_EXTRACT(dw, GEN6_INST_SRC_SUBREG_ALIGN16) <<
    459                GEN6_INST_SRC_SUBREG_ALIGN16__SHR;
    460          }
    461       } else {
    462          if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
    463             src->base.addr_subreg =
    464                GEN_EXTRACT(dw, GEN8_INST_SRC_ADDR_SUBREG);
    465 
    466             if (inst->access_mode == GEN6_ALIGN_1) {
    467                src->base.addr_imm = GEN_EXTRACT(dw, GEN8_INST_SRC_ADDR_IMM);
    468             } else {
    469                src->base.addr_imm =
    470                   GEN_EXTRACT(dw, GEN8_INST_SRC_ADDR_IMM_ALIGN16) <<
    471                   GEN8_INST_SRC_ADDR_IMM_ALIGN16__SHR;
    472             }
    473 
    474             if (i == 0) {
    475                inst->dst.base.addr_imm |= GEN_EXTRACT(dw,
    476                      GEN8_INST_SRC0_ADDR_IMM_BIT9) <<
    477                   GEN8_INST_SRC0_ADDR_IMM_BIT9__SHR;
    478             } else {
    479                inst->dst.base.addr_imm |= GEN_EXTRACT(dw,
    480                      GEN8_INST_SRC1_ADDR_IMM_BIT9) <<
    481                   GEN8_INST_SRC1_ADDR_IMM_BIT9__SHR;
    482             }
    483          } else {
    484             src->base.addr_subreg =
    485                GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_SUBREG);
    486 
    487             if (inst->access_mode == GEN6_ALIGN_1) {
    488                src->base.addr_imm = GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_IMM);
    489             } else {
    490                src->base.addr_imm =
    491                   GEN_EXTRACT(dw, GEN6_INST_SRC_ADDR_IMM_ALIGN16) <<
    492                   GEN6_INST_SRC_ADDR_IMM_ALIGN16__SHR;
    493             }
    494          }
    495       }
    496 
    497       src->vert_stride = GEN_EXTRACT(dw, GEN6_INST_SRC_VERTSTRIDE);
    498 
    499       if (inst->access_mode == GEN6_ALIGN_1) {
    500          src->width = GEN_EXTRACT(dw, GEN6_INST_SRC_WIDTH);
    501          src->horz_stride = GEN_EXTRACT(dw, GEN6_INST_SRC_HORZSTRIDE);
    502 
    503          src->swizzle_x = GEN6_SWIZZLE_X;
    504          src->swizzle_y = GEN6_SWIZZLE_Y;
    505          src->swizzle_z = GEN6_SWIZZLE_Z;
    506          src->swizzle_w = GEN6_SWIZZLE_W;
    507       } else {
    508          src->width = GEN6_WIDTH_4;
    509          src->horz_stride = GEN6_HORZSTRIDE_1;
    510 
    511          src->swizzle_x = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_X);
    512          src->swizzle_y = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_Y);
    513          src->swizzle_z = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_Z);
    514          src->swizzle_w = GEN_EXTRACT(dw, GEN6_INST_SRC_SWIZZLE_W);
    515       }
    516 
    517       src->negate = (bool) (dw & GEN6_INST_SRC_NEGATE);
    518       src->absolute = (bool) (dw & GEN6_INST_SRC_ABSOLUTE);
    519    }
    520 }
    521 
    522 static void
    523 disasm_inst_decode_3src_dw1_gen6(struct disasm_inst *inst, uint32_t dw1)
    524 {
    525    static const unsigned type_mapping[4] = {
    526       [GEN7_TYPE_F_3SRC]   = GEN6_TYPE_F,
    527       [GEN7_TYPE_D_3SRC]   = GEN6_TYPE_D,
    528       [GEN7_TYPE_UD_3SRC]  = GEN6_TYPE_UD,
    529       [GEN7_TYPE_DF_3SRC]  = GEN7_TYPE_DF,
    530    };
    531 
    532    ILO_DEV_ASSERT(inst->dev, 6, 7.5);
    533 
    534    inst->flag_subreg = GEN_EXTRACT(dw1, GEN6_3SRC_FLAG_SUBREG);
    535 
    536    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
    537       inst->nib_ctrl = (bool) (dw1 & GEN7_3SRC_NIBCTRL);
    538       inst->flag_reg = GEN_EXTRACT(dw1, GEN7_3SRC_FLAG_REG);
    539 
    540       inst->dst.base.file = GEN6_FILE_GRF;
    541       inst->dst.base.type = GEN_EXTRACT(dw1, GEN7_3SRC_DST_TYPE);
    542       inst->dst.base.type = type_mapping[inst->dst.base.type];
    543 
    544       inst->src0.base.type = GEN_EXTRACT(dw1, GEN7_3SRC_SRC_TYPE);
    545       inst->src0.base.type = type_mapping[inst->src0.base.type];
    546 
    547       inst->src1.base.type = inst->src0.base.type;
    548       inst->u.src2.base.type = inst->src0.base.type;
    549    } else {
    550       inst->dst.base.file = (dw1 & GEN6_3SRC_DST_FILE_MRF) ?
    551          GEN6_FILE_MRF: GEN6_FILE_GRF;
    552       inst->dst.base.type = GEN6_TYPE_F;
    553 
    554       inst->src0.base.type = GEN6_TYPE_F;
    555       inst->src1.base.type = GEN6_TYPE_F;
    556       inst->u.src2.base.type = GEN6_TYPE_F;
    557    }
    558 
    559    inst->dst.base.addr_mode = GEN6_ADDRMODE_DIRECT;
    560    inst->dst.base.reg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_REG);
    561    inst->dst.base.subreg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_SUBREG) <<
    562       GEN6_3SRC_DST_SUBREG__SHR;
    563 
    564    inst->dst.horz_stride = GEN6_HORZSTRIDE_1;
    565    inst->dst.writemask = GEN_EXTRACT(dw1, GEN6_3SRC_DST_WRITEMASK);
    566 
    567    inst->src0.base.file = GEN6_FILE_GRF;
    568    inst->src0.negate = (bool) (dw1 & GEN6_3SRC_SRC0_NEGATE);
    569    inst->src0.absolute = (bool) (dw1 & GEN6_3SRC_SRC0_ABSOLUTE);
    570    inst->src1.base.file = GEN6_FILE_GRF;
    571    inst->src1.negate = (bool) (dw1 & GEN6_3SRC_SRC1_NEGATE);
    572    inst->src1.absolute = (bool) (dw1 & GEN6_3SRC_SRC1_ABSOLUTE);
    573    inst->u.src2.base.file = GEN6_FILE_GRF;
    574    inst->u.src2.negate = (bool) (dw1 & GEN6_3SRC_SRC2_NEGATE);
    575    inst->u.src2.absolute = (bool) (dw1 & GEN6_3SRC_SRC2_ABSOLUTE);
    576 }
    577 
    578 static void
    579 disasm_inst_decode_3src_dw1_gen8(struct disasm_inst *inst, uint32_t dw1)
    580 {
    581    static const unsigned type_mapping[8] = {
    582       [GEN7_TYPE_F_3SRC]   = GEN6_TYPE_F,
    583       [GEN7_TYPE_D_3SRC]   = GEN6_TYPE_D,
    584       [GEN7_TYPE_UD_3SRC]  = GEN6_TYPE_UD,
    585       [GEN7_TYPE_DF_3SRC]  = GEN7_TYPE_DF,
    586       /* map unknown types to unknown types */
    587       [0x4]                = 0xf,
    588       [0x5]                = 0xf,
    589       [0x6]                = 0xf,
    590       [0x7]                = 0xf,
    591    };
    592 
    593    ILO_DEV_ASSERT(inst->dev, 8, 8);
    594 
    595    inst->flag_subreg = GEN_EXTRACT(dw1, GEN8_3SRC_FLAG_SUBREG);
    596    inst->flag_reg = GEN_EXTRACT(dw1, GEN8_3SRC_FLAG_REG);
    597    inst->mask_ctrl = GEN_EXTRACT(dw1, GEN8_3SRC_MASKCTRL);
    598    inst->src0.absolute = (bool) (dw1 & GEN8_3SRC_SRC0_ABSOLUTE);
    599    inst->src0.negate = (bool) (dw1 & GEN8_3SRC_SRC0_NEGATE);
    600    inst->src1.negate = (bool) (dw1 & GEN8_3SRC_SRC1_NEGATE);
    601    inst->src1.absolute = (bool) (dw1 & GEN8_3SRC_SRC1_ABSOLUTE);
    602    inst->u.src2.negate = (bool) (dw1 & GEN8_3SRC_SRC2_NEGATE);
    603    inst->u.src2.absolute = (bool) (dw1 & GEN8_3SRC_SRC2_ABSOLUTE);
    604 
    605    inst->src0.base.file = GEN6_FILE_GRF;
    606    inst->src0.base.type = GEN_EXTRACT(dw1, GEN8_3SRC_SRC_TYPE);
    607    inst->src0.base.type = type_mapping[inst->src0.base.type];
    608 
    609    inst->src1.base.file = GEN6_FILE_GRF;
    610    inst->src1.base.type = inst->src0.base.type;
    611 
    612    inst->u.src2.base.file = GEN6_FILE_GRF;
    613    inst->u.src2.base.type = inst->src0.base.type;
    614 
    615    inst->dst.base.file = GEN6_FILE_GRF;
    616    inst->dst.base.type = GEN_EXTRACT(dw1, GEN8_3SRC_DST_TYPE);
    617    inst->dst.base.type = type_mapping[inst->dst.base.type];
    618    inst->dst.base.addr_mode = GEN6_ADDRMODE_DIRECT;
    619    inst->dst.horz_stride = GEN6_HORZSTRIDE_1;
    620 
    621    inst->dst.writemask = GEN_EXTRACT(dw1, GEN6_3SRC_DST_WRITEMASK);
    622    inst->dst.base.subreg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_SUBREG) <<
    623       GEN6_3SRC_DST_SUBREG__SHR;
    624    inst->dst.base.reg = GEN_EXTRACT(dw1, GEN6_3SRC_DST_REG);
    625 }
    626 
    627 static void
    628 disasm_inst_decode_3src_dw2_dw3_gen6(struct disasm_inst *inst,
    629                                      uint32_t dw2, uint32_t dw3)
    630 {
    631    const uint64_t qw = (uint64_t) dw3 << 32 | dw2;
    632    int i;
    633 
    634    ILO_DEV_ASSERT(inst->dev, 6, 8);
    635 
    636    for (i = 0; i < 3; i++) {
    637       struct disasm_src_operand *src = (i == 0) ? &inst->src0 :
    638                                        (i == 1) ? &inst->src1 :
    639                                        &inst->u.src2;
    640       const uint32_t dw = (i == 0) ? GEN_EXTRACT(qw, GEN6_3SRC_SRC_0) :
    641                           (i == 1) ? GEN_EXTRACT(qw, GEN6_3SRC_SRC_1) :
    642                           GEN_EXTRACT(qw, GEN6_3SRC_SRC_2);
    643 
    644       src->base.addr_mode = GEN6_ADDRMODE_DIRECT;
    645       src->base.reg = GEN_EXTRACT(dw, GEN6_3SRC_SRC_REG);
    646       src->base.subreg = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SUBREG) <<
    647          GEN6_3SRC_SRC_SUBREG__SHR;
    648 
    649       if (dw & GEN6_3SRC_SRC_REPCTRL) {
    650          src->vert_stride = GEN6_VERTSTRIDE_0;
    651          src->width = GEN6_WIDTH_1;
    652          src->horz_stride = GEN6_HORZSTRIDE_0;
    653       } else {
    654          src->vert_stride = GEN6_VERTSTRIDE_4;
    655          src->width = GEN6_WIDTH_4;
    656          src->horz_stride = GEN6_HORZSTRIDE_1;
    657       }
    658 
    659       src->swizzle_x = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_X);
    660       src->swizzle_y = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_Y);
    661       src->swizzle_z = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_Z);
    662       src->swizzle_w = GEN_EXTRACT(dw, GEN6_3SRC_SRC_SWIZZLE_W);
    663    }
    664 }
    665 
    666 /*
    667  * When GEN6_INST_CMPTCTRL of DW0 is set, the instruction has 64 bits and is
    668  * in EU_INSTRUCTION_COMPACT_TWO_SRC form.  We should have expanded it to its
    669  * original form.
    670  *
    671  * Depending on the opcode, the 128-bits instruction is in one of the
    672  * following forms
    673  *
    674  *  - EU_INSTRUCTION_BASIC_ONE_SRC
    675  *  - EU_INSTRUCTION_BASIC_TWO_SRC
    676  *  - EU_INSTRUCTION_BASIC_THREE_SRC
    677  *  - EU_INSTRUCTION_BRANCH_CONDITIONAL
    678  *  - EU_INSTRUCTION_BRANCH_ONE_SRC
    679  *  - EU_INSTRUCTION_BRANCH_TWO_SRC
    680  *  - EU_INSTRUCTION_ILLEGAL
    681  *  - EU_INSTRUCTION_MATH
    682  *  - EU_INSTRUCTION_NOP
    683  *  - EU_INSTRUCTION_SEND
    684  *
    685  * In EU_INSTRUCTION_BASIC_ONE_SRC form,
    686  *
    687  *  - DW0 is EU_INSTRUCTION_HEADER
    688  *  - DW1 is EU_INSTRUCTION_OPERAND_CONTROLS
    689  *  - DW2 is Source 0 and EU_INSTRUCTION_FLAGS
    690  *  - DW3 is reserved unless Source 0 is an immediate
    691  *
    692  * All other forms except EU_INSTRUCTION_BASIC_THREE_SRC are quite compatible
    693  * with EU_INSTRUCTION_BASIC_ONE_SRC.
    694  */
    695 static void
    696 disasm_inst_decode(struct disasm_inst *inst,
    697                    const uint32_t *dw)
    698 {
    699    assert(!(dw[0] & GEN6_INST_CMPTCTRL));
    700 
    701    disasm_inst_decode_dw0_gen6(inst, dw[0]);
    702 
    703    if (disasm_opcode_table[inst->opcode].src_count == 3) {
    704       if (ilo_dev_gen(inst->dev) >= ILO_GEN(8))
    705          disasm_inst_decode_3src_dw1_gen8(inst, dw[1]);
    706       else
    707          disasm_inst_decode_3src_dw1_gen6(inst, dw[1]);
    708       disasm_inst_decode_3src_dw2_dw3_gen6(inst, dw[2], dw[3]);
    709    } else {
    710       disasm_inst_decode_dw1_gen6(inst, dw[1]);
    711       disasm_inst_decode_dw2_dw3_gen6(inst, dw[2], dw[3]);
    712    }
    713 }
    714 
    715 static const char *
    716 disasm_inst_opcode(const struct disasm_inst *inst)
    717 {
    718    return (disasm_opcode_table[inst->opcode].name) ?
    719       disasm_opcode_table[inst->opcode].name : "BAD";
    720 }
    721 
    722 static const char *
    723 disasm_inst_pred_ctrl(const struct disasm_inst *inst)
    724 {
    725    if (inst->access_mode == GEN6_ALIGN_1) {
    726       switch (inst->pred_ctrl) {
    727       case GEN6_PREDCTRL_NORMAL: return "";
    728       case GEN6_PREDCTRL_ANYV:   return ".anyv";
    729       case GEN6_PREDCTRL_ALLV:   return ".allv";
    730       case GEN6_PREDCTRL_ANY2H:  return ".any2h";
    731       case GEN6_PREDCTRL_ALL2H:  return ".all2h";
    732       case GEN6_PREDCTRL_ANY4H:  return ".any4h";
    733       case GEN6_PREDCTRL_ALL4H:  return ".all4h";
    734       case GEN6_PREDCTRL_ANY8H:  return ".any8h";
    735       case GEN6_PREDCTRL_ALL8H:  return ".all8h";
    736       case GEN6_PREDCTRL_ANY16H: return ".any16h";
    737       case GEN6_PREDCTRL_ALL16H: return ".all16h";
    738       case GEN7_PREDCTRL_ANY32H: return ".any32h";
    739       case GEN7_PREDCTRL_ALL32H: return ".all32h";
    740       default:                   return ".BAD";
    741       }
    742    } else {
    743       switch (inst->pred_ctrl) {
    744       case GEN6_PREDCTRL_NORMAL: return "";
    745       case GEN6_PREDCTRL_X:      return ".x";
    746       case GEN6_PREDCTRL_Y:      return ".y";
    747       case GEN6_PREDCTRL_Z:      return ".z";
    748       case GEN6_PREDCTRL_W:      return ".w";
    749       default:                   return ".BAD";
    750       }
    751    }
    752 }
    753 
    754 static char
    755 disasm_inst_pred_inv(const struct disasm_inst *inst)
    756 {
    757    return (inst->pred_inv) ? '-' : '+';
    758 }
    759 
    760 static const char *
    761 disasm_inst_exec_size(const struct disasm_inst *inst)
    762 {
    763    switch (inst->exec_size) {
    764    case GEN6_EXECSIZE_1:   return "1";
    765    case GEN6_EXECSIZE_2:   return "2";
    766    case GEN6_EXECSIZE_4:   return "4";
    767    case GEN6_EXECSIZE_8:   return "8";
    768    case GEN6_EXECSIZE_16:  return "16";
    769    case GEN6_EXECSIZE_32:  return "32";
    770    default:                return "BAD";
    771    }
    772 }
    773 
    774 static const char *
    775 disasm_inst_fc(const struct disasm_inst *inst)
    776 {
    777    assert(inst->opcode == GEN6_OPCODE_MATH);
    778 
    779    switch (inst->fc) {
    780    case GEN6_MATH_INV:                 return "inv";
    781    case GEN6_MATH_LOG:                 return "log";
    782    case GEN6_MATH_EXP:                 return "exp";
    783    case GEN6_MATH_SQRT:                return "sqrt";
    784    case GEN6_MATH_RSQ:                 return "rsq";
    785    case GEN6_MATH_SIN:                 return "sin";
    786    case GEN6_MATH_COS:                 return "cos";
    787    case GEN6_MATH_FDIV:                return "fdiv";
    788    case GEN6_MATH_POW:                 return "pow";
    789    case GEN6_MATH_INT_DIV:             return "int_div";
    790    case GEN6_MATH_INT_DIV_QUOTIENT:    return "int_div_quotient";
    791    case GEN6_MATH_INT_DIV_REMAINDER:   return "int_div_remainder";
    792    case GEN8_MATH_INVM:                return "invm";
    793    case GEN8_MATH_RSQRTM:              return "rsqrtm";
    794    default:                            return "BAD";
    795    }
    796 }
    797 
    798 static const char *
    799 disasm_inst_sfid(const struct disasm_inst *inst)
    800 {
    801    assert(inst->opcode == GEN6_OPCODE_SEND ||
    802           inst->opcode == GEN6_OPCODE_SENDC);
    803 
    804    switch (inst->sfid) {
    805    case GEN6_SFID_NULL:          return "null";
    806    case GEN6_SFID_SAMPLER:       return "sampler";
    807    case GEN6_SFID_GATEWAY:       return "gateway";
    808    case GEN6_SFID_DP_SAMPLER:    return "dp sampler";
    809    case GEN6_SFID_DP_RC:         return "dp render";
    810    case GEN6_SFID_URB:           return "urb";
    811    case GEN6_SFID_SPAWNER:       return "spawner";
    812    case GEN6_SFID_VME:           return "vme";
    813    case GEN6_SFID_DP_CC:         return "dp const";
    814    case GEN7_SFID_DP_DC0:        return "dp data 0";
    815    case GEN7_SFID_PI:            return "pixel interp";
    816    case GEN75_SFID_DP_DC1:       return "dp data 1";
    817    default:                      return "BAD";
    818    }
    819 }
    820 
    821 static const char *
    822 disasm_inst_cond_modifier(const struct disasm_inst *inst)
    823 {
    824    switch (inst->cond_modifier) {
    825    case GEN6_COND_NONE:    return "";
    826    case GEN6_COND_Z:       return ".z";
    827    case GEN6_COND_NZ:      return ".nz";
    828    case GEN6_COND_G:       return ".g";
    829    case GEN6_COND_GE:      return ".ge";
    830    case GEN6_COND_L:       return ".l";
    831    case GEN6_COND_LE:      return ".le";
    832    case GEN6_COND_O:       return ".o";
    833    case GEN6_COND_U:       return ".u";
    834    default:                return ".BAD";
    835    }
    836 }
    837 
    838 static const char *
    839 disasm_inst_debug_ctrl(const struct disasm_inst *inst)
    840 {
    841    return (inst->debug_ctrl) ? ".breakpoint" : "";
    842 }
    843 
    844 static const char *
    845 disasm_inst_saturate(const struct disasm_inst *inst)
    846 {
    847    return (inst->saturate) ? ".sat" : "";
    848 }
    849 
    850 static const char *
    851 disasm_inst_flag_reg(const struct disasm_inst *inst)
    852 {
    853    static const char *flag_names[2][2] = {
    854       { "f0",   "f0.1" },
    855       { "f1.0", "f1.1" },
    856    };
    857 
    858    return (inst->flag_reg <= 1 && inst->flag_subreg <= 1) ?
    859       flag_names[inst->flag_reg][inst->flag_subreg] : "fBAD";
    860 }
    861 
    862 static const char *
    863 disasm_inst_access_mode(const struct disasm_inst *inst)
    864 {
    865    switch (inst->access_mode) {
    866    case GEN6_ALIGN_1:   return " align1";
    867    case GEN6_ALIGN_16:  return " align16";
    868    default:             return " alignBAD";
    869    }
    870 }
    871 
    872 static const char *
    873 disasm_inst_mask_ctrl(const struct disasm_inst *inst)
    874 {
    875    switch (inst->mask_ctrl) {
    876    case GEN6_MASKCTRL_NORMAL: return "";
    877    case GEN6_MASKCTRL_NOMASK: return " WE_all";
    878    default:                   return " WE_BAD";
    879    }
    880 }
    881 
    882 static const char *
    883 disasm_inst_dep_ctrl(const struct disasm_inst *inst)
    884 {
    885    switch (inst->dep_ctrl) {
    886    case GEN6_DEPCTRL_NORMAL:  return "";
    887    case GEN6_DEPCTRL_NODDCLR: return " NoDDClr";
    888    case GEN6_DEPCTRL_NODDCHK: return " NoDDChk";
    889    case GEN6_DEPCTRL_NEITHER: return " NoDDClr,NoDDChk";
    890    default:                   return " NoDDBAD";
    891    }
    892 }
    893 
    894 static const char *
    895 disasm_inst_qtr_ctrl(const struct disasm_inst *inst)
    896 {
    897    switch (inst->exec_size) {
    898    case GEN6_EXECSIZE_8:
    899       switch (inst->qtr_ctrl) {
    900       case GEN6_QTRCTRL_1Q:   return " 1Q";
    901       case GEN6_QTRCTRL_2Q:   return " 2Q";
    902       case GEN6_QTRCTRL_3Q:   return " 3Q";
    903       case GEN6_QTRCTRL_4Q:   return " 4Q";
    904       default:                return " BADQ";
    905       }
    906       break;
    907    case GEN6_EXECSIZE_16:
    908       switch (inst->qtr_ctrl) {
    909       case GEN6_QTRCTRL_1H:   return " 1H";
    910       case GEN6_QTRCTRL_2H:   return " 2H";
    911       default:                return " BADH";
    912       }
    913       break;
    914    default:
    915       return                  "";
    916    }
    917 
    918 }
    919 
    920 static const char *
    921 disasm_inst_thread_ctrl(const struct disasm_inst *inst)
    922 {
    923    switch (inst->thread_ctrl) {
    924    case GEN6_THREADCTRL_NORMAL:  return "";
    925    case GEN6_THREADCTRL_ATOMIC:  return " atomic";
    926    case GEN6_THREADCTRL_SWITCH:  return " switch";
    927    default:                      return " BAD";
    928    }
    929 }
    930 
    931 static const char *
    932 disasm_inst_acc_wr_ctrl(const struct disasm_inst *inst)
    933 {
    934    return (inst->acc_wr_ctrl) ? " AccWrEnable" : "";
    935 }
    936 
    937 static const char *
    938 disasm_inst_cmpt_ctrl(const struct disasm_inst *inst)
    939 {
    940    return (inst->cmpt_ctrl) ? " compacted" : "";
    941 }
    942 
    943 static const char *
    944 disasm_inst_eot(const struct disasm_inst *inst)
    945 {
    946    const uint32_t mdesc = inst->u.ud;
    947 
    948    if (inst->opcode == GEN6_OPCODE_SEND ||
    949        inst->opcode == GEN6_OPCODE_SENDC)
    950       return (mdesc & GEN6_MSG_EOT) ? " EOT" : "";
    951    else
    952       return "";
    953 }
    954 
    955 static const char *
    956 disasm_inst_file(const struct disasm_inst *inst,
    957                  const struct disasm_operand *operand,
    958                  bool *multi_regs)
    959 {
    960    switch (operand->file) {
    961    case GEN6_FILE_ARF:
    962       switch (operand->reg & 0xf0) {
    963       case GEN6_ARF_NULL:  *multi_regs = false; return "null";
    964       case GEN6_ARF_A0:    *multi_regs = true;  return "a";
    965       case GEN6_ARF_ACC0:  *multi_regs = true;  return "acc";
    966       case GEN6_ARF_F0:    *multi_regs = true;  return "f";
    967       case GEN6_ARF_SR0:   *multi_regs = true;  return "sr";
    968       case GEN6_ARF_CR0:   *multi_regs = true;  return "cr";
    969       case GEN6_ARF_N0:    *multi_regs = true;  return "n";
    970       case GEN6_ARF_IP:    *multi_regs = false; return "ip";
    971       case GEN6_ARF_TDR:   *multi_regs = false; return "tdr";
    972       case GEN7_ARF_TM0:   *multi_regs = true;  return "tm";
    973       default:             *multi_regs = false; return "BAD";
    974       }
    975       break;
    976    case GEN6_FILE_GRF:     *multi_regs = true;  return "g";
    977    case GEN6_FILE_MRF:     *multi_regs = true;  return "m";
    978    case GEN6_FILE_IMM:     *multi_regs = true;  return "";
    979    default:                *multi_regs = false; return "BAD";
    980    }
    981 }
    982 
    983 static const char *
    984 disasm_inst_type(const struct disasm_inst *inst,
    985                  const struct disasm_operand *operand)
    986 {
    987    if (operand->file == GEN6_FILE_IMM) {
    988       switch (operand->type) {
    989       case GEN6_TYPE_UD:      return "UD";
    990       case GEN6_TYPE_D:       return "D";
    991       case GEN6_TYPE_UW:      return "UW";
    992       case GEN6_TYPE_W:       return "W";
    993       case GEN6_TYPE_UV_IMM:  return "UV";
    994       case GEN6_TYPE_VF_IMM:  return "VF";
    995       case GEN6_TYPE_V_IMM:   return "V";
    996       case GEN6_TYPE_F:       return "F";
    997       case GEN8_TYPE_DF_IMM:  return "DF";
    998       case GEN8_TYPE_HF_IMM:  return "HF";
    999       default:                return "BAD";
   1000       }
   1001    } else {
   1002       switch (operand->type) {
   1003       case GEN6_TYPE_UD:      return "UD";
   1004       case GEN6_TYPE_D:       return "D";
   1005       case GEN6_TYPE_UW:      return "UW";
   1006       case GEN6_TYPE_W:       return "W";
   1007       case GEN6_TYPE_UB:      return "UB";
   1008       case GEN6_TYPE_B:       return "B";
   1009       case GEN7_TYPE_DF:      return "DF";
   1010       case GEN6_TYPE_F:       return "F";
   1011       case GEN8_TYPE_UQ:      return "UQ";
   1012       case GEN8_TYPE_Q:       return "Q";
   1013       case GEN8_TYPE_HF:      return "HF";
   1014       default:                return "BAD";
   1015       }
   1016    }
   1017 }
   1018 
   1019 static const char *
   1020 disasm_inst_vert_stride(const struct disasm_inst *inst, unsigned vert_stride)
   1021 {
   1022    switch (vert_stride) {
   1023    case GEN6_VERTSTRIDE_0:    return "0";
   1024    case GEN6_VERTSTRIDE_1:    return "1";
   1025    case GEN6_VERTSTRIDE_2:    return "2";
   1026    case GEN6_VERTSTRIDE_4:    return "4";
   1027    case GEN6_VERTSTRIDE_8:    return "8";
   1028    case GEN6_VERTSTRIDE_16:   return "16";
   1029    case GEN6_VERTSTRIDE_32:   return "32";
   1030    case GEN6_VERTSTRIDE_VXH:  return "VxH";
   1031    default:                   return "BAD";
   1032    }
   1033 }
   1034 
   1035 static const char *
   1036 disasm_inst_width(const struct disasm_inst *inst, unsigned width)
   1037 {
   1038    switch (width) {
   1039    case GEN6_WIDTH_1:   return "1";
   1040    case GEN6_WIDTH_2:   return "2";
   1041    case GEN6_WIDTH_4:   return "4";
   1042    case GEN6_WIDTH_8:   return "8";
   1043    case GEN6_WIDTH_16:  return "16";
   1044    default:             return "BAD";
   1045    }
   1046 }
   1047 
   1048 static const char *
   1049 disasm_inst_horz_stride(const struct disasm_inst *inst, unsigned horz_stride)
   1050 {
   1051    switch (horz_stride) {
   1052    case GEN6_HORZSTRIDE_0: return "0";
   1053    case GEN6_HORZSTRIDE_1: return "1";
   1054    case GEN6_HORZSTRIDE_2: return "2";
   1055    case GEN6_HORZSTRIDE_4: return "4";
   1056    default:                return "BAD";
   1057    }
   1058 }
   1059 
   1060 static const char *
   1061 disasm_inst_writemask(const struct disasm_inst *inst, unsigned writemask)
   1062 {
   1063    switch (writemask) {
   1064    case 0x0:   return ".";
   1065    case 0x1:   return ".x";
   1066    case 0x2:   return ".y";
   1067    case 0x3:   return ".xy";
   1068    case 0x4:   return ".z";
   1069    case 0x5:   return ".xz";
   1070    case 0x6:   return ".yz";
   1071    case 0x7:   return ".xyz";
   1072    case 0x8:   return ".w";
   1073    case 0x9:   return ".xw";
   1074    case 0xa:   return ".yw";
   1075    case 0xb:   return ".xyw";
   1076    case 0xc:   return ".zw";
   1077    case 0xd:   return ".xzw";
   1078    case 0xe:   return ".yzw";
   1079    case 0xf:   return "";
   1080    default:    return ".BAD";
   1081    }
   1082 }
   1083 
   1084 static const char *
   1085 disasm_inst_negate(const struct disasm_inst *inst, bool negate)
   1086 {
   1087    if (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) {
   1088       switch (inst->opcode) {
   1089       case GEN6_OPCODE_AND:
   1090       case GEN6_OPCODE_NOT:
   1091       case GEN6_OPCODE_OR:
   1092       case GEN6_OPCODE_XOR:
   1093          return (negate) ? "~" : "";
   1094          break;
   1095       default:
   1096          break;
   1097       }
   1098    }
   1099 
   1100    return (negate) ? "-" : "";
   1101 }
   1102 
   1103 static const char *
   1104 disasm_inst_absolute(const struct disasm_inst *inst, bool absolute)
   1105 {
   1106    return (absolute) ? "(abs)" : "";
   1107 }
   1108 
   1109 static const char *
   1110 disasm_inst_mdesc_sampler_op(const struct disasm_inst *inst, int op)
   1111 {
   1112    switch (op) {
   1113    case GEN6_MSG_SAMPLER_SAMPLE:       return "sample";
   1114    case GEN6_MSG_SAMPLER_SAMPLE_B:     return "sample_b";
   1115    case GEN6_MSG_SAMPLER_SAMPLE_L:     return "sample_l";
   1116    case GEN6_MSG_SAMPLER_SAMPLE_C:     return "sample_c";
   1117    case GEN6_MSG_SAMPLER_SAMPLE_D:     return "sample_d";
   1118    case GEN6_MSG_SAMPLER_SAMPLE_B_C:   return "sample_b_c";
   1119    case GEN6_MSG_SAMPLER_SAMPLE_L_C:   return "sample_l_c";
   1120    case GEN6_MSG_SAMPLER_LD:           return "ld";
   1121    case GEN6_MSG_SAMPLER_GATHER4:      return "gather4";
   1122    case GEN6_MSG_SAMPLER_LOD:          return "lod";
   1123    case GEN6_MSG_SAMPLER_RESINFO:      return "resinfo";
   1124    case GEN6_MSG_SAMPLER_SAMPLEINFO:   return "sampleinfo";
   1125    case GEN7_MSG_SAMPLER_GATHER4_C:    return "gather4_c";
   1126    case GEN7_MSG_SAMPLER_GATHER4_PO:   return "gather4_po";
   1127    case GEN7_MSG_SAMPLER_GATHER4_PO_C: return "gather4_po_c";
   1128    case GEN7_MSG_SAMPLER_SAMPLE_D_C:   return "sample_d_c";
   1129    case GEN7_MSG_SAMPLER_SAMPLE_LZ:    return "sample_lz";
   1130    case GEN7_MSG_SAMPLER_SAMPLE_C_LC:  return "sample_c_lc";
   1131    case GEN7_MSG_SAMPLER_LD_LZ:        return "ld_lz";
   1132    case GEN7_MSG_SAMPLER_LD_MCS:       return "ld_mcs";
   1133    case GEN7_MSG_SAMPLER_LD2DMS:       return "ld2dms";
   1134    case GEN7_MSG_SAMPLER_LD2DSS:       return "ld2dss";
   1135    default:                            return "BAD";
   1136    }
   1137 }
   1138 
   1139 static const char *
   1140 disasm_inst_mdesc_sampler_simd(const struct disasm_inst *inst, int simd)
   1141 {
   1142    switch (simd) {
   1143    case GEN6_MSG_SAMPLER_SIMD4X2:   return "SIMD4x2";
   1144    case GEN6_MSG_SAMPLER_SIMD8:     return "SIMD8";
   1145    case GEN6_MSG_SAMPLER_SIMD16:    return "SIMD16";
   1146    case GEN6_MSG_SAMPLER_SIMD32_64: return "SIMD32";
   1147    default:                         return "BAD";
   1148    }
   1149 }
   1150 
   1151 static const char *
   1152 disasm_inst_mdesc_urb_op(const struct disasm_inst *inst, int op)
   1153 {
   1154    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
   1155       switch (op) {
   1156       case GEN7_MSG_URB_WRITE_HWORD:   return "write HWord";
   1157       case GEN7_MSG_URB_WRITE_OWORD:   return "write OWord";
   1158       case GEN7_MSG_URB_READ_HWORD:    return "read HWord";
   1159       case GEN7_MSG_URB_READ_OWORD:    return "read OWord";
   1160       case GEN7_MSG_URB_ATOMIC_MOV:    return "atomic mov";
   1161       case GEN7_MSG_URB_ATOMIC_INC:    return "atomic inc";
   1162       default:                         return "BAD";
   1163       }
   1164    } else {
   1165       switch (op) {
   1166       case GEN6_MSG_URB_WRITE:         return "urb_write";
   1167       case GEN6_MSG_URB_FF_SYNC:       return "ff_sync";
   1168       default:                         return "BAD";
   1169       }
   1170    }
   1171 }
   1172 
   1173 static const char *
   1174 disasm_inst_mdesc_dp_op_gen6(const struct disasm_inst *inst,
   1175                              int sfid, int op)
   1176 {
   1177    ILO_DEV_ASSERT(inst->dev, 6, 6);
   1178 
   1179    switch (op) {
   1180    case GEN6_MSG_DP_OWORD_BLOCK_READ:           return "OWORD block read";
   1181    case GEN6_MSG_DP_RT_UNORM_READ:              return "RT UNORM read";
   1182    case GEN6_MSG_DP_OWORD_DUAL_BLOCK_READ:      return "OWORD dual block read";
   1183    case GEN6_MSG_DP_MEDIA_BLOCK_READ:           return "media block read";
   1184    case GEN6_MSG_DP_UNALIGNED_OWORD_BLOCK_READ: return "unaligned OWORD block read";
   1185    case GEN6_MSG_DP_DWORD_SCATTERED_READ:       return "DWORD scattered read";
   1186    case GEN6_MSG_DP_DWORD_ATOMIC_WRITE:         return "DWORD atomic write";
   1187    case GEN6_MSG_DP_OWORD_BLOCK_WRITE:          return "OWORD block write";
   1188    case GEN6_MSG_DP_OWORD_DUAL_BLOCK_WRITE:     return "OWORD dual block_write";
   1189    case GEN6_MSG_DP_MEDIA_BLOCK_WRITE:          return "media block write";
   1190    case GEN6_MSG_DP_DWORD_SCATTERED_WRITE:      return "DWORD scattered write";
   1191    case GEN6_MSG_DP_RT_WRITE:                   return "RT write";
   1192    case GEN6_MSG_DP_SVB_WRITE:                  return "SVB write";
   1193    case GEN6_MSG_DP_RT_UNORM_WRITE:             return "RT UNORM write";
   1194    default:                                     return "BAD";
   1195    }
   1196 }
   1197 
   1198 static const char *
   1199 disasm_inst_mdesc_dp_op_gen7(const struct disasm_inst *inst,
   1200                              int sfid, int op)
   1201 {
   1202    ILO_DEV_ASSERT(inst->dev, 7, 7);
   1203 
   1204    switch (sfid) {
   1205    case GEN6_SFID_DP_SAMPLER:
   1206       switch (op) {
   1207       case GEN7_MSG_DP_SAMPLER_UNALIGNED_OWORD_BLOCK_READ: return "OWORD block read";
   1208       case GEN7_MSG_DP_SAMPLER_MEDIA_BLOCK_READ:         return "media block read";
   1209       default:                                           return "BAD";
   1210       }
   1211    case GEN6_SFID_DP_RC:
   1212       switch (op) {
   1213       case GEN7_MSG_DP_RC_MEDIA_BLOCK_READ:              return "media block read";
   1214       case GEN7_MSG_DP_RC_TYPED_SURFACE_READ:            return "typed surface read";
   1215       case GEN7_MSG_DP_RC_TYPED_ATOMIC_OP:               return "typed atomic op";
   1216       case GEN7_MSG_DP_RC_MEMORY_FENCE:                  return "memory fence";
   1217       case GEN7_MSG_DP_RC_MEDIA_BLOCK_WRITE:             return "media block write";
   1218       case GEN7_MSG_DP_RC_RT_WRITE:                      return "RT write";
   1219       case GEN7_MSG_DP_RC_TYPED_SURFACE_WRITE:           return "typed surface write";
   1220       default:                                           return "BAD";
   1221       }
   1222    case GEN6_SFID_DP_CC:
   1223       switch (op) {
   1224       case GEN7_MSG_DP_CC_OWORD_BLOCK_READ:              return "OWROD block read";
   1225       case GEN7_MSG_DP_CC_UNALIGNED_OWORD_BLOCK_READ:    return "unaligned OWORD block read";
   1226       case GEN7_MSG_DP_CC_OWORD_DUAL_BLOCK_READ:         return "OWORD dual block read";
   1227       case GEN7_MSG_DP_CC_DWORD_SCATTERED_READ:          return "DWORD scattered read";
   1228       default:                                           return "BAD";
   1229       }
   1230    case GEN7_SFID_DP_DC0:
   1231       switch (op) {
   1232       case GEN7_MSG_DP_DC0_OWORD_BLOCK_READ:             return "OWORD block read";
   1233       case GEN7_MSG_DP_DC0_UNALIGNED_OWORD_BLOCK_READ:   return "unaligned OWORD block read";
   1234       case GEN7_MSG_DP_DC0_OWORD_DUAL_BLOCK_READ:        return "OWORD dual block read";
   1235       case GEN7_MSG_DP_DC0_DWORD_SCATTERED_READ:         return "DWORD scattered read";
   1236       case GEN7_MSG_DP_DC0_BYTE_SCATTERED_READ:          return "BYTE scattered read";
   1237       case GEN7_MSG_DP_DC0_UNTYPED_SURFACE_READ:         return "untyped surface read";
   1238       case GEN7_MSG_DP_DC0_UNTYPED_ATOMIC_OP:            return "untyped atomic op";
   1239       case GEN7_MSG_DP_DC0_MEMORY_FENCE:                 return "memory fence";
   1240       case GEN7_MSG_DP_DC0_OWORD_BLOCK_WRITE:            return "OWORD block write";
   1241       case GEN7_MSG_DP_DC0_OWORD_DUAL_BLOCK_WRITE:       return "OWORD dual block write";
   1242       case GEN7_MSG_DP_DC0_DWORD_SCATTERED_WRITE:        return "OWORD scattered write";
   1243       case GEN7_MSG_DP_DC0_BYTE_SCATTERED_WRITE:         return "BYTE scattered write";
   1244       case GEN7_MSG_DP_DC0_UNTYPED_SURFACE_WRITE:        return "untyped surface write";
   1245       default:                                           return "BAD";
   1246       }
   1247    default:                                              return "BAD";
   1248    }
   1249 }
   1250 
   1251 static const char *
   1252 disasm_inst_mdesc_dp_op_gen75(const struct disasm_inst *inst,
   1253                               int sfid, int op)
   1254 {
   1255    ILO_DEV_ASSERT(inst->dev, 7.5, 8);
   1256 
   1257    switch (sfid) {
   1258    case GEN6_SFID_DP_SAMPLER:
   1259       switch (op) {
   1260       case GEN75_MSG_DP_SAMPLER_READ_SURFACE_INFO:          return "read surface info";
   1261       case GEN75_MSG_DP_SAMPLER_UNALIGNED_OWORD_BLOCK_READ: return "unaligned OWORD block read";
   1262       case GEN75_MSG_DP_SAMPLER_MEDIA_BLOCK_READ:           return "media block read";
   1263       default:                                              return "BAD";
   1264       }
   1265 
   1266    case GEN6_SFID_DP_RC:
   1267       switch (op) {
   1268       case GEN75_MSG_DP_RC_MEDIA_BLOCK_READ:                return "media block read";
   1269       case GEN75_MSG_DP_RC_MEMORY_FENCE:                    return "memory fence";
   1270       case GEN75_MSG_DP_RC_MEDIA_BLOCK_WRITE:               return "media block write";
   1271       case GEN75_MSG_DP_RC_RT_WRITE:                        return "RT write";
   1272       default:                                              return "BAD";
   1273       }
   1274    case GEN6_SFID_DP_CC:
   1275       switch (op) {
   1276       case GEN75_MSG_DP_CC_OWORD_BLOCK_READ:                return "OWROD block read";
   1277       case GEN75_MSG_DP_CC_UNALIGNED_OWORD_BLOCK_READ:      return "unaligned OWORD block read";
   1278       case GEN75_MSG_DP_CC_OWORD_DUAL_BLOCK_READ:           return "OWORD dual block read";
   1279       case GEN75_MSG_DP_CC_DWORD_SCATTERED_READ:            return "DWORD scattered read";
   1280       default:                                              return "BAD";
   1281       }
   1282    case GEN7_SFID_DP_DC0:
   1283       switch (op) {
   1284       case GEN75_MSG_DP_DC0_OWORD_BLOCK_READ:               return "OWORD block read";
   1285       case GEN75_MSG_DP_DC0_UNALIGNED_OWORD_BLOCK_READ:     return "unaligned OWORD block read";
   1286       case GEN75_MSG_DP_DC0_OWORD_DUAL_BLOCK_READ:          return "OWORD dual block read";
   1287       case GEN75_MSG_DP_DC0_DWORD_SCATTERED_READ:           return "DWORD scattered read";
   1288       case GEN75_MSG_DP_DC0_BYTE_SCATTERED_READ:            return "BYTE scattered read";
   1289       case GEN75_MSG_DP_DC0_MEMORY_FENCE:                   return "memory fence";
   1290       case GEN75_MSG_DP_DC0_OWORD_BLOCK_WRITE:              return "OWORD block write";
   1291       case GEN75_MSG_DP_DC0_OWORD_DUAL_BLOCK_WRITE:         return "OWORD dual block write";
   1292       case GEN75_MSG_DP_DC0_DWORD_SCATTERED_WRITE:          return "OWORD scattered write";
   1293       case GEN75_MSG_DP_DC0_BYTE_SCATTERED_WRITE:           return "BYTE scattered write";
   1294       default:                                              return "BAD";
   1295       }
   1296    case GEN75_SFID_DP_DC1:
   1297       switch (op) {
   1298       case GEN75_MSG_DP_DC1_UNTYPED_SURFACE_READ:           return "untyped surface read";
   1299       case GEN75_MSG_DP_DC1_UNTYPED_ATOMIC_OP:              return "DC untyped atomic op";
   1300       case GEN75_MSG_DP_DC1_UNTYPED_ATOMIC_OP_SIMD4X2:      return "DC untyped 4x2 atomic op";
   1301       case GEN75_MSG_DP_DC1_MEDIA_BLOCK_READ:               return "DC media block read";
   1302       case GEN75_MSG_DP_DC1_TYPED_SURFACE_READ:             return "DC typed surface read";
   1303       case GEN75_MSG_DP_DC1_TYPED_ATOMIC_OP:                return "DC typed atomic";
   1304       case GEN75_MSG_DP_DC1_TYPED_ATOMIC_OP_SIMD4X2:        return "DC typed 4x2 atomic op";
   1305       case GEN75_MSG_DP_DC1_UNTYPED_SURFACE_WRITE:          return "DC untyped surface write";
   1306       case GEN75_MSG_DP_DC1_MEDIA_BLOCK_WRITE:              return "DC media block write";
   1307       case GEN75_MSG_DP_DC1_ATOMIC_COUNTER_OP:              return "DC atomic counter op";
   1308       case GEN75_MSG_DP_DC1_ATOMIC_COUNTER_OP_SIMD4X2:      return "DC 4x2 atomic counter op";
   1309       case GEN75_MSG_DP_DC1_TYPED_SURFACE_WRITE:            return "DC typed surface write";
   1310       default:                                              return "BAD";
   1311       }
   1312    default:                                              return "BAD";
   1313    }
   1314 }
   1315 
   1316 static const char *
   1317 disasm_inst_mdesc_dp_op(const struct disasm_inst *inst, int sfid, int op)
   1318 {
   1319    switch (ilo_dev_gen(inst->dev)) {
   1320    case ILO_GEN(8):
   1321    case ILO_GEN(7.5):   return disasm_inst_mdesc_dp_op_gen75(inst, sfid, op);
   1322    case ILO_GEN(7):     return disasm_inst_mdesc_dp_op_gen7(inst, sfid, op);
   1323    case ILO_GEN(6):     return disasm_inst_mdesc_dp_op_gen6(inst, sfid, op);
   1324    default:             return "BAD";
   1325    }
   1326 }
   1327 
   1328 static const char *
   1329 disasm_inst_mdesc_dp_untyped_surface_simd_mode(const struct disasm_inst *inst,
   1330                                                uint32_t mdesc)
   1331 {
   1332    switch (mdesc & GEN7_MSG_DP_UNTYPED_MODE__MASK) {
   1333    case GEN7_MSG_DP_UNTYPED_MODE_SIMD4X2: return "SIMD4x2";
   1334    case GEN7_MSG_DP_UNTYPED_MODE_SIMD16:  return "SIMD16";
   1335    case GEN7_MSG_DP_UNTYPED_MODE_SIMD8:   return "SIMD8";
   1336    default:                               return "BAD";
   1337    }
   1338 }
   1339 
   1340 static const char *
   1341 disasm_inst_mdesc_dp_rt_write_simd_mode(const struct disasm_inst *inst,
   1342                                         uint32_t mdesc)
   1343 {
   1344    switch (mdesc & GEN6_MSG_DP_RT_MODE__MASK) {
   1345    case GEN6_MSG_DP_RT_MODE_SIMD16:             return "SIMD16";
   1346    case GEN6_MSG_DP_RT_MODE_SIMD16_REPDATA:     return "SIMD16/RepData";
   1347    case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_LO:   return "SIMD8/DualSrcLow";
   1348    case GEN6_MSG_DP_RT_MODE_SIMD8_DUALSRC_HI:   return "SIMD8/DualSrcHigh";
   1349    case GEN6_MSG_DP_RT_MODE_SIMD8_LO:           return "SIMD8";
   1350    case GEN6_MSG_DP_RT_MODE_SIMD8_IMAGE_WR:     return "SIMD8/ImageWrite";
   1351    default:                                     return "BAD";
   1352    }
   1353 }
   1354 
   1355 static bool
   1356 disasm_inst_is_null(const struct disasm_inst *inst,
   1357                     const struct disasm_operand *operand)
   1358 {
   1359    return (operand->file == GEN6_FILE_ARF && operand->reg == GEN6_ARF_NULL);
   1360 }
   1361 
   1362 static int
   1363 disasm_inst_type_size(const struct disasm_inst *inst,
   1364                       const struct disasm_operand *operand)
   1365 {
   1366    assert(operand->file != GEN6_FILE_IMM);
   1367 
   1368    switch (operand->type) {
   1369    case GEN6_TYPE_UD:      return 4;
   1370    case GEN6_TYPE_D:       return 4;
   1371    case GEN6_TYPE_UW:      return 2;
   1372    case GEN6_TYPE_W:       return 2;
   1373    case GEN6_TYPE_UB:      return 1;
   1374    case GEN6_TYPE_B:       return 1;
   1375    case GEN7_TYPE_DF:      return 8;
   1376    case GEN6_TYPE_F:       return 4;
   1377    default:                return 1;
   1378    }
   1379 }
   1380 
   1381 static void
   1382 disasm_printer_reset(struct disasm_printer *printer)
   1383 {
   1384    printer->buf[0] = '\0';
   1385    printer->len = 0;
   1386 }
   1387 
   1388 static const char *
   1389 disasm_printer_get_string(struct disasm_printer *printer)
   1390 {
   1391    return printer->buf;
   1392 }
   1393 
   1394 static void _util_printf_format(2, 3)
   1395 disasm_printer_add(struct disasm_printer *printer, const char *format, ...)
   1396 {
   1397    const size_t avail = sizeof(printer->buf) - printer->len;
   1398    va_list ap;
   1399    int written;
   1400 
   1401    va_start(ap, format);
   1402    written = vsnprintf(printer->buf + printer->len, avail, format, ap);
   1403    va_end(ap);
   1404 
   1405    /* truncated */
   1406    if (written < 0 || written >= avail) {
   1407       memcpy(printer->buf + sizeof(printer->buf) - 4, "...", 4);
   1408       printer->len = sizeof(printer->buf) - 1;
   1409    } else {
   1410       printer->len += written;
   1411    }
   1412 }
   1413 
   1414 /**
   1415  * Pad to the specified column.
   1416  */
   1417 static void
   1418 disasm_printer_column(struct disasm_printer *printer, int col)
   1419 {
   1420    int len = DISASM_PRINTER_COLUMN_WIDTH * col;
   1421 
   1422    if (len <= printer->len) {
   1423       if (!printer->len)
   1424          return;
   1425 
   1426       /* at least one space */
   1427       len = printer->len + 1;
   1428    }
   1429 
   1430    if (len >= sizeof(printer->buf)) {
   1431       len = sizeof(printer->buf) - 1;
   1432 
   1433       if (len <= printer->len)
   1434          return;
   1435    }
   1436 
   1437    memset(printer->buf + printer->len, ' ', len - printer->len);
   1438    printer->len = len;
   1439    printer->buf[printer->len] = '\0';
   1440 }
   1441 
   1442 static void
   1443 disasm_printer_add_op(struct disasm_printer *printer,
   1444                       const struct disasm_inst *inst)
   1445 {
   1446    if (inst->pred_ctrl != GEN6_PREDCTRL_NONE) {
   1447       disasm_printer_add(printer, "(%c%s%s) ",
   1448             disasm_inst_pred_inv(inst),
   1449             disasm_inst_flag_reg(inst),
   1450             disasm_inst_pred_ctrl(inst));
   1451    }
   1452 
   1453    disasm_printer_add(printer, "%s%s%s%s",
   1454          disasm_inst_opcode(inst),
   1455          disasm_inst_saturate(inst),
   1456          disasm_inst_debug_ctrl(inst),
   1457          disasm_inst_cond_modifier(inst));
   1458 
   1459    if (inst->cond_modifier != GEN6_COND_NONE) {
   1460       switch (inst->opcode) {
   1461       case GEN6_OPCODE_SEL:
   1462       case GEN6_OPCODE_IF:
   1463       case GEN6_OPCODE_WHILE:
   1464          /* these do not update flag registers */
   1465          break;
   1466       default:
   1467          disasm_printer_add(printer, ".%s", disasm_inst_flag_reg(inst));
   1468          break;
   1469       }
   1470    }
   1471 
   1472    if (inst->opcode == GEN6_OPCODE_MATH)
   1473       disasm_printer_add(printer, " %s", disasm_inst_fc(inst));
   1474    if (inst->opcode != GEN6_OPCODE_NOP)
   1475       disasm_printer_add(printer, "(%s)", disasm_inst_exec_size(inst));
   1476 }
   1477 
   1478 static void
   1479 disasm_printer_add_operand(struct disasm_printer *printer,
   1480                            const struct disasm_inst *inst,
   1481                            const struct disasm_operand *operand)
   1482 {
   1483    const char *name;
   1484    bool multi_regs;
   1485 
   1486    name = disasm_inst_file(inst, operand, &multi_regs);
   1487    if (!multi_regs) {
   1488       disasm_printer_add(printer, "%s", name);
   1489       return;
   1490    }
   1491 
   1492    if (operand->file == GEN6_FILE_IMM) {
   1493       switch (operand->type) {
   1494       case GEN6_TYPE_UD:
   1495          disasm_printer_add(printer, "0x%08xUD", inst->u.ud);
   1496          break;
   1497       case GEN6_TYPE_D:
   1498          disasm_printer_add(printer, "%dD", inst->u.d);
   1499          break;
   1500       case GEN6_TYPE_UW:
   1501          disasm_printer_add(printer, "0x%04xUW", inst->u.uw);
   1502          break;
   1503       case GEN6_TYPE_W:
   1504          disasm_printer_add(printer, "%dW", inst->u.w);
   1505          break;
   1506       case GEN6_TYPE_UV_IMM:
   1507          disasm_printer_add(printer, "0x%08xUV", inst->u.ud);
   1508          break;
   1509       case GEN6_TYPE_VF_IMM:
   1510          disasm_printer_add(printer, "Vector Float");
   1511          break;
   1512       case GEN6_TYPE_V_IMM:
   1513          disasm_printer_add(printer, "0x%08xV", inst->u.ud);
   1514          break;
   1515       case GEN6_TYPE_F:
   1516          disasm_printer_add(printer, "%-gF", uif(inst->u.f));
   1517          break;
   1518       default:
   1519          disasm_printer_add(printer, "BAD");
   1520          break;
   1521       }
   1522 
   1523       return;
   1524    }
   1525 
   1526    if (operand->addr_mode == GEN6_ADDRMODE_DIRECT) {
   1527       unsigned reg, subreg;
   1528 
   1529       reg = operand->reg;
   1530       if (operand->file == GEN6_FILE_ARF)
   1531          reg &= 0xf;
   1532 
   1533       subreg = operand->subreg / disasm_inst_type_size(inst, operand);
   1534 
   1535       if (subreg)
   1536          disasm_printer_add(printer, "%s%d.%d", name, reg, subreg);
   1537       else
   1538          disasm_printer_add(printer, "%s%d", name, reg);
   1539    } else {
   1540       disasm_printer_add(printer, "%s[a0.%d %d]",
   1541             name, operand->addr_subreg, operand->addr_imm);
   1542    }
   1543 }
   1544 
   1545 static void
   1546 disasm_printer_add_dst(struct disasm_printer *printer,
   1547                        const struct disasm_inst *inst,
   1548                        const struct disasm_dst_operand *dst)
   1549 {
   1550    disasm_printer_add_operand(printer, inst, &dst->base);
   1551 
   1552    /* dst is an immediate when in EU_INSTRUCTION_BRANCH_CONDITIONAL form */
   1553    if (disasm_inst_is_null(inst, &dst->base) ||
   1554        dst->base.file == GEN6_FILE_IMM)
   1555       return;
   1556 
   1557    disasm_printer_add(printer, "<%s>%s%s",
   1558          disasm_inst_horz_stride(inst, dst->horz_stride),
   1559          disasm_inst_writemask(inst, dst->writemask),
   1560          disasm_inst_type(inst, &dst->base));
   1561 }
   1562 
   1563 static void
   1564 disasm_printer_add_src(struct disasm_printer *printer,
   1565                        const struct disasm_inst *inst,
   1566                        const struct disasm_src_operand *src)
   1567 {
   1568    static const char swizzle_chars[4] = { 'x', 'y', 'z', 'w' };
   1569    char swizzle[5];
   1570 
   1571    disasm_printer_add(printer, "%s%s",
   1572          disasm_inst_negate(inst, src->negate),
   1573          disasm_inst_absolute(inst, src->absolute));
   1574 
   1575    disasm_printer_add_operand(printer, inst, &src->base);
   1576 
   1577    if (disasm_inst_is_null(inst, &src->base) ||
   1578        src->base.file == GEN6_FILE_IMM)
   1579       return;
   1580 
   1581    if (src->swizzle_x == 0 && src->swizzle_y == 1 &&
   1582        src->swizzle_z == 2 && src->swizzle_w == 3) {
   1583       swizzle[0] = '\0';
   1584    } else if (src->swizzle_x == src->swizzle_y &&
   1585               src->swizzle_x == src->swizzle_z &&
   1586               src->swizzle_x == src->swizzle_w) {
   1587       swizzle[0] = swizzle_chars[src->swizzle_x];
   1588       swizzle[1] = '\0';
   1589    } else {
   1590       swizzle[0] = swizzle_chars[src->swizzle_x];
   1591       swizzle[1] = swizzle_chars[src->swizzle_y];
   1592       swizzle[2] = swizzle_chars[src->swizzle_z];
   1593       swizzle[3] = swizzle_chars[src->swizzle_w];
   1594       swizzle[4] = '\0';
   1595    }
   1596 
   1597    disasm_printer_add(printer, "<%s,%s,%s>%s%s",
   1598          disasm_inst_vert_stride(inst, src->vert_stride),
   1599          disasm_inst_width(inst, src->width),
   1600          disasm_inst_horz_stride(inst, src->horz_stride),
   1601          swizzle,
   1602          disasm_inst_type(inst, &src->base));
   1603 }
   1604 
   1605 static void
   1606 disasm_printer_add_ctrl(struct disasm_printer *printer,
   1607                         const struct disasm_inst *inst)
   1608 {
   1609    if (inst->opcode == GEN6_OPCODE_NOP) {
   1610       disasm_printer_add(printer, ";");
   1611       return;
   1612    }
   1613 
   1614    disasm_printer_add(printer, "{%s%s%s%s%s%s%s%s };",
   1615          disasm_inst_access_mode(inst),
   1616          disasm_inst_mask_ctrl(inst),
   1617          disasm_inst_dep_ctrl(inst),
   1618          disasm_inst_qtr_ctrl(inst),
   1619          disasm_inst_cmpt_ctrl(inst),
   1620          disasm_inst_thread_ctrl(inst),
   1621          disasm_inst_acc_wr_ctrl(inst),
   1622          disasm_inst_eot(inst));
   1623 }
   1624 
   1625 static void
   1626 disasm_printer_add_mdesc_sampler(struct disasm_printer *printer,
   1627                                  const struct disasm_inst *inst,
   1628                                  uint32_t mdesc)
   1629 {
   1630    int op, simd;
   1631 
   1632    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
   1633       op = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_OP);
   1634       simd = GEN_EXTRACT(mdesc, GEN7_MSG_SAMPLER_SIMD);
   1635    } else {
   1636       op = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_OP);
   1637       simd = GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SIMD);
   1638    }
   1639 
   1640    disasm_printer_add(printer,
   1641          "%s %s samp %d surf %d",
   1642          disasm_inst_mdesc_sampler_op(inst, op),
   1643          disasm_inst_mdesc_sampler_simd(inst, simd),
   1644          GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_INDEX),
   1645          GEN_EXTRACT(mdesc, GEN6_MSG_SAMPLER_SURFACE));
   1646 }
   1647 
   1648 static void
   1649 disasm_printer_add_mdesc_urb(struct disasm_printer *printer,
   1650                              const struct disasm_inst *inst,
   1651                              uint32_t mdesc)
   1652 {
   1653    int op, offset;
   1654    bool interleaved, complete, allocate, used;
   1655 
   1656    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) {
   1657       op = GEN_EXTRACT(mdesc, GEN7_MSG_URB_OP);
   1658       offset = GEN_EXTRACT(mdesc, GEN7_MSG_URB_GLOBAL_OFFSET);
   1659       interleaved = mdesc & GEN7_MSG_URB_INTERLEAVED;
   1660 
   1661       complete = (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) ?
   1662          false : (mdesc & GEN7_MSG_URB_COMPLETE);
   1663 
   1664       allocate = false;
   1665       used = false;
   1666    } else {
   1667       op = GEN_EXTRACT(mdesc, GEN6_MSG_URB_OP);
   1668       offset = GEN_EXTRACT(mdesc, GEN6_MSG_URB_OFFSET);
   1669       interleaved = mdesc & GEN6_MSG_URB_INTERLEAVED;
   1670       complete = mdesc & GEN6_MSG_URB_COMPLETE;
   1671 
   1672       allocate = mdesc & GEN6_MSG_URB_ALLOCATE;
   1673       used = mdesc & GEN6_MSG_URB_USED;
   1674    }
   1675 
   1676    disasm_printer_add(printer, "%s offset %d%s%s%s%s",
   1677          disasm_inst_mdesc_urb_op(inst, op),
   1678          offset,
   1679          (interleaved) ? " interleave" : "",
   1680          (allocate) ? " allocate" : "",
   1681          (used) ? " used" : "",
   1682          (complete) ? " complete" : "");
   1683 }
   1684 
   1685 static void
   1686 disasm_printer_add_mdesc_spawner(struct disasm_printer *printer,
   1687                                  const struct disasm_inst *inst,
   1688                                  uint32_t mdesc)
   1689 {
   1690    const char *requester, *op;
   1691 
   1692    switch (mdesc & GEN6_MSG_TS_REQUESTER_TYPE__MASK) {
   1693    case GEN6_MSG_TS_REQUESTER_TYPE_ROOT:  requester = "root";  break;
   1694    case GEN6_MSG_TS_REQUESTER_TYPE_CHILD: requester = "child"; break;
   1695    default:                               requester = "BAD";   break;
   1696    }
   1697 
   1698    switch (mdesc & GEN6_MSG_TS_OPCODE__MASK) {
   1699    case GEN6_MSG_TS_OPCODE_DEREF:
   1700       op = (mdesc & GEN6_MSG_TS_RESOURCE_SELECT_NO_DEREF) ?
   1701          "no deref" : "deref";
   1702       break;
   1703    case GEN6_MSG_TS_OPCODE_SPAWN:
   1704       op = (mdesc & GEN6_MSG_TS_RESOURCE_SELECT_ROOT) ?
   1705          "spawn root" : "spawn child";
   1706       break;
   1707    default:
   1708       op = "BAD";
   1709       break;
   1710    }
   1711 
   1712    disasm_printer_add(printer, "%s thread %s", requester, op);
   1713 }
   1714 
   1715 static void
   1716 disasm_printer_add_mdesc_dp_sampler(struct disasm_printer *printer,
   1717                                     const struct disasm_inst *inst,
   1718                                     uint32_t mdesc)
   1719 {
   1720    const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
   1721       GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
   1722    const bool write_commit = (ilo_dev_gen(inst->dev) == ILO_GEN(6)) ?
   1723          (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT) : 0;
   1724 
   1725    disasm_printer_add(printer, "%s block size %d commit %d surf %d",
   1726          disasm_inst_mdesc_dp_op(inst, GEN6_SFID_DP_SAMPLER, op),
   1727          GEN_EXTRACT(mdesc, GEN6_MSG_DP_OWORD_BLOCK_SIZE),
   1728          write_commit,
   1729          GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1730 }
   1731 
   1732 static void
   1733 disasm_printer_add_mdesc_dp_dc0(struct disasm_printer *printer,
   1734                                 const struct disasm_inst *inst,
   1735                                 uint32_t mdesc)
   1736 {
   1737    const int op = GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP);
   1738 
   1739    ILO_DEV_ASSERT(inst->dev, 7, 7.5);
   1740 
   1741    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7.5)) {
   1742       disasm_printer_add(printer, "%s ctrl 0x%x surf %d",
   1743             disasm_inst_mdesc_dp_op(inst, GEN7_SFID_DP_DC0, op),
   1744             GEN_EXTRACT(mdesc, GEN6_MSG_DP_CTRL),
   1745             GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1746    } else {
   1747       switch (op) {
   1748       case GEN7_MSG_DP_DC0_UNTYPED_SURFACE_READ:
   1749       case GEN7_MSG_DP_DC0_UNTYPED_SURFACE_WRITE:
   1750          disasm_printer_add(printer, "%s %s mask 0x%x surf %d",
   1751                disasm_inst_mdesc_dp_op(inst, GEN7_SFID_DP_DC0, op),
   1752                disasm_inst_mdesc_dp_untyped_surface_simd_mode(inst, mdesc),
   1753                GEN_EXTRACT(mdesc, GEN7_MSG_DP_UNTYPED_MASK),
   1754                GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1755          break;
   1756       default:
   1757          disasm_printer_add(printer, "%s ctrl 0x%x surf %d",
   1758                disasm_inst_mdesc_dp_op(inst, GEN7_SFID_DP_DC0, op),
   1759                GEN_EXTRACT(mdesc, GEN6_MSG_DP_CTRL),
   1760                GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1761          break;
   1762       }
   1763    }
   1764 }
   1765 
   1766 static void
   1767 disasm_printer_add_mdesc_dp_dc1(struct disasm_printer *printer,
   1768                                 const struct disasm_inst *inst,
   1769                                 uint32_t mdesc)
   1770 {
   1771    const int op = GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP);
   1772 
   1773    ILO_DEV_ASSERT(inst->dev, 7.5, 7.5);
   1774 
   1775    switch (op) {
   1776    case GEN75_MSG_DP_DC1_UNTYPED_SURFACE_READ:
   1777    case GEN75_MSG_DP_DC1_UNTYPED_SURFACE_WRITE:
   1778       disasm_printer_add(printer, "%s %s mask 0x%x surf %d",
   1779             disasm_inst_mdesc_dp_op(inst, GEN75_SFID_DP_DC1, op),
   1780             disasm_inst_mdesc_dp_untyped_surface_simd_mode(inst, mdesc),
   1781             GEN_EXTRACT(mdesc, GEN7_MSG_DP_UNTYPED_MASK),
   1782             GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1783       break;
   1784    default:
   1785       disasm_printer_add(printer, "%s ctrl 0x%x surf %d",
   1786             disasm_inst_mdesc_dp_op(inst, GEN75_SFID_DP_DC1, op),
   1787             GEN_EXTRACT(mdesc, GEN6_MSG_DP_CTRL),
   1788             GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1789       break;
   1790    }
   1791 }
   1792 
   1793 static void
   1794 disasm_printer_add_mdesc_dp_rc(struct disasm_printer *printer,
   1795                                const struct disasm_inst *inst,
   1796                                uint32_t mdesc)
   1797 {
   1798    const int op = (ilo_dev_gen(inst->dev) >= ILO_GEN(7)) ?
   1799       GEN_EXTRACT(mdesc, GEN7_MSG_DP_OP) : GEN_EXTRACT(mdesc, GEN6_MSG_DP_OP);
   1800    bool is_rt_write;
   1801 
   1802    if (ilo_dev_gen(inst->dev) >= ILO_GEN(7.5))
   1803       is_rt_write = (op == GEN75_MSG_DP_RC_RT_WRITE);
   1804    else if (ilo_dev_gen(inst->dev) >= ILO_GEN(7))
   1805       is_rt_write = (op == GEN7_MSG_DP_RC_RT_WRITE);
   1806    else
   1807       is_rt_write = (op == GEN6_MSG_DP_RT_WRITE);
   1808 
   1809    disasm_printer_add(printer, "%s",
   1810          disasm_inst_mdesc_dp_op(inst, GEN6_SFID_DP_RC, op));
   1811 
   1812    if (is_rt_write) {
   1813       disasm_printer_add(printer, " %s%s%s%s",
   1814             disasm_inst_mdesc_dp_rt_write_simd_mode(inst, mdesc),
   1815             (mdesc & GEN6_MSG_DP_RT_SLOTGRP_HI) ? " Hi" : "",
   1816             (mdesc & GEN6_MSG_DP_RT_LAST) ? " LastRT" : "",
   1817             (ilo_dev_gen(inst->dev) == ILO_GEN(6) &&
   1818              (mdesc & GEN6_MSG_DP_SEND_WRITE_COMMIT)) ? " WriteCommit" : "");
   1819    }
   1820 
   1821    disasm_printer_add(printer, " surf %d",
   1822          GEN_EXTRACT(mdesc, GEN6_MSG_DP_SURFACE));
   1823 }
   1824 
   1825 static void
   1826 disasm_printer_add_mdesc(struct disasm_printer *printer,
   1827                          const struct disasm_inst *inst)
   1828 {
   1829    const uint32_t mdesc = inst->u.ud;
   1830 
   1831    assert(inst->opcode == GEN6_OPCODE_SEND ||
   1832           inst->opcode == GEN6_OPCODE_SENDC);
   1833    assert(inst->src1.base.file == GEN6_FILE_IMM);
   1834 
   1835    disasm_printer_add(printer, "            %s (", disasm_inst_sfid(inst));
   1836 
   1837    switch (inst->sfid) {
   1838    case GEN6_SFID_SAMPLER:
   1839       disasm_printer_add_mdesc_sampler(printer, inst, mdesc);
   1840       break;
   1841    case GEN6_SFID_DP_SAMPLER:
   1842       disasm_printer_add_mdesc_dp_sampler(printer, inst, mdesc);
   1843       break;
   1844    case GEN6_SFID_DP_RC:
   1845       disasm_printer_add_mdesc_dp_rc(printer, inst, mdesc);
   1846       break;
   1847    case GEN6_SFID_URB:
   1848       disasm_printer_add_mdesc_urb(printer, inst, mdesc);
   1849       break;
   1850    case GEN6_SFID_SPAWNER:
   1851       disasm_printer_add_mdesc_spawner(printer, inst, mdesc);
   1852       break;
   1853    case GEN7_SFID_DP_DC0:
   1854       disasm_printer_add_mdesc_dp_dc0(printer, inst, mdesc);
   1855       break;
   1856    case GEN75_SFID_DP_DC1:
   1857       disasm_printer_add_mdesc_dp_dc1(printer, inst, mdesc);
   1858       break;
   1859    case GEN6_SFID_DP_CC:
   1860    case GEN7_SFID_PI:
   1861    default:
   1862       break;
   1863    }
   1864 
   1865    disasm_printer_add(printer, ") mlen %d rlen %d",
   1866          GEN_EXTRACT(mdesc, GEN6_MSG_MLEN),
   1867          GEN_EXTRACT(mdesc, GEN6_MSG_RLEN));
   1868 }
   1869 
   1870 static void
   1871 disasm_printer_print_inst(struct disasm_printer *printer,
   1872                           const struct disasm_inst *inst)
   1873 {
   1874    int col = 0;
   1875 
   1876    disasm_printer_reset(printer);
   1877 
   1878    disasm_printer_column(printer, col++);
   1879    disasm_printer_add_op(printer, inst);
   1880 
   1881    if (inst->has_jip || inst->has_uip) {
   1882       if (inst->has_jip) {
   1883          const int32_t jip = (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) ?
   1884             inst->u.ip32.jip : inst->u.ip16.jip;
   1885 
   1886          disasm_printer_column(printer, col++);
   1887          disasm_printer_add(printer, "JIP: %d", jip);
   1888       }
   1889 
   1890       if (inst->has_uip) {
   1891          const int32_t uip = (ilo_dev_gen(inst->dev) >= ILO_GEN(8)) ?
   1892             inst->u.ip32.uip : inst->u.ip16.uip;
   1893 
   1894          disasm_printer_column(printer, col++);
   1895          disasm_printer_add(printer, "UIP: %d", uip);
   1896       }
   1897    } else {
   1898       const int src_count = disasm_opcode_table[inst->opcode].src_count;
   1899 
   1900       if (src_count) {
   1901          const struct disasm_src_operand *src[3] = {
   1902             &inst->src0, &inst->src1, &inst->u.src2
   1903          };
   1904          int i;
   1905 
   1906          disasm_printer_column(printer, col++);
   1907          disasm_printer_add_dst(printer, inst, &inst->dst);
   1908 
   1909          for (i = 0; i < src_count; i++) {
   1910             disasm_printer_column(printer, col++);
   1911             disasm_printer_add_src(printer, inst, src[i]);
   1912          }
   1913       }
   1914    }
   1915 
   1916    if (inst->opcode == GEN6_OPCODE_SEND ||
   1917        inst->opcode == GEN6_OPCODE_SENDC) {
   1918       /* start a new line */
   1919       ilo_printf("%s\n", disasm_printer_get_string(printer));
   1920       disasm_printer_reset(printer);
   1921       col = 0;
   1922 
   1923       disasm_printer_column(printer, col++);
   1924 
   1925       disasm_printer_column(printer, col++);
   1926       disasm_printer_add_mdesc(printer, inst);
   1927    }
   1928 
   1929    if (col < 4)
   1930       col = 4;
   1931 
   1932    disasm_printer_column(printer, col++);
   1933    disasm_printer_add_ctrl(printer, inst);
   1934 
   1935    ilo_printf("%s\n", disasm_printer_get_string(printer));
   1936 }
   1937 
   1938 static void
   1939 disasm_uncompact_3src(const struct ilo_dev *dev,
   1940                       uint64_t compact, uint32_t *dw)
   1941 {
   1942    const struct toy_compaction_table *tbl =
   1943       toy_compiler_get_compaction_table(dev);
   1944    uint32_t src[3], tmp;
   1945    uint64_t tmp64;
   1946 
   1947    ILO_DEV_ASSERT(dev, 8, 8);
   1948 
   1949    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_OPCODE);
   1950    dw[0] = GEN_SHIFT32(tmp, GEN6_INST_OPCODE);
   1951 
   1952    /* ControlIndex */
   1953    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_CONTROL_INDEX);
   1954    tmp = tbl->control_3src[tmp];
   1955 
   1956    dw[0] |= (tmp & 0x1fffff) << GEN6_INST_ACCESSMODE__SHIFT;
   1957    dw[1] = (tmp >> 21) & ((ilo_dev_gen(dev) >= ILO_GEN(9)) ? 0x1f : 0x7);
   1958 
   1959    /* SourceIndex */
   1960    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SOURCE_INDEX);
   1961    tmp64 = tbl->source_3src[tmp];
   1962 
   1963    dw[1] |= (tmp64 & 0x7ffff) << 5;
   1964    src[0] = ((tmp64 >> 19) & 0xff) << 1;
   1965    src[1] = ((tmp64 >> 27) & 0xff) << 1;
   1966    src[2] = ((tmp64 >> 35) & 0xff) << 1;
   1967    if (ilo_dev_gen(dev) >= ILO_GEN(9)) {
   1968       src[0] |= ((tmp64 >> 43) & 0x3) << 19;
   1969       src[1] |= ((tmp64 >> 45) & 0x3) << 19;
   1970       src[2] |= ((tmp64 >> 47) & 0x3) << 19;
   1971    } else {
   1972       src[0] |= ((tmp64 >> 43) & 0x1) << 19;
   1973       src[1] |= ((tmp64 >> 44) & 0x1) << 19;
   1974       src[2] |= ((tmp64 >> 45) & 0x1) << 19;
   1975    }
   1976 
   1977    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_DST_REG);
   1978    dw[1] |= GEN_SHIFT32(tmp, GEN6_3SRC_DST_REG);
   1979 
   1980    if (compact & GEN8_COMPACT_3SRC_SRC0_REPCTRL)
   1981       src[0] |= GEN6_3SRC_SRC_REPCTRL;
   1982 
   1983    assert(compact & GEN8_COMPACT_3SRC_CMPTCTRL);
   1984 
   1985    if (compact & GEN8_COMPACT_3SRC_DEBUGCTRL)
   1986       dw[0] |= GEN6_INST_DEBUGCTRL;
   1987    if (compact & GEN8_COMPACT_3SRC_SATURATE)
   1988       dw[0] |= GEN6_INST_SATURATE;
   1989 
   1990    if (compact & GEN8_COMPACT_3SRC_SRC1_REPCTRL)
   1991       src[1] |= GEN6_3SRC_SRC_REPCTRL;
   1992    if (compact & GEN8_COMPACT_3SRC_SRC2_REPCTRL)
   1993       src[2] |= GEN6_3SRC_SRC_REPCTRL;
   1994 
   1995    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC0_SUBREG);
   1996    src[0] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_SUBREG);
   1997    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC1_SUBREG);
   1998    src[1] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_SUBREG);
   1999    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC2_SUBREG);
   2000    src[2] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_SUBREG);
   2001 
   2002    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC0_REG);
   2003    src[0] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_REG);
   2004    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC1_REG);
   2005    src[1] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_REG);
   2006    tmp = GEN_EXTRACT(compact, GEN8_COMPACT_3SRC_SRC2_REG);
   2007    src[2] |= GEN_SHIFT32(tmp, GEN6_3SRC_SRC_REG);
   2008 
   2009    tmp64 = (uint64_t) src[2] << 42 |
   2010            (uint64_t) src[1] << 21 |
   2011            (uint64_t) src[0];
   2012    dw[2] = (uint32_t) tmp64;
   2013    dw[3] = (uint32_t) (tmp64 >> 32);
   2014 }
   2015 
   2016 static void
   2017 disasm_uncompact(const struct ilo_dev *dev,
   2018                  uint64_t compact, uint32_t *dw)
   2019 {
   2020    const struct toy_compaction_table *tbl =
   2021       toy_compiler_get_compaction_table(dev);
   2022    bool src_is_imm;
   2023    uint32_t tmp;
   2024 
   2025    ILO_DEV_ASSERT(dev, 6, 8);
   2026 
   2027    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_OPCODE);
   2028    if (disasm_opcode_table[tmp].src_count == 3) {
   2029       disasm_uncompact_3src(dev, compact, dw);
   2030       return;
   2031    }
   2032 
   2033    memset(dw, 0, sizeof(*dw) * 4);
   2034 
   2035    dw[0] |= GEN_SHIFT32(tmp, GEN6_INST_OPCODE);
   2036 
   2037    if (ilo_dev_gen(dev) >= ILO_GEN(7) && (compact & GEN6_COMPACT_DEBUGCTRL))
   2038       dw[0] |= GEN6_INST_DEBUGCTRL;
   2039 
   2040    /* ControlIndex */
   2041    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_CONTROL_INDEX);
   2042    tmp = tbl->control[tmp];
   2043 
   2044    dw[0] |= (tmp & 0xffff) << GEN6_INST_ACCESSMODE__SHIFT;
   2045    if (tmp & 0x10000)
   2046       dw[0] |= GEN6_INST_SATURATE;
   2047 
   2048    if (ilo_dev_gen(dev) >= ILO_GEN(7))
   2049       dw[2] |= (tmp >> 17) << GEN6_INST_FLAG_SUBREG__SHIFT;
   2050 
   2051    /* DataTypeIndex */
   2052    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_DATATYPE_INDEX);
   2053    tmp = tbl->datatype[tmp];
   2054 
   2055    dw[1] |= (tmp & 0x7fff) << GEN6_INST_DST_FILE__SHIFT;
   2056    dw[1] |= (tmp >> 15) << GEN6_INST_DST_HORZSTRIDE__SHIFT;
   2057 
   2058    /* SubRegIndex */
   2059    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_SUBREG_INDEX);
   2060    tmp = tbl->subreg[tmp];
   2061 
   2062    dw[1] |= (tmp & 0x1f) << 16;
   2063    dw[2] |= ((tmp >> 5) & 0x1f);
   2064    dw[3] |= ((tmp >> 10) & 0x1f);
   2065 
   2066    if (compact & GEN6_COMPACT_ACCWRCTRL)
   2067       dw[0] |= GEN6_INST_ACCWRCTRL;
   2068 
   2069    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_CONDMODIFIER);
   2070    dw[0] |= GEN_SHIFT32(tmp, GEN6_INST_CONDMODIFIER);
   2071 
   2072    if (ilo_dev_gen(dev) == ILO_GEN(6)) {
   2073       tmp = GEN_EXTRACT(compact, GEN6_COMPACT_FLAG_SUBREG);
   2074       dw[2] |= GEN_SHIFT32(compact, GEN6_INST_FLAG_SUBREG);
   2075    }
   2076 
   2077    assert(compact & GEN6_COMPACT_CMPTCTRL);
   2078 
   2079    /* Src0Index */
   2080    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_SRC0_INDEX);
   2081    tmp = tbl->src[tmp];
   2082    dw[2] |= tmp << 13;
   2083 
   2084    src_is_imm = (GEN_EXTRACT(dw[1], GEN6_INST_SRC0_FILE) == GEN6_FILE_IMM) ||
   2085                 (GEN_EXTRACT(dw[1], GEN6_INST_SRC1_FILE) == GEN6_FILE_IMM);
   2086 
   2087    /* Src1Index */
   2088    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_SRC1_INDEX);
   2089    if (src_is_imm) {
   2090       if (tmp & 0x10)
   2091          tmp |= 0xfffff0;
   2092       dw[3] |= tmp << 8;
   2093    } else {
   2094       tmp = tbl->src[tmp];
   2095       dw[3] |= tmp << 13;
   2096    }
   2097 
   2098    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_DST_REG);
   2099    dw[1] |= GEN_SHIFT32(tmp, GEN6_INST_DST_REG);
   2100 
   2101    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_SRC0_REG);
   2102    dw[2] |= GEN_SHIFT32(tmp, GEN6_INST_SRC_REG);
   2103 
   2104    tmp = GEN_EXTRACT(compact, GEN6_COMPACT_SRC1_REG);
   2105    if (src_is_imm)
   2106       dw[3] |= tmp;
   2107    else
   2108       dw[3] |= GEN_SHIFT32(tmp, GEN6_INST_SRC_REG);
   2109 }
   2110 
   2111 void
   2112 toy_compiler_disassemble(const struct ilo_dev *dev,
   2113                          const void *kernel, int size,
   2114                          bool dump_hex)
   2115 {
   2116    const uint32_t *cur = (const uint32_t *) kernel;
   2117    const uint32_t *end = cur + size / sizeof(*cur);
   2118    struct disasm_printer printer;
   2119 
   2120    disasm_printer_reset(&printer);
   2121 
   2122    while (cur < end) {
   2123       struct disasm_inst inst;
   2124       const bool compacted = (cur[0] & GEN6_INST_CMPTCTRL);
   2125       const uint32_t *dw = cur;
   2126       uint32_t temp[4];
   2127 
   2128       cur += (compacted) ? 2 : 4;
   2129       /* incomplete instruction */
   2130       if (cur > end)
   2131          break;
   2132 
   2133       if (compacted) {
   2134          const uint64_t compact = (uint64_t) dw[1] << 32 | dw[0];
   2135          disasm_uncompact(dev, compact, temp);
   2136          dw = temp;
   2137       }
   2138 
   2139       if (dump_hex) {
   2140          ilo_printf("0x%08x 0x%08x 0x%08x 0x%08x ",
   2141                dw[0], dw[1], dw[2], dw[3]);
   2142       }
   2143 
   2144       memset(&inst, 0, sizeof(inst));
   2145       inst.dev = dev;
   2146       disasm_inst_decode(&inst, dw);
   2147       inst.cmpt_ctrl = compacted;
   2148 
   2149       disasm_printer_print_inst(&printer, &inst);
   2150    }
   2151 }
   2152