Path: blob/21.2-virgl/src/freedreno/ir3/ir3_cf.c
4565 views
/*1* Copyright (C) 2019 Google.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*/2223#include "util/ralloc.h"2425#include "ir3.h"2627static bool28is_safe_conv(struct ir3_instruction *instr, type_t src_type, opc_t *src_opc)29{30if (instr->opc != OPC_MOV)31return false;3233/* Only allow half->full or full->half without any type conversion (like34* int to float).35*/36if (type_size(instr->cat1.src_type) == type_size(instr->cat1.dst_type) ||37full_type(instr->cat1.src_type) != full_type(instr->cat1.dst_type))38return false;3940struct ir3_register *dst = instr->dsts[0];41struct ir3_register *src = instr->srcs[0];4243/* disallow conversions that cannot be folded into44* alu instructions:45*/46if (instr->cat1.round != ROUND_ZERO)47return false;4849if (dst->flags & (IR3_REG_RELATIV | IR3_REG_ARRAY))50return false;51if (src->flags & (IR3_REG_RELATIV | IR3_REG_ARRAY))52return false;5354/* Check that the source of the conv matches the type of the src55* instruction.56*/57if (src_type == instr->cat1.src_type)58return true;5960/* We can handle mismatches with integer types by converting the opcode61* but not when an integer is reinterpreted as a float or vice-versa.62*/63if (type_float(src_type) != type_float(instr->cat1.src_type))64return false;6566/* We have types with mismatched signedness. Mismatches on the signedness67* don't matter when narrowing:68*/69if (type_size(instr->cat1.dst_type) < type_size(instr->cat1.src_type))70return true;7172/* Try swapping the opcode: */73bool can_swap = true;74*src_opc = ir3_try_swap_signedness(*src_opc, &can_swap);75return can_swap;76}7778static bool79all_uses_safe_conv(struct ir3_instruction *conv_src, type_t src_type)80{81opc_t opc = conv_src->opc;82bool first = true;83foreach_ssa_use (use, conv_src) {84opc_t new_opc = opc;85if (!is_safe_conv(use, src_type, &new_opc))86return false;87/* Check if multiple uses have conflicting requirements on the opcode.88*/89if (!first && opc != new_opc)90return false;91first = false;92opc = new_opc;93}94conv_src->opc = opc;95return true;96}9798/* For an instruction which has a conversion folded in, re-write the99* uses of *all* conv's that used that src to be a simple mov that100* cp can eliminate. This avoids invalidating the SSA uses, it just101* shifts the use to a simple mov.102*/103static void104rewrite_src_uses(struct ir3_instruction *src)105{106foreach_ssa_use (use, src) {107assert(use->opc == OPC_MOV);108109if (is_half(src)) {110use->srcs[0]->flags |= IR3_REG_HALF;111} else {112use->srcs[0]->flags &= ~IR3_REG_HALF;113}114115use->cat1.src_type = use->cat1.dst_type;116}117}118119static bool120try_conversion_folding(struct ir3_instruction *conv)121{122struct ir3_instruction *src;123124if (conv->opc != OPC_MOV)125return false;126127/* NOTE: we can have non-ssa srcs after copy propagation: */128src = ssa(conv->srcs[0]);129if (!src)130return false;131132if (!is_alu(src))133return false;134135bool can_fold;136type_t base_type = ir3_output_conv_type(src, &can_fold);137if (!can_fold)138return false;139140type_t src_type = ir3_output_conv_src_type(src, base_type);141type_t dst_type = ir3_output_conv_dst_type(src, base_type);142143/* Avoid cases where we've already folded in a conversion. We assume that144* if there is a chain of conversions that's foldable then it's been145* folded in NIR already.146*/147if (src_type != dst_type)148return false;149150if (!all_uses_safe_conv(src, src_type))151return false;152153ir3_set_dst_type(src, is_half(conv));154rewrite_src_uses(src);155156return true;157}158159bool160ir3_cf(struct ir3 *ir)161{162void *mem_ctx = ralloc_context(NULL);163bool progress = false;164165ir3_find_ssa_uses(ir, mem_ctx, false);166167foreach_block (block, &ir->block_list) {168foreach_instr (instr, &block->instr_list) {169progress |= try_conversion_folding(instr);170}171}172173ralloc_free(mem_ctx);174175return progress;176}177178179