1/* 2 * Copyright (C) 2020 Collabora Ltd. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "compiler.h" 25#include "bi_builder.h" 26 27/* Dead simple constant folding to cleanup compiler frontend patterns. Before 28 * adding a new pattern here, check why you need it and whether we can avoid 29 * generating the constant BIR at all. */ 30 31uint32_t 32bi_fold_constant(bi_instr *I, bool *unsupported) 33{ 34 /* We can only fold instructions where all sources are constant */ 35 bi_foreach_src(I, s) { 36 enum bi_index_type type = I->src[s].type; 37 38 if (!(type == BI_INDEX_NULL || type == BI_INDEX_CONSTANT)) { 39 *unsupported = true; 40 return 0; 41 } 42 } 43 44 /* Grab the sources */ 45 uint32_t a = bi_apply_swizzle(I->src[0].value, I->src[0].swizzle); 46 uint32_t b = bi_apply_swizzle(I->src[1].value, I->src[1].swizzle); 47 uint32_t c = bi_apply_swizzle(I->src[2].value, I->src[2].swizzle); 48 uint32_t d = bi_apply_swizzle(I->src[3].value, I->src[3].swizzle); 49 50 /* Evaluate the instruction */ 51 switch (I->op) { 52 case BI_OPCODE_SWZ_V2I16: 53 return a; 54 55 case BI_OPCODE_MKVEC_V2I16: 56 return (b << 16) | (a & 0xFFFF); 57 58 case BI_OPCODE_MKVEC_V4I8: 59 return (d << 24) | ((c & 0xFF) << 16) | ((b & 0xFF) << 8) | (a & 0xFF); 60 61 case BI_OPCODE_MKVEC_V2I8: 62 return (c << 16) | ((b & 0xFF) << 8) | (a & 0xFF); 63 64 case BI_OPCODE_LSHIFT_OR_I32: 65 if (I->not_result || I->src[0].neg || I->src[1].neg) 66 break; 67 68 return (a << c) | b; 69 70 case BI_OPCODE_F32_TO_U32: 71 if (I->round == BI_ROUND_NONE) { 72 /* Explicitly clamp to prevent undefined behaviour and 73 * match hardware rules */ 74 float f = uif(a); 75 return (f >= 0.0) ? (uint32_t) f : 0; 76 } else 77 break; 78 79 default: 80 break; 81 } 82 83 *unsupported = true; 84 return 0; 85} 86 87bool 88bi_opt_constant_fold(bi_context *ctx) 89{ 90 bool progress = false; 91 92 bi_foreach_instr_global_safe(ctx, ins) { 93 bool unsupported = false; 94 uint32_t replace = bi_fold_constant(ins, &unsupported); 95 if (unsupported) continue; 96 97 /* Replace with constant move, to be copypropped */ 98 bi_builder b = bi_init_builder(ctx, bi_after_instr(ins)); 99 bi_mov_i32_to(&b, ins->dest[0], bi_imm_u32(replace)); 100 bi_remove_instruction(ins); 101 progress = true; 102 } 103 104 return progress; 105} 106