17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2018-2019 Alyssa Rosenzweig <alyssa@rosenzweig.io>
37ec681f3Smrg * Copyright (C) 2019-2020 Collabora, Ltd.
47ec681f3Smrg *
57ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
67ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
77ec681f3Smrg * to deal in the Software without restriction, including without limitation
87ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
97ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
107ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
117ec681f3Smrg *
127ec681f3Smrg * The above copyright notice and this permission notice (including the next
137ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
147ec681f3Smrg * Software.
157ec681f3Smrg *
167ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
197ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
207ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
217ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
227ec681f3Smrg * SOFTWARE.
237ec681f3Smrg */
247ec681f3Smrg
257ec681f3Smrg#include <math.h>
267ec681f3Smrg
277ec681f3Smrg#include "util/bitscan.h"
287ec681f3Smrg#include "util/half_float.h"
297ec681f3Smrg#include "compiler.h"
307ec681f3Smrg#include "helpers.h"
317ec681f3Smrg#include "midgard_ops.h"
327ec681f3Smrg
337ec681f3Smrg/* Pretty printer for Midgard IR, for use debugging compiler-internal
347ec681f3Smrg * passes like register allocation. The output superficially resembles
357ec681f3Smrg * Midgard assembly, with the exception that unit information and such is
367ec681f3Smrg * (normally) omitted, and generic indices are usually used instead of
377ec681f3Smrg * registers */
387ec681f3Smrg
397ec681f3Smrgstatic void
407ec681f3Smrgmir_print_index(int source)
417ec681f3Smrg{
427ec681f3Smrg        if (source == ~0) {
437ec681f3Smrg                printf("_");
447ec681f3Smrg                return;
457ec681f3Smrg        }
467ec681f3Smrg
477ec681f3Smrg        if (source >= SSA_FIXED_MINIMUM) {
487ec681f3Smrg                /* Specific register */
497ec681f3Smrg                int reg = SSA_REG_FROM_FIXED(source);
507ec681f3Smrg
517ec681f3Smrg                /* TODO: Moving threshold */
527ec681f3Smrg                if (reg > 16 && reg < 24)
537ec681f3Smrg                        printf("u%d", 23 - reg);
547ec681f3Smrg                else
557ec681f3Smrg                        printf("r%d", reg);
567ec681f3Smrg        } else {
577ec681f3Smrg                printf("%d", source);
587ec681f3Smrg        }
597ec681f3Smrg}
607ec681f3Smrg
617ec681f3Smrgstatic const char components[16] = "xyzwefghijklmnop";
627ec681f3Smrg
637ec681f3Smrgstatic void
647ec681f3Smrgmir_print_mask(unsigned mask)
657ec681f3Smrg{
667ec681f3Smrg        printf(".");
677ec681f3Smrg
687ec681f3Smrg        for (unsigned i = 0; i < 16; ++i) {
697ec681f3Smrg                if (mask & (1 << i))
707ec681f3Smrg                        putchar(components[i]);
717ec681f3Smrg        }
727ec681f3Smrg}
737ec681f3Smrg
747ec681f3Smrgstatic void
757ec681f3Smrgmir_print_swizzle(unsigned *swizzle, nir_alu_type T)
767ec681f3Smrg{
777ec681f3Smrg        unsigned comps = mir_components_for_type(T);
787ec681f3Smrg
797ec681f3Smrg        printf(".");
807ec681f3Smrg
817ec681f3Smrg        for (unsigned i = 0; i < comps; ++i) {
827ec681f3Smrg                unsigned C = swizzle[i];
837ec681f3Smrg                assert(C < comps);
847ec681f3Smrg                putchar(components[C]);
857ec681f3Smrg        }
867ec681f3Smrg}
877ec681f3Smrg
887ec681f3Smrgstatic const char *
897ec681f3Smrgmir_get_unit(unsigned unit)
907ec681f3Smrg{
917ec681f3Smrg        switch (unit) {
927ec681f3Smrg        case ALU_ENAB_VEC_MUL:
937ec681f3Smrg                return "vmul";
947ec681f3Smrg        case ALU_ENAB_SCAL_ADD:
957ec681f3Smrg                return "sadd";
967ec681f3Smrg        case ALU_ENAB_VEC_ADD:
977ec681f3Smrg                return "vadd";
987ec681f3Smrg        case ALU_ENAB_SCAL_MUL:
997ec681f3Smrg                return "smul";
1007ec681f3Smrg        case ALU_ENAB_VEC_LUT:
1017ec681f3Smrg                return "lut";
1027ec681f3Smrg        case ALU_ENAB_BR_COMPACT:
1037ec681f3Smrg                return "br";
1047ec681f3Smrg        case ALU_ENAB_BRANCH:
1057ec681f3Smrg                return "brx";
1067ec681f3Smrg        default:
1077ec681f3Smrg                return "???";
1087ec681f3Smrg        }
1097ec681f3Smrg}
1107ec681f3Smrg
1117ec681f3Smrgstatic void
1127ec681f3Smrgmir_print_embedded_constant(midgard_instruction *ins, unsigned src_idx)
1137ec681f3Smrg{
1147ec681f3Smrg        assert(src_idx <= 1);
1157ec681f3Smrg
1167ec681f3Smrg        unsigned base_size = max_bitsize_for_alu(ins);
1177ec681f3Smrg        unsigned sz = nir_alu_type_get_type_size(ins->src_types[src_idx]);
1187ec681f3Smrg        bool half = (sz == (base_size >> 1));
1197ec681f3Smrg        unsigned mod = mir_pack_mod(ins, src_idx, false);
1207ec681f3Smrg        unsigned *swizzle = ins->swizzle[src_idx];
1217ec681f3Smrg        midgard_reg_mode reg_mode = reg_mode_for_bitsize(max_bitsize_for_alu(ins));
1227ec681f3Smrg        unsigned comp_mask = effective_writemask(ins->op, ins->mask);
1237ec681f3Smrg        unsigned num_comp = util_bitcount(comp_mask);
1247ec681f3Smrg        unsigned max_comp = mir_components_for_type(ins->dest_type);
1257ec681f3Smrg        bool first = true;
1267ec681f3Smrg
1277ec681f3Smrg        printf("#");
1287ec681f3Smrg
1297ec681f3Smrg        if (num_comp > 1)
1307ec681f3Smrg                printf("vec%d(", num_comp);
1317ec681f3Smrg
1327ec681f3Smrg        for (unsigned comp = 0; comp < max_comp; comp++) {
1337ec681f3Smrg                if (!(comp_mask & (1 << comp)))
1347ec681f3Smrg                        continue;
1357ec681f3Smrg
1367ec681f3Smrg                if (first)
1377ec681f3Smrg                        first = false;
1387ec681f3Smrg                else
1397ec681f3Smrg                        printf(", ");
1407ec681f3Smrg
1417ec681f3Smrg                mir_print_constant_component(stdout, &ins->constants,
1427ec681f3Smrg                                             swizzle[comp], reg_mode,
1437ec681f3Smrg                                             half, mod, ins->op);
1447ec681f3Smrg        }
1457ec681f3Smrg
1467ec681f3Smrg        if (num_comp > 1)
1477ec681f3Smrg                printf(")");
1487ec681f3Smrg}
1497ec681f3Smrg
1507ec681f3Smrg#define PRINT_SRC(ins, c) \
1517ec681f3Smrg        do { mir_print_index(ins->src[c]); \
1527ec681f3Smrg             if (ins->src[c] != ~0 && ins->src_types[c] != nir_type_invalid) { \
1537ec681f3Smrg                     pan_print_alu_type(ins->src_types[c], stdout); \
1547ec681f3Smrg                     mir_print_swizzle(ins->swizzle[c], ins->src_types[c]); \
1557ec681f3Smrg             } } while (0)
1567ec681f3Smrg
1577ec681f3Smrgvoid
1587ec681f3Smrgmir_print_instruction(midgard_instruction *ins)
1597ec681f3Smrg{
1607ec681f3Smrg        printf("\t");
1617ec681f3Smrg
1627ec681f3Smrg        if (midgard_is_branch_unit(ins->unit)) {
1637ec681f3Smrg                const char *branch_target_names[] = {
1647ec681f3Smrg                        "goto", "break", "continue", "discard"
1657ec681f3Smrg                };
1667ec681f3Smrg
1677ec681f3Smrg                printf("%s.", mir_get_unit(ins->unit));
1687ec681f3Smrg                if (ins->branch.target_type == TARGET_DISCARD)
1697ec681f3Smrg                        printf("discard.");
1707ec681f3Smrg                else if (ins->writeout)
1717ec681f3Smrg                        printf("write.");
1727ec681f3Smrg                else if (ins->unit == ALU_ENAB_BR_COMPACT &&
1737ec681f3Smrg                         !ins->branch.conditional)
1747ec681f3Smrg                        printf("uncond.");
1757ec681f3Smrg                else
1767ec681f3Smrg                        printf("cond.");
1777ec681f3Smrg
1787ec681f3Smrg                if (!ins->branch.conditional)
1797ec681f3Smrg                        printf("always");
1807ec681f3Smrg                else if (ins->branch.invert_conditional)
1817ec681f3Smrg                        printf("false");
1827ec681f3Smrg                else
1837ec681f3Smrg                        printf("true");
1847ec681f3Smrg
1857ec681f3Smrg                if (ins->writeout) {
1867ec681f3Smrg                        printf(" (c: ");
1877ec681f3Smrg                        PRINT_SRC(ins, 0);
1887ec681f3Smrg                        printf(", z: ");
1897ec681f3Smrg                        PRINT_SRC(ins, 2);
1907ec681f3Smrg                        printf(", s: ");
1917ec681f3Smrg                        PRINT_SRC(ins, 3);
1927ec681f3Smrg                        printf(")");
1937ec681f3Smrg                }
1947ec681f3Smrg
1957ec681f3Smrg                if (ins->branch.target_type != TARGET_DISCARD)
1967ec681f3Smrg                        printf(" %s -> block(%d)\n",
1977ec681f3Smrg                               ins->branch.target_type < 4 ?
1987ec681f3Smrg                                       branch_target_names[ins->branch.target_type] : "??",
1997ec681f3Smrg                               ins->branch.target_block);
2007ec681f3Smrg
2017ec681f3Smrg                return;
2027ec681f3Smrg        }
2037ec681f3Smrg
2047ec681f3Smrg        switch (ins->type) {
2057ec681f3Smrg        case TAG_ALU_4: {
2067ec681f3Smrg                midgard_alu_op op = ins->op;
2077ec681f3Smrg                const char *name = alu_opcode_props[op].name;
2087ec681f3Smrg
2097ec681f3Smrg                if (ins->unit)
2107ec681f3Smrg                        printf("%s.", mir_get_unit(ins->unit));
2117ec681f3Smrg
2127ec681f3Smrg                printf("%s", name ? name : "??");
2137ec681f3Smrg                break;
2147ec681f3Smrg        }
2157ec681f3Smrg
2167ec681f3Smrg        case TAG_LOAD_STORE_4: {
2177ec681f3Smrg                midgard_load_store_op op = ins->op;
2187ec681f3Smrg                const char *name = load_store_opcode_props[op].name;
2197ec681f3Smrg
2207ec681f3Smrg                assert(name);
2217ec681f3Smrg                printf("%s", name);
2227ec681f3Smrg                break;
2237ec681f3Smrg        }
2247ec681f3Smrg
2257ec681f3Smrg        case TAG_TEXTURE_4: {
2267ec681f3Smrg                printf("TEX");
2277ec681f3Smrg
2287ec681f3Smrg                if (ins->helper_terminate)
2297ec681f3Smrg                        printf(".terminate");
2307ec681f3Smrg
2317ec681f3Smrg                if (ins->helper_execute)
2327ec681f3Smrg                        printf(".execute");
2337ec681f3Smrg
2347ec681f3Smrg                break;
2357ec681f3Smrg        }
2367ec681f3Smrg
2377ec681f3Smrg        default:
2387ec681f3Smrg                assert(0);
2397ec681f3Smrg        }
2407ec681f3Smrg
2417ec681f3Smrg        if (ins->compact_branch && ins->branch.invert_conditional)
2427ec681f3Smrg                printf(".not");
2437ec681f3Smrg
2447ec681f3Smrg        printf(" ");
2457ec681f3Smrg        mir_print_index(ins->dest);
2467ec681f3Smrg
2477ec681f3Smrg        if (ins->dest != ~0) {
2487ec681f3Smrg                pan_print_alu_type(ins->dest_type, stdout);
2497ec681f3Smrg                mir_print_mask(ins->mask);
2507ec681f3Smrg        }
2517ec681f3Smrg
2527ec681f3Smrg        printf(", ");
2537ec681f3Smrg
2547ec681f3Smrg        /* Only ALU can have an embedded constant, r26 as read on load/store is
2557ec681f3Smrg         * something else entirely */
2567ec681f3Smrg        bool is_alu = ins->type == TAG_ALU_4;
2577ec681f3Smrg        unsigned r_constant = SSA_FIXED_REGISTER(REGISTER_CONSTANT);
2587ec681f3Smrg
2597ec681f3Smrg        if (ins->src[0] == r_constant && is_alu)
2607ec681f3Smrg                mir_print_embedded_constant(ins, 0);
2617ec681f3Smrg        else
2627ec681f3Smrg                PRINT_SRC(ins, 0);
2637ec681f3Smrg
2647ec681f3Smrg        printf(", ");
2657ec681f3Smrg
2667ec681f3Smrg        if (ins->has_inline_constant)
2677ec681f3Smrg                printf("#%d", ins->inline_constant);
2687ec681f3Smrg        else if (ins->src[1] == r_constant && is_alu)
2697ec681f3Smrg                mir_print_embedded_constant(ins, 1);
2707ec681f3Smrg        else
2717ec681f3Smrg                PRINT_SRC(ins, 1);
2727ec681f3Smrg
2737ec681f3Smrg        for (unsigned c = 2; c <= 3; ++c) {
2747ec681f3Smrg                printf(", ");
2757ec681f3Smrg                PRINT_SRC(ins, c);
2767ec681f3Smrg        }
2777ec681f3Smrg
2787ec681f3Smrg        if (ins->no_spill)
2797ec681f3Smrg                printf(" /* no spill */");
2807ec681f3Smrg
2817ec681f3Smrg        printf("\n");
2827ec681f3Smrg}
2837ec681f3Smrg
2847ec681f3Smrg/* Dumps MIR for a block or entire shader respective */
2857ec681f3Smrg
2867ec681f3Smrgvoid
2877ec681f3Smrgmir_print_block(midgard_block *block)
2887ec681f3Smrg{
2897ec681f3Smrg        printf("block%u: {\n", block->base.name);
2907ec681f3Smrg
2917ec681f3Smrg        if (block->scheduled) {
2927ec681f3Smrg                mir_foreach_bundle_in_block(block, bundle) {
2937ec681f3Smrg                        for (unsigned i = 0; i < bundle->instruction_count; ++i)
2947ec681f3Smrg                                mir_print_instruction(bundle->instructions[i]);
2957ec681f3Smrg
2967ec681f3Smrg                        printf("\n");
2977ec681f3Smrg                }
2987ec681f3Smrg        } else {
2997ec681f3Smrg                mir_foreach_instr_in_block(block, ins) {
3007ec681f3Smrg                        mir_print_instruction(ins);
3017ec681f3Smrg                }
3027ec681f3Smrg        }
3037ec681f3Smrg
3047ec681f3Smrg        printf("}");
3057ec681f3Smrg
3067ec681f3Smrg        if (block->base.successors[0]) {
3077ec681f3Smrg                printf(" -> ");
3087ec681f3Smrg                pan_foreach_successor((&block->base), succ)
3097ec681f3Smrg                        printf(" block%u ", succ->name);
3107ec681f3Smrg        }
3117ec681f3Smrg
3127ec681f3Smrg        printf(" from { ");
3137ec681f3Smrg        mir_foreach_predecessor(block, pred)
3147ec681f3Smrg                printf("block%u ", pred->base.name);
3157ec681f3Smrg        printf("}");
3167ec681f3Smrg
3177ec681f3Smrg        printf("\n\n");
3187ec681f3Smrg}
3197ec681f3Smrg
3207ec681f3Smrgvoid
3217ec681f3Smrgmir_print_shader(compiler_context *ctx)
3227ec681f3Smrg{
3237ec681f3Smrg        mir_foreach_block(ctx, block) {
3247ec681f3Smrg                mir_print_block((midgard_block *) block);
3257ec681f3Smrg        }
3267ec681f3Smrg}
327