1/* 2 * Copyright (C) 2021 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_test.h" 26#include "bi_builder.h" 27 28#include <gtest/gtest.h> 29 30static std::string 31to_string(const bi_instr *I) { 32 char *cstr = NULL; 33 size_t size = 0; 34 FILE *f = open_memstream(&cstr, &size); 35 bi_print_instr(I, f); 36 fclose(f); 37 auto str = std::string(cstr); 38 free(cstr); 39 return str; 40} 41 42static testing::AssertionResult 43constant_fold_pred(const char *I_expr, 44 const char *expected_expr, 45 bi_instr *I, 46 uint32_t expected) 47{ 48 bool unsupported = false; 49 uint32_t v = bi_fold_constant(I, &unsupported); 50 if (unsupported) { 51 return testing::AssertionFailure() 52 << "Constant fold unsupported for instruction \n\n" 53 << " " << to_string(I); 54 } else if (v != expected) { 55 return testing::AssertionFailure() 56 << "Unexpected result when constant folding instruction\n\n" 57 << " " << to_string(I) << "\n" 58 << " Actual: " << v << "\n" 59 << "Expected: " << expected << "\n"; 60 } else { 61 return testing::AssertionSuccess(); 62 } 63} 64 65#define EXPECT_FOLD(i, e) EXPECT_PRED_FORMAT2(constant_fold_pred, i, e) 66 67 68static testing::AssertionResult 69not_constant_fold_pred(const char *I_expr, bi_instr *I) 70{ 71 bool unsupported = false; 72 uint32_t v = bi_fold_constant(I, &unsupported); 73 if (unsupported) { 74 return testing::AssertionSuccess(); 75 } else { 76 return testing::AssertionFailure() 77 << "Instruction\n\n" 78 << " " << to_string(I) << "\n" 79 << "shouldn't have constant folded, but folded to: " << v; 80 } 81} 82 83#define EXPECT_NOT_FOLD(i) EXPECT_PRED_FORMAT1(not_constant_fold_pred, i) 84 85 86class ConstantFold : public testing::Test { 87protected: 88 ConstantFold() { 89 mem_ctx = ralloc_context(NULL); 90 b = bit_builder(mem_ctx); 91 } 92 ~ConstantFold() { 93 ralloc_free(mem_ctx); 94 } 95 96 void *mem_ctx; 97 bi_builder *b; 98}; 99 100TEST_F(ConstantFold, Swizzles) 101{ 102 bi_index reg = bi_register(0); 103 104 EXPECT_FOLD( 105 bi_swz_v2i16_to(b, reg, bi_imm_u32(0xCAFEBABE)), 106 0xCAFEBABE); 107 108 EXPECT_FOLD( 109 bi_swz_v2i16_to(b, reg, bi_swz_16(bi_imm_u32(0xCAFEBABE), false, false)), 110 0xBABEBABE); 111 112 EXPECT_FOLD( 113 bi_swz_v2i16_to(b, reg, bi_swz_16(bi_imm_u32(0xCAFEBABE), true, false)), 114 0xBABECAFE); 115 116 EXPECT_FOLD( 117 bi_swz_v2i16_to(b, reg, bi_swz_16(bi_imm_u32(0xCAFEBABE), true, true)), 118 0xCAFECAFE); 119} 120 121TEST_F(ConstantFold, VectorConstructions2i16) 122{ 123 bi_index reg = bi_register(0); 124 125 EXPECT_FOLD( 126 bi_mkvec_v2i16_to(b, reg, bi_imm_u16(0xCAFE), 127 bi_imm_u16(0xBABE)), 128 0xBABECAFE); 129 130 EXPECT_FOLD( 131 bi_mkvec_v2i16_to(b, reg, bi_swz_16(bi_imm_u32(0xCAFEBABE), true, true), 132 bi_imm_u16(0xBABE)), 133 0xBABECAFE); 134 135 EXPECT_FOLD( 136 bi_mkvec_v2i16_to(b, reg, bi_swz_16(bi_imm_u32(0xCAFEBABE), true, true), 137 bi_swz_16(bi_imm_u32(0xCAFEBABE), false, false)), 138 0xBABECAFE); 139} 140 141TEST_F(ConstantFold, VectorConstructions4i8) 142{ 143 bi_index reg = bi_register(0); 144 bi_index u32 = bi_imm_u32(0xCAFEBABE); 145 146 bi_index a = bi_byte(u32, 0); /* 0xBE */ 147 bi_index c = bi_byte(u32, 2); /* 0xFE */ 148 149 EXPECT_FOLD(bi_mkvec_v4i8_to(b, reg, a, a, a, a), 0xBEBEBEBE); 150 EXPECT_FOLD(bi_mkvec_v4i8_to(b, reg, a, c, a, c), 0xFEBEFEBE); 151 EXPECT_FOLD(bi_mkvec_v4i8_to(b, reg, c, a, c, a), 0xBEFEBEFE); 152 EXPECT_FOLD(bi_mkvec_v4i8_to(b, reg, c, c, c, c), 0xFEFEFEFE); 153} 154 155TEST_F(ConstantFold, VectorConstructions2i8) 156{ 157 bi_index reg = bi_register(0); 158 bi_index u32 = bi_imm_u32(0xCAFEBABE); 159 bi_index rem = bi_imm_u32(0xABCD1234); 160 161 bi_index a = bi_byte(u32, 0); /* 0xBE */ 162 bi_index B = bi_byte(u32, 1); /* 0xBA */ 163 bi_index c = bi_byte(u32, 2); /* 0xFE */ 164 bi_index d = bi_byte(u32, 3); /* 0xCA */ 165 166 EXPECT_FOLD(bi_mkvec_v2i8_to(b, reg, a, B, rem), 0x1234BABE); 167 EXPECT_FOLD(bi_mkvec_v2i8_to(b, reg, a, d, rem), 0x1234CABE); 168 EXPECT_FOLD(bi_mkvec_v2i8_to(b, reg, c, d, rem), 0x1234CAFE); 169 EXPECT_FOLD(bi_mkvec_v2i8_to(b, reg, d, d, rem), 0x1234CACA); 170} 171 172TEST_F(ConstantFold, LimitedShiftsForTexturing) 173{ 174 bi_index reg = bi_register(0); 175 176 EXPECT_FOLD( 177 bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_imm_u32(0xA0000), bi_imm_u8(4)), 178 (0xCAFE << 4) | 0xA0000); 179 180 EXPECT_NOT_FOLD( 181 bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_not(bi_imm_u32(0xA0000)), bi_imm_u8(4))); 182 183 EXPECT_NOT_FOLD( 184 bi_lshift_or_i32_to(b, reg, bi_not(bi_imm_u32(0xCAFE)), bi_imm_u32(0xA0000), bi_imm_u8(4))); 185 186 bi_instr *I = bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_imm_u32(0xA0000), bi_imm_u8(4)); 187 I->not_result = true; 188 EXPECT_NOT_FOLD(I); 189} 190 191TEST_F(ConstantFold, NonConstantSourcesCannotBeFolded) 192{ 193 bi_index reg = bi_register(0); 194 195 EXPECT_NOT_FOLD(bi_swz_v2i16_to(b, reg, bi_temp(b->shader))); 196 EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_temp(b->shader), bi_temp(b->shader))); 197 EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_temp(b->shader), bi_imm_u32(0xDEADBEEF))); 198 EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_imm_u32(0xDEADBEEF), bi_temp(b->shader))); 199} 200 201TEST_F(ConstantFold, OtherOperationsShouldNotFold) 202{ 203 bi_index zero = bi_fau(bir_fau(BIR_FAU_IMMEDIATE | 0), false); 204 bi_index reg = bi_register(0); 205 206 EXPECT_NOT_FOLD(bi_fma_f32_to(b, reg, zero, zero, zero)); 207 EXPECT_NOT_FOLD(bi_fadd_f32_to(b, reg, zero, zero)); 208} 209