Home | History | Annotate | Download | only in shader
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2012-2013 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 "toy_compiler.h"
     29 
     30 /**
     31  * Dump an operand.
     32  */
     33 static void
     34 tc_dump_operand(struct toy_compiler *tc,
     35                 enum toy_file file, enum toy_type type, enum toy_rect rect,
     36                 bool indirect, unsigned indirect_subreg, uint32_t val32,
     37                 bool is_dst)
     38 {
     39    static const char *toy_file_names[TOY_FILE_COUNT] = {
     40       [TOY_FILE_VRF]        = "v",
     41       [TOY_FILE_ARF]        = "NOT USED",
     42       [TOY_FILE_GRF]        = "r",
     43       [TOY_FILE_MRF]        = "m",
     44       [TOY_FILE_IMM]        = "NOT USED",
     45    };
     46    const char *name = toy_file_names[file];
     47    int reg, subreg;
     48 
     49    if (file != TOY_FILE_IMM) {
     50       reg = val32 / TOY_REG_WIDTH;
     51       subreg = (val32 % TOY_REG_WIDTH) / toy_type_size(type);
     52    }
     53 
     54    switch (file) {
     55    case TOY_FILE_GRF:
     56       if (indirect) {
     57          const int addr_subreg = indirect_subreg / toy_type_size(TOY_TYPE_UW);
     58 
     59          ilo_printf("%s[a0.%d", name, addr_subreg);
     60          if (val32)
     61             ilo_printf("%+d", (int) val32);
     62          ilo_printf("]");
     63          break;
     64       }
     65       /* fall through */
     66    case TOY_FILE_VRF:
     67    case TOY_FILE_MRF:
     68       ilo_printf("%s%d", name, reg);
     69       if (subreg)
     70          ilo_printf(".%d", subreg);
     71       break;
     72    case TOY_FILE_ARF:
     73       switch (reg) {
     74       case GEN6_ARF_NULL:
     75          ilo_printf("null");
     76          break;
     77       case GEN6_ARF_A0:
     78          ilo_printf("a0.%d", subreg);
     79          break;
     80       case GEN6_ARF_ACC0:
     81       case GEN6_ARF_ACC0 + 1:
     82          ilo_printf("acc%d.%d", (reg & 1), subreg);
     83          break;
     84       case GEN6_ARF_F0:
     85          ilo_printf("f0.%d", subreg);
     86          break;
     87       case GEN6_ARF_SR0:
     88          ilo_printf("sr0.%d", subreg);
     89          break;
     90       case GEN6_ARF_CR0:
     91          ilo_printf("cr0.%d", subreg);
     92          break;
     93       case GEN6_ARF_N0:
     94       case GEN6_ARF_N0 + 1:
     95          ilo_printf("n%d.%d", (reg & 1), subreg);
     96          break;
     97       case GEN6_ARF_IP:
     98          ilo_printf("ip");
     99          break;
    100       }
    101       break;
    102    case TOY_FILE_IMM:
    103       switch (type) {
    104       case TOY_TYPE_F:
    105          {
    106             union fi fi = { .ui = val32 };
    107             ilo_printf("%f", fi.f);
    108          }
    109          break;
    110       case TOY_TYPE_D:
    111          ilo_printf("%d", (int32_t) val32);
    112          break;
    113       case TOY_TYPE_UD:
    114          ilo_printf("%u", val32);
    115          break;
    116       case TOY_TYPE_W:
    117          ilo_printf("%d", (int16_t) (val32 & 0xffff));
    118          break;
    119       case TOY_TYPE_UW:
    120          ilo_printf("%u", val32 & 0xffff);
    121          break;
    122       case TOY_TYPE_V:
    123          ilo_printf("0x%08x", val32);
    124          break;
    125       default:
    126          assert(!"unknown imm type");
    127          break;
    128       }
    129       break;
    130    default:
    131       assert(!"unexpected file");
    132       break;
    133    }
    134 
    135    /* dump the region parameter */
    136    if (file != TOY_FILE_IMM) {
    137       int vert_stride, width, horz_stride;
    138 
    139       switch (rect) {
    140       case TOY_RECT_LINEAR:
    141          vert_stride = tc->rect_linear_width;
    142          width = tc->rect_linear_width;
    143          horz_stride = 1;
    144          break;
    145       case TOY_RECT_041:
    146          vert_stride = 0;
    147          width = 4;
    148          horz_stride = 1;
    149          break;
    150       case TOY_RECT_010:
    151          vert_stride = 0;
    152          width = 1;
    153          horz_stride = 0;
    154          break;
    155       case TOY_RECT_220:
    156          vert_stride = 2;
    157          width = 2;
    158          horz_stride = 0;
    159          break;
    160       case TOY_RECT_440:
    161          vert_stride = 4;
    162          width = 4;
    163          horz_stride = 0;
    164          break;
    165       case TOY_RECT_240:
    166          vert_stride = 2;
    167          width = 4;
    168          horz_stride = 0;
    169          break;
    170       default:
    171          assert(!"unknown rect parameter");
    172          vert_stride = 0;
    173          width = 0;
    174          horz_stride = 0;
    175          break;
    176       }
    177 
    178       if (is_dst)
    179          ilo_printf("<%d>", horz_stride);
    180       else
    181          ilo_printf("<%d;%d,%d>", vert_stride, width, horz_stride);
    182    }
    183 
    184    switch (type) {
    185    case TOY_TYPE_F:
    186       ilo_printf(":f");
    187       break;
    188    case TOY_TYPE_D:
    189       ilo_printf(":d");
    190       break;
    191    case TOY_TYPE_UD:
    192       ilo_printf(":ud");
    193       break;
    194    case TOY_TYPE_W:
    195       ilo_printf(":w");
    196       break;
    197    case TOY_TYPE_UW:
    198       ilo_printf(":uw");
    199       break;
    200    case TOY_TYPE_V:
    201       ilo_printf(":v");
    202       break;
    203    default:
    204       assert(!"unexpected type");
    205       break;
    206    }
    207 }
    208 
    209 /**
    210  * Dump a source operand.
    211  */
    212 static void
    213 tc_dump_src(struct toy_compiler *tc, struct toy_src src)
    214 {
    215    if (src.negate)
    216       ilo_printf("-");
    217    if (src.absolute)
    218       ilo_printf("|");
    219 
    220    tc_dump_operand(tc, src.file, src.type, src.rect,
    221          src.indirect, src.indirect_subreg, src.val32, false);
    222 
    223    if (tsrc_is_swizzled(src)) {
    224       const char xyzw[] = "xyzw";
    225       ilo_printf(".%c%c%c%c",
    226             xyzw[src.swizzle_x],
    227             xyzw[src.swizzle_y],
    228             xyzw[src.swizzle_z],
    229             xyzw[src.swizzle_w]);
    230    }
    231 
    232    if (src.absolute)
    233       ilo_printf("|");
    234 }
    235 
    236 /**
    237  * Dump a destination operand.
    238  */
    239 static void
    240 tc_dump_dst(struct toy_compiler *tc, struct toy_dst dst)
    241 {
    242    tc_dump_operand(tc, dst.file, dst.type, dst.rect,
    243          dst.indirect, dst.indirect_subreg, dst.val32, true);
    244 
    245    if (dst.writemask != TOY_WRITEMASK_XYZW) {
    246       ilo_printf(".");
    247       if (dst.writemask & TOY_WRITEMASK_X)
    248          ilo_printf("x");
    249       if (dst.writemask & TOY_WRITEMASK_Y)
    250          ilo_printf("y");
    251       if (dst.writemask & TOY_WRITEMASK_Z)
    252          ilo_printf("z");
    253       if (dst.writemask & TOY_WRITEMASK_W)
    254          ilo_printf("w");
    255    }
    256 }
    257 
    258 static const char *
    259 get_opcode_name(unsigned opcode)
    260 {
    261    switch (opcode) {
    262    case GEN6_OPCODE_MOV:                   return "mov";
    263    case GEN6_OPCODE_SEL:                   return "sel";
    264    case GEN6_OPCODE_NOT:                   return "not";
    265    case GEN6_OPCODE_AND:                   return "and";
    266    case GEN6_OPCODE_OR:                    return "or";
    267    case GEN6_OPCODE_XOR:                   return "xor";
    268    case GEN6_OPCODE_SHR:                   return "shr";
    269    case GEN6_OPCODE_SHL:                   return "shl";
    270    case 0xa:                   return "rsr";
    271    case 0xb:                   return "rsl";
    272    case GEN6_OPCODE_ASR:                   return "asr";
    273    case GEN6_OPCODE_CMP:                   return "cmp";
    274    case GEN6_OPCODE_CMPN:                  return "cmpn";
    275    case GEN6_OPCODE_JMPI:                  return "jmpi";
    276    case GEN6_OPCODE_IF:                    return "if";
    277    case 0x23:                   return "iff";
    278    case GEN6_OPCODE_ELSE:                  return "else";
    279    case GEN6_OPCODE_ENDIF:                 return "endif";
    280    case 0x26:                    return "do";
    281    case GEN6_OPCODE_WHILE:                 return "while";
    282    case GEN6_OPCODE_BREAK:                 return "break";
    283    case GEN6_OPCODE_CONT:              return "continue";
    284    case GEN6_OPCODE_HALT:                  return "halt";
    285    case 0x2c:                 return "msave";
    286    case 0x2d:              return "mrestore";
    287    case 0x2e:                  return "push";
    288    case 0x2f:                   return "pop";
    289    case GEN6_OPCODE_WAIT:                  return "wait";
    290    case GEN6_OPCODE_SEND:                  return "send";
    291    case GEN6_OPCODE_SENDC:                 return "sendc";
    292    case GEN6_OPCODE_MATH:                  return "math";
    293    case GEN6_OPCODE_ADD:                   return "add";
    294    case GEN6_OPCODE_MUL:                   return "mul";
    295    case GEN6_OPCODE_AVG:                   return "avg";
    296    case GEN6_OPCODE_FRC:                   return "frc";
    297    case GEN6_OPCODE_RNDU:                  return "rndu";
    298    case GEN6_OPCODE_RNDD:                  return "rndd";
    299    case GEN6_OPCODE_RNDE:                  return "rnde";
    300    case GEN6_OPCODE_RNDZ:                  return "rndz";
    301    case GEN6_OPCODE_MAC:                   return "mac";
    302    case GEN6_OPCODE_MACH:                  return "mach";
    303    case GEN6_OPCODE_LZD:                   return "lzd";
    304    case GEN6_OPCODE_SAD2:                  return "sad2";
    305    case GEN6_OPCODE_SADA2:                 return "sada2";
    306    case GEN6_OPCODE_DP4:                   return "dp4";
    307    case GEN6_OPCODE_DPH:                   return "dph";
    308    case GEN6_OPCODE_DP3:                   return "dp3";
    309    case GEN6_OPCODE_DP2:                   return "dp2";
    310    case 0x58:                  return "dpa2";
    311    case GEN6_OPCODE_LINE:                  return "line";
    312    case GEN6_OPCODE_PLN:                   return "pln";
    313    case GEN6_OPCODE_MAD:                   return "mad";
    314    case GEN6_OPCODE_NOP:                   return "nop";
    315    case TOY_OPCODE_DO:                    return "do";
    316    /* TGSI */
    317    case TOY_OPCODE_TGSI_IN:               return "tgsi.in";
    318    case TOY_OPCODE_TGSI_CONST:            return "tgsi.const";
    319    case TOY_OPCODE_TGSI_SV:               return "tgsi.sv";
    320    case TOY_OPCODE_TGSI_IMM:              return "tgsi.imm";
    321    case TOY_OPCODE_TGSI_INDIRECT_FETCH:   return "tgsi.indirect_fetch";
    322    case TOY_OPCODE_TGSI_INDIRECT_STORE:   return "tgsi.indirect_store";
    323    case TOY_OPCODE_TGSI_TEX:              return "tgsi.tex";
    324    case TOY_OPCODE_TGSI_TXB:              return "tgsi.txb";
    325    case TOY_OPCODE_TGSI_TXD:              return "tgsi.txd";
    326    case TOY_OPCODE_TGSI_TXL:              return "tgsi.txl";
    327    case TOY_OPCODE_TGSI_TXP:              return "tgsi.txp";
    328    case TOY_OPCODE_TGSI_TXF:              return "tgsi.txf";
    329    case TOY_OPCODE_TGSI_TXQ:              return "tgsi.txq";
    330    case TOY_OPCODE_TGSI_TXQ_LZ:           return "tgsi.txq_lz";
    331    case TOY_OPCODE_TGSI_TEX2:             return "tgsi.tex2";
    332    case TOY_OPCODE_TGSI_TXB2:             return "tgsi.txb2";
    333    case TOY_OPCODE_TGSI_TXL2:             return "tgsi.txl2";
    334    case TOY_OPCODE_TGSI_SAMPLE:           return "tgsi.sample";
    335    case TOY_OPCODE_TGSI_SAMPLE_I:         return "tgsi.sample_i";
    336    case TOY_OPCODE_TGSI_SAMPLE_I_MS:      return "tgsi.sample_i_ms";
    337    case TOY_OPCODE_TGSI_SAMPLE_B:         return "tgsi.sample_b";
    338    case TOY_OPCODE_TGSI_SAMPLE_C:         return "tgsi.sample_c";
    339    case TOY_OPCODE_TGSI_SAMPLE_C_LZ:      return "tgsi.sample_c_lz";
    340    case TOY_OPCODE_TGSI_SAMPLE_D:         return "tgsi.sample_d";
    341    case TOY_OPCODE_TGSI_SAMPLE_L:         return "tgsi.sample_l";
    342    case TOY_OPCODE_TGSI_GATHER4:          return "tgsi.gather4";
    343    case TOY_OPCODE_TGSI_SVIEWINFO:        return "tgsi.sviewinfo";
    344    case TOY_OPCODE_TGSI_SAMPLE_POS:       return "tgsi.sample_pos";
    345    case TOY_OPCODE_TGSI_SAMPLE_INFO:      return "tgsi.sample_info";
    346    /* math */
    347    case TOY_OPCODE_INV:                   return "math.inv";
    348    case TOY_OPCODE_LOG:                   return "math.log";
    349    case TOY_OPCODE_EXP:                   return "math.exp";
    350    case TOY_OPCODE_SQRT:                  return "math.sqrt";
    351    case TOY_OPCODE_RSQ:                   return "math.rsq";
    352    case TOY_OPCODE_SIN:                   return "math.sin";
    353    case TOY_OPCODE_COS:                   return "math.cos";
    354    case TOY_OPCODE_FDIV:                  return "math.fdiv";
    355    case TOY_OPCODE_POW:                   return "math.pow";
    356    case TOY_OPCODE_INT_DIV_QUOTIENT:      return "math.int_div_quotient";
    357    case TOY_OPCODE_INT_DIV_REMAINDER:     return "math.int_div_remainer";
    358    /* urb */
    359    case TOY_OPCODE_URB_WRITE:             return "urb.urb_write";
    360    /* gs */
    361    case TOY_OPCODE_EMIT:                  return "gs.emit";
    362    case TOY_OPCODE_ENDPRIM:               return "gs.endprim";
    363    /* fs */
    364    case TOY_OPCODE_DDX:                   return "fs.ddx";
    365    case TOY_OPCODE_DDY:                   return "fs.ddy";
    366    case TOY_OPCODE_FB_WRITE:              return "fs.fb_write";
    367    case TOY_OPCODE_KIL:                   return "fs.kil";
    368    default:                               return "unk";
    369    }
    370 }
    371 
    372 static const char *
    373 get_cond_modifier_name(unsigned opcode, unsigned cond_modifier)
    374 {
    375    switch (opcode) {
    376    case GEN6_OPCODE_SEND:
    377    case GEN6_OPCODE_SENDC:
    378       /* SFID */
    379       switch (cond_modifier) {
    380       case GEN6_SFID_NULL:                       return "Null";
    381       case GEN6_SFID_SAMPLER:                    return "Sampling Engine";
    382       case GEN6_SFID_GATEWAY:            return "Message Gateway";
    383       case GEN6_SFID_DP_SAMPLER:    return "Data Port Sampler Cache";
    384       case GEN6_SFID_DP_RC:     return "Data Port Render Cache";
    385       case GEN6_SFID_URB:                        return "URB";
    386       case GEN6_SFID_SPAWNER:             return "Thread Spawner";
    387       case GEN6_SFID_DP_CC:   return "Constant Cache";
    388       default:                                  return "Unknown";
    389       }
    390       break;
    391    case GEN6_OPCODE_MATH:
    392       /* FC */
    393       switch (cond_modifier) {
    394       case GEN6_MATH_INV:               return "INV";
    395       case GEN6_MATH_LOG:               return "LOG";
    396       case GEN6_MATH_EXP:               return "EXP";
    397       case GEN6_MATH_SQRT:              return "SQRT";
    398       case GEN6_MATH_RSQ:               return "RSQ";
    399       case GEN6_MATH_SIN:               return "SIN";
    400       case GEN6_MATH_COS:               return "COS";
    401       case GEN6_MATH_FDIV:              return "FDIV";
    402       case GEN6_MATH_POW:               return "POW";
    403       case GEN6_MATH_INT_DIV_QUOTIENT:  return "INT DIV (quotient)";
    404       case GEN6_MATH_INT_DIV_REMAINDER: return "INT DIV (remainder)";
    405       default:                                  return "UNK";
    406       }
    407       break;
    408    default:
    409       switch (cond_modifier) {
    410       case GEN6_COND_NONE:                return NULL;
    411       case GEN6_COND_Z:                   return "z";
    412       case GEN6_COND_NZ:                  return "nz";
    413       case GEN6_COND_G:                   return "g";
    414       case GEN6_COND_GE:                  return "ge";
    415       case GEN6_COND_L:                   return "l";
    416       case GEN6_COND_LE:                  return "le";
    417       default:                                  return "unk";
    418       }
    419       break;
    420    }
    421 }
    422 
    423 /**
    424  * Dump an instruction.
    425  */
    426 static void
    427 tc_dump_inst(struct toy_compiler *tc, const struct toy_inst *inst)
    428 {
    429    const char *name;
    430    int i;
    431 
    432    name = get_opcode_name(inst->opcode);
    433 
    434    ilo_printf("  %s", name);
    435 
    436    if (inst->opcode == GEN6_OPCODE_NOP) {
    437       ilo_printf("\n");
    438       return;
    439    }
    440 
    441    if (inst->saturate)
    442       ilo_printf(".sat");
    443 
    444    name = get_cond_modifier_name(inst->opcode, inst->cond_modifier);
    445    if (name)
    446       ilo_printf(".%s", name);
    447 
    448    ilo_printf(" ");
    449 
    450    tc_dump_dst(tc, inst->dst);
    451 
    452    for (i = 0; i < ARRAY_SIZE(inst->src); i++) {
    453       if (tsrc_is_null(inst->src[i]))
    454          break;
    455 
    456       ilo_printf(", ");
    457       tc_dump_src(tc, inst->src[i]);
    458    }
    459 
    460    ilo_printf("\n");
    461 }
    462 
    463 /**
    464  * Dump the instructions added to the compiler.
    465  */
    466 void
    467 toy_compiler_dump(struct toy_compiler *tc)
    468 {
    469    struct toy_inst *inst;
    470    int pc;
    471 
    472    pc = 0;
    473    tc_head(tc);
    474    while ((inst = tc_next_no_skip(tc)) != NULL) {
    475       /* we do not generate code for markers */
    476       if (inst->marker)
    477          ilo_printf("marker:");
    478       else
    479          ilo_printf("%6d:", pc++);
    480 
    481       tc_dump_inst(tc, inst);
    482    }
    483 }
    484 
    485 /**
    486  * Clean up the toy compiler.
    487  */
    488 void
    489 toy_compiler_cleanup(struct toy_compiler *tc)
    490 {
    491    struct toy_inst *inst, *next;
    492 
    493    LIST_FOR_EACH_ENTRY_SAFE(inst, next, &tc->instructions, list)
    494       slab_free_st(&tc->mempool, inst);
    495 
    496    slab_destroy(&tc->mempool);
    497 }
    498 
    499 /**
    500  * Initialize the instruction template, from which tc_add() initializes the
    501  * newly added instructions.
    502  */
    503 static void
    504 tc_init_inst_templ(struct toy_compiler *tc)
    505 {
    506    struct toy_inst *templ = &tc->templ;
    507    int i;
    508 
    509    templ->opcode = GEN6_OPCODE_NOP;
    510    templ->access_mode = GEN6_ALIGN_1;
    511    templ->mask_ctrl = GEN6_MASKCTRL_NORMAL;
    512    templ->dep_ctrl = GEN6_DEPCTRL_NORMAL;
    513    templ->qtr_ctrl = GEN6_QTRCTRL_1Q;
    514    templ->thread_ctrl = GEN6_THREADCTRL_NORMAL;
    515    templ->pred_ctrl = GEN6_PREDCTRL_NONE;
    516    templ->pred_inv = false;
    517    templ->exec_size = GEN6_EXECSIZE_1;
    518    templ->cond_modifier = GEN6_COND_NONE;
    519    templ->acc_wr_ctrl = false;
    520    templ->saturate = false;
    521 
    522    templ->marker = false;
    523 
    524    templ->dst = tdst_null();
    525    for (i = 0; i < ARRAY_SIZE(templ->src); i++)
    526       templ->src[i] = tsrc_null();
    527 
    528    for (i = 0; i < ARRAY_SIZE(templ->tex.offsets); i++)
    529       templ->tex.offsets[i] = tsrc_null();
    530 
    531    list_inithead(&templ->list);
    532 }
    533 
    534 /**
    535  * Initialize the toy compiler.
    536  */
    537 void
    538 toy_compiler_init(struct toy_compiler *tc, const struct ilo_dev *dev)
    539 {
    540    memset(tc, 0, sizeof(*tc));
    541 
    542    tc->dev = dev;
    543 
    544    tc_init_inst_templ(tc);
    545 
    546    slab_create(&tc->mempool, sizeof(struct toy_inst),
    547          64);
    548 
    549    list_inithead(&tc->instructions);
    550    /* instructions are added to the tail */
    551    tc_tail(tc);
    552 
    553    tc->rect_linear_width = 1;
    554 
    555    /* skip 0 so that util_hash_table_get() never returns NULL */
    556    tc->next_vrf = 1;
    557 }
    558