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