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