17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2019-2020 Collabora, Ltd.
37ec681f3Smrg * Copyright (C) 2019 Alyssa Rosenzweig <alyssa@rosenzweig.io>
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#ifndef _MDG_COMPILER_H
267ec681f3Smrg#define _MDG_COMPILER_H
277ec681f3Smrg
287ec681f3Smrg#include "midgard.h"
297ec681f3Smrg#include "helpers.h"
307ec681f3Smrg#include "midgard_compile.h"
317ec681f3Smrg#include "midgard_ops.h"
327ec681f3Smrg
337ec681f3Smrg#include "util/hash_table.h"
347ec681f3Smrg#include "util/u_dynarray.h"
357ec681f3Smrg#include "util/set.h"
367ec681f3Smrg#include "util/list.h"
377ec681f3Smrg
387ec681f3Smrg#include "main/mtypes.h"
397ec681f3Smrg#include "compiler/nir_types.h"
407ec681f3Smrg#include "compiler/nir/nir.h"
417ec681f3Smrg#include "panfrost/util/pan_ir.h"
427ec681f3Smrg#include "panfrost/util/lcra.h"
437ec681f3Smrg
447ec681f3Smrg/* Forward declare */
457ec681f3Smrgstruct midgard_block;
467ec681f3Smrg
477ec681f3Smrg/* Target types. Defaults to TARGET_GOTO (the type corresponding directly to
487ec681f3Smrg * the hardware), hence why that must be zero. TARGET_DISCARD signals this
497ec681f3Smrg * instruction is actually a discard op. */
507ec681f3Smrg
517ec681f3Smrg#define TARGET_GOTO 0
527ec681f3Smrg#define TARGET_BREAK 1
537ec681f3Smrg#define TARGET_CONTINUE 2
547ec681f3Smrg#define TARGET_DISCARD 3
557ec681f3Smrg#define TARGET_TILEBUF_WAIT 4
567ec681f3Smrg
577ec681f3Smrgtypedef struct midgard_branch {
587ec681f3Smrg        /* If conditional, the condition is specified in r31.w */
597ec681f3Smrg        bool conditional;
607ec681f3Smrg
617ec681f3Smrg        /* For conditionals, if this is true, we branch on FALSE. If false, we  branch on TRUE. */
627ec681f3Smrg        bool invert_conditional;
637ec681f3Smrg
647ec681f3Smrg        /* Branch targets: the start of a block, the start of a loop (continue), the end of a loop (break). Value is one of TARGET_ */
657ec681f3Smrg        unsigned target_type;
667ec681f3Smrg
677ec681f3Smrg        /* The actual target */
687ec681f3Smrg        union {
697ec681f3Smrg                int target_block;
707ec681f3Smrg                int target_break;
717ec681f3Smrg                int target_continue;
727ec681f3Smrg        };
737ec681f3Smrg} midgard_branch;
747ec681f3Smrg
757ec681f3Smrg/* Generic in-memory data type repesenting a single logical instruction, rather
767ec681f3Smrg * than a single instruction group. This is the preferred form for code gen.
777ec681f3Smrg * Multiple midgard_insturctions will later be combined during scheduling,
787ec681f3Smrg * though this is not represented in this structure.  Its format bridges
797ec681f3Smrg * the low-level binary representation with the higher level semantic meaning.
807ec681f3Smrg *
817ec681f3Smrg * Notably, it allows registers to be specified as block local SSA, for code
827ec681f3Smrg * emitted before the register allocation pass.
837ec681f3Smrg */
847ec681f3Smrg
857ec681f3Smrg#define MIR_SRC_COUNT 4
867ec681f3Smrg#define MIR_VEC_COMPONENTS 16
877ec681f3Smrg
887ec681f3Smrgtypedef struct midgard_instruction {
897ec681f3Smrg        /* Must be first for casting */
907ec681f3Smrg        struct list_head link;
917ec681f3Smrg
927ec681f3Smrg        unsigned type; /* ALU, load/store, texture */
937ec681f3Smrg
947ec681f3Smrg        /* Instruction arguments represented as block-local SSA
957ec681f3Smrg         * indices, rather than registers. ~0 means unused. */
967ec681f3Smrg        unsigned src[MIR_SRC_COUNT];
977ec681f3Smrg        unsigned dest;
987ec681f3Smrg
997ec681f3Smrg        /* vec16 swizzle, unpacked, per source */
1007ec681f3Smrg        unsigned swizzle[MIR_SRC_COUNT][MIR_VEC_COMPONENTS];
1017ec681f3Smrg
1027ec681f3Smrg        /* Types! */
1037ec681f3Smrg        nir_alu_type src_types[MIR_SRC_COUNT];
1047ec681f3Smrg        nir_alu_type dest_type;
1057ec681f3Smrg
1067ec681f3Smrg        /* Packing ops have non-32-bit dest types even though they functionally
1077ec681f3Smrg         * work at the 32-bit level, use this as a signal to disable copyprop.
1087ec681f3Smrg         * We maybe need synthetic pack ops instead. */
1097ec681f3Smrg        bool is_pack;
1107ec681f3Smrg
1117ec681f3Smrg        /* Modifiers, depending on type */
1127ec681f3Smrg        union {
1137ec681f3Smrg                struct {
1147ec681f3Smrg                        bool src_abs[MIR_SRC_COUNT];
1157ec681f3Smrg                        bool src_neg[MIR_SRC_COUNT];
1167ec681f3Smrg                };
1177ec681f3Smrg
1187ec681f3Smrg                struct {
1197ec681f3Smrg                        bool src_shift[MIR_SRC_COUNT];
1207ec681f3Smrg                };
1217ec681f3Smrg        };
1227ec681f3Smrg
1237ec681f3Smrg        /* Out of the union for csel (could maybe be fixed..) */
1247ec681f3Smrg        bool src_invert[MIR_SRC_COUNT];
1257ec681f3Smrg
1267ec681f3Smrg        /* If the op supports it */
1277ec681f3Smrg        enum midgard_roundmode roundmode;
1287ec681f3Smrg
1297ec681f3Smrg        /* For textures: should helpers execute this instruction (instead of
1307ec681f3Smrg         * just helping with derivatives)? Should helpers terminate after? */
1317ec681f3Smrg        bool helper_terminate;
1327ec681f3Smrg        bool helper_execute;
1337ec681f3Smrg
1347ec681f3Smrg        /* I.e. (1 << alu_bit) */
1357ec681f3Smrg        int unit;
1367ec681f3Smrg
1377ec681f3Smrg        bool has_constants;
1387ec681f3Smrg        midgard_constants constants;
1397ec681f3Smrg        uint16_t inline_constant;
1407ec681f3Smrg        bool has_inline_constant;
1417ec681f3Smrg
1427ec681f3Smrg        bool compact_branch;
1437ec681f3Smrg        uint8_t writeout;
1447ec681f3Smrg        bool last_writeout;
1457ec681f3Smrg
1467ec681f3Smrg        /* Masks in a saneish format. One bit per channel, not packed fancy.
1477ec681f3Smrg         * Use this instead of the op specific ones, and switch over at emit
1487ec681f3Smrg         * time */
1497ec681f3Smrg
1507ec681f3Smrg        uint16_t mask;
1517ec681f3Smrg
1527ec681f3Smrg        /* Hint for the register allocator not to spill the destination written
1537ec681f3Smrg         * from this instruction (because it is a spill/unspill node itself).
1547ec681f3Smrg         * Bitmask of spilled classes */
1557ec681f3Smrg
1567ec681f3Smrg        unsigned no_spill;
1577ec681f3Smrg
1587ec681f3Smrg        /* Generic hint for intra-pass use */
1597ec681f3Smrg        bool hint;
1607ec681f3Smrg
1617ec681f3Smrg        /* During scheduling, the backwards dependency graph
1627ec681f3Smrg         * (DAG). nr_dependencies is the number of unscheduled
1637ec681f3Smrg         * instructions that must still be scheduled after
1647ec681f3Smrg         * (before) this instruction. dependents are which
1657ec681f3Smrg         * instructions need to be scheduled before (after) this
1667ec681f3Smrg         * instruction. */
1677ec681f3Smrg
1687ec681f3Smrg        unsigned nr_dependencies;
1697ec681f3Smrg        BITSET_WORD *dependents;
1707ec681f3Smrg
1717ec681f3Smrg        /* Use this in conjunction with `type` */
1727ec681f3Smrg        unsigned op;
1737ec681f3Smrg
1747ec681f3Smrg        /* This refers to midgard_outmod_float or midgard_outmod_int.
1757ec681f3Smrg         * In case of a ALU op, use midgard_is_integer_out_op() to know which
1767ec681f3Smrg         * one is used.
1777ec681f3Smrg         * If it's a texture op, it's always midgard_outmod_float. */
1787ec681f3Smrg        unsigned outmod;
1797ec681f3Smrg
1807ec681f3Smrg        union {
1817ec681f3Smrg                midgard_load_store_word load_store;
1827ec681f3Smrg                midgard_texture_word texture;
1837ec681f3Smrg
1847ec681f3Smrg                midgard_branch branch;
1857ec681f3Smrg        };
1867ec681f3Smrg
1877ec681f3Smrg        unsigned bundle_id;
1887ec681f3Smrg} midgard_instruction;
1897ec681f3Smrg
1907ec681f3Smrgtypedef struct midgard_block {
1917ec681f3Smrg        pan_block base;
1927ec681f3Smrg
1937ec681f3Smrg        bool scheduled;
1947ec681f3Smrg
1957ec681f3Smrg        /* List of midgard_bundles emitted (after the scheduler has run) */
1967ec681f3Smrg        struct util_dynarray bundles;
1977ec681f3Smrg
1987ec681f3Smrg        /* Number of quadwords _actually_ emitted, as determined after scheduling */
1997ec681f3Smrg        unsigned quadword_count;
2007ec681f3Smrg
2017ec681f3Smrg        /* Indicates this is a fixed-function fragment epilogue block */
2027ec681f3Smrg        bool epilogue;
2037ec681f3Smrg
2047ec681f3Smrg        /* Are helper invocations required by this block? */
2057ec681f3Smrg        bool helpers_in;
2067ec681f3Smrg} midgard_block;
2077ec681f3Smrg
2087ec681f3Smrgtypedef struct midgard_bundle {
2097ec681f3Smrg        /* Tag for the overall bundle */
2107ec681f3Smrg        int tag;
2117ec681f3Smrg
2127ec681f3Smrg        /* Instructions contained by the bundle. instruction_count <= 6 (vmul,
2137ec681f3Smrg         * sadd, vadd, smul, vlut, branch) */
2147ec681f3Smrg        int instruction_count;
2157ec681f3Smrg        midgard_instruction *instructions[6];
2167ec681f3Smrg
2177ec681f3Smrg        /* Bundle-wide ALU configuration */
2187ec681f3Smrg        int padding;
2197ec681f3Smrg        int control;
2207ec681f3Smrg        bool has_embedded_constants;
2217ec681f3Smrg        midgard_constants constants;
2227ec681f3Smrg        bool last_writeout;
2237ec681f3Smrg} midgard_bundle;
2247ec681f3Smrg
2257ec681f3Smrgenum midgard_rt_id {
2267ec681f3Smrg        MIDGARD_COLOR_RT0 = 0,
2277ec681f3Smrg        MIDGARD_COLOR_RT1,
2287ec681f3Smrg        MIDGARD_COLOR_RT2,
2297ec681f3Smrg        MIDGARD_COLOR_RT3,
2307ec681f3Smrg        MIDGARD_COLOR_RT4,
2317ec681f3Smrg        MIDGARD_COLOR_RT5,
2327ec681f3Smrg        MIDGARD_COLOR_RT6,
2337ec681f3Smrg        MIDGARD_COLOR_RT7,
2347ec681f3Smrg        MIDGARD_ZS_RT,
2357ec681f3Smrg        MIDGARD_NUM_RTS,
2367ec681f3Smrg};
2377ec681f3Smrg
2387ec681f3Smrg#define MIDGARD_MAX_SAMPLE_ITER 16
2397ec681f3Smrg
2407ec681f3Smrgtypedef struct compiler_context {
2417ec681f3Smrg        const struct panfrost_compile_inputs *inputs;
2427ec681f3Smrg        nir_shader *nir;
2437ec681f3Smrg        struct pan_shader_info *info;
2447ec681f3Smrg        gl_shader_stage stage;
2457ec681f3Smrg
2467ec681f3Smrg        /* Number of samples for a keyed blend shader. Depends on is_blend */
2477ec681f3Smrg        unsigned blend_sample_iterations;
2487ec681f3Smrg
2497ec681f3Smrg        /* Index to precolour to r0 for an input blend colour */
2507ec681f3Smrg        unsigned blend_input;
2517ec681f3Smrg
2527ec681f3Smrg        /* Index to precolour to r2 for a dual-source blend colour */
2537ec681f3Smrg        unsigned blend_src1;
2547ec681f3Smrg
2557ec681f3Smrg        /* Count of spills and fills for shaderdb */
2567ec681f3Smrg        unsigned spills;
2577ec681f3Smrg        unsigned fills;
2587ec681f3Smrg
2597ec681f3Smrg        /* Current NIR function */
2607ec681f3Smrg        nir_function *func;
2617ec681f3Smrg
2627ec681f3Smrg        /* Allocated compiler temporary counter */
2637ec681f3Smrg        unsigned temp_alloc;
2647ec681f3Smrg
2657ec681f3Smrg        /* Unordered list of midgard_blocks */
2667ec681f3Smrg        int block_count;
2677ec681f3Smrg        struct list_head blocks;
2687ec681f3Smrg
2697ec681f3Smrg        /* TODO merge with block_count? */
2707ec681f3Smrg        unsigned block_source_count;
2717ec681f3Smrg
2727ec681f3Smrg        /* List of midgard_instructions emitted for the current block */
2737ec681f3Smrg        midgard_block *current_block;
2747ec681f3Smrg
2757ec681f3Smrg        /* If there is a preset after block, use this, otherwise emit_block will create one if NULL */
2767ec681f3Smrg        midgard_block *after_block;
2777ec681f3Smrg
2787ec681f3Smrg        /* The current "depth" of the loop, for disambiguating breaks/continues
2797ec681f3Smrg         * when using nested loops */
2807ec681f3Smrg        int current_loop_depth;
2817ec681f3Smrg
2827ec681f3Smrg        /* Total number of loops for shader-db */
2837ec681f3Smrg        unsigned loop_count;
2847ec681f3Smrg
2857ec681f3Smrg        /* Constants which have been loaded, for later inlining */
2867ec681f3Smrg        struct hash_table_u64 *ssa_constants;
2877ec681f3Smrg
2887ec681f3Smrg        int temp_count;
2897ec681f3Smrg        int max_hash;
2907ec681f3Smrg
2917ec681f3Smrg        /* Set of NIR indices that were already emitted as outmods */
2927ec681f3Smrg        BITSET_WORD *already_emitted;
2937ec681f3Smrg
2947ec681f3Smrg        /* Count of instructions emitted from NIR overall, across all blocks */
2957ec681f3Smrg        int instruction_count;
2967ec681f3Smrg
2977ec681f3Smrg        unsigned quadword_count;
2987ec681f3Smrg
2997ec681f3Smrg        /* Bitmask of valid metadata */
3007ec681f3Smrg        unsigned metadata;
3017ec681f3Smrg
3027ec681f3Smrg        /* Model-specific quirk set */
3037ec681f3Smrg        uint32_t quirks;
3047ec681f3Smrg
3057ec681f3Smrg        /* Writeout instructions for each render target */
3067ec681f3Smrg        midgard_instruction *writeout_branch[MIDGARD_NUM_RTS][MIDGARD_MAX_SAMPLE_ITER];
3077ec681f3Smrg
3087ec681f3Smrg        struct hash_table_u64 *sysval_to_id;
3097ec681f3Smrg
3107ec681f3Smrg        /* Mask of UBOs that need to be uploaded */
3117ec681f3Smrg        uint32_t ubo_mask;
3127ec681f3Smrg} compiler_context;
3137ec681f3Smrg
3147ec681f3Smrg/* Per-block live_in/live_out */
3157ec681f3Smrg#define MIDGARD_METADATA_LIVENESS (1 << 0)
3167ec681f3Smrg
3177ec681f3Smrg/* Helpers for manipulating the above structures (forming the driver IR) */
3187ec681f3Smrg
3197ec681f3Smrg/* Append instruction to end of current block */
3207ec681f3Smrg
3217ec681f3Smrgstatic inline midgard_instruction *
3227ec681f3Smrgmir_upload_ins(struct compiler_context *ctx, struct midgard_instruction ins)
3237ec681f3Smrg{
3247ec681f3Smrg        midgard_instruction *heap = ralloc(ctx, struct midgard_instruction);
3257ec681f3Smrg        memcpy(heap, &ins, sizeof(ins));
3267ec681f3Smrg        return heap;
3277ec681f3Smrg}
3287ec681f3Smrg
3297ec681f3Smrgstatic inline midgard_instruction *
3307ec681f3Smrgemit_mir_instruction(struct compiler_context *ctx, struct midgard_instruction ins)
3317ec681f3Smrg{
3327ec681f3Smrg        midgard_instruction *u = mir_upload_ins(ctx, ins);
3337ec681f3Smrg        list_addtail(&u->link, &ctx->current_block->base.instructions);
3347ec681f3Smrg        return u;
3357ec681f3Smrg}
3367ec681f3Smrg
3377ec681f3Smrgstatic inline struct midgard_instruction *
3387ec681f3Smrgmir_insert_instruction_before(struct compiler_context *ctx,
3397ec681f3Smrg                              struct midgard_instruction *tag,
3407ec681f3Smrg                              struct midgard_instruction ins)
3417ec681f3Smrg{
3427ec681f3Smrg        struct midgard_instruction *u = mir_upload_ins(ctx, ins);
3437ec681f3Smrg        list_addtail(&u->link, &tag->link);
3447ec681f3Smrg        return u;
3457ec681f3Smrg}
3467ec681f3Smrg
3477ec681f3Smrgstatic inline void
3487ec681f3Smrgmir_remove_instruction(struct midgard_instruction *ins)
3497ec681f3Smrg{
3507ec681f3Smrg        list_del(&ins->link);
3517ec681f3Smrg}
3527ec681f3Smrg
3537ec681f3Smrgstatic inline midgard_instruction*
3547ec681f3Smrgmir_prev_op(struct midgard_instruction *ins)
3557ec681f3Smrg{
3567ec681f3Smrg        return list_last_entry(&(ins->link), midgard_instruction, link);
3577ec681f3Smrg}
3587ec681f3Smrg
3597ec681f3Smrgstatic inline midgard_instruction*
3607ec681f3Smrgmir_next_op(struct midgard_instruction *ins)
3617ec681f3Smrg{
3627ec681f3Smrg        return list_first_entry(&(ins->link), midgard_instruction, link);
3637ec681f3Smrg}
3647ec681f3Smrg
3657ec681f3Smrg#define mir_foreach_block(ctx, v) \
3667ec681f3Smrg        list_for_each_entry(pan_block, v, &ctx->blocks, link)
3677ec681f3Smrg
3687ec681f3Smrg#define mir_foreach_block_from(ctx, from, v) \
3697ec681f3Smrg        list_for_each_entry_from(pan_block, v, &from->base, &ctx->blocks, link)
3707ec681f3Smrg
3717ec681f3Smrg#define mir_foreach_instr_in_block(block, v) \
3727ec681f3Smrg        list_for_each_entry(struct midgard_instruction, v, &block->base.instructions, link)
3737ec681f3Smrg#define mir_foreach_instr_in_block_rev(block, v) \
3747ec681f3Smrg        list_for_each_entry_rev(struct midgard_instruction, v, &block->base.instructions, link)
3757ec681f3Smrg
3767ec681f3Smrg#define mir_foreach_instr_in_block_safe(block, v) \
3777ec681f3Smrg        list_for_each_entry_safe(struct midgard_instruction, v, &block->base.instructions, link)
3787ec681f3Smrg
3797ec681f3Smrg#define mir_foreach_instr_in_block_safe_rev(block, v) \
3807ec681f3Smrg        list_for_each_entry_safe_rev(struct midgard_instruction, v, &block->base.instructions, link)
3817ec681f3Smrg
3827ec681f3Smrg#define mir_foreach_instr_in_block_from(block, v, from) \
3837ec681f3Smrg        list_for_each_entry_from(struct midgard_instruction, v, from, &block->base.instructions, link)
3847ec681f3Smrg
3857ec681f3Smrg#define mir_foreach_instr_in_block_from_rev(block, v, from) \
3867ec681f3Smrg        list_for_each_entry_from_rev(struct midgard_instruction, v, from, &block->base.instructions, link)
3877ec681f3Smrg
3887ec681f3Smrg#define mir_foreach_bundle_in_block(block, v) \
3897ec681f3Smrg        util_dynarray_foreach(&block->bundles, midgard_bundle, v)
3907ec681f3Smrg
3917ec681f3Smrg#define mir_foreach_bundle_in_block_rev(block, v) \
3927ec681f3Smrg        util_dynarray_foreach_reverse(&block->bundles, midgard_bundle, v)
3937ec681f3Smrg
3947ec681f3Smrg#define mir_foreach_instr_in_block_scheduled_rev(block, v) \
3957ec681f3Smrg        midgard_instruction* v; \
3967ec681f3Smrg        signed i = 0; \
3977ec681f3Smrg        mir_foreach_bundle_in_block_rev(block, _bundle) \
3987ec681f3Smrg                for (i = (_bundle->instruction_count - 1), v = _bundle->instructions[i]; \
3997ec681f3Smrg                                i >= 0; \
4007ec681f3Smrg                                --i, v = (i >= 0) ? _bundle->instructions[i] : NULL) \
4017ec681f3Smrg
4027ec681f3Smrg#define mir_foreach_instr_global(ctx, v) \
4037ec681f3Smrg        mir_foreach_block(ctx, v_block) \
4047ec681f3Smrg                mir_foreach_instr_in_block(((midgard_block *) v_block), v)
4057ec681f3Smrg
4067ec681f3Smrg#define mir_foreach_instr_global_safe(ctx, v) \
4077ec681f3Smrg        mir_foreach_block(ctx, v_block) \
4087ec681f3Smrg                mir_foreach_instr_in_block_safe(((midgard_block *) v_block), v)
4097ec681f3Smrg
4107ec681f3Smrg/* Based on set_foreach, expanded with automatic type casts */
4117ec681f3Smrg
4127ec681f3Smrg#define mir_foreach_predecessor(blk, v) \
4137ec681f3Smrg        struct set_entry *_entry_##v; \
4147ec681f3Smrg        struct midgard_block *v; \
4157ec681f3Smrg        for (_entry_##v = _mesa_set_next_entry(blk->base.predecessors, NULL), \
4167ec681f3Smrg                v = (struct midgard_block *) (_entry_##v ? _entry_##v->key : NULL);  \
4177ec681f3Smrg                _entry_##v != NULL; \
4187ec681f3Smrg                _entry_##v = _mesa_set_next_entry(blk->base.predecessors, _entry_##v), \
4197ec681f3Smrg                v = (struct midgard_block *) (_entry_##v ? _entry_##v->key : NULL))
4207ec681f3Smrg
4217ec681f3Smrg#define mir_foreach_src(ins, v) \
4227ec681f3Smrg        for (unsigned v = 0; v < ARRAY_SIZE(ins->src); ++v)
4237ec681f3Smrg
4247ec681f3Smrgstatic inline midgard_instruction *
4257ec681f3Smrgmir_last_in_block(struct midgard_block *block)
4267ec681f3Smrg{
4277ec681f3Smrg        return list_last_entry(&block->base.instructions, struct midgard_instruction, link);
4287ec681f3Smrg}
4297ec681f3Smrg
4307ec681f3Smrgstatic inline midgard_block *
4317ec681f3Smrgmir_get_block(compiler_context *ctx, int idx)
4327ec681f3Smrg{
4337ec681f3Smrg        struct list_head *lst = &ctx->blocks;
4347ec681f3Smrg
4357ec681f3Smrg        while ((idx--) + 1)
4367ec681f3Smrg                lst = lst->next;
4377ec681f3Smrg
4387ec681f3Smrg        return (struct midgard_block *) lst;
4397ec681f3Smrg}
4407ec681f3Smrg
4417ec681f3Smrgstatic inline bool
4427ec681f3Smrgmir_is_alu_bundle(midgard_bundle *bundle)
4437ec681f3Smrg{
4447ec681f3Smrg        return IS_ALU(bundle->tag);
4457ec681f3Smrg}
4467ec681f3Smrg
4477ec681f3Smrgstatic inline unsigned
4487ec681f3Smrgmake_compiler_temp(compiler_context *ctx)
4497ec681f3Smrg{
4507ec681f3Smrg        return (ctx->func->impl->ssa_alloc + ctx->temp_alloc++) << 1;
4517ec681f3Smrg}
4527ec681f3Smrg
4537ec681f3Smrgstatic inline unsigned
4547ec681f3Smrgmake_compiler_temp_reg(compiler_context *ctx)
4557ec681f3Smrg{
4567ec681f3Smrg        return ((ctx->func->impl->reg_alloc + ctx->temp_alloc++) << 1) | PAN_IS_REG;
4577ec681f3Smrg}
4587ec681f3Smrg
4597ec681f3Smrgstatic inline unsigned
4607ec681f3Smrgnir_ssa_index(nir_ssa_def *ssa)
4617ec681f3Smrg{
4627ec681f3Smrg        return (ssa->index << 1) | 0;
4637ec681f3Smrg}
4647ec681f3Smrg
4657ec681f3Smrgstatic inline unsigned
4667ec681f3Smrgnir_src_index(compiler_context *ctx, nir_src *src)
4677ec681f3Smrg{
4687ec681f3Smrg        if (src->is_ssa)
4697ec681f3Smrg                return nir_ssa_index(src->ssa);
4707ec681f3Smrg        else {
4717ec681f3Smrg                assert(!src->reg.indirect);
4727ec681f3Smrg                return (src->reg.reg->index << 1) | PAN_IS_REG;
4737ec681f3Smrg        }
4747ec681f3Smrg}
4757ec681f3Smrg
4767ec681f3Smrgstatic inline unsigned
4777ec681f3Smrgnir_dest_index(nir_dest *dst)
4787ec681f3Smrg{
4797ec681f3Smrg        if (dst->is_ssa)
4807ec681f3Smrg                return (dst->ssa.index << 1) | 0;
4817ec681f3Smrg        else {
4827ec681f3Smrg                assert(!dst->reg.indirect);
4837ec681f3Smrg                return (dst->reg.reg->index << 1) | PAN_IS_REG;
4847ec681f3Smrg        }
4857ec681f3Smrg}
4867ec681f3Smrg
4877ec681f3Smrg
4887ec681f3Smrg
4897ec681f3Smrg/* MIR manipulation */
4907ec681f3Smrg
4917ec681f3Smrgvoid mir_rewrite_index(compiler_context *ctx, unsigned old, unsigned new);
4927ec681f3Smrgvoid mir_rewrite_index_src(compiler_context *ctx, unsigned old, unsigned new);
4937ec681f3Smrgvoid mir_rewrite_index_dst(compiler_context *ctx, unsigned old, unsigned new);
4947ec681f3Smrgvoid mir_rewrite_index_dst_single(midgard_instruction *ins, unsigned old, unsigned new);
4957ec681f3Smrgvoid mir_rewrite_index_src_single(midgard_instruction *ins, unsigned old, unsigned new);
4967ec681f3Smrgvoid mir_rewrite_index_src_swizzle(compiler_context *ctx, unsigned old, unsigned new, unsigned *swizzle);
4977ec681f3Smrgbool mir_single_use(compiler_context *ctx, unsigned value);
4987ec681f3Smrgunsigned mir_use_count(compiler_context *ctx, unsigned value);
4997ec681f3Smrguint16_t mir_bytemask_of_read_components(midgard_instruction *ins, unsigned node);
5007ec681f3Smrguint16_t mir_bytemask_of_read_components_index(midgard_instruction *ins, unsigned i);
5017ec681f3Smrguint16_t mir_from_bytemask(uint16_t bytemask, unsigned bits);
5027ec681f3Smrguint16_t mir_bytemask(midgard_instruction *ins);
5037ec681f3Smrguint16_t mir_round_bytemask_up(uint16_t mask, unsigned bits);
5047ec681f3Smrgvoid mir_set_bytemask(midgard_instruction *ins, uint16_t bytemask);
5057ec681f3Smrgsigned mir_upper_override(midgard_instruction *ins, unsigned inst_size);
5067ec681f3Smrgunsigned mir_components_for_type(nir_alu_type T);
5077ec681f3Smrgunsigned max_bitsize_for_alu(midgard_instruction *ins);
5087ec681f3Smrgmidgard_reg_mode reg_mode_for_bitsize(unsigned bitsize);
5097ec681f3Smrg
5107ec681f3Smrg/* MIR printing */
5117ec681f3Smrg
5127ec681f3Smrgvoid mir_print_instruction(midgard_instruction *ins);
5137ec681f3Smrgvoid mir_print_bundle(midgard_bundle *ctx);
5147ec681f3Smrgvoid mir_print_block(midgard_block *block);
5157ec681f3Smrgvoid mir_print_shader(compiler_context *ctx);
5167ec681f3Smrgbool mir_nontrivial_mod(midgard_instruction *ins, unsigned i, bool check_swizzle);
5177ec681f3Smrgbool mir_nontrivial_outmod(midgard_instruction *ins);
5187ec681f3Smrg
5197ec681f3Smrgvoid mir_insert_instruction_before_scheduled(compiler_context *ctx, midgard_block *block, midgard_instruction *tag, midgard_instruction ins);
5207ec681f3Smrgvoid mir_insert_instruction_after_scheduled(compiler_context *ctx, midgard_block *block, midgard_instruction *tag, midgard_instruction ins);
5217ec681f3Smrgvoid mir_flip(midgard_instruction *ins);
5227ec681f3Smrgvoid mir_compute_temp_count(compiler_context *ctx);
5237ec681f3Smrg
5247ec681f3Smrg#define LDST_GLOBAL (REGISTER_LDST_ZERO << 2)
5257ec681f3Smrg#define LDST_SHARED ((REGISTER_LDST_LOCAL_STORAGE_PTR << 2) | COMPONENT_Z)
5267ec681f3Smrg#define LDST_SCRATCH ((REGISTER_LDST_PC_SP << 2) | COMPONENT_Z)
5277ec681f3Smrg
5287ec681f3Smrgvoid mir_set_offset(compiler_context *ctx, midgard_instruction *ins, nir_src *offset, unsigned seg);
5297ec681f3Smrgvoid mir_set_ubo_offset(midgard_instruction *ins, nir_src *src, unsigned bias);
5307ec681f3Smrg
5317ec681f3Smrg/* 'Intrinsic' move for aliasing */
5327ec681f3Smrg
5337ec681f3Smrgstatic inline midgard_instruction
5347ec681f3Smrgv_mov(unsigned src, unsigned dest)
5357ec681f3Smrg{
5367ec681f3Smrg        midgard_instruction ins = {
5377ec681f3Smrg                .type = TAG_ALU_4,
5387ec681f3Smrg                .mask = 0xF,
5397ec681f3Smrg                .src = { ~0, src, ~0, ~0 },
5407ec681f3Smrg                .src_types = { 0, nir_type_uint32 },
5417ec681f3Smrg                .swizzle = SWIZZLE_IDENTITY,
5427ec681f3Smrg                .dest = dest,
5437ec681f3Smrg                .dest_type = nir_type_uint32,
5447ec681f3Smrg                .op = midgard_alu_op_imov,
5457ec681f3Smrg                .outmod = midgard_outmod_keeplo
5467ec681f3Smrg        };
5477ec681f3Smrg
5487ec681f3Smrg        return ins;
5497ec681f3Smrg}
5507ec681f3Smrg
5517ec681f3Smrg/* Broad types of register classes so we can handle special
5527ec681f3Smrg * registers */
5537ec681f3Smrg
5547ec681f3Smrg#define REG_CLASS_WORK          0
5557ec681f3Smrg#define REG_CLASS_LDST          1
5567ec681f3Smrg#define REG_CLASS_TEXR          3
5577ec681f3Smrg#define REG_CLASS_TEXW          4
5587ec681f3Smrg
5597ec681f3Smrg/* Like a move, but to thread local storage! */
5607ec681f3Smrg
5617ec681f3Smrgstatic inline midgard_instruction
5627ec681f3Smrgv_load_store_scratch(
5637ec681f3Smrg                unsigned srcdest,
5647ec681f3Smrg                unsigned index,
5657ec681f3Smrg                bool is_store,
5667ec681f3Smrg                unsigned mask)
5677ec681f3Smrg{
5687ec681f3Smrg        /* We index by 32-bit vec4s */
5697ec681f3Smrg        unsigned byte = (index * 4 * 4);
5707ec681f3Smrg
5717ec681f3Smrg        midgard_instruction ins = {
5727ec681f3Smrg                .type = TAG_LOAD_STORE_4,
5737ec681f3Smrg                .mask = mask,
5747ec681f3Smrg                .dest_type = nir_type_uint32,
5757ec681f3Smrg                .dest = ~0,
5767ec681f3Smrg                .src = { ~0, ~0, ~0, ~0 },
5777ec681f3Smrg                .swizzle = SWIZZLE_IDENTITY_4,
5787ec681f3Smrg                .op = is_store ? midgard_op_st_128 : midgard_op_ld_128,
5797ec681f3Smrg                .load_store = {
5807ec681f3Smrg                        /* For register spilling - to thread local storage */
5817ec681f3Smrg                        .arg_reg = REGISTER_LDST_LOCAL_STORAGE_PTR,
5827ec681f3Smrg                        .arg_comp = COMPONENT_X,
5837ec681f3Smrg                        .bitsize_toggle = true,
5847ec681f3Smrg                        .index_format = midgard_index_address_u32,
5857ec681f3Smrg                        .index_reg = REGISTER_LDST_ZERO,
5867ec681f3Smrg                },
5877ec681f3Smrg
5887ec681f3Smrg                /* If we spill an unspill, RA goes into an infinite loop */
5897ec681f3Smrg                .no_spill = (1 << REG_CLASS_WORK)
5907ec681f3Smrg        };
5917ec681f3Smrg
5927ec681f3Smrg        ins.constants.u32[0] = byte;
5937ec681f3Smrg
5947ec681f3Smrg        if (is_store) {
5957ec681f3Smrg                ins.src[0] = srcdest;
5967ec681f3Smrg                ins.src_types[0] = nir_type_uint32;
5977ec681f3Smrg
5987ec681f3Smrg                /* Ensure we are tightly swizzled so liveness analysis is
5997ec681f3Smrg                 * correct */
6007ec681f3Smrg
6017ec681f3Smrg                for (unsigned i = 0; i < 4; ++i) {
6027ec681f3Smrg                        if (!(mask & (1 << i)))
6037ec681f3Smrg                                ins.swizzle[0][i] = COMPONENT_X;
6047ec681f3Smrg                }
6057ec681f3Smrg        } else
6067ec681f3Smrg                ins.dest = srcdest;
6077ec681f3Smrg
6087ec681f3Smrg        return ins;
6097ec681f3Smrg}
6107ec681f3Smrg
6117ec681f3Smrgstatic inline bool
6127ec681f3Smrgmir_has_arg(midgard_instruction *ins, unsigned arg)
6137ec681f3Smrg{
6147ec681f3Smrg        if (!ins)
6157ec681f3Smrg                return false;
6167ec681f3Smrg
6177ec681f3Smrg        mir_foreach_src(ins, i) {
6187ec681f3Smrg                if (ins->src[i] == arg)
6197ec681f3Smrg                        return true;
6207ec681f3Smrg        }
6217ec681f3Smrg
6227ec681f3Smrg        return false;
6237ec681f3Smrg}
6247ec681f3Smrg
6257ec681f3Smrg/* Scheduling */
6267ec681f3Smrg
6277ec681f3Smrgvoid midgard_schedule_program(compiler_context *ctx);
6287ec681f3Smrg
6297ec681f3Smrgvoid mir_ra(compiler_context *ctx);
6307ec681f3Smrgvoid mir_squeeze_index(compiler_context *ctx);
6317ec681f3Smrgvoid mir_lower_special_reads(compiler_context *ctx);
6327ec681f3Smrgvoid mir_liveness_ins_update(uint16_t *live, midgard_instruction *ins, unsigned max);
6337ec681f3Smrgvoid mir_compute_liveness(compiler_context *ctx);
6347ec681f3Smrgvoid mir_invalidate_liveness(compiler_context *ctx);
6357ec681f3Smrgbool mir_is_live_after(compiler_context *ctx, midgard_block *block, midgard_instruction *start, int src);
6367ec681f3Smrg
6377ec681f3Smrgvoid mir_create_pipeline_registers(compiler_context *ctx);
6387ec681f3Smrgvoid midgard_promote_uniforms(compiler_context *ctx);
6397ec681f3Smrg
6407ec681f3Smrgvoid
6417ec681f3Smrgmidgard_emit_derivatives(compiler_context *ctx, nir_alu_instr *instr);
6427ec681f3Smrg
6437ec681f3Smrgvoid
6447ec681f3Smrgmidgard_lower_derivatives(compiler_context *ctx, midgard_block *block);
6457ec681f3Smrg
6467ec681f3Smrgbool mir_op_computes_derivatives(gl_shader_stage stage, unsigned op);
6477ec681f3Smrg
6487ec681f3Smrgvoid mir_analyze_helper_terminate(compiler_context *ctx);
6497ec681f3Smrgvoid mir_analyze_helper_requirements(compiler_context *ctx);
6507ec681f3Smrg
6517ec681f3Smrg/* Final emission */
6527ec681f3Smrg
6537ec681f3Smrgvoid emit_binary_bundle(
6547ec681f3Smrg        compiler_context *ctx,
6557ec681f3Smrg        midgard_block *block,
6567ec681f3Smrg        midgard_bundle *bundle,
6577ec681f3Smrg        struct util_dynarray *emission,
6587ec681f3Smrg        int next_tag);
6597ec681f3Smrg
6607ec681f3Smrgbool nir_fuse_io_16(nir_shader *shader);
6617ec681f3Smrg
6627ec681f3Smrgbool midgard_nir_lod_errata(nir_shader *shader);
6637ec681f3Smrg
6647ec681f3Smrgunsigned midgard_get_first_tag_from_block(compiler_context *ctx, unsigned block_idx);
6657ec681f3Smrg
6667ec681f3Smrg/* Optimizations */
6677ec681f3Smrg
6687ec681f3Smrgbool midgard_opt_copy_prop(compiler_context *ctx, midgard_block *block);
6697ec681f3Smrgbool midgard_opt_combine_projection(compiler_context *ctx, midgard_block *block);
6707ec681f3Smrgbool midgard_opt_varying_projection(compiler_context *ctx, midgard_block *block);
6717ec681f3Smrgbool midgard_opt_dead_code_eliminate(compiler_context *ctx);
6727ec681f3Smrgbool midgard_opt_dead_move_eliminate(compiler_context *ctx, midgard_block *block);
6737ec681f3Smrg
6747ec681f3Smrg#endif
675