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