Home | History | Annotate | Line # | Download | only in midgard
      1 /*
      2  * Copyright (C) 2018-2019 Alyssa Rosenzweig <alyssa (at) rosenzweig.io>
      3  * Copyright (C) 2019-2020 Collabora, Ltd.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * 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 FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 
     25 #include <math.h>
     26 
     27 #include "util/bitscan.h"
     28 #include "util/half_float.h"
     29 #include "compiler.h"
     30 #include "helpers.h"
     31 #include "midgard_ops.h"
     32 
     33 /* Pretty printer for Midgard IR, for use debugging compiler-internal
     34  * passes like register allocation. The output superficially resembles
     35  * Midgard assembly, with the exception that unit information and such is
     36  * (normally) omitted, and generic indices are usually used instead of
     37  * registers */
     38 
     39 static void
     40 mir_print_index(int source)
     41 {
     42         if (source == ~0) {
     43                 printf("_");
     44                 return;
     45         }
     46 
     47         if (source >= SSA_FIXED_MINIMUM) {
     48                 /* Specific register */
     49                 int reg = SSA_REG_FROM_FIXED(source);
     50 
     51                 /* TODO: Moving threshold */
     52                 if (reg > 16 && reg < 24)
     53                         printf("u%d", 23 - reg);
     54                 else
     55                         printf("r%d", reg);
     56         } else {
     57                 printf("%d", source);
     58         }
     59 }
     60 
     61 static const char components[16] = "xyzwefghijklmnop";
     62 
     63 static void
     64 mir_print_mask(unsigned mask)
     65 {
     66         printf(".");
     67 
     68         for (unsigned i = 0; i < 16; ++i) {
     69                 if (mask & (1 << i))
     70                         putchar(components[i]);
     71         }
     72 }
     73 
     74 static void
     75 mir_print_swizzle(unsigned *swizzle, nir_alu_type T)
     76 {
     77         unsigned comps = mir_components_for_type(T);
     78 
     79         printf(".");
     80 
     81         for (unsigned i = 0; i < comps; ++i) {
     82                 unsigned C = swizzle[i];
     83                 assert(C < comps);
     84                 putchar(components[C]);
     85         }
     86 }
     87 
     88 static const char *
     89 mir_get_unit(unsigned unit)
     90 {
     91         switch (unit) {
     92         case ALU_ENAB_VEC_MUL:
     93                 return "vmul";
     94         case ALU_ENAB_SCAL_ADD:
     95                 return "sadd";
     96         case ALU_ENAB_VEC_ADD:
     97                 return "vadd";
     98         case ALU_ENAB_SCAL_MUL:
     99                 return "smul";
    100         case ALU_ENAB_VEC_LUT:
    101                 return "lut";
    102         case ALU_ENAB_BR_COMPACT:
    103                 return "br";
    104         case ALU_ENAB_BRANCH:
    105                 return "brx";
    106         default:
    107                 return "???";
    108         }
    109 }
    110 
    111 static void
    112 mir_print_embedded_constant(midgard_instruction *ins, unsigned src_idx)
    113 {
    114         assert(src_idx <= 1);
    115 
    116         unsigned base_size = max_bitsize_for_alu(ins);
    117         unsigned sz = nir_alu_type_get_type_size(ins->src_types[src_idx]);
    118         bool half = (sz == (base_size >> 1));
    119         unsigned mod = mir_pack_mod(ins, src_idx, false);
    120         unsigned *swizzle = ins->swizzle[src_idx];
    121         midgard_reg_mode reg_mode = reg_mode_for_bitsize(max_bitsize_for_alu(ins));
    122         unsigned comp_mask = effective_writemask(ins->op, ins->mask);
    123         unsigned num_comp = util_bitcount(comp_mask);
    124         unsigned max_comp = mir_components_for_type(ins->dest_type);
    125         bool first = true;
    126 
    127         printf("#");
    128 
    129         if (num_comp > 1)
    130                 printf("vec%d(", num_comp);
    131 
    132         for (unsigned comp = 0; comp < max_comp; comp++) {
    133                 if (!(comp_mask & (1 << comp)))
    134                         continue;
    135 
    136                 if (first)
    137                         first = false;
    138                 else
    139                         printf(", ");
    140 
    141                 mir_print_constant_component(stdout, &ins->constants,
    142                                              swizzle[comp], reg_mode,
    143                                              half, mod, ins->op);
    144         }
    145 
    146         if (num_comp > 1)
    147                 printf(")");
    148 }
    149 
    150 #define PRINT_SRC(ins, c) \
    151         do { mir_print_index(ins->src[c]); \
    152              if (ins->src[c] != ~0 && ins->src_types[c] != nir_type_invalid) { \
    153                      pan_print_alu_type(ins->src_types[c], stdout); \
    154                      mir_print_swizzle(ins->swizzle[c], ins->src_types[c]); \
    155              } } while (0)
    156 
    157 void
    158 mir_print_instruction(midgard_instruction *ins)
    159 {
    160         printf("\t");
    161 
    162         if (midgard_is_branch_unit(ins->unit)) {
    163                 const char *branch_target_names[] = {
    164                         "goto", "break", "continue", "discard"
    165                 };
    166 
    167                 printf("%s.", mir_get_unit(ins->unit));
    168                 if (ins->branch.target_type == TARGET_DISCARD)
    169                         printf("discard.");
    170                 else if (ins->writeout)
    171                         printf("write.");
    172                 else if (ins->unit == ALU_ENAB_BR_COMPACT &&
    173                          !ins->branch.conditional)
    174                         printf("uncond.");
    175                 else
    176                         printf("cond.");
    177 
    178                 if (!ins->branch.conditional)
    179                         printf("always");
    180                 else if (ins->branch.invert_conditional)
    181                         printf("false");
    182                 else
    183                         printf("true");
    184 
    185                 if (ins->writeout) {
    186                         printf(" (c: ");
    187                         PRINT_SRC(ins, 0);
    188                         printf(", z: ");
    189                         PRINT_SRC(ins, 2);
    190                         printf(", s: ");
    191                         PRINT_SRC(ins, 3);
    192                         printf(")");
    193                 }
    194 
    195                 if (ins->branch.target_type != TARGET_DISCARD)
    196                         printf(" %s -> block(%d)\n",
    197                                ins->branch.target_type < 4 ?
    198                                        branch_target_names[ins->branch.target_type] : "??",
    199                                ins->branch.target_block);
    200 
    201                 return;
    202         }
    203 
    204         switch (ins->type) {
    205         case TAG_ALU_4: {
    206                 midgard_alu_op op = ins->op;
    207                 const char *name = alu_opcode_props[op].name;
    208 
    209                 if (ins->unit)
    210                         printf("%s.", mir_get_unit(ins->unit));
    211 
    212                 printf("%s", name ? name : "??");
    213                 break;
    214         }
    215 
    216         case TAG_LOAD_STORE_4: {
    217                 midgard_load_store_op op = ins->op;
    218                 const char *name = load_store_opcode_props[op].name;
    219 
    220                 assert(name);
    221                 printf("%s", name);
    222                 break;
    223         }
    224 
    225         case TAG_TEXTURE_4: {
    226                 printf("TEX");
    227 
    228                 if (ins->helper_terminate)
    229                         printf(".terminate");
    230 
    231                 if (ins->helper_execute)
    232                         printf(".execute");
    233 
    234                 break;
    235         }
    236 
    237         default:
    238                 assert(0);
    239         }
    240 
    241         if (ins->compact_branch && ins->branch.invert_conditional)
    242                 printf(".not");
    243 
    244         printf(" ");
    245         mir_print_index(ins->dest);
    246 
    247         if (ins->dest != ~0) {
    248                 pan_print_alu_type(ins->dest_type, stdout);
    249                 mir_print_mask(ins->mask);
    250         }
    251 
    252         printf(", ");
    253 
    254         /* Only ALU can have an embedded constant, r26 as read on load/store is
    255          * something else entirely */
    256         bool is_alu = ins->type == TAG_ALU_4;
    257         unsigned r_constant = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
    258 
    259         if (ins->src[0] == r_constant && is_alu)
    260                 mir_print_embedded_constant(ins, 0);
    261         else
    262                 PRINT_SRC(ins, 0);
    263 
    264         printf(", ");
    265 
    266         if (ins->has_inline_constant)
    267                 printf("#%d", ins->inline_constant);
    268         else if (ins->src[1] == r_constant && is_alu)
    269                 mir_print_embedded_constant(ins, 1);
    270         else
    271                 PRINT_SRC(ins, 1);
    272 
    273         for (unsigned c = 2; c <= 3; ++c) {
    274                 printf(", ");
    275                 PRINT_SRC(ins, c);
    276         }
    277 
    278         if (ins->no_spill)
    279                 printf(" /* no spill */");
    280 
    281         printf("\n");
    282 }
    283 
    284 /* Dumps MIR for a block or entire shader respective */
    285 
    286 void
    287 mir_print_block(midgard_block *block)
    288 {
    289         printf("block%u: {\n", block->base.name);
    290 
    291         if (block->scheduled) {
    292                 mir_foreach_bundle_in_block(block, bundle) {
    293                         for (unsigned i = 0; i < bundle->instruction_count; ++i)
    294                                 mir_print_instruction(bundle->instructions[i]);
    295 
    296                         printf("\n");
    297                 }
    298         } else {
    299                 mir_foreach_instr_in_block(block, ins) {
    300                         mir_print_instruction(ins);
    301                 }
    302         }
    303 
    304         printf("}");
    305 
    306         if (block->base.successors[0]) {
    307                 printf(" -> ");
    308                 pan_foreach_successor((&block->base), succ)
    309                         printf(" block%u ", succ->name);
    310         }
    311 
    312         printf(" from { ");
    313         mir_foreach_predecessor(block, pred)
    314                 printf("block%u ", pred->base.name);
    315         printf("}");
    316 
    317         printf("\n\n");
    318 }
    319 
    320 void
    321 mir_print_shader(compiler_context *ctx)
    322 {
    323         mir_foreach_block(ctx, block) {
    324                 mir_print_block((midgard_block *) block);
    325         }
    326 }
    327