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,LimitedShiftsForTexturing)155 TEST_F(ConstantFold, LimitedShiftsForTexturing)
156 {
157    bi_index reg = bi_register(0);
158 
159    EXPECT_FOLD(
160       bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_imm_u32(0xA0000), bi_imm_u8(4)),
161       (0xCAFE << 4) | 0xA0000);
162 
163    EXPECT_NOT_FOLD(
164       bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_not(bi_imm_u32(0xA0000)), bi_imm_u8(4)));
165 
166    EXPECT_NOT_FOLD(
167       bi_lshift_or_i32_to(b, reg, bi_not(bi_imm_u32(0xCAFE)), bi_imm_u32(0xA0000), bi_imm_u8(4)));
168 
169    bi_instr *I = bi_lshift_or_i32_to(b, reg, bi_imm_u32(0xCAFE), bi_imm_u32(0xA0000), bi_imm_u8(4));
170    I->not_result = true;
171    EXPECT_NOT_FOLD(I);
172 }
173 
TEST_F(ConstantFold,LimitedRoundingForTexturing)174 TEST_F(ConstantFold, LimitedRoundingForTexturing)
175 {
176    bi_index reg = bi_register(0);
177 
178    EXPECT_FOLD(bi_f32_to_u32_to(b, reg, bi_imm_f32(15.0), BI_ROUND_NONE), 15);
179    EXPECT_FOLD(bi_f32_to_u32_to(b, reg, bi_imm_f32(15.9), BI_ROUND_NONE), 15);
180    EXPECT_FOLD(bi_f32_to_u32_to(b, reg, bi_imm_f32(-20.4), BI_ROUND_NONE), 0);
181 
182    EXPECT_NOT_FOLD(bi_f32_to_u32_to(b, reg, bi_imm_f32(-20.4), BI_ROUND_RTP));
183    EXPECT_NOT_FOLD(bi_f32_to_u32_to(b, reg, bi_imm_f32(-20.4), BI_ROUND_RTZ));
184 }
185 
TEST_F(ConstantFold,NonConstantSourcesCannotBeFolded)186 TEST_F(ConstantFold, NonConstantSourcesCannotBeFolded)
187 {
188    bi_index reg = bi_register(0);
189 
190    EXPECT_NOT_FOLD(bi_swz_v2i16_to(b, reg, bi_temp(b->shader)));
191    EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_temp(b->shader), bi_temp(b->shader)));
192    EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_temp(b->shader), bi_imm_u32(0xDEADBEEF)));
193    EXPECT_NOT_FOLD(bi_mkvec_v2i16_to(b, reg, bi_imm_u32(0xDEADBEEF), bi_temp(b->shader)));
194 }
195 
TEST_F(ConstantFold,OtherOperationsShouldNotFold)196 TEST_F(ConstantFold, OtherOperationsShouldNotFold)
197 {
198    bi_index zero = bi_fau(bir_fau(BIR_FAU_IMMEDIATE | 0), false);
199    bi_index reg = bi_register(0);
200 
201    EXPECT_NOT_FOLD(bi_fma_f32_to(b, reg, zero, zero, zero, BI_ROUND_NONE));
202    EXPECT_NOT_FOLD(bi_fadd_f32_to(b, reg, zero, zero, BI_ROUND_NONE));
203 }
204