bir.c revision 7ec681f3
17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2020 Collabora Ltd.
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217ec681f3Smrg * SOFTWARE.
227ec681f3Smrg *
237ec681f3Smrg * Authors (Collabora):
247ec681f3Smrg *      Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
257ec681f3Smrg */
267ec681f3Smrg
277ec681f3Smrg#include "compiler.h"
287ec681f3Smrg
297ec681f3Smrgbool
307ec681f3Smrgbi_has_arg(const bi_instr *ins, bi_index arg)
317ec681f3Smrg{
327ec681f3Smrg        if (!ins)
337ec681f3Smrg                return false;
347ec681f3Smrg
357ec681f3Smrg        bi_foreach_src(ins, s) {
367ec681f3Smrg                if (bi_is_equiv(ins->src[s], arg))
377ec681f3Smrg                        return true;
387ec681f3Smrg        }
397ec681f3Smrg
407ec681f3Smrg        return false;
417ec681f3Smrg}
427ec681f3Smrg
437ec681f3Smrg/* Precondition: valid 16-bit or 32-bit register format. Returns whether it is
447ec681f3Smrg * 32-bit. Note auto reads to 32-bit registers even if the memory format is
457ec681f3Smrg * 16-bit, so is considered as such here */
467ec681f3Smrg
477ec681f3Smrgbool
487ec681f3Smrgbi_is_regfmt_16(enum bi_register_format fmt)
497ec681f3Smrg{
507ec681f3Smrg        switch  (fmt) {
517ec681f3Smrg        case BI_REGISTER_FORMAT_F16:
527ec681f3Smrg        case BI_REGISTER_FORMAT_S16:
537ec681f3Smrg        case BI_REGISTER_FORMAT_U16:
547ec681f3Smrg                return true;
557ec681f3Smrg        case BI_REGISTER_FORMAT_F32:
567ec681f3Smrg        case BI_REGISTER_FORMAT_S32:
577ec681f3Smrg        case BI_REGISTER_FORMAT_U32:
587ec681f3Smrg        case BI_REGISTER_FORMAT_AUTO:
597ec681f3Smrg                return false;
607ec681f3Smrg        default:
617ec681f3Smrg                unreachable("Invalid register format");
627ec681f3Smrg        }
637ec681f3Smrg}
647ec681f3Smrg
657ec681f3Smrgstatic unsigned
667ec681f3Smrgbi_count_staging_registers(const bi_instr *ins)
677ec681f3Smrg{
687ec681f3Smrg        enum bi_sr_count count = bi_opcode_props[ins->op].sr_count;
697ec681f3Smrg        unsigned vecsize = ins->vecsize + 1; /* XXX: off-by-one */
707ec681f3Smrg
717ec681f3Smrg        switch (count) {
727ec681f3Smrg        case BI_SR_COUNT_0 ... BI_SR_COUNT_4:
737ec681f3Smrg                return count;
747ec681f3Smrg        case BI_SR_COUNT_FORMAT:
757ec681f3Smrg                return bi_is_regfmt_16(ins->register_format) ?
767ec681f3Smrg                        DIV_ROUND_UP(vecsize, 2) : vecsize;
777ec681f3Smrg        case BI_SR_COUNT_VECSIZE:
787ec681f3Smrg                return vecsize;
797ec681f3Smrg        case BI_SR_COUNT_SR_COUNT:
807ec681f3Smrg                return ins->sr_count;
817ec681f3Smrg        }
827ec681f3Smrg
837ec681f3Smrg        unreachable("Invalid sr_count");
847ec681f3Smrg}
857ec681f3Smrg
867ec681f3Smrgunsigned
877ec681f3Smrgbi_count_read_registers(const bi_instr *ins, unsigned s)
887ec681f3Smrg{
897ec681f3Smrg        /* PATOM_C reads 1 but writes 2 */
907ec681f3Smrg        if (s == 0 && ins->op == BI_OPCODE_PATOM_C_I32)
917ec681f3Smrg                return 1;
927ec681f3Smrg        else if (s == 0 && bi_opcode_props[ins->op].sr_read)
937ec681f3Smrg                return bi_count_staging_registers(ins);
947ec681f3Smrg        else
957ec681f3Smrg                return 1;
967ec681f3Smrg}
977ec681f3Smrg
987ec681f3Smrgunsigned
997ec681f3Smrgbi_count_write_registers(const bi_instr *ins, unsigned d)
1007ec681f3Smrg{
1017ec681f3Smrg        if (d == 0 && bi_opcode_props[ins->op].sr_write) {
1027ec681f3Smrg                /* TODO: this special case is even more special, TEXC has a
1037ec681f3Smrg                 * generic write mask stuffed in the desc... */
1047ec681f3Smrg                if (ins->op == BI_OPCODE_TEXC)
1057ec681f3Smrg                        return 4;
1067ec681f3Smrg                else
1077ec681f3Smrg                        return bi_count_staging_registers(ins);
1087ec681f3Smrg        } else if (ins->op == BI_OPCODE_SEG_ADD_I64) {
1097ec681f3Smrg                return 2;
1107ec681f3Smrg        }
1117ec681f3Smrg
1127ec681f3Smrg        return 1;
1137ec681f3Smrg}
1147ec681f3Smrg
1157ec681f3Smrgunsigned
1167ec681f3Smrgbi_writemask(const bi_instr *ins, unsigned d)
1177ec681f3Smrg{
1187ec681f3Smrg        unsigned mask = BITFIELD_MASK(bi_count_write_registers(ins, d));
1197ec681f3Smrg        unsigned shift = ins->dest[d].offset;
1207ec681f3Smrg        return (mask << shift);
1217ec681f3Smrg}
1227ec681f3Smrg
1237ec681f3Smrgbi_clause *
1247ec681f3Smrgbi_next_clause(bi_context *ctx, bi_block *block, bi_clause *clause)
1257ec681f3Smrg{
1267ec681f3Smrg        if (!block && !clause)
1277ec681f3Smrg                return NULL;
1287ec681f3Smrg
1297ec681f3Smrg        /* Try the first clause in this block if we're starting from scratch */
1307ec681f3Smrg        if (!clause && !list_is_empty(&block->clauses))
1317ec681f3Smrg                return list_first_entry(&block->clauses, bi_clause, link);
1327ec681f3Smrg
1337ec681f3Smrg        /* Try the next clause in this block */
1347ec681f3Smrg        if (clause && clause->link.next != &block->clauses)
1357ec681f3Smrg                return list_first_entry(&(clause->link), bi_clause, link);
1367ec681f3Smrg
1377ec681f3Smrg        /* Try the next block, or the one after that if it's empty, etc .*/
1387ec681f3Smrg        bi_block *next_block = bi_next_block(block);
1397ec681f3Smrg
1407ec681f3Smrg        bi_foreach_block_from(ctx, next_block, block) {
1417ec681f3Smrg                if (!list_is_empty(&block->clauses))
1427ec681f3Smrg                        return list_first_entry(&block->clauses, bi_clause, link);
1437ec681f3Smrg        }
1447ec681f3Smrg
1457ec681f3Smrg        return NULL;
1467ec681f3Smrg}
1477ec681f3Smrg
1487ec681f3Smrg/* Does an instruction have a side effect not captured by its register
1497ec681f3Smrg * destination? Applies to certain message-passing instructions, +DISCARD, and
1507ec681f3Smrg * branching only, used in dead code elimation. Branches are characterized by
1517ec681f3Smrg * `last` which applies to them and some atomics, +BARRIER, +BLEND which
1527ec681f3Smrg * implies no loss of generality */
1537ec681f3Smrg
1547ec681f3Smrgbool
1557ec681f3Smrgbi_side_effects(enum bi_opcode op)
1567ec681f3Smrg{
1577ec681f3Smrg        if (bi_opcode_props[op].last)
1587ec681f3Smrg                return true;
1597ec681f3Smrg
1607ec681f3Smrg        switch (op) {
1617ec681f3Smrg        case BI_OPCODE_DISCARD_F32:
1627ec681f3Smrg        case BI_OPCODE_DISCARD_B32:
1637ec681f3Smrg                return true;
1647ec681f3Smrg        default:
1657ec681f3Smrg                break;
1667ec681f3Smrg        }
1677ec681f3Smrg
1687ec681f3Smrg        switch (bi_opcode_props[op].message) {
1697ec681f3Smrg        case BIFROST_MESSAGE_NONE:
1707ec681f3Smrg        case BIFROST_MESSAGE_VARYING:
1717ec681f3Smrg        case BIFROST_MESSAGE_ATTRIBUTE:
1727ec681f3Smrg        case BIFROST_MESSAGE_TEX:
1737ec681f3Smrg        case BIFROST_MESSAGE_VARTEX:
1747ec681f3Smrg        case BIFROST_MESSAGE_LOAD:
1757ec681f3Smrg        case BIFROST_MESSAGE_64BIT:
1767ec681f3Smrg                return false;
1777ec681f3Smrg
1787ec681f3Smrg        case BIFROST_MESSAGE_STORE:
1797ec681f3Smrg        case BIFROST_MESSAGE_ATOMIC:
1807ec681f3Smrg        case BIFROST_MESSAGE_BARRIER:
1817ec681f3Smrg        case BIFROST_MESSAGE_BLEND:
1827ec681f3Smrg        case BIFROST_MESSAGE_Z_STENCIL:
1837ec681f3Smrg        case BIFROST_MESSAGE_ATEST:
1847ec681f3Smrg        case BIFROST_MESSAGE_JOB:
1857ec681f3Smrg                return true;
1867ec681f3Smrg
1877ec681f3Smrg        case BIFROST_MESSAGE_TILE:
1887ec681f3Smrg                return (op != BI_OPCODE_LD_TILE);
1897ec681f3Smrg        }
1907ec681f3Smrg
1917ec681f3Smrg        unreachable("Invalid message type");
1927ec681f3Smrg}
1937ec681f3Smrg
1947ec681f3Smrg/* Branch reconvergence is required when the execution mask may change
1957ec681f3Smrg * between adjacent instructions (clauses). This occurs for conditional
1967ec681f3Smrg * branches and for the last instruction (clause) in a block whose
1977ec681f3Smrg * fallthrough successor has multiple predecessors.
1987ec681f3Smrg */
1997ec681f3Smrg
2007ec681f3Smrgbool
2017ec681f3Smrgbi_reconverge_branches(bi_block *block)
2027ec681f3Smrg{
2037ec681f3Smrg        /* Last block of a program */
2047ec681f3Smrg        if (!block->successors[0]) {
2057ec681f3Smrg                assert(!block->successors[1]);
2067ec681f3Smrg                return true;
2077ec681f3Smrg        }
2087ec681f3Smrg
2097ec681f3Smrg        /* Multiple successors? We're branching */
2107ec681f3Smrg        if (block->successors[1])
2117ec681f3Smrg                return true;
2127ec681f3Smrg
2137ec681f3Smrg        /* Must have at least one successor */
2147ec681f3Smrg        struct bi_block *succ = block->successors[0];
2157ec681f3Smrg        assert(succ->predecessors);
2167ec681f3Smrg
2177ec681f3Smrg        /* Reconverge if the successor has multiple predecessors */
2187ec681f3Smrg        return (succ->predecessors->entries > 1);
2197ec681f3Smrg}
220