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
30 static std::string
to_string(const bi_instr * I)31 to_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
42 static testing::AssertionResult
constant_fold_pred(const char * I_expr,const char * expected_expr,bi_instr * I,uint32_t expected)43 constant_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
68 static testing::AssertionResult
not_constant_fold_pred(const char * I_expr,bi_instr * I)69 not_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
86 class ConstantFold : public testing::Test {
87 protected:
ConstantFold()88 ConstantFold() {
89 mem_ctx = ralloc_context(NULL);
90 b = bit_builder(mem_ctx);
91 }
~ConstantFold()92 ~ConstantFold() {
93 ralloc_free(mem_ctx);
94 }
95
96 void *mem_ctx;
97 bi_builder *b;
98 };
99
TEST_F(ConstantFold,Swizzles)100 TEST_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
TEST_F(ConstantFold,VectorConstructions2i16)121 TEST_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
TEST_F(ConstantFold,VectorConstructions4i8)141 TEST_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
TEST_F(ConstantFold,VectorConstructions2i8)155 TEST_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
TEST_F(ConstantFold,LimitedShiftsForTexturing)172 TEST_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
TEST_F(ConstantFold,NonConstantSourcesCannotBeFolded)191 TEST_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
TEST_F(ConstantFold,OtherOperationsShouldNotFold)201 TEST_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