1 // Copyright (c) 2016 Google Inc.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 #include "source/opt/fold.h"
15
16 #include <limits>
17 #include <memory>
18 #include <string>
19 #include <unordered_set>
20 #include <vector>
21
22 #include "effcee/effcee.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "source/opt/build_module.h"
26 #include "source/opt/def_use_manager.h"
27 #include "source/opt/ir_context.h"
28 #include "source/opt/module.h"
29 #include "spirv-tools/libspirv.hpp"
30
31 namespace spvtools {
32 namespace opt {
33 namespace {
34
35 using ::testing::Contains;
36
Disassemble(const std::string& original, IRContext* context, uint32_t disassemble_options = 0)37 std::string Disassemble(const std::string& original, IRContext* context,
38 uint32_t disassemble_options = 0) {
39 std::vector<uint32_t> optimized_bin;
40 context->module()->ToBinary(&optimized_bin, true);
41 spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
42 SpirvTools tools(target_env);
43 std::string optimized_asm;
44 EXPECT_TRUE(
45 tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
46 << "Disassembling failed for shader:\n"
47 << original << std::endl;
48 return optimized_asm;
49 }
50
Match(const std::string& original, IRContext* context, uint32_t disassemble_options = 0)51 void Match(const std::string& original, IRContext* context,
52 uint32_t disassemble_options = 0) {
53 std::string disassembly = Disassemble(original, context, disassemble_options);
54 auto match_result = effcee::Match(disassembly, original);
55 EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
56 << match_result.message() << "\nChecking result:\n"
57 << disassembly;
58 }
59
60 template <class ResultType>
61 struct InstructionFoldingCase {
InstructionFoldingCasespvtools::opt::__anon26957::InstructionFoldingCase62 InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
63 : test_body(tb), id_to_fold(id), expected_result(result) {}
64
65 std::string test_body;
66 uint32_t id_to_fold;
67 ResultType expected_result;
68 };
69
70 using IntegerInstructionFoldingTest =
71 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
72
TEST_P(IntegerInstructionFoldingTest, Case)73 TEST_P(IntegerInstructionFoldingTest, Case) {
74 const auto& tc = GetParam();
75
76 // Build module.
77 std::unique_ptr<IRContext> context =
78 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
79 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
80 ASSERT_NE(nullptr, context);
81
82 // Fold the instruction to test.
83 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
84 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
85 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
86
87 // Make sure the instruction folded as expected.
88 EXPECT_TRUE(succeeded);
89 if (inst != nullptr) {
90 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
91 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
92 EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
93 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
94 const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst);
95 // We expect to see either integer types or 16-bit float types here.
96 EXPECT_TRUE((constant->AsIntConstant() != nullptr) ||
97 ((constant->AsFloatConstant() != nullptr) &&
98 (constant->type()->AsFloat()->width() == 16)));
99 const analysis::ScalarConstant* result =
100 const_mrg->GetConstantFromInst(inst)->AsScalarConstant();
101 EXPECT_NE(result, nullptr);
102 if (result != nullptr) {
103 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
104 }
105 }
106 }
107
108 // Returns a common SPIR-V header for all of the test that follow.
109 #define INT_0_ID 100
110 #define TRUE_ID 101
111 #define VEC2_0_ID 102
112 #define INT_7_ID 103
113 #define FLOAT_0_ID 104
114 #define DOUBLE_0_ID 105
115 #define VEC4_0_ID 106
116 #define DVEC4_0_ID 106
117 #define HALF_0_ID 108
Header()118 const std::string& Header() {
119 static const std::string header = R"(OpCapability Shader
120 OpCapability Float16
121 OpCapability Float64
122 OpCapability Int8
123 OpCapability Int16
124 OpCapability Int64
125 %1 = OpExtInstImport "GLSL.std.450"
126 OpMemoryModel Logical GLSL450
127 OpEntryPoint Fragment %main "main"
128 OpExecutionMode %main OriginUpperLeft
129 OpSource GLSL 140
130 OpName %main "main"
131 %void = OpTypeVoid
132 %void_func = OpTypeFunction %void
133 %bool = OpTypeBool
134 %float = OpTypeFloat 32
135 %double = OpTypeFloat 64
136 %half = OpTypeFloat 16
137 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
138 %true = OpConstantTrue %bool
139 %false = OpConstantFalse %bool
140 %bool_null = OpConstantNull %bool
141 %short = OpTypeInt 16 1
142 %ushort = OpTypeInt 16 0
143 %byte = OpTypeInt 8 1
144 %ubyte = OpTypeInt 8 0
145 %int = OpTypeInt 32 1
146 %long = OpTypeInt 64 1
147 %uint = OpTypeInt 32 0
148 %ulong = OpTypeInt 64 0
149 %v2int = OpTypeVector %int 2
150 %v4int = OpTypeVector %int 4
151 %v4float = OpTypeVector %float 4
152 %v4double = OpTypeVector %double 4
153 %v2uint = OpTypeVector %uint 2
154 %v2float = OpTypeVector %float 2
155 %v2double = OpTypeVector %double 2
156 %v2half = OpTypeVector %half 2
157 %v2bool = OpTypeVector %bool 2
158 %m2x2int = OpTypeMatrix %v2int 2
159 %mat4v2float = OpTypeMatrix %v2float 4
160 %mat2v4float = OpTypeMatrix %v4float 2
161 %mat4v4float = OpTypeMatrix %v4float 4
162 %mat4v4double = OpTypeMatrix %v4double 4
163 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
164 %_ptr_int = OpTypePointer Function %int
165 %_ptr_uint = OpTypePointer Function %uint
166 %_ptr_bool = OpTypePointer Function %bool
167 %_ptr_float = OpTypePointer Function %float
168 %_ptr_double = OpTypePointer Function %double
169 %_ptr_half = OpTypePointer Function %half
170 %_ptr_long = OpTypePointer Function %long
171 %_ptr_ulong = OpTypePointer Function %ulong
172 %_ptr_v2int = OpTypePointer Function %v2int
173 %_ptr_v4int = OpTypePointer Function %v4int
174 %_ptr_v4float = OpTypePointer Function %v4float
175 %_ptr_v4double = OpTypePointer Function %v4double
176 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
177 %_ptr_v2float = OpTypePointer Function %v2float
178 %_ptr_v2double = OpTypePointer Function %v2double
179 %int_2 = OpConstant %int 2
180 %int_arr_2 = OpTypeArray %int %int_2
181 %short_0 = OpConstant %short 0
182 %short_2 = OpConstant %short 2
183 %short_3 = OpConstant %short 3
184 %ubyte_1 = OpConstant %ubyte 1
185 %byte_n1 = OpConstant %byte -1
186 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
187 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
188 %int_0 = OpConstant %int 0
189 %int_1 = OpConstant %int 1
190 %int_3 = OpConstant %int 3
191 %int_4 = OpConstant %int 4
192 %int_10 = OpConstant %int 10
193 %int_1073741824 = OpConstant %int 1073741824
194 %int_n1 = OpConstant %int -1
195 %int_n24 = OpConstant %int -24
196 %int_n858993459 = OpConstant %int -858993459
197 %int_min = OpConstant %int -2147483648
198 %int_max = OpConstant %int 2147483647
199 %long_0 = OpConstant %long 0
200 %long_1 = OpConstant %long 1
201 %long_2 = OpConstant %long 2
202 %long_3 = OpConstant %long 3
203 %long_10 = OpConstant %long 10
204 %long_4611686018427387904 = OpConstant %long 4611686018427387904
205 %long_n1 = OpConstant %long -1
206 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
207 %long_min = OpConstant %long -9223372036854775808
208 %long_max = OpConstant %long 9223372036854775807
209 %uint_0 = OpConstant %uint 0
210 %uint_1 = OpConstant %uint 1
211 %uint_2 = OpConstant %uint 2
212 %uint_3 = OpConstant %uint 3
213 %uint_4 = OpConstant %uint 4
214 %uint_32 = OpConstant %uint 32
215 %uint_42 = OpConstant %uint 42
216 %uint_2147483649 = OpConstant %uint 2147483649
217 %uint_max = OpConstant %uint 4294967295
218 %ulong_0 = OpConstant %ulong 0
219 %ulong_1 = OpConstant %ulong 1
220 %ulong_2 = OpConstant %ulong 2
221 %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809
222 %ulong_max = OpConstant %ulong 18446744073709551615
223 %v2int_undef = OpUndef %v2int
224 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
225 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
226 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
227 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
228 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
229 %v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24
230 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
231 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
232 %v2bool_null = OpConstantNull %v2bool
233 %v2bool_true_false = OpConstantComposite %v2bool %true %false
234 %v2bool_false_true = OpConstantComposite %v2bool %false %true
235 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
236 %v2int_null = OpConstantNull %v2int
237 %102 = OpConstantComposite %v2int %103 %103
238 %v4int_undef = OpUndef %v4int
239 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
240 %m2x2int_undef = OpUndef %m2x2int
241 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
242 %float_n1 = OpConstant %float -1
243 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
244 %float_null = OpConstantNull %float
245 %float_0 = OpConstant %float 0
246 %float_n0 = OpConstant %float -0.0
247 %float_1 = OpConstant %float 1
248 %float_2 = OpConstant %float 2
249 %float_3 = OpConstant %float 3
250 %float_4 = OpConstant %float 4
251 %float_2049 = OpConstant %float 2049
252 %float_n2049 = OpConstant %float -2049
253 %float_0p5 = OpConstant %float 0.5
254 %float_0p2 = OpConstant %float 0.2
255 %float_pi = OpConstant %float 1.5555
256 %float_1e16 = OpConstant %float 1e16
257 %float_n1e16 = OpConstant %float -1e16
258 %float_1en16 = OpConstant %float 1e-16
259 %float_n1en16 = OpConstant %float -1e-16
260 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
261 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
262 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
263 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
264 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
265 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
266 %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
267 %v2float_null = OpConstantNull %v2float
268 %double_n1 = OpConstant %double -1
269 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
270 %double_null = OpConstantNull %double
271 %double_0 = OpConstant %double 0
272 %double_n0 = OpConstant %double -0.0
273 %double_1 = OpConstant %double 1
274 %double_2 = OpConstant %double 2
275 %double_3 = OpConstant %double 3
276 %double_4 = OpConstant %double 4
277 %double_5 = OpConstant %double 5
278 %double_0p5 = OpConstant %double 0.5
279 %double_0p2 = OpConstant %double 0.2
280 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
281 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
282 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
283 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
284 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
285 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
286 %v2double_null = OpConstantNull %v2double
287 %108 = OpConstant %half 0
288 %half_1 = OpConstant %half 1
289 %half_2 = OpConstant %half 2
290 %half_0_1 = OpConstantComposite %v2half %108 %half_1
291 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
292 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
293 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
294 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
295 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
296 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
297 %v4float_null = OpConstantNull %v4float
298 %mat2v4float_null = OpConstantNull %mat2v4float
299 %mat4v4float_null = OpConstantNull %mat4v4float
300 %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4
301 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null
302 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
303 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
304 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
305 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
306 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
307 %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4
308 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
309 %v4double_null = OpConstantNull %v4double
310 %mat4v4double_null = OpConstantNull %mat4v4double
311 %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4
312 %mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null
313 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
314 %uint_0x3f800000 = OpConstant %uint 0x3f800000
315 %uint_0xbf800000 = OpConstant %uint 0xbf800000
316 %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000
317 %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000
318 %int_0x3FF00000 = OpConstant %int 0x3FF00000
319 %int_0x00000000 = OpConstant %int 0x00000000
320 %int_0xC05FD666 = OpConstant %int 0xC05FD666
321 %int_0x66666666 = OpConstant %int 0x66666666
322 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
323 %ushort_0x4400 = OpConstant %ushort 0x4400
324 %short_0x4400 = OpConstant %short 0x4400
325 %ushort_0xBC00 = OpConstant %ushort 0xBC00
326 %short_0xBC00 = OpConstant %short 0xBC00
327 %int_arr_2_undef = OpUndef %int_arr_2
328 )";
329
330 return header;
331 }
332
333 // Returns the header with definitions of float NaN and double NaN. Since FC
334 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
335 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
336 // %double_n0 = OpConstant %double -0,
337 // we separates those definitions from Header().
HeaderWithNaN()338 const std::string& HeaderWithNaN() {
339 static const std::string headerWithNaN =
340 Header() +
341 R"(%float_nan = OpConstant %float -0x1.8p+128
342 %double_nan = OpConstant %double -0x1.8p+1024
343 )";
344
345 return headerWithNaN;
346 }
347
348 // clang-format off
349 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
350 ::testing::Values(
351 // Test case 0: fold 0*n
352 InstructionFoldingCase<uint32_t>(
353 Header() + "%main = OpFunction %void None %void_func\n" +
354 "%main_lab = OpLabel\n" +
355 "%n = OpVariable %_ptr_int Function\n" +
356 "%load = OpLoad %int %n\n" +
357 "%2 = OpIMul %int %int_0 %load\n" +
358 "OpReturn\n" +
359 "OpFunctionEnd",
360 2, 0),
361 // Test case 1: fold n*0
362 InstructionFoldingCase<uint32_t>(
363 Header() + "%main = OpFunction %void None %void_func\n" +
364 "%main_lab = OpLabel\n" +
365 "%n = OpVariable %_ptr_int Function\n" +
366 "%load = OpLoad %int %n\n" +
367 "%2 = OpIMul %int %load %int_0\n" +
368 "OpReturn\n" +
369 "OpFunctionEnd",
370 2, 0),
371 // Test case 2: fold 0/n (signed)
372 InstructionFoldingCase<uint32_t>(
373 Header() + "%main = OpFunction %void None %void_func\n" +
374 "%main_lab = OpLabel\n" +
375 "%n = OpVariable %_ptr_int Function\n" +
376 "%load = OpLoad %int %n\n" +
377 "%2 = OpSDiv %int %int_0 %load\n" +
378 "OpReturn\n" +
379 "OpFunctionEnd",
380 2, 0),
381 // Test case 3: fold n/0 (signed)
382 InstructionFoldingCase<uint32_t>(
383 Header() + "%main = OpFunction %void None %void_func\n" +
384 "%main_lab = OpLabel\n" +
385 "%n = OpVariable %_ptr_int Function\n" +
386 "%load = OpLoad %int %n\n" +
387 "%2 = OpSDiv %int %load %int_0\n" +
388 "OpReturn\n" +
389 "OpFunctionEnd",
390 2, 0),
391 // Test case 4: fold 0/n (unsigned)
392 InstructionFoldingCase<uint32_t>(
393 Header() + "%main = OpFunction %void None %void_func\n" +
394 "%main_lab = OpLabel\n" +
395 "%n = OpVariable %_ptr_uint Function\n" +
396 "%load = OpLoad %uint %n\n" +
397 "%2 = OpUDiv %uint %uint_0 %load\n" +
398 "OpReturn\n" +
399 "OpFunctionEnd",
400 2, 0),
401 // Test case 5: fold n/0 (unsigned)
402 InstructionFoldingCase<uint32_t>(
403 Header() + "%main = OpFunction %void None %void_func\n" +
404 "%main_lab = OpLabel\n" +
405 "%n = OpVariable %_ptr_int Function\n" +
406 "%load = OpLoad %int %n\n" +
407 "%2 = OpSDiv %int %load %int_0\n" +
408 "OpReturn\n" +
409 "OpFunctionEnd",
410 2, 0),
411 // Test case 6: fold 0 remainder n
412 InstructionFoldingCase<uint32_t>(
413 Header() + "%main = OpFunction %void None %void_func\n" +
414 "%main_lab = OpLabel\n" +
415 "%n = OpVariable %_ptr_int Function\n" +
416 "%load = OpLoad %int %n\n" +
417 "%2 = OpSRem %int %int_0 %load\n" +
418 "OpReturn\n" +
419 "OpFunctionEnd",
420 2, 0),
421 // Test case 7: fold n remainder 0
422 InstructionFoldingCase<uint32_t>(
423 Header() + "%main = OpFunction %void None %void_func\n" +
424 "%main_lab = OpLabel\n" +
425 "%n = OpVariable %_ptr_int Function\n" +
426 "%load = OpLoad %int %n\n" +
427 "%2 = OpSRem %int %load %int_0\n" +
428 "OpReturn\n" +
429 "OpFunctionEnd",
430 2, 0),
431 // Test case 8: fold 0%n (signed)
432 InstructionFoldingCase<uint32_t>(
433 Header() + "%main = OpFunction %void None %void_func\n" +
434 "%main_lab = OpLabel\n" +
435 "%n = OpVariable %_ptr_int Function\n" +
436 "%load = OpLoad %int %n\n" +
437 "%2 = OpSMod %int %int_0 %load\n" +
438 "OpReturn\n" +
439 "OpFunctionEnd",
440 2, 0),
441 // Test case 9: fold n%0 (signed)
442 InstructionFoldingCase<uint32_t>(
443 Header() + "%main = OpFunction %void None %void_func\n" +
444 "%main_lab = OpLabel\n" +
445 "%n = OpVariable %_ptr_int Function\n" +
446 "%load = OpLoad %int %n\n" +
447 "%2 = OpSMod %int %load %int_0\n" +
448 "OpReturn\n" +
449 "OpFunctionEnd",
450 2, 0),
451 // Test case 10: fold 0%n (unsigned)
452 InstructionFoldingCase<uint32_t>(
453 Header() + "%main = OpFunction %void None %void_func\n" +
454 "%main_lab = OpLabel\n" +
455 "%n = OpVariable %_ptr_uint Function\n" +
456 "%load = OpLoad %uint %n\n" +
457 "%2 = OpUMod %uint %uint_0 %load\n" +
458 "OpReturn\n" +
459 "OpFunctionEnd",
460 2, 0),
461 // Test case 11: fold n%0 (unsigned)
462 InstructionFoldingCase<uint32_t>(
463 Header() + "%main = OpFunction %void None %void_func\n" +
464 "%main_lab = OpLabel\n" +
465 "%n = OpVariable %_ptr_uint Function\n" +
466 "%load = OpLoad %uint %n\n" +
467 "%2 = OpUMod %uint %load %uint_0\n" +
468 "OpReturn\n" +
469 "OpFunctionEnd",
470 2, 0),
471 // Test case 12: fold n << 32
472 InstructionFoldingCase<uint32_t>(
473 Header() + "%main = OpFunction %void None %void_func\n" +
474 "%main_lab = OpLabel\n" +
475 "%n = OpVariable %_ptr_uint Function\n" +
476 "%load = OpLoad %uint %n\n" +
477 "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
478 "OpReturn\n" +
479 "OpFunctionEnd",
480 2, 0),
481 // Test case 13: fold n >> 32
482 InstructionFoldingCase<uint32_t>(
483 Header() + "%main = OpFunction %void None %void_func\n" +
484 "%main_lab = OpLabel\n" +
485 "%n = OpVariable %_ptr_uint Function\n" +
486 "%load = OpLoad %uint %n\n" +
487 "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
488 "OpReturn\n" +
489 "OpFunctionEnd",
490 2, 0),
491 // Test case 14: fold n | 0xFFFFFFFF
492 InstructionFoldingCase<uint32_t>(
493 Header() + "%main = OpFunction %void None %void_func\n" +
494 "%main_lab = OpLabel\n" +
495 "%n = OpVariable %_ptr_uint Function\n" +
496 "%load = OpLoad %uint %n\n" +
497 "%2 = OpBitwiseOr %uint %load %uint_max\n" +
498 "OpReturn\n" +
499 "OpFunctionEnd",
500 2, 0xFFFFFFFF),
501 // Test case 15: fold 0xFFFFFFFF | n
502 InstructionFoldingCase<uint32_t>(
503 Header() + "%main = OpFunction %void None %void_func\n" +
504 "%main_lab = OpLabel\n" +
505 "%n = OpVariable %_ptr_uint Function\n" +
506 "%load = OpLoad %uint %n\n" +
507 "%2 = OpBitwiseOr %uint %uint_max %load\n" +
508 "OpReturn\n" +
509 "OpFunctionEnd",
510 2, 0xFFFFFFFF),
511 // Test case 16: fold n & 0
512 InstructionFoldingCase<uint32_t>(
513 Header() + "%main = OpFunction %void None %void_func\n" +
514 "%main_lab = OpLabel\n" +
515 "%n = OpVariable %_ptr_uint Function\n" +
516 "%load = OpLoad %uint %n\n" +
517 "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
518 "OpReturn\n" +
519 "OpFunctionEnd",
520 2, 0),
521 // Test case 17: fold 1/0 (signed)
522 InstructionFoldingCase<uint32_t>(
523 Header() + "%main = OpFunction %void None %void_func\n" +
524 "%main_lab = OpLabel\n" +
525 "%2 = OpSDiv %int %int_1 %int_0\n" +
526 "OpReturn\n" +
527 "OpFunctionEnd",
528 2, 0),
529 // Test case 18: fold 1/0 (unsigned)
530 InstructionFoldingCase<uint32_t>(
531 Header() + "%main = OpFunction %void None %void_func\n" +
532 "%main_lab = OpLabel\n" +
533 "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
534 "OpReturn\n" +
535 "OpFunctionEnd",
536 2, 0),
537 // Test case 19: fold OpSRem 1 0 (signed)
538 InstructionFoldingCase<uint32_t>(
539 Header() + "%main = OpFunction %void None %void_func\n" +
540 "%main_lab = OpLabel\n" +
541 "%2 = OpSRem %int %int_1 %int_0\n" +
542 "OpReturn\n" +
543 "OpFunctionEnd",
544 2, 0),
545 // Test case 20: fold 1%0 (signed)
546 InstructionFoldingCase<uint32_t>(
547 Header() + "%main = OpFunction %void None %void_func\n" +
548 "%main_lab = OpLabel\n" +
549 "%2 = OpSMod %int %int_1 %int_0\n" +
550 "OpReturn\n" +
551 "OpFunctionEnd",
552 2, 0),
553 // Test case 21: fold 1%0 (unsigned)
554 InstructionFoldingCase<uint32_t>(
555 Header() + "%main = OpFunction %void None %void_func\n" +
556 "%main_lab = OpLabel\n" +
557 "%2 = OpUMod %uint %uint_1 %uint_0\n" +
558 "OpReturn\n" +
559 "OpFunctionEnd",
560 2, 0),
561 // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
562 InstructionFoldingCase<uint32_t>(
563 Header() + "%main = OpFunction %void None %void_func\n" +
564 "%main_lab = OpLabel\n" +
565 "%n = OpVariable %_ptr_uint Function\n" +
566 "%load = OpLoad %uint %n\n" +
567 "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
568 "OpReturn\n" +
569 "OpFunctionEnd",
570 2, 0),
571 // Test case 23: fold signed n >> 42 (undefined, so set to zero).
572 InstructionFoldingCase<uint32_t>(
573 Header() + "%main = OpFunction %void None %void_func\n" +
574 "%main_lab = OpLabel\n" +
575 "%n = OpVariable %_ptr_int Function\n" +
576 "%load = OpLoad %int %n\n" +
577 "%2 = OpShiftRightLogical %int %load %uint_42\n" +
578 "OpReturn\n" +
579 "OpFunctionEnd",
580 2, 0),
581 // Test case 24: fold n << 42 (undefined, so set to zero).
582 InstructionFoldingCase<uint32_t>(
583 Header() + "%main = OpFunction %void None %void_func\n" +
584 "%main_lab = OpLabel\n" +
585 "%n = OpVariable %_ptr_int Function\n" +
586 "%load = OpLoad %int %n\n" +
587 "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
588 "OpReturn\n" +
589 "OpFunctionEnd",
590 2, 0),
591 // Test case 25: fold -24 >> 32 (defined as -1)
592 InstructionFoldingCase<uint32_t>(
593 Header() + "%main = OpFunction %void None %void_func\n" +
594 "%main_lab = OpLabel\n" +
595 "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
596 "OpReturn\n" +
597 "OpFunctionEnd",
598 2, -1),
599 // Test case 26: fold 2 >> 32 (signed)
600 InstructionFoldingCase<uint32_t>(
601 Header() + "%main = OpFunction %void None %void_func\n" +
602 "%main_lab = OpLabel\n" +
603 "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
604 "OpReturn\n" +
605 "OpFunctionEnd",
606 2, 0),
607 // Test case 27: fold 2 >> 32 (unsigned)
608 InstructionFoldingCase<uint32_t>(
609 Header() + "%main = OpFunction %void None %void_func\n" +
610 "%main_lab = OpLabel\n" +
611 "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
612 "OpReturn\n" +
613 "OpFunctionEnd",
614 2, 0),
615 // Test case 28: fold 2 << 32
616 InstructionFoldingCase<uint32_t>(
617 Header() + "%main = OpFunction %void None %void_func\n" +
618 "%main_lab = OpLabel\n" +
619 "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
620 "OpReturn\n" +
621 "OpFunctionEnd",
622 2, 0),
623 // Test case 29: fold -INT_MIN
624 InstructionFoldingCase<uint32_t>(
625 Header() + "%main = OpFunction %void None %void_func\n" +
626 "%main_lab = OpLabel\n" +
627 "%2 = OpSNegate %int %int_min\n" +
628 "OpReturn\n" +
629 "OpFunctionEnd",
630 2, std::numeric_limits<int32_t>::min()),
631 // Test case 30: fold UMin 3 4
632 InstructionFoldingCase<uint32_t>(
633 Header() + "%main = OpFunction %void None %void_func\n" +
634 "%main_lab = OpLabel\n" +
635 "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
636 "OpReturn\n" +
637 "OpFunctionEnd",
638 2, 3),
639 // Test case 31: fold UMin 4 2
640 InstructionFoldingCase<uint32_t>(
641 Header() + "%main = OpFunction %void None %void_func\n" +
642 "%main_lab = OpLabel\n" +
643 "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
644 "OpReturn\n" +
645 "OpFunctionEnd",
646 2, 2),
647 // Test case 32: fold SMin 3 4
648 InstructionFoldingCase<uint32_t>(
649 Header() + "%main = OpFunction %void None %void_func\n" +
650 "%main_lab = OpLabel\n" +
651 "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
652 "OpReturn\n" +
653 "OpFunctionEnd",
654 2, 3),
655 // Test case 33: fold SMin 4 2
656 InstructionFoldingCase<uint32_t>(
657 Header() + "%main = OpFunction %void None %void_func\n" +
658 "%main_lab = OpLabel\n" +
659 "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
660 "OpReturn\n" +
661 "OpFunctionEnd",
662 2, 2),
663 // Test case 34: fold UMax 3 4
664 InstructionFoldingCase<uint32_t>(
665 Header() + "%main = OpFunction %void None %void_func\n" +
666 "%main_lab = OpLabel\n" +
667 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
668 "OpReturn\n" +
669 "OpFunctionEnd",
670 2, 4),
671 // Test case 35: fold UMax 3 2
672 InstructionFoldingCase<uint32_t>(
673 Header() + "%main = OpFunction %void None %void_func\n" +
674 "%main_lab = OpLabel\n" +
675 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
676 "OpReturn\n" +
677 "OpFunctionEnd",
678 2, 3),
679 // Test case 36: fold SMax 3 4
680 InstructionFoldingCase<uint32_t>(
681 Header() + "%main = OpFunction %void None %void_func\n" +
682 "%main_lab = OpLabel\n" +
683 "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
684 "OpReturn\n" +
685 "OpFunctionEnd",
686 2, 4),
687 // Test case 37: fold SMax 3 2
688 InstructionFoldingCase<uint32_t>(
689 Header() + "%main = OpFunction %void None %void_func\n" +
690 "%main_lab = OpLabel\n" +
691 "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
692 "OpReturn\n" +
693 "OpFunctionEnd",
694 2, 3),
695 // Test case 38: fold UClamp 2 3 4
696 InstructionFoldingCase<uint32_t>(
697 Header() + "%main = OpFunction %void None %void_func\n" +
698 "%main_lab = OpLabel\n" +
699 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
700 "OpReturn\n" +
701 "OpFunctionEnd",
702 2, 3),
703 // Test case 39: fold UClamp 2 0 4
704 InstructionFoldingCase<uint32_t>(
705 Header() + "%main = OpFunction %void None %void_func\n" +
706 "%main_lab = OpLabel\n" +
707 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
708 "OpReturn\n" +
709 "OpFunctionEnd",
710 2, 2),
711 // Test case 40: fold UClamp 2 0 1
712 InstructionFoldingCase<uint32_t>(
713 Header() + "%main = OpFunction %void None %void_func\n" +
714 "%main_lab = OpLabel\n" +
715 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
716 "OpReturn\n" +
717 "OpFunctionEnd",
718 2, 1),
719 // Test case 41: fold SClamp 2 3 4
720 InstructionFoldingCase<uint32_t>(
721 Header() + "%main = OpFunction %void None %void_func\n" +
722 "%main_lab = OpLabel\n" +
723 "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
724 "OpReturn\n" +
725 "OpFunctionEnd",
726 2, 3),
727 // Test case 42: fold SClamp 2 0 4
728 InstructionFoldingCase<uint32_t>(
729 Header() + "%main = OpFunction %void None %void_func\n" +
730 "%main_lab = OpLabel\n" +
731 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
732 "OpReturn\n" +
733 "OpFunctionEnd",
734 2, 2),
735 // Test case 43: fold SClamp 2 0 1
736 InstructionFoldingCase<uint32_t>(
737 Header() + "%main = OpFunction %void None %void_func\n" +
738 "%main_lab = OpLabel\n" +
739 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
740 "OpReturn\n" +
741 "OpFunctionEnd",
742 2, 1),
743 // Test case 44: SClamp 1 2 x
744 InstructionFoldingCase<uint32_t>(
745 Header() + "%main = OpFunction %void None %void_func\n" +
746 "%main_lab = OpLabel\n" +
747 "%undef = OpUndef %int\n" +
748 "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
749 "OpReturn\n" +
750 "OpFunctionEnd",
751 2, 2),
752 // Test case 45: SClamp 2 x 1
753 InstructionFoldingCase<uint32_t>(
754 Header() + "%main = OpFunction %void None %void_func\n" +
755 "%main_lab = OpLabel\n" +
756 "%undef = OpUndef %int\n" +
757 "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
758 "OpReturn\n" +
759 "OpFunctionEnd",
760 2, 1),
761 // Test case 46: UClamp 1 2 x
762 InstructionFoldingCase<uint32_t>(
763 Header() + "%main = OpFunction %void None %void_func\n" +
764 "%main_lab = OpLabel\n" +
765 "%undef = OpUndef %uint\n" +
766 "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
767 "OpReturn\n" +
768 "OpFunctionEnd",
769 2, 2),
770 // Test case 47: UClamp 2 x 1
771 InstructionFoldingCase<uint32_t>(
772 Header() + "%main = OpFunction %void None %void_func\n" +
773 "%main_lab = OpLabel\n" +
774 "%undef = OpUndef %uint\n" +
775 "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
776 "OpReturn\n" +
777 "OpFunctionEnd",
778 2, 1),
779 // Test case 48: Bit-cast int 0 to unsigned int
780 InstructionFoldingCase<uint32_t>(
781 Header() + "%main = OpFunction %void None %void_func\n" +
782 "%main_lab = OpLabel\n" +
783 "%2 = OpBitcast %uint %int_0\n" +
784 "OpReturn\n" +
785 "OpFunctionEnd",
786 2, 0),
787 // Test case 49: Bit-cast int -24 to unsigned int
788 InstructionFoldingCase<uint32_t>(
789 Header() + "%main = OpFunction %void None %void_func\n" +
790 "%main_lab = OpLabel\n" +
791 "%2 = OpBitcast %uint %int_n24\n" +
792 "OpReturn\n" +
793 "OpFunctionEnd",
794 2, static_cast<uint32_t>(-24)),
795 // Test case 50: Bit-cast float 1.0f to unsigned int
796 InstructionFoldingCase<uint32_t>(
797 Header() + "%main = OpFunction %void None %void_func\n" +
798 "%main_lab = OpLabel\n" +
799 "%2 = OpBitcast %uint %float_1\n" +
800 "OpReturn\n" +
801 "OpFunctionEnd",
802 2, static_cast<uint32_t>(0x3f800000)),
803 // Test case 51: Bit-cast ushort 0xBC00 to ushort
804 InstructionFoldingCase<uint32_t>(
805 Header() + "%main = OpFunction %void None %void_func\n" +
806 "%main_lab = OpLabel\n" +
807 "%2 = OpBitcast %ushort %ushort_0xBC00\n" +
808 "OpReturn\n" +
809 "OpFunctionEnd",
810 2, 0xBC00),
811 // Test case 52: Bit-cast short 0xBC00 to ushort
812 InstructionFoldingCase<uint32_t>(
813 Header() + "%main = OpFunction %void None %void_func\n" +
814 "%main_lab = OpLabel\n" +
815 "%2 = OpBitcast %ushort %short_0xBC00\n" +
816 "OpReturn\n" +
817 "OpFunctionEnd",
818 2, 0xFFFFBC00),
819 // Test case 53: Bit-cast half 1 to ushort
820 InstructionFoldingCase<uint32_t>(
821 Header() + "%main = OpFunction %void None %void_func\n" +
822 "%main_lab = OpLabel\n" +
823 "%2 = OpBitcast %ushort %half_1\n" +
824 "OpReturn\n" +
825 "OpFunctionEnd",
826 2, 0x3C00),
827 // Test case 54: Bit-cast ushort 0xBC00 to short
828 InstructionFoldingCase<uint32_t>(
829 Header() + "%main = OpFunction %void None %void_func\n" +
830 "%main_lab = OpLabel\n" +
831 "%2 = OpBitcast %short %ushort_0xBC00\n" +
832 "OpReturn\n" +
833 "OpFunctionEnd",
834 2, 0xBC00),
835 // Test case 55: Bit-cast short 0xBC00 to short
836 InstructionFoldingCase<uint32_t>(
837 Header() + "%main = OpFunction %void None %void_func\n" +
838 "%main_lab = OpLabel\n" +
839 "%2 = OpBitcast %short %short_0xBC00\n" +
840 "OpReturn\n" +
841 "OpFunctionEnd",
842 2, 0xFFFFBC00),
843 // Test case 56: Bit-cast half 1 to short
844 InstructionFoldingCase<uint32_t>(
845 Header() + "%main = OpFunction %void None %void_func\n" +
846 "%main_lab = OpLabel\n" +
847 "%2 = OpBitcast %short %half_1\n" +
848 "OpReturn\n" +
849 "OpFunctionEnd",
850 2, 0x3C00),
851 // Test case 57: Bit-cast ushort 0xBC00 to half
852 InstructionFoldingCase<uint32_t>(
853 Header() + "%main = OpFunction %void None %void_func\n" +
854 "%main_lab = OpLabel\n" +
855 "%2 = OpBitcast %half %ushort_0xBC00\n" +
856 "OpReturn\n" +
857 "OpFunctionEnd",
858 2, 0xBC00),
859 // Test case 58: Bit-cast short 0xBC00 to half
860 InstructionFoldingCase<uint32_t>(
861 Header() + "%main = OpFunction %void None %void_func\n" +
862 "%main_lab = OpLabel\n" +
863 "%2 = OpBitcast %half %short_0xBC00\n" +
864 "OpReturn\n" +
865 "OpFunctionEnd",
866 2, 0xFFFFBC00),
867 // Test case 59: Bit-cast half 1 to half
868 InstructionFoldingCase<uint32_t>(
869 Header() + "%main = OpFunction %void None %void_func\n" +
870 "%main_lab = OpLabel\n" +
871 "%2 = OpBitcast %half %half_1\n" +
872 "OpReturn\n" +
873 "OpFunctionEnd",
874 2, 0x3C00),
875 // Test case 60: Bit-cast ubyte 1 to byte
876 InstructionFoldingCase<uint32_t>(
877 Header() + "%main = OpFunction %void None %void_func\n" +
878 "%main_lab = OpLabel\n" +
879 "%2 = OpBitcast %byte %ubyte_1\n" +
880 "OpReturn\n" +
881 "OpFunctionEnd",
882 2, 1),
883 // Test case 61: Bit-cast byte -1 to ubyte
884 InstructionFoldingCase<uint32_t>(
885 Header() + "%main = OpFunction %void None %void_func\n" +
886 "%main_lab = OpLabel\n" +
887 "%2 = OpBitcast %ubyte %byte_n1\n" +
888 "OpReturn\n" +
889 "OpFunctionEnd",
890 2, 0xFFFFFFFF),
891 // Test case 62: Negate 2.
892 InstructionFoldingCase<uint32_t>(
893 Header() + "%main = OpFunction %void None %void_func\n" +
894 "%main_lab = OpLabel\n" +
895 "%2 = OpSNegate %int %int_2\n" +
896 "OpReturn\n" +
897 "OpFunctionEnd",
898 2, -2),
899 // Test case 63: Negate negative short.
900 InstructionFoldingCase<uint32_t>(
901 Header() + "%main = OpFunction %void None %void_func\n" +
902 "%main_lab = OpLabel\n" +
903 "%2 = OpSNegate %short %short_0xBC00\n" +
904 "OpReturn\n" +
905 "OpFunctionEnd",
906 2, 0x4400 /* expected to be sign extended. */),
907 // Test case 64: Negate positive short.
908 InstructionFoldingCase<uint32_t>(
909 Header() + "%main = OpFunction %void None %void_func\n" +
910 "%main_lab = OpLabel\n" +
911 "%2 = OpSNegate %short %short_0x4400\n" +
912 "OpReturn\n" +
913 "OpFunctionEnd",
914 2, 0xFFFFBC00 /* expected to be sign extended. */),
915 // Test case 65: Negate a negative short.
916 InstructionFoldingCase<uint32_t>(
917 Header() + "%main = OpFunction %void None %void_func\n" +
918 "%main_lab = OpLabel\n" +
919 "%2 = OpSNegate %ushort %ushort_0xBC00\n" +
920 "OpReturn\n" +
921 "OpFunctionEnd",
922 2, 0x4400 /* expected to be zero extended. */),
923 // Test case 66: Negate positive short.
924 InstructionFoldingCase<uint32_t>(
925 Header() + "%main = OpFunction %void None %void_func\n" +
926 "%main_lab = OpLabel\n" +
927 "%2 = OpSNegate %ushort %ushort_0x4400\n" +
928 "OpReturn\n" +
929 "OpFunctionEnd",
930 2, 0xBC00 /* expected to be zero extended. */)
931 ));
932 // clang-format on
933
934 using UIntVectorInstructionFoldingTest =
935 ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
936
TEST_P(UIntVectorInstructionFoldingTest, Case)937 TEST_P(UIntVectorInstructionFoldingTest, Case) {
938 const auto& tc = GetParam();
939
940 // Build module.
941 std::unique_ptr<IRContext> context =
942 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
943 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
944 ASSERT_NE(nullptr, context);
945
946 // Fold the instruction to test.
947 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
948 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
949 spv::Op original_opcode = inst->opcode();
950 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
951
952 // Make sure the instruction folded as expected.
953 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
954 if (succeeded && inst != nullptr) {
955 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
956 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
957 std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
958 EXPECT_THAT(opcodes, Contains(inst->opcode()));
959 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
960 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
961 EXPECT_NE(result, nullptr);
962 if (result != nullptr) {
963 const std::vector<const analysis::Constant*>& componenets =
964 result->AsVectorConstant()->GetComponents();
965 EXPECT_EQ(componenets.size(), tc.expected_result.size());
966 for (size_t i = 0; i < componenets.size(); i++) {
967 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
968 }
969 }
970 }
971 }
972
973 // clang-format off
974 INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest,
975 ::testing::Values(
976 // Test case 0: fold 0*n
977 InstructionFoldingCase<std::vector<uint32_t>>(
978 Header() + "%main = OpFunction %void None %void_func\n" +
979 "%main_lab = OpLabel\n" +
980 "%n = OpVariable %_ptr_int Function\n" +
981 "%load = OpLoad %int %n\n" +
982 "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
983 "OpReturn\n" +
984 "OpFunctionEnd",
985 2, {2,3}),
986 InstructionFoldingCase<std::vector<uint32_t>>(
987 Header() + "%main = OpFunction %void None %void_func\n" +
988 "%main_lab = OpLabel\n" +
989 "%n = OpVariable %_ptr_int Function\n" +
990 "%load = OpLoad %int %n\n" +
991 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
992 "OpReturn\n" +
993 "OpFunctionEnd",
994 2, {0,3}),
995 InstructionFoldingCase<std::vector<uint32_t>>(
996 Header() + "%main = OpFunction %void None %void_func\n" +
997 "%main_lab = OpLabel\n" +
998 "%n = OpVariable %_ptr_int Function\n" +
999 "%load = OpLoad %int %n\n" +
1000 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
1001 "OpReturn\n" +
1002 "OpFunctionEnd",
1003 2, {0,0}),
1004 InstructionFoldingCase<std::vector<uint32_t>>(
1005 Header() + "%main = OpFunction %void None %void_func\n" +
1006 "%main_lab = OpLabel\n" +
1007 "%n = OpVariable %_ptr_int Function\n" +
1008 "%load = OpLoad %int %n\n" +
1009 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
1010 "OpReturn\n" +
1011 "OpFunctionEnd",
1012 2, {0,0}),
1013 // Test case 4: fold bit-cast int -24 to unsigned int
1014 InstructionFoldingCase<std::vector<uint32_t>>(
1015 Header() + "%main = OpFunction %void None %void_func\n" +
1016 "%main_lab = OpLabel\n" +
1017 "%n = OpVariable %_ptr_int Function\n" +
1018 "%load = OpLoad %int %n\n" +
1019 "%2 = OpBitcast %v2uint %v2int_min_max\n" +
1020 "OpReturn\n" +
1021 "OpFunctionEnd",
1022 2, {2147483648, 2147483647}),
1023 // Test case 5: fold SNegate vector of uint
1024 InstructionFoldingCase<std::vector<uint32_t>>(
1025 Header() + "%main = OpFunction %void None %void_func\n" +
1026 "%main_lab = OpLabel\n" +
1027 "%n = OpVariable %_ptr_int Function\n" +
1028 "%load = OpLoad %int %n\n" +
1029 "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" +
1030 "OpReturn\n" +
1031 "OpFunctionEnd",
1032 2, {static_cast<uint32_t>(-0x3f800000), static_cast<uint32_t>(-0xbf800000)}),
1033 // Test case 6: fold vector components of uint (incuding integer overflow)
1034 InstructionFoldingCase<std::vector<uint32_t>>(
1035 Header() + "%main = OpFunction %void None %void_func\n" +
1036 "%main_lab = OpLabel\n" +
1037 "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" +
1038 "OpReturn\n" +
1039 "OpFunctionEnd",
1040 2, {0x7f000000u, 0x7f000000u})
1041 ));
1042 // clang-format on
1043
1044 using IntVectorInstructionFoldingTest =
1045 ::testing::TestWithParam<InstructionFoldingCase<std::vector<int32_t>>>;
1046
TEST_P(IntVectorInstructionFoldingTest, Case)1047 TEST_P(IntVectorInstructionFoldingTest, Case) {
1048 const auto& tc = GetParam();
1049
1050 // Build module.
1051 std::unique_ptr<IRContext> context =
1052 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1053 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1054 ASSERT_NE(nullptr, context);
1055
1056 // Fold the instruction to test.
1057 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1058 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1059 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1060
1061 // Make sure the instruction folded as expected.
1062 EXPECT_TRUE(succeeded);
1063 if (succeeded && inst != nullptr) {
1064 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1065 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1066 std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1067 EXPECT_THAT(opcodes, Contains(inst->opcode()));
1068 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1069 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1070 EXPECT_NE(result, nullptr);
1071 if (result != nullptr) {
1072 const std::vector<const analysis::Constant*>& componenets =
1073 result->AsVectorConstant()->GetComponents();
1074 EXPECT_EQ(componenets.size(), tc.expected_result.size());
1075 for (size_t i = 0; i < componenets.size(); i++) {
1076 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetS32());
1077 }
1078 }
1079 }
1080 }
1081
1082 // clang-format off
1083 INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
1084 ::testing::Values(
1085 // Test case 0: fold negate of a vector
1086 InstructionFoldingCase<std::vector<int32_t>>(
1087 Header() + "%main = OpFunction %void None %void_func\n" +
1088 "%main_lab = OpLabel\n" +
1089 "%2 = OpSNegate %v2int %v2int_2_3\n" +
1090 "OpReturn\n" +
1091 "OpFunctionEnd",
1092 2, {-2, -3}),
1093 // Test case 1: fold negate of a vector containing negative values.
1094 InstructionFoldingCase<std::vector<int32_t>>(
1095 Header() + "%main = OpFunction %void None %void_func\n" +
1096 "%main_lab = OpLabel\n" +
1097 "%2 = OpSNegate %v2int %v2int_n1_n24\n" +
1098 "OpReturn\n" +
1099 "OpFunctionEnd",
1100 2, {1, 24}),
1101 // Test case 2: fold negate of a vector at the limits
1102 InstructionFoldingCase<std::vector<int32_t>>(
1103 Header() + "%main = OpFunction %void None %void_func\n" +
1104 "%main_lab = OpLabel\n" +
1105 "%2 = OpSNegate %v2int %v2int_min_max\n" +
1106 "OpReturn\n" +
1107 "OpFunctionEnd",
1108 2, {INT_MIN, -INT_MAX}),
1109 // Test case 3: fold vector components of int
1110 InstructionFoldingCase<std::vector<int32_t>>(
1111 Header() + "%main = OpFunction %void None %void_func\n" +
1112 "%main_lab = OpLabel\n" +
1113 "%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" +
1114 "OpReturn\n" +
1115 "OpFunctionEnd",
1116 2, {4,9})
1117 ));
1118 // clang-format on
1119
1120 using DoubleVectorInstructionFoldingTest =
1121 ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
1122
TEST_P(DoubleVectorInstructionFoldingTest, Case)1123 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
1124 const auto& tc = GetParam();
1125
1126 // Build module.
1127 std::unique_ptr<IRContext> context =
1128 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1129 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1130 ASSERT_NE(nullptr, context);
1131
1132 // Fold the instruction to test.
1133 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1134 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1135 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1136
1137 // Make sure the instruction folded as expected.
1138 EXPECT_TRUE(succeeded);
1139 if (succeeded && inst != nullptr) {
1140 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1141 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1142 std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1143 EXPECT_THAT(opcodes, Contains(inst->opcode()));
1144 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1145 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1146 EXPECT_NE(result, nullptr);
1147 if (result != nullptr) {
1148 const std::vector<const analysis::Constant*>& componenets =
1149 result->AsVectorConstant()->GetComponents();
1150 EXPECT_EQ(componenets.size(), tc.expected_result.size());
1151 for (size_t i = 0; i < componenets.size(); i++) {
1152 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble());
1153 }
1154 }
1155 }
1156 }
1157
1158 // clang-format off
1159 INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
1160 ::testing::Values(
1161 // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
1162 // to double vector
1163 InstructionFoldingCase<std::vector<double>>(
1164 Header() + "%main = OpFunction %void None %void_func\n" +
1165 "%main_lab = OpLabel\n" +
1166 "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
1167 "OpReturn\n" +
1168 "OpFunctionEnd",
1169 2, {1.0,-127.35}),
1170 // Test case 1: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1171 InstructionFoldingCase<std::vector<double>>(
1172 Header() +
1173 "%main = OpFunction %void None %void_func\n" +
1174 "%main_lab = OpLabel\n" +
1175 "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" +
1176 "OpReturn\n" +
1177 "OpFunctionEnd",
1178 2, {0.0,0.0,0.0,0.0}),
1179 // Test case 2: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1180 InstructionFoldingCase<std::vector<double>>(
1181 Header() +
1182 "%main = OpFunction %void None %void_func\n" +
1183 "%main_lab = OpLabel\n" +
1184 "%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" +
1185 "OpReturn\n" +
1186 "OpFunctionEnd",
1187 2, {0.0,0.0,0.0,0.0}),
1188 // Test case 3: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1189 InstructionFoldingCase<std::vector<double>>(
1190 Header() +
1191 "%main = OpFunction %void None %void_func\n" +
1192 "%main_lab = OpLabel\n" +
1193 "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" +
1194 "OpReturn\n" +
1195 "OpFunctionEnd",
1196 2, {30.0,30.0,30.0,30.0}),
1197 // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
1198 InstructionFoldingCase<std::vector<double>>(
1199 Header() +
1200 "%main = OpFunction %void None %void_func\n" +
1201 "%main_lab = OpLabel\n" +
1202 "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null\n" +
1203 "OpReturn\n" +
1204 "OpFunctionEnd",
1205 2, {30.0,0.0,30.0,0.0}),
1206 // Test case 5: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1207 InstructionFoldingCase<std::vector<double>>(
1208 Header() +
1209 "%main = OpFunction %void None %void_func\n" +
1210 "%main_lab = OpLabel\n" +
1211 "%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" +
1212 "OpReturn\n" +
1213 "OpFunctionEnd",
1214 2, {0.0,0.0,0.0,0.0}),
1215 // Test case 6: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1216 InstructionFoldingCase<std::vector<double>>(
1217 Header() +
1218 "%main = OpFunction %void None %void_func\n" +
1219 "%main_lab = OpLabel\n" +
1220 "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" +
1221 "OpReturn\n" +
1222 "OpFunctionEnd",
1223 2, {0.0,0.0,0.0,0.0}),
1224 // Test case 7: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1225 InstructionFoldingCase<std::vector<double>>(
1226 Header() +
1227 "%main = OpFunction %void None %void_func\n" +
1228 "%main_lab = OpLabel\n" +
1229 "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" +
1230 "OpReturn\n" +
1231 "OpFunctionEnd",
1232 2, {10.0,20.0,30.0,40.0}),
1233 // Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
1234 InstructionFoldingCase<std::vector<double>>(
1235 Header() +
1236 "%main = OpFunction %void None %void_func\n" +
1237 "%main_lab = OpLabel\n" +
1238 "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4_null %v4double_1_2_3_4\n" +
1239 "OpReturn\n" +
1240 "OpFunctionEnd",
1241 2, {4.0,8.0,12.0,16.0})
1242 ));
1243
1244 using FloatVectorInstructionFoldingTest =
1245 ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
1246
TEST_P(FloatVectorInstructionFoldingTest, Case)1247 TEST_P(FloatVectorInstructionFoldingTest, Case) {
1248 const auto& tc = GetParam();
1249
1250 // Build module.
1251 std::unique_ptr<IRContext> context =
1252 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1253 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1254 ASSERT_NE(nullptr, context);
1255
1256 // Fold the instruction to test.
1257 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1258 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1259 spv::Op original_opcode = inst->opcode();
1260 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1261
1262 // Make sure the instruction folded as expected.
1263 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
1264 if (succeeded && inst != nullptr) {
1265 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1266 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1267 std::vector<spv::Op> opcodes = {spv::Op::OpConstantComposite};
1268 EXPECT_THAT(opcodes, Contains(inst->opcode()));
1269 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1270 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1271 EXPECT_NE(result, nullptr);
1272 if (result != nullptr) {
1273 const std::vector<const analysis::Constant*>& componenets =
1274 result->AsVectorConstant()->GetComponents();
1275 EXPECT_EQ(componenets.size(), tc.expected_result.size());
1276 for (size_t i = 0; i < componenets.size(); i++) {
1277 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
1278 }
1279 }
1280 }
1281 }
1282
1283 // clang-format off
1284 INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
1285 ::testing::Values(
1286 // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
1287 InstructionFoldingCase<std::vector<float>>(
1288 Header() + "%main = OpFunction %void None %void_func\n" +
1289 "%main_lab = OpLabel\n" +
1290 "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
1291 "OpReturn\n" +
1292 "OpFunctionEnd",
1293 2, {1.6f,1.5f}),
1294 // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
1295 // float vector
1296 InstructionFoldingCase<std::vector<float>>(
1297 Header() + "%main = OpFunction %void None %void_func\n" +
1298 "%main_lab = OpLabel\n" +
1299 "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
1300 "OpReturn\n" +
1301 "OpFunctionEnd",
1302 2, {1.0f,-1.0f}),
1303 // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
1304 InstructionFoldingCase<std::vector<float>>(
1305 Header() + "%main = OpFunction %void None %void_func\n" +
1306 "%main_lab = OpLabel\n" +
1307 "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
1308 "OpReturn\n" +
1309 "OpFunctionEnd",
1310 2, {1.0f,-1.0f}),
1311 // Test case 3: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1312 InstructionFoldingCase<std::vector<float>>(
1313 Header() +
1314 "%main = OpFunction %void None %void_func\n" +
1315 "%main_lab = OpLabel\n" +
1316 "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" +
1317 "OpReturn\n" +
1318 "OpFunctionEnd",
1319 2, {0.0f,0.0f,0.0f,0.0f}),
1320 // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0}
1321 InstructionFoldingCase<std::vector<float>>(
1322 Header() +
1323 "%main = OpFunction %void None %void_func\n" +
1324 "%main_lab = OpLabel\n" +
1325 "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null\n" +
1326 "OpReturn\n" +
1327 "OpFunctionEnd",
1328 2, {30.0,0.0,30.0,0.0}),
1329 // Test case 5: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1330 InstructionFoldingCase<std::vector<float>>(
1331 Header() +
1332 "%main = OpFunction %void None %void_func\n" +
1333 "%main_lab = OpLabel\n" +
1334 "%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" +
1335 "OpReturn\n" +
1336 "OpFunctionEnd",
1337 2, {0.0f,0.0f,0.0f,0.0f}),
1338 // Test case 6: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1339 InstructionFoldingCase<std::vector<float>>(
1340 Header() +
1341 "%main = OpFunction %void None %void_func\n" +
1342 "%main_lab = OpLabel\n" +
1343 "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" +
1344 "OpReturn\n" +
1345 "OpFunctionEnd",
1346 2, {30.0f,30.0f,30.0f,30.0f}),
1347 // Test case 7: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1348 InstructionFoldingCase<std::vector<float>>(
1349 Header() +
1350 "%main = OpFunction %void None %void_func\n" +
1351 "%main_lab = OpLabel\n" +
1352 "%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" +
1353 "OpReturn\n" +
1354 "OpFunctionEnd",
1355 2, {0.0f,0.0f,0.0f,0.0f}),
1356 // Test case 8: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1357 InstructionFoldingCase<std::vector<float>>(
1358 Header() +
1359 "%main = OpFunction %void None %void_func\n" +
1360 "%main_lab = OpLabel\n" +
1361 "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" +
1362 "OpReturn\n" +
1363 "OpFunctionEnd",
1364 2, {0.0f,0.0f,0.0f,0.0f}),
1365 // Test case 9: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1366 InstructionFoldingCase<std::vector<float>>(
1367 Header() +
1368 "%main = OpFunction %void None %void_func\n" +
1369 "%main_lab = OpLabel\n" +
1370 "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" +
1371 "OpReturn\n" +
1372 "OpFunctionEnd",
1373 2, {10.0f,20.0f,30.0f,40.0f}),
1374 // Test case 10: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0}
1375 InstructionFoldingCase<std::vector<float>>(
1376 Header() +
1377 "%main = OpFunction %void None %void_func\n" +
1378 "%main_lab = OpLabel\n" +
1379 "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4_null %v4float_1_2_3_4\n" +
1380 "OpReturn\n" +
1381 "OpFunctionEnd",
1382 2, {4.0,8.0,12.0,16.0})
1383 ));
1384 // clang-format on
1385
1386 using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam<
1387 InstructionFoldingCase<std::vector<std::vector<float>>>>;
1388
TEST_P(FloatMatrixInstructionFoldingTest, Case)1389 TEST_P(FloatMatrixInstructionFoldingTest, Case) {
1390 const auto& tc = GetParam();
1391
1392 // Build module.
1393 std::unique_ptr<IRContext> context =
1394 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1395 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1396 ASSERT_NE(nullptr, context);
1397
1398 // Fold the instruction to test.
1399 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1400 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1401 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1402
1403 // Make sure the instruction folded as expected.
1404 EXPECT_TRUE(succeeded);
1405 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1406
1407 if (inst->opcode() == spv::Op::OpCopyObject) {
1408 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1409 analysis::ConstantManager* const_mgr = context->get_constant_mgr();
1410 const analysis::Constant* result = const_mgr->GetConstantFromInst(inst);
1411 EXPECT_NE(result, nullptr);
1412 if (result != nullptr) {
1413 std::vector<const analysis::Constant*> matrix =
1414 result->AsMatrixConstant()->GetComponents();
1415 EXPECT_EQ(matrix.size(), tc.expected_result.size());
1416 for (size_t c = 0; c < matrix.size(); c++) {
1417 if (matrix[c]->AsNullConstant() != nullptr) {
1418 matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type());
1419 }
1420 const analysis::VectorConstant* column_const =
1421 matrix[c]->AsVectorConstant();
1422 ASSERT_NE(column_const, nullptr);
1423 const std::vector<const analysis::Constant*>& column =
1424 column_const->GetComponents();
1425 EXPECT_EQ(column.size(), tc.expected_result[c].size());
1426 for (size_t r = 0; r < column.size(); r++) {
1427 EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat());
1428 }
1429 }
1430 }
1431 }
1432 }
1433
1434 // clang-format off
1435 INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest,
1436 ::testing::Values(
1437 // Test case 0: OpTranspose square null matrix
1438 InstructionFoldingCase<std::vector<std::vector<float>>>(
1439 Header() + "%main = OpFunction %void None %void_func\n" +
1440 "%main_lab = OpLabel\n" +
1441 "%2 = OpTranspose %mat4v4float %mat4v4float_null\n" +
1442 "OpReturn\n" +
1443 "OpFunctionEnd",
1444 2, {{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f}}),
1445 // Test case 1: OpTranspose rectangular null matrix
1446 InstructionFoldingCase<std::vector<std::vector<float>>>(
1447 Header() + "%main = OpFunction %void None %void_func\n" +
1448 "%main_lab = OpLabel\n" +
1449 "%2 = OpTranspose %mat4v2float %mat2v4float_null\n" +
1450 "OpReturn\n" +
1451 "OpFunctionEnd",
1452 2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}),
1453 InstructionFoldingCase<std::vector<std::vector<float>>>(
1454 Header() + "%main = OpFunction %void None %void_func\n" +
1455 "%main_lab = OpLabel\n" +
1456 "%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" +
1457 "OpReturn\n" +
1458 "OpFunctionEnd",
1459 2, {{1.0f, 1.0f, 1.0f, 1.0f},{2.0f, 2.0f, 2.0f, 2.0f},{3.0f, 3.0f, 3.0f, 3.0f},{4.0f, 4.0f, 4.0f, 4.0f}})
1460 ));
1461 // clang-format on
1462
1463 using BooleanInstructionFoldingTest =
1464 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
1465
TEST_P(BooleanInstructionFoldingTest, Case)1466 TEST_P(BooleanInstructionFoldingTest, Case) {
1467 const auto& tc = GetParam();
1468
1469 // Build module.
1470 std::unique_ptr<IRContext> context =
1471 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1472 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1473 ASSERT_NE(nullptr, context);
1474
1475 // Fold the instruction to test.
1476 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1477 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1478 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1479
1480 // Make sure the instruction folded as expected.
1481 EXPECT_TRUE(succeeded);
1482 if (inst != nullptr) {
1483 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
1484 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1485 std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
1486 spv::Op::OpConstantFalse};
1487 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
1488 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1489 const analysis::BoolConstant* result =
1490 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
1491 EXPECT_NE(result, nullptr);
1492 if (result != nullptr) {
1493 EXPECT_EQ(result->value(), tc.expected_result);
1494 }
1495 }
1496 }
1497
1498 // clang-format off
1499 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
1500 ::testing::Values(
1501 // Test case 0: fold true || n
1502 InstructionFoldingCase<bool>(
1503 Header() + "%main = OpFunction %void None %void_func\n" +
1504 "%main_lab = OpLabel\n" +
1505 "%n = OpVariable %_ptr_bool Function\n" +
1506 "%load = OpLoad %bool %n\n" +
1507 "%2 = OpLogicalOr %bool %true %load\n" +
1508 "OpReturn\n" +
1509 "OpFunctionEnd",
1510 2, true),
1511 // Test case 1: fold n || true
1512 InstructionFoldingCase<bool>(
1513 Header() + "%main = OpFunction %void None %void_func\n" +
1514 "%main_lab = OpLabel\n" +
1515 "%n = OpVariable %_ptr_bool Function\n" +
1516 "%load = OpLoad %bool %n\n" +
1517 "%2 = OpLogicalOr %bool %load %true\n" +
1518 "OpReturn\n" +
1519 "OpFunctionEnd",
1520 2, true),
1521 // Test case 2: fold false && n
1522 InstructionFoldingCase<bool>(
1523 Header() + "%main = OpFunction %void None %void_func\n" +
1524 "%main_lab = OpLabel\n" +
1525 "%n = OpVariable %_ptr_bool Function\n" +
1526 "%load = OpLoad %bool %n\n" +
1527 "%2 = OpLogicalAnd %bool %false %load\n" +
1528 "OpReturn\n" +
1529 "OpFunctionEnd",
1530 2, false),
1531 // Test case 3: fold n && false
1532 InstructionFoldingCase<bool>(
1533 Header() + "%main = OpFunction %void None %void_func\n" +
1534 "%main_lab = OpLabel\n" +
1535 "%n = OpVariable %_ptr_bool Function\n" +
1536 "%load = OpLoad %bool %n\n" +
1537 "%2 = OpLogicalAnd %bool %load %false\n" +
1538 "OpReturn\n" +
1539 "OpFunctionEnd",
1540 2, false),
1541 // Test case 4: fold n < 0 (unsigned)
1542 InstructionFoldingCase<bool>(
1543 Header() + "%main = OpFunction %void None %void_func\n" +
1544 "%main_lab = OpLabel\n" +
1545 "%n = OpVariable %_ptr_uint Function\n" +
1546 "%load = OpLoad %uint %n\n" +
1547 "%2 = OpULessThan %bool %load %uint_0\n" +
1548 "OpReturn\n" +
1549 "OpFunctionEnd",
1550 2, false),
1551 // Test case 5: fold UINT_MAX < n (unsigned)
1552 InstructionFoldingCase<bool>(
1553 Header() + "%main = OpFunction %void None %void_func\n" +
1554 "%main_lab = OpLabel\n" +
1555 "%n = OpVariable %_ptr_uint Function\n" +
1556 "%load = OpLoad %uint %n\n" +
1557 "%2 = OpULessThan %bool %uint_max %load\n" +
1558 "OpReturn\n" +
1559 "OpFunctionEnd",
1560 2, false),
1561 // Test case 6: fold INT_MAX < n (signed)
1562 InstructionFoldingCase<bool>(
1563 Header() + "%main = OpFunction %void None %void_func\n" +
1564 "%main_lab = OpLabel\n" +
1565 "%n = OpVariable %_ptr_int Function\n" +
1566 "%load = OpLoad %int %n\n" +
1567 "%2 = OpSLessThan %bool %int_max %load\n" +
1568 "OpReturn\n" +
1569 "OpFunctionEnd",
1570 2, false),
1571 // Test case 7: fold n < INT_MIN (signed)
1572 InstructionFoldingCase<bool>(
1573 Header() + "%main = OpFunction %void None %void_func\n" +
1574 "%main_lab = OpLabel\n" +
1575 "%n = OpVariable %_ptr_int Function\n" +
1576 "%load = OpLoad %int %n\n" +
1577 "%2 = OpSLessThan %bool %load %int_min\n" +
1578 "OpReturn\n" +
1579 "OpFunctionEnd",
1580 2, false),
1581 // Test case 8: fold 0 > n (unsigned)
1582 InstructionFoldingCase<bool>(
1583 Header() + "%main = OpFunction %void None %void_func\n" +
1584 "%main_lab = OpLabel\n" +
1585 "%n = OpVariable %_ptr_uint Function\n" +
1586 "%load = OpLoad %uint %n\n" +
1587 "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
1588 "OpReturn\n" +
1589 "OpFunctionEnd",
1590 2, false),
1591 // Test case 9: fold n > UINT_MAX (unsigned)
1592 InstructionFoldingCase<bool>(
1593 Header() + "%main = OpFunction %void None %void_func\n" +
1594 "%main_lab = OpLabel\n" +
1595 "%n = OpVariable %_ptr_uint Function\n" +
1596 "%load = OpLoad %uint %n\n" +
1597 "%2 = OpUGreaterThan %bool %load %uint_max\n" +
1598 "OpReturn\n" +
1599 "OpFunctionEnd",
1600 2, false),
1601 // Test case 10: fold n > INT_MAX (signed)
1602 InstructionFoldingCase<bool>(
1603 Header() + "%main = OpFunction %void None %void_func\n" +
1604 "%main_lab = OpLabel\n" +
1605 "%n = OpVariable %_ptr_int Function\n" +
1606 "%load = OpLoad %int %n\n" +
1607 "%2 = OpSGreaterThan %bool %load %int_max\n" +
1608 "OpReturn\n" +
1609 "OpFunctionEnd",
1610 2, false),
1611 // Test case 11: fold INT_MIN > n (signed)
1612 InstructionFoldingCase<bool>(
1613 Header() + "%main = OpFunction %void None %void_func\n" +
1614 "%main_lab = OpLabel\n" +
1615 "%n = OpVariable %_ptr_uint Function\n" +
1616 "%load = OpLoad %uint %n\n" +
1617 "%2 = OpSGreaterThan %bool %int_min %load\n" +
1618 "OpReturn\n" +
1619 "OpFunctionEnd",
1620 2, false),
1621 // Test case 12: fold 0 <= n (unsigned)
1622 InstructionFoldingCase<bool>(
1623 Header() + "%main = OpFunction %void None %void_func\n" +
1624 "%main_lab = OpLabel\n" +
1625 "%n = OpVariable %_ptr_uint Function\n" +
1626 "%load = OpLoad %uint %n\n" +
1627 "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
1628 "OpReturn\n" +
1629 "OpFunctionEnd",
1630 2, true),
1631 // Test case 13: fold n <= UINT_MAX (unsigned)
1632 InstructionFoldingCase<bool>(
1633 Header() + "%main = OpFunction %void None %void_func\n" +
1634 "%main_lab = OpLabel\n" +
1635 "%n = OpVariable %_ptr_uint Function\n" +
1636 "%load = OpLoad %uint %n\n" +
1637 "%2 = OpULessThanEqual %bool %load %uint_max\n" +
1638 "OpReturn\n" +
1639 "OpFunctionEnd",
1640 2, true),
1641 // Test case 14: fold INT_MIN <= n (signed)
1642 InstructionFoldingCase<bool>(
1643 Header() + "%main = OpFunction %void None %void_func\n" +
1644 "%main_lab = OpLabel\n" +
1645 "%n = OpVariable %_ptr_int Function\n" +
1646 "%load = OpLoad %int %n\n" +
1647 "%2 = OpSLessThanEqual %bool %int_min %load\n" +
1648 "OpReturn\n" +
1649 "OpFunctionEnd",
1650 2, true),
1651 // Test case 15: fold n <= INT_MAX (signed)
1652 InstructionFoldingCase<bool>(
1653 Header() + "%main = OpFunction %void None %void_func\n" +
1654 "%main_lab = OpLabel\n" +
1655 "%n = OpVariable %_ptr_int Function\n" +
1656 "%load = OpLoad %int %n\n" +
1657 "%2 = OpSLessThanEqual %bool %load %int_max\n" +
1658 "OpReturn\n" +
1659 "OpFunctionEnd",
1660 2, true),
1661 // Test case 16: fold n >= 0 (unsigned)
1662 InstructionFoldingCase<bool>(
1663 Header() + "%main = OpFunction %void None %void_func\n" +
1664 "%main_lab = OpLabel\n" +
1665 "%n = OpVariable %_ptr_uint Function\n" +
1666 "%load = OpLoad %uint %n\n" +
1667 "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
1668 "OpReturn\n" +
1669 "OpFunctionEnd",
1670 2, true),
1671 // Test case 17: fold UINT_MAX >= n (unsigned)
1672 InstructionFoldingCase<bool>(
1673 Header() + "%main = OpFunction %void None %void_func\n" +
1674 "%main_lab = OpLabel\n" +
1675 "%n = OpVariable %_ptr_uint Function\n" +
1676 "%load = OpLoad %uint %n\n" +
1677 "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
1678 "OpReturn\n" +
1679 "OpFunctionEnd",
1680 2, true),
1681 // Test case 18: fold n >= INT_MIN (signed)
1682 InstructionFoldingCase<bool>(
1683 Header() + "%main = OpFunction %void None %void_func\n" +
1684 "%main_lab = OpLabel\n" +
1685 "%n = OpVariable %_ptr_int Function\n" +
1686 "%load = OpLoad %int %n\n" +
1687 "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
1688 "OpReturn\n" +
1689 "OpFunctionEnd",
1690 2, true),
1691 // Test case 19: fold INT_MAX >= n (signed)
1692 InstructionFoldingCase<bool>(
1693 Header() + "%main = OpFunction %void None %void_func\n" +
1694 "%main_lab = OpLabel\n" +
1695 "%n = OpVariable %_ptr_int Function\n" +
1696 "%load = OpLoad %int %n\n" +
1697 "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
1698 "OpReturn\n" +
1699 "OpFunctionEnd",
1700 2, true)
1701 ));
1702
1703 INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
1704 ::testing::Values(
1705 // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
1706 InstructionFoldingCase<bool>(
1707 Header() + "%main = OpFunction %void None %void_func\n" +
1708 "%main_lab = OpLabel\n" +
1709 "%n = OpVariable %_ptr_float Function\n" +
1710 "%ld = OpLoad %float %n\n" +
1711 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1712 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1713 "OpReturn\n" +
1714 "OpFunctionEnd",
1715 2, false),
1716 // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
1717 InstructionFoldingCase<bool>(
1718 Header() + "%main = OpFunction %void None %void_func\n" +
1719 "%main_lab = OpLabel\n" +
1720 "%n = OpVariable %_ptr_float Function\n" +
1721 "%ld = OpLoad %float %n\n" +
1722 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1723 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1724 "OpReturn\n" +
1725 "OpFunctionEnd",
1726 2, true),
1727 // Test case 2: fold 0.0 >= clamp(n, 1, 2)
1728 InstructionFoldingCase<bool>(
1729 Header() + "%main = OpFunction %void None %void_func\n" +
1730 "%main_lab = OpLabel\n" +
1731 "%n = OpVariable %_ptr_float Function\n" +
1732 "%ld = OpLoad %float %n\n" +
1733 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1734 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1735 "OpReturn\n" +
1736 "OpFunctionEnd",
1737 2, false),
1738 // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
1739 InstructionFoldingCase<bool>(
1740 Header() + "%main = OpFunction %void None %void_func\n" +
1741 "%main_lab = OpLabel\n" +
1742 "%n = OpVariable %_ptr_float Function\n" +
1743 "%ld = OpLoad %float %n\n" +
1744 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1745 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1746 "OpReturn\n" +
1747 "OpFunctionEnd",
1748 2, true),
1749 // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
1750 InstructionFoldingCase<bool>(
1751 Header() + "%main = OpFunction %void None %void_func\n" +
1752 "%main_lab = OpLabel\n" +
1753 "%n = OpVariable %_ptr_float Function\n" +
1754 "%ld = OpLoad %float %n\n" +
1755 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1756 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1757 "OpReturn\n" +
1758 "OpFunctionEnd",
1759 2, true),
1760 // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
1761 InstructionFoldingCase<bool>(
1762 Header() + "%main = OpFunction %void None %void_func\n" +
1763 "%main_lab = OpLabel\n" +
1764 "%n = OpVariable %_ptr_float Function\n" +
1765 "%ld = OpLoad %float %n\n" +
1766 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1767 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1768 "OpReturn\n" +
1769 "OpFunctionEnd",
1770 2, false),
1771 // Test case 6: fold 0.0 < clamp(n, 1, 2)
1772 InstructionFoldingCase<bool>(
1773 Header() + "%main = OpFunction %void None %void_func\n" +
1774 "%main_lab = OpLabel\n" +
1775 "%n = OpVariable %_ptr_float Function\n" +
1776 "%ld = OpLoad %float %n\n" +
1777 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1778 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1779 "OpReturn\n" +
1780 "OpFunctionEnd",
1781 2, true),
1782 // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
1783 InstructionFoldingCase<bool>(
1784 Header() + "%main = OpFunction %void None %void_func\n" +
1785 "%main_lab = OpLabel\n" +
1786 "%n = OpVariable %_ptr_float Function\n" +
1787 "%ld = OpLoad %float %n\n" +
1788 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1789 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1790 "OpReturn\n" +
1791 "OpFunctionEnd",
1792 2, false),
1793 // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
1794 InstructionFoldingCase<bool>(
1795 Header() + "%main = OpFunction %void None %void_func\n" +
1796 "%main_lab = OpLabel\n" +
1797 "%n = OpVariable %_ptr_float Function\n" +
1798 "%ld = OpLoad %float %n\n" +
1799 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1800 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1801 "OpReturn\n" +
1802 "OpFunctionEnd",
1803 2, false),
1804 // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
1805 InstructionFoldingCase<bool>(
1806 Header() + "%main = OpFunction %void None %void_func\n" +
1807 "%main_lab = OpLabel\n" +
1808 "%n = OpVariable %_ptr_float Function\n" +
1809 "%ld = OpLoad %float %n\n" +
1810 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1811 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1812 "OpReturn\n" +
1813 "OpFunctionEnd",
1814 2, true),
1815 // Test case 10: fold 0.0 >= clamp(n, 1, 2)
1816 InstructionFoldingCase<bool>(
1817 Header() + "%main = OpFunction %void None %void_func\n" +
1818 "%main_lab = OpLabel\n" +
1819 "%n = OpVariable %_ptr_float Function\n" +
1820 "%ld = OpLoad %float %n\n" +
1821 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1822 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1823 "OpReturn\n" +
1824 "OpFunctionEnd",
1825 2, false),
1826 // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
1827 InstructionFoldingCase<bool>(
1828 Header() + "%main = OpFunction %void None %void_func\n" +
1829 "%main_lab = OpLabel\n" +
1830 "%n = OpVariable %_ptr_float Function\n" +
1831 "%ld = OpLoad %float %n\n" +
1832 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1833 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1834 "OpReturn\n" +
1835 "OpFunctionEnd",
1836 2, true),
1837 // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
1838 InstructionFoldingCase<bool>(
1839 Header() + "%main = OpFunction %void None %void_func\n" +
1840 "%main_lab = OpLabel\n" +
1841 "%n = OpVariable %_ptr_float Function\n" +
1842 "%ld = OpLoad %float %n\n" +
1843 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1844 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1845 "OpReturn\n" +
1846 "OpFunctionEnd",
1847 2, true),
1848 // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
1849 InstructionFoldingCase<bool>(
1850 Header() + "%main = OpFunction %void None %void_func\n" +
1851 "%main_lab = OpLabel\n" +
1852 "%n = OpVariable %_ptr_float Function\n" +
1853 "%ld = OpLoad %float %n\n" +
1854 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1855 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1856 "OpReturn\n" +
1857 "OpFunctionEnd",
1858 2, false),
1859 // Test case 14: fold 0.0 < clamp(n, 1, 2)
1860 InstructionFoldingCase<bool>(
1861 Header() + "%main = OpFunction %void None %void_func\n" +
1862 "%main_lab = OpLabel\n" +
1863 "%n = OpVariable %_ptr_float Function\n" +
1864 "%ld = OpLoad %float %n\n" +
1865 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1866 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1867 "OpReturn\n" +
1868 "OpFunctionEnd",
1869 2, true),
1870 // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
1871 InstructionFoldingCase<bool>(
1872 Header() + "%main = OpFunction %void None %void_func\n" +
1873 "%main_lab = OpLabel\n" +
1874 "%n = OpVariable %_ptr_float Function\n" +
1875 "%ld = OpLoad %float %n\n" +
1876 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1877 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1878 "OpReturn\n" +
1879 "OpFunctionEnd",
1880 2, false)
1881 ));
1882
1883 INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
1884 ::testing::Values(
1885 // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
1886 InstructionFoldingCase<bool>(
1887 Header() + "%main = OpFunction %void None %void_func\n" +
1888 "%main_lab = OpLabel\n" +
1889 "%n = OpVariable %_ptr_float Function\n" +
1890 "%ld = OpLoad %float %n\n" +
1891 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1892 "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
1893 "OpReturn\n" +
1894 "OpFunctionEnd",
1895 2, false),
1896 // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
1897 InstructionFoldingCase<bool>(
1898 Header() + "%main = OpFunction %void None %void_func\n" +
1899 "%main_lab = OpLabel\n" +
1900 "%n = OpVariable %_ptr_float Function\n" +
1901 "%ld = OpLoad %float %n\n" +
1902 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1903 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
1904 "OpReturn\n" +
1905 "OpFunctionEnd",
1906 2, true),
1907 // Test case 2: fold clamp(n, 1, 2) >= 0.0
1908 InstructionFoldingCase<bool>(
1909 Header() + "%main = OpFunction %void None %void_func\n" +
1910 "%main_lab = OpLabel\n" +
1911 "%n = OpVariable %_ptr_float Function\n" +
1912 "%ld = OpLoad %float %n\n" +
1913 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1914 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
1915 "OpReturn\n" +
1916 "OpFunctionEnd",
1917 2, true),
1918 // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
1919 InstructionFoldingCase<bool>(
1920 Header() + "%main = OpFunction %void None %void_func\n" +
1921 "%main_lab = OpLabel\n" +
1922 "%n = OpVariable %_ptr_float Function\n" +
1923 "%ld = OpLoad %float %n\n" +
1924 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1925 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
1926 "OpReturn\n" +
1927 "OpFunctionEnd",
1928 2, false),
1929 // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
1930 InstructionFoldingCase<bool>(
1931 Header() + "%main = OpFunction %void None %void_func\n" +
1932 "%main_lab = OpLabel\n" +
1933 "%n = OpVariable %_ptr_float Function\n" +
1934 "%ld = OpLoad %float %n\n" +
1935 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1936 "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
1937 "OpReturn\n" +
1938 "OpFunctionEnd",
1939 2, true),
1940 // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
1941 InstructionFoldingCase<bool>(
1942 Header() + "%main = OpFunction %void None %void_func\n" +
1943 "%main_lab = OpLabel\n" +
1944 "%n = OpVariable %_ptr_float Function\n" +
1945 "%ld = OpLoad %float %n\n" +
1946 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1947 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
1948 "OpReturn\n" +
1949 "OpFunctionEnd",
1950 2, false),
1951 // Test case 6: fold clamp(n, 1, 2) < 3
1952 InstructionFoldingCase<bool>(
1953 Header() + "%main = OpFunction %void None %void_func\n" +
1954 "%main_lab = OpLabel\n" +
1955 "%n = OpVariable %_ptr_float Function\n" +
1956 "%ld = OpLoad %float %n\n" +
1957 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1958 "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
1959 "OpReturn\n" +
1960 "OpFunctionEnd",
1961 2, true),
1962 // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
1963 InstructionFoldingCase<bool>(
1964 Header() + "%main = OpFunction %void None %void_func\n" +
1965 "%main_lab = OpLabel\n" +
1966 "%n = OpVariable %_ptr_float Function\n" +
1967 "%ld = OpLoad %float %n\n" +
1968 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1969 "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
1970 "OpReturn\n" +
1971 "OpFunctionEnd",
1972 2, false),
1973 // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
1974 InstructionFoldingCase<bool>(
1975 Header() + "%main = OpFunction %void None %void_func\n" +
1976 "%main_lab = OpLabel\n" +
1977 "%n = OpVariable %_ptr_float Function\n" +
1978 "%ld = OpLoad %float %n\n" +
1979 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1980 "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
1981 "OpReturn\n" +
1982 "OpFunctionEnd",
1983 2, false),
1984 // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
1985 InstructionFoldingCase<bool>(
1986 Header() + "%main = OpFunction %void None %void_func\n" +
1987 "%main_lab = OpLabel\n" +
1988 "%n = OpVariable %_ptr_float Function\n" +
1989 "%ld = OpLoad %float %n\n" +
1990 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1991 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
1992 "OpReturn\n" +
1993 "OpFunctionEnd",
1994 2, true),
1995 // Test case 10: fold clamp(n, 1, 2) >= 3.0
1996 InstructionFoldingCase<bool>(
1997 Header() + "%main = OpFunction %void None %void_func\n" +
1998 "%main_lab = OpLabel\n" +
1999 "%n = OpVariable %_ptr_float Function\n" +
2000 "%ld = OpLoad %float %n\n" +
2001 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2002 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
2003 "OpReturn\n" +
2004 "OpFunctionEnd",
2005 2, false),
2006 // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
2007 InstructionFoldingCase<bool>(
2008 Header() + "%main = OpFunction %void None %void_func\n" +
2009 "%main_lab = OpLabel\n" +
2010 "%n = OpVariable %_ptr_float Function\n" +
2011 "%ld = OpLoad %float %n\n" +
2012 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2013 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
2014 "OpReturn\n" +
2015 "OpFunctionEnd",
2016 2, true),
2017 // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
2018 InstructionFoldingCase<bool>(
2019 Header() + "%main = OpFunction %void None %void_func\n" +
2020 "%main_lab = OpLabel\n" +
2021 "%n = OpVariable %_ptr_float Function\n" +
2022 "%ld = OpLoad %float %n\n" +
2023 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
2024 "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
2025 "OpReturn\n" +
2026 "OpFunctionEnd",
2027 2, true),
2028 // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
2029 InstructionFoldingCase<bool>(
2030 Header() + "%main = OpFunction %void None %void_func\n" +
2031 "%main_lab = OpLabel\n" +
2032 "%n = OpVariable %_ptr_float Function\n" +
2033 "%ld = OpLoad %float %n\n" +
2034 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
2035 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
2036 "OpReturn\n" +
2037 "OpFunctionEnd",
2038 2, false),
2039 // Test case 14: fold clamp(n, 1, 2) < 3
2040 InstructionFoldingCase<bool>(
2041 Header() + "%main = OpFunction %void None %void_func\n" +
2042 "%main_lab = OpLabel\n" +
2043 "%n = OpVariable %_ptr_float Function\n" +
2044 "%ld = OpLoad %float %n\n" +
2045 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
2046 "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
2047 "OpReturn\n" +
2048 "OpFunctionEnd",
2049 2, true),
2050 // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
2051 InstructionFoldingCase<bool>(
2052 Header() + "%main = OpFunction %void None %void_func\n" +
2053 "%main_lab = OpLabel\n" +
2054 "%n = OpVariable %_ptr_float Function\n" +
2055 "%ld = OpLoad %float %n\n" +
2056 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
2057 "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
2058 "OpReturn\n" +
2059 "OpFunctionEnd",
2060 2, false),
2061 // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
2062 InstructionFoldingCase<bool>(
2063 Header() + "%main = OpFunction %void None %void_func\n" +
2064 "%main_lab = OpLabel\n" +
2065 "%n = OpVariable %_ptr_double Function\n" +
2066 "%ld = OpLoad %double %n\n" +
2067 "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
2068 "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
2069 "OpReturn\n" +
2070 "OpFunctionEnd",
2071 2, false)
2072 ));
2073 // clang-format on
2074
2075 using FloatInstructionFoldingTest =
2076 ::testing::TestWithParam<InstructionFoldingCase<float>>;
2077
TEST_P(FloatInstructionFoldingTest, Case)2078 TEST_P(FloatInstructionFoldingTest, Case) {
2079 const auto& tc = GetParam();
2080
2081 // Build module.
2082 std::unique_ptr<IRContext> context =
2083 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2084 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2085 ASSERT_NE(nullptr, context);
2086
2087 // Fold the instruction to test.
2088 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2089 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2090 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2091
2092 // Make sure the instruction folded as expected.
2093 EXPECT_TRUE(succeeded);
2094 if (inst != nullptr) {
2095 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
2096 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2097 EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
2098 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2099 const analysis::FloatConstant* result =
2100 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2101 EXPECT_NE(result, nullptr);
2102 if (result != nullptr) {
2103 if (!std::isnan(tc.expected_result)) {
2104 EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
2105 } else {
2106 EXPECT_TRUE(std::isnan(result->GetFloatValue()));
2107 }
2108 }
2109 }
2110 }
2111
2112 // Not testing NaNs because there are no expectations concerning NaNs according
2113 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
2114 // specification.
2115
2116 // clang-format off
2117 INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
2118 ::testing::Values(
2119 // Test case 0: Fold 2.0 - 1.0
2120 InstructionFoldingCase<float>(
2121 Header() + "%main = OpFunction %void None %void_func\n" +
2122 "%main_lab = OpLabel\n" +
2123 "%2 = OpFSub %float %float_2 %float_1\n" +
2124 "OpReturn\n" +
2125 "OpFunctionEnd",
2126 2, 1.0),
2127 // Test case 1: Fold 2.0 + 1.0
2128 InstructionFoldingCase<float>(
2129 Header() + "%main = OpFunction %void None %void_func\n" +
2130 "%main_lab = OpLabel\n" +
2131 "%2 = OpFAdd %float %float_2 %float_1\n" +
2132 "OpReturn\n" +
2133 "OpFunctionEnd",
2134 2, 3.0),
2135 // Test case 2: Fold 3.0 * 2.0
2136 InstructionFoldingCase<float>(
2137 Header() + "%main = OpFunction %void None %void_func\n" +
2138 "%main_lab = OpLabel\n" +
2139 "%2 = OpFMul %float %float_3 %float_2\n" +
2140 "OpReturn\n" +
2141 "OpFunctionEnd",
2142 2, 6.0),
2143 // Test case 3: Fold 1.0 / 2.0
2144 InstructionFoldingCase<float>(
2145 Header() + "%main = OpFunction %void None %void_func\n" +
2146 "%main_lab = OpLabel\n" +
2147 "%2 = OpFDiv %float %float_1 %float_2\n" +
2148 "OpReturn\n" +
2149 "OpFunctionEnd",
2150 2, 0.5),
2151 // Test case 4: Fold 1.0 / 0.0
2152 InstructionFoldingCase<float>(
2153 Header() + "%main = OpFunction %void None %void_func\n" +
2154 "%main_lab = OpLabel\n" +
2155 "%2 = OpFDiv %float %float_1 %float_0\n" +
2156 "OpReturn\n" +
2157 "OpFunctionEnd",
2158 2, std::numeric_limits<float>::infinity()),
2159 // Test case 5: Fold -1.0 / 0.0
2160 InstructionFoldingCase<float>(
2161 Header() + "%main = OpFunction %void None %void_func\n" +
2162 "%main_lab = OpLabel\n" +
2163 "%2 = OpFDiv %float %float_n1 %float_0\n" +
2164 "OpReturn\n" +
2165 "OpFunctionEnd",
2166 2, -std::numeric_limits<float>::infinity()),
2167 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2168 InstructionFoldingCase<float>(
2169 Header() + "%main = OpFunction %void None %void_func\n" +
2170 "%main_lab = OpLabel\n" +
2171 "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
2172 "OpReturn\n" +
2173 "OpFunctionEnd",
2174 2, 5.5f),
2175 // Test case 7: Fold (0.0, 0.0) dot v
2176 InstructionFoldingCase<float>(
2177 Header() + "%main = OpFunction %void None %void_func\n" +
2178 "%main_lab = OpLabel\n" +
2179 "%v = OpVariable %_ptr_v2float Function\n" +
2180 "%2 = OpLoad %v2float %v\n" +
2181 "%3 = OpDot %float %v2float_0_0 %2\n" +
2182 "OpReturn\n" +
2183 "OpFunctionEnd",
2184 3, 0.0f),
2185 // Test case 8: Fold v dot (0.0, 0.0)
2186 InstructionFoldingCase<float>(
2187 Header() + "%main = OpFunction %void None %void_func\n" +
2188 "%main_lab = OpLabel\n" +
2189 "%v = OpVariable %_ptr_v2float Function\n" +
2190 "%2 = OpLoad %v2float %v\n" +
2191 "%3 = OpDot %float %2 %v2float_0_0\n" +
2192 "OpReturn\n" +
2193 "OpFunctionEnd",
2194 3, 0.0f),
2195 // Test case 9: Fold Null dot v
2196 InstructionFoldingCase<float>(
2197 Header() + "%main = OpFunction %void None %void_func\n" +
2198 "%main_lab = OpLabel\n" +
2199 "%v = OpVariable %_ptr_v2float Function\n" +
2200 "%2 = OpLoad %v2float %v\n" +
2201 "%3 = OpDot %float %v2float_null %2\n" +
2202 "OpReturn\n" +
2203 "OpFunctionEnd",
2204 3, 0.0f),
2205 // Test case 10: Fold v dot Null
2206 InstructionFoldingCase<float>(
2207 Header() + "%main = OpFunction %void None %void_func\n" +
2208 "%main_lab = OpLabel\n" +
2209 "%v = OpVariable %_ptr_v2float Function\n" +
2210 "%2 = OpLoad %v2float %v\n" +
2211 "%3 = OpDot %float %2 %v2float_null\n" +
2212 "OpReturn\n" +
2213 "OpFunctionEnd",
2214 3, 0.0f),
2215 // Test case 11: Fold -2.0
2216 InstructionFoldingCase<float>(
2217 Header() + "%main = OpFunction %void None %void_func\n" +
2218 "%main_lab = OpLabel\n" +
2219 "%2 = OpFNegate %float %float_2\n" +
2220 "OpReturn\n" +
2221 "OpFunctionEnd",
2222 2, -2),
2223 // Test case 12: QuantizeToF16 1.0
2224 InstructionFoldingCase<float>(
2225 Header() + "%main = OpFunction %void None %void_func\n" +
2226 "%main_lab = OpLabel\n" +
2227 "%2 = OpQuantizeToF16 %float %float_1\n" +
2228 "OpReturn\n" +
2229 "OpFunctionEnd",
2230 2, 1.0),
2231 // Test case 13: QuantizeToF16 positive non exact
2232 InstructionFoldingCase<float>(
2233 Header() + "%main = OpFunction %void None %void_func\n" +
2234 "%main_lab = OpLabel\n" +
2235 "%2 = OpQuantizeToF16 %float %float_2049\n" +
2236 "OpReturn\n" +
2237 "OpFunctionEnd",
2238 2, 2048),
2239 // Test case 14: QuantizeToF16 negative non exact
2240 InstructionFoldingCase<float>(
2241 Header() + "%main = OpFunction %void None %void_func\n" +
2242 "%main_lab = OpLabel\n" +
2243 "%2 = OpQuantizeToF16 %float %float_n2049\n" +
2244 "OpReturn\n" +
2245 "OpFunctionEnd",
2246 2, -2048),
2247 // Test case 15: QuantizeToF16 large positive
2248 InstructionFoldingCase<float>(
2249 Header() + "%main = OpFunction %void None %void_func\n" +
2250 "%main_lab = OpLabel\n" +
2251 "%2 = OpQuantizeToF16 %float %float_1e16\n" +
2252 "OpReturn\n" +
2253 "OpFunctionEnd",
2254 2, std::numeric_limits<float>::infinity()),
2255 // Test case 16: QuantizeToF16 large negative
2256 InstructionFoldingCase<float>(
2257 Header() + "%main = OpFunction %void None %void_func\n" +
2258 "%main_lab = OpLabel\n" +
2259 "%2 = OpQuantizeToF16 %float %float_n1e16\n" +
2260 "OpReturn\n" +
2261 "OpFunctionEnd",
2262 2, -std::numeric_limits<float>::infinity()),
2263 // Test case 17: QuantizeToF16 small positive
2264 InstructionFoldingCase<float>(
2265 Header() + "%main = OpFunction %void None %void_func\n" +
2266 "%main_lab = OpLabel\n" +
2267 "%2 = OpQuantizeToF16 %float %float_1en16\n" +
2268 "OpReturn\n" +
2269 "OpFunctionEnd",
2270 2, 0.0),
2271 // Test case 18: QuantizeToF16 small negative
2272 InstructionFoldingCase<float>(
2273 Header() + "%main = OpFunction %void None %void_func\n" +
2274 "%main_lab = OpLabel\n" +
2275 "%2 = OpQuantizeToF16 %float %float_n1en16\n" +
2276 "OpReturn\n" +
2277 "OpFunctionEnd",
2278 2, 0.0),
2279 // Test case 19: QuantizeToF16 nan
2280 InstructionFoldingCase<float>(
2281 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2282 "%main_lab = OpLabel\n" +
2283 "%2 = OpQuantizeToF16 %float %float_nan\n" +
2284 "OpReturn\n" +
2285 "OpFunctionEnd",
2286 2, std::numeric_limits<float>::quiet_NaN()),
2287 // Test case 20: FMix 1.0 4.0 0.2
2288 InstructionFoldingCase<float>(
2289 Header() + "%main = OpFunction %void None %void_func\n" +
2290 "%main_lab = OpLabel\n" +
2291 "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
2292 "OpReturn\n" +
2293 "OpFunctionEnd",
2294 2, 1.6f),
2295 // Test case 21: FMin 1.0 4.0
2296 InstructionFoldingCase<float>(
2297 Header() + "%main = OpFunction %void None %void_func\n" +
2298 "%main_lab = OpLabel\n" +
2299 "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
2300 "OpReturn\n" +
2301 "OpFunctionEnd",
2302 2, 1.0f),
2303 // Test case 22: FMin 4.0 0.2
2304 InstructionFoldingCase<float>(
2305 Header() + "%main = OpFunction %void None %void_func\n" +
2306 "%main_lab = OpLabel\n" +
2307 "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
2308 "OpReturn\n" +
2309 "OpFunctionEnd",
2310 2, 0.2f),
2311 // Test case 23: FMax 1.0 4.0
2312 InstructionFoldingCase<float>(
2313 Header() + "%main = OpFunction %void None %void_func\n" +
2314 "%main_lab = OpLabel\n" +
2315 "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
2316 "OpReturn\n" +
2317 "OpFunctionEnd",
2318 2, 4.0f),
2319 // Test case 24: FMax 1.0 0.2
2320 InstructionFoldingCase<float>(
2321 Header() + "%main = OpFunction %void None %void_func\n" +
2322 "%main_lab = OpLabel\n" +
2323 "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
2324 "OpReturn\n" +
2325 "OpFunctionEnd",
2326 2, 1.0f),
2327 // Test case 25: FClamp 1.0 0.2 4.0
2328 InstructionFoldingCase<float>(
2329 Header() + "%main = OpFunction %void None %void_func\n" +
2330 "%main_lab = OpLabel\n" +
2331 "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
2332 "OpReturn\n" +
2333 "OpFunctionEnd",
2334 2, 1.0f),
2335 // Test case 26: FClamp 0.2 2.0 4.0
2336 InstructionFoldingCase<float>(
2337 Header() + "%main = OpFunction %void None %void_func\n" +
2338 "%main_lab = OpLabel\n" +
2339 "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
2340 "OpReturn\n" +
2341 "OpFunctionEnd",
2342 2, 2.0f),
2343 // Test case 27: FClamp 2049.0 2.0 4.0
2344 InstructionFoldingCase<float>(
2345 Header() + "%main = OpFunction %void None %void_func\n" +
2346 "%main_lab = OpLabel\n" +
2347 "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
2348 "OpReturn\n" +
2349 "OpFunctionEnd",
2350 2, 4.0f),
2351 // Test case 28: FClamp 1.0 2.0 x
2352 InstructionFoldingCase<float>(
2353 Header() + "%main = OpFunction %void None %void_func\n" +
2354 "%main_lab = OpLabel\n" +
2355 "%undef = OpUndef %float\n" +
2356 "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
2357 "OpReturn\n" +
2358 "OpFunctionEnd",
2359 2, 2.0),
2360 // Test case 29: FClamp 1.0 x 0.5
2361 InstructionFoldingCase<float>(
2362 Header() + "%main = OpFunction %void None %void_func\n" +
2363 "%main_lab = OpLabel\n" +
2364 "%undef = OpUndef %float\n" +
2365 "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
2366 "OpReturn\n" +
2367 "OpFunctionEnd",
2368 2, 0.5),
2369 // Test case 30: Sin 0.0
2370 InstructionFoldingCase<float>(
2371 Header() + "%main = OpFunction %void None %void_func\n" +
2372 "%main_lab = OpLabel\n" +
2373 "%2 = OpExtInst %float %1 Sin %float_0\n" +
2374 "OpReturn\n" +
2375 "OpFunctionEnd",
2376 2, 0.0),
2377 // Test case 31: Cos 0.0
2378 InstructionFoldingCase<float>(
2379 Header() + "%main = OpFunction %void None %void_func\n" +
2380 "%main_lab = OpLabel\n" +
2381 "%2 = OpExtInst %float %1 Cos %float_0\n" +
2382 "OpReturn\n" +
2383 "OpFunctionEnd",
2384 2, 1.0),
2385 // Test case 32: Tan 0.0
2386 InstructionFoldingCase<float>(
2387 Header() + "%main = OpFunction %void None %void_func\n" +
2388 "%main_lab = OpLabel\n" +
2389 "%2 = OpExtInst %float %1 Tan %float_0\n" +
2390 "OpReturn\n" +
2391 "OpFunctionEnd",
2392 2, 0.0),
2393 // Test case 33: Asin 0.0
2394 InstructionFoldingCase<float>(
2395 Header() + "%main = OpFunction %void None %void_func\n" +
2396 "%main_lab = OpLabel\n" +
2397 "%2 = OpExtInst %float %1 Asin %float_0\n" +
2398 "OpReturn\n" +
2399 "OpFunctionEnd",
2400 2, 0.0),
2401 // Test case 34: Acos 1.0
2402 InstructionFoldingCase<float>(
2403 Header() + "%main = OpFunction %void None %void_func\n" +
2404 "%main_lab = OpLabel\n" +
2405 "%2 = OpExtInst %float %1 Acos %float_1\n" +
2406 "OpReturn\n" +
2407 "OpFunctionEnd",
2408 2, 0.0),
2409 // Test case 35: Atan 0.0
2410 InstructionFoldingCase<float>(
2411 Header() + "%main = OpFunction %void None %void_func\n" +
2412 "%main_lab = OpLabel\n" +
2413 "%2 = OpExtInst %float %1 Atan %float_0\n" +
2414 "OpReturn\n" +
2415 "OpFunctionEnd",
2416 2, 0.0),
2417 // Test case 36: Exp 0.0
2418 InstructionFoldingCase<float>(
2419 Header() + "%main = OpFunction %void None %void_func\n" +
2420 "%main_lab = OpLabel\n" +
2421 "%2 = OpExtInst %float %1 Exp %float_0\n" +
2422 "OpReturn\n" +
2423 "OpFunctionEnd",
2424 2, 1.0),
2425 // Test case 37: Log 1.0
2426 InstructionFoldingCase<float>(
2427 Header() + "%main = OpFunction %void None %void_func\n" +
2428 "%main_lab = OpLabel\n" +
2429 "%2 = OpExtInst %float %1 Log %float_1\n" +
2430 "OpReturn\n" +
2431 "OpFunctionEnd",
2432 2, 0.0),
2433 // Test case 38: Exp2 2.0
2434 InstructionFoldingCase<float>(
2435 Header() + "%main = OpFunction %void None %void_func\n" +
2436 "%main_lab = OpLabel\n" +
2437 "%2 = OpExtInst %float %1 Exp2 %float_2\n" +
2438 "OpReturn\n" +
2439 "OpFunctionEnd",
2440 2, 4.0),
2441 // Test case 39: Log2 4.0
2442 InstructionFoldingCase<float>(
2443 Header() + "%main = OpFunction %void None %void_func\n" +
2444 "%main_lab = OpLabel\n" +
2445 "%2 = OpExtInst %float %1 Log2 %float_4\n" +
2446 "OpReturn\n" +
2447 "OpFunctionEnd",
2448 2, 2.0),
2449 // Test case 40: Sqrt 4.0
2450 InstructionFoldingCase<float>(
2451 Header() + "%main = OpFunction %void None %void_func\n" +
2452 "%main_lab = OpLabel\n" +
2453 "%2 = OpExtInst %float %1 Sqrt %float_4\n" +
2454 "OpReturn\n" +
2455 "OpFunctionEnd",
2456 2, 2.0),
2457 // Test case 41: Atan2 0.0 1.0
2458 InstructionFoldingCase<float>(
2459 Header() + "%main = OpFunction %void None %void_func\n" +
2460 "%main_lab = OpLabel\n" +
2461 "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
2462 "OpReturn\n" +
2463 "OpFunctionEnd",
2464 2, 0.0),
2465 // Test case 42: Pow 2.0 3.0
2466 InstructionFoldingCase<float>(
2467 Header() + "%main = OpFunction %void None %void_func\n" +
2468 "%main_lab = OpLabel\n" +
2469 "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
2470 "OpReturn\n" +
2471 "OpFunctionEnd",
2472 2, 8.0),
2473 // Test case 43: Fold 1.0 / -0.0.
2474 InstructionFoldingCase<float>(
2475 Header() + "%main = OpFunction %void None %void_func\n" +
2476 "%main_lab = OpLabel\n" +
2477 "%2 = OpFDiv %float %float_1 %float_n0\n" +
2478 "OpReturn\n" +
2479 "OpFunctionEnd",
2480 2, -std::numeric_limits<float>::infinity()),
2481 // Test case 44: Fold -1.0 / -0.0
2482 InstructionFoldingCase<float>(
2483 Header() + "%main = OpFunction %void None %void_func\n" +
2484 "%main_lab = OpLabel\n" +
2485 "%2 = OpFDiv %float %float_n1 %float_n0\n" +
2486 "OpReturn\n" +
2487 "OpFunctionEnd",
2488 2, std::numeric_limits<float>::infinity()),
2489 // Test case 45: Fold 0.0 / 0.0
2490 InstructionFoldingCase<float>(
2491 Header() + "%main = OpFunction %void None %void_func\n" +
2492 "%main_lab = OpLabel\n" +
2493 "%2 = OpFDiv %float %float_0 %float_0\n" +
2494 "OpReturn\n" +
2495 "OpFunctionEnd",
2496 2, std::numeric_limits<float>::quiet_NaN()),
2497 // Test case 46: Fold 0.0 / -0.0
2498 InstructionFoldingCase<float>(
2499 Header() + "%main = OpFunction %void None %void_func\n" +
2500 "%main_lab = OpLabel\n" +
2501 "%2 = OpFDiv %float %float_0 %float_n0\n" +
2502 "OpReturn\n" +
2503 "OpFunctionEnd",
2504 2, std::numeric_limits<float>::quiet_NaN())
2505 ));
2506 // clang-format on
2507
2508 using DoubleInstructionFoldingTest =
2509 ::testing::TestWithParam<InstructionFoldingCase<double>>;
2510
TEST_P(DoubleInstructionFoldingTest, Case)2511 TEST_P(DoubleInstructionFoldingTest, Case) {
2512 const auto& tc = GetParam();
2513
2514 // Build module.
2515 std::unique_ptr<IRContext> context =
2516 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2517 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2518 ASSERT_NE(nullptr, context);
2519
2520 // Fold the instruction to test.
2521 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2522 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2523 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2524
2525 // Make sure the instruction folded as expected.
2526 EXPECT_TRUE(succeeded);
2527 if (inst != nullptr) {
2528 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
2529 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2530 EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
2531 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2532 const analysis::FloatConstant* result =
2533 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2534 EXPECT_NE(result, nullptr);
2535 if (result != nullptr) {
2536 if (!std::isnan(tc.expected_result)) {
2537 EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
2538 } else {
2539 EXPECT_TRUE(std::isnan(result->GetDoubleValue()));
2540 }
2541 }
2542 }
2543 }
2544
2545 // clang-format off
2546 INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
2547 ::testing::Values(
2548 // Test case 0: Fold 2.0 - 1.0
2549 InstructionFoldingCase<double>(
2550 Header() + "%main = OpFunction %void None %void_func\n" +
2551 "%main_lab = OpLabel\n" +
2552 "%2 = OpFSub %double %double_2 %double_1\n" +
2553 "OpReturn\n" +
2554 "OpFunctionEnd",
2555 2, 1.0),
2556 // Test case 1: Fold 2.0 + 1.0
2557 InstructionFoldingCase<double>(
2558 Header() + "%main = OpFunction %void None %void_func\n" +
2559 "%main_lab = OpLabel\n" +
2560 "%2 = OpFAdd %double %double_2 %double_1\n" +
2561 "OpReturn\n" +
2562 "OpFunctionEnd",
2563 2, 3.0),
2564 // Test case 2: Fold 3.0 * 2.0
2565 InstructionFoldingCase<double>(
2566 Header() + "%main = OpFunction %void None %void_func\n" +
2567 "%main_lab = OpLabel\n" +
2568 "%2 = OpFMul %double %double_3 %double_2\n" +
2569 "OpReturn\n" +
2570 "OpFunctionEnd",
2571 2, 6.0),
2572 // Test case 3: Fold 1.0 / 2.0
2573 InstructionFoldingCase<double>(
2574 Header() + "%main = OpFunction %void None %void_func\n" +
2575 "%main_lab = OpLabel\n" +
2576 "%2 = OpFDiv %double %double_1 %double_2\n" +
2577 "OpReturn\n" +
2578 "OpFunctionEnd",
2579 2, 0.5),
2580 // Test case 4: Fold 1.0 / 0.0
2581 InstructionFoldingCase<double>(
2582 Header() + "%main = OpFunction %void None %void_func\n" +
2583 "%main_lab = OpLabel\n" +
2584 "%2 = OpFDiv %double %double_1 %double_0\n" +
2585 "OpReturn\n" +
2586 "OpFunctionEnd",
2587 2, std::numeric_limits<double>::infinity()),
2588 // Test case 5: Fold -1.0 / 0.0
2589 InstructionFoldingCase<double>(
2590 Header() + "%main = OpFunction %void None %void_func\n" +
2591 "%main_lab = OpLabel\n" +
2592 "%2 = OpFDiv %double %double_n1 %double_0\n" +
2593 "OpReturn\n" +
2594 "OpFunctionEnd",
2595 2, -std::numeric_limits<double>::infinity()),
2596 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2597 InstructionFoldingCase<double>(
2598 Header() + "%main = OpFunction %void None %void_func\n" +
2599 "%main_lab = OpLabel\n" +
2600 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
2601 "OpReturn\n" +
2602 "OpFunctionEnd",
2603 2, 5.5f),
2604 // Test case 7: Fold (0.0, 0.0) dot v
2605 InstructionFoldingCase<double>(
2606 Header() + "%main = OpFunction %void None %void_func\n" +
2607 "%main_lab = OpLabel\n" +
2608 "%v = OpVariable %_ptr_v2double Function\n" +
2609 "%2 = OpLoad %v2double %v\n" +
2610 "%3 = OpDot %double %v2double_0_0 %2\n" +
2611 "OpReturn\n" +
2612 "OpFunctionEnd",
2613 3, 0.0f),
2614 // Test case 8: Fold v dot (0.0, 0.0)
2615 InstructionFoldingCase<double>(
2616 Header() + "%main = OpFunction %void None %void_func\n" +
2617 "%main_lab = OpLabel\n" +
2618 "%v = OpVariable %_ptr_v2double Function\n" +
2619 "%2 = OpLoad %v2double %v\n" +
2620 "%3 = OpDot %double %2 %v2double_0_0\n" +
2621 "OpReturn\n" +
2622 "OpFunctionEnd",
2623 3, 0.0f),
2624 // Test case 9: Fold Null dot v
2625 InstructionFoldingCase<double>(
2626 Header() + "%main = OpFunction %void None %void_func\n" +
2627 "%main_lab = OpLabel\n" +
2628 "%v = OpVariable %_ptr_v2double Function\n" +
2629 "%2 = OpLoad %v2double %v\n" +
2630 "%3 = OpDot %double %v2double_null %2\n" +
2631 "OpReturn\n" +
2632 "OpFunctionEnd",
2633 3, 0.0f),
2634 // Test case 10: Fold v dot Null
2635 InstructionFoldingCase<double>(
2636 Header() + "%main = OpFunction %void None %void_func\n" +
2637 "%main_lab = OpLabel\n" +
2638 "%v = OpVariable %_ptr_v2double Function\n" +
2639 "%2 = OpLoad %v2double %v\n" +
2640 "%3 = OpDot %double %2 %v2double_null\n" +
2641 "OpReturn\n" +
2642 "OpFunctionEnd",
2643 3, 0.0f),
2644 // Test case 11: Fold -2.0
2645 InstructionFoldingCase<double>(
2646 Header() + "%main = OpFunction %void None %void_func\n" +
2647 "%main_lab = OpLabel\n" +
2648 "%2 = OpFNegate %double %double_2\n" +
2649 "OpReturn\n" +
2650 "OpFunctionEnd",
2651 2, -2),
2652 // Test case 12: FMin 1.0 4.0
2653 InstructionFoldingCase<double>(
2654 Header() + "%main = OpFunction %void None %void_func\n" +
2655 "%main_lab = OpLabel\n" +
2656 "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
2657 "OpReturn\n" +
2658 "OpFunctionEnd",
2659 2, 1.0),
2660 // Test case 13: FMin 4.0 0.2
2661 InstructionFoldingCase<double>(
2662 Header() + "%main = OpFunction %void None %void_func\n" +
2663 "%main_lab = OpLabel\n" +
2664 "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
2665 "OpReturn\n" +
2666 "OpFunctionEnd",
2667 2, 0.2),
2668 // Test case 14: FMax 1.0 4.0
2669 InstructionFoldingCase<double>(
2670 Header() + "%main = OpFunction %void None %void_func\n" +
2671 "%main_lab = OpLabel\n" +
2672 "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
2673 "OpReturn\n" +
2674 "OpFunctionEnd",
2675 2, 4.0),
2676 // Test case 15: FMax 1.0 0.2
2677 InstructionFoldingCase<double>(
2678 Header() + "%main = OpFunction %void None %void_func\n" +
2679 "%main_lab = OpLabel\n" +
2680 "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
2681 "OpReturn\n" +
2682 "OpFunctionEnd",
2683 2, 1.0),
2684 // Test case 16: FClamp 1.0 0.2 4.0
2685 InstructionFoldingCase<double>(
2686 Header() + "%main = OpFunction %void None %void_func\n" +
2687 "%main_lab = OpLabel\n" +
2688 "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
2689 "OpReturn\n" +
2690 "OpFunctionEnd",
2691 2, 1.0),
2692 // Test case 17: FClamp 0.2 2.0 4.0
2693 InstructionFoldingCase<double>(
2694 Header() + "%main = OpFunction %void None %void_func\n" +
2695 "%main_lab = OpLabel\n" +
2696 "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
2697 "OpReturn\n" +
2698 "OpFunctionEnd",
2699 2, 2.0),
2700 // Test case 18: FClamp 5.0 2.0 4.0
2701 InstructionFoldingCase<double>(
2702 Header() + "%main = OpFunction %void None %void_func\n" +
2703 "%main_lab = OpLabel\n" +
2704 "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
2705 "OpReturn\n" +
2706 "OpFunctionEnd",
2707 2, 4.0),
2708 // Test case 19: FClamp 1.0 2.0 x
2709 InstructionFoldingCase<double>(
2710 Header() + "%main = OpFunction %void None %void_func\n" +
2711 "%main_lab = OpLabel\n" +
2712 "%undef = OpUndef %double\n" +
2713 "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
2714 "OpReturn\n" +
2715 "OpFunctionEnd",
2716 2, 2.0),
2717 // Test case 20: FClamp 1.0 x 0.5
2718 InstructionFoldingCase<double>(
2719 Header() + "%main = OpFunction %void None %void_func\n" +
2720 "%main_lab = OpLabel\n" +
2721 "%undef = OpUndef %double\n" +
2722 "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
2723 "OpReturn\n" +
2724 "OpFunctionEnd",
2725 2, 0.5),
2726 // Test case 21: Sqrt 4.0
2727 InstructionFoldingCase<double>(
2728 Header() + "%main = OpFunction %void None %void_func\n" +
2729 "%main_lab = OpLabel\n" +
2730 "%undef = OpUndef %double\n" +
2731 "%2 = OpExtInst %double %1 Sqrt %double_4\n" +
2732 "OpReturn\n" +
2733 "OpFunctionEnd",
2734 2, 2.0),
2735 // Test case 22: Pow 2.0 3.0
2736 InstructionFoldingCase<double>(
2737 Header() + "%main = OpFunction %void None %void_func\n" +
2738 "%main_lab = OpLabel\n" +
2739 "%undef = OpUndef %double\n" +
2740 "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" +
2741 "OpReturn\n" +
2742 "OpFunctionEnd",
2743 2, 8.0),
2744 // Test case 23: Fold 1.0 / -0.0.
2745 InstructionFoldingCase<double>(
2746 Header() + "%main = OpFunction %void None %void_func\n" +
2747 "%main_lab = OpLabel\n" +
2748 "%2 = OpFDiv %double %double_1 %double_n0\n" +
2749 "OpReturn\n" +
2750 "OpFunctionEnd",
2751 2, -std::numeric_limits<double>::infinity()),
2752 // Test case 24: Fold -1.0 / -0.0
2753 InstructionFoldingCase<double>(
2754 Header() + "%main = OpFunction %void None %void_func\n" +
2755 "%main_lab = OpLabel\n" +
2756 "%2 = OpFDiv %double %double_n1 %double_n0\n" +
2757 "OpReturn\n" +
2758 "OpFunctionEnd",
2759 2, std::numeric_limits<double>::infinity()),
2760 // Test case 25: Fold 0.0 / 0.0
2761 InstructionFoldingCase<double>(
2762 Header() + "%main = OpFunction %void None %void_func\n" +
2763 "%main_lab = OpLabel\n" +
2764 "%2 = OpFDiv %double %double_0 %double_0\n" +
2765 "OpReturn\n" +
2766 "OpFunctionEnd",
2767 2, std::numeric_limits<double>::quiet_NaN()),
2768 // Test case 26: Fold 0.0 / -0.0
2769 InstructionFoldingCase<double>(
2770 Header() + "%main = OpFunction %void None %void_func\n" +
2771 "%main_lab = OpLabel\n" +
2772 "%2 = OpFDiv %double %double_0 %double_n0\n" +
2773 "OpReturn\n" +
2774 "OpFunctionEnd",
2775 2, std::numeric_limits<double>::quiet_NaN())
2776 ));
2777 // clang-format on
2778
2779 // clang-format off
2780 INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2781 ::testing::Values(
2782 // Test case 0: fold 1.0 == 2.0
2783 InstructionFoldingCase<bool>(
2784 Header() + "%main = OpFunction %void None %void_func\n" +
2785 "%main_lab = OpLabel\n" +
2786 "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
2787 "OpReturn\n" +
2788 "OpFunctionEnd",
2789 2, false),
2790 // Test case 1: fold 1.0 != 2.0
2791 InstructionFoldingCase<bool>(
2792 Header() + "%main = OpFunction %void None %void_func\n" +
2793 "%main_lab = OpLabel\n" +
2794 "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
2795 "OpReturn\n" +
2796 "OpFunctionEnd",
2797 2, true),
2798 // Test case 2: fold 1.0 < 2.0
2799 InstructionFoldingCase<bool>(
2800 Header() + "%main = OpFunction %void None %void_func\n" +
2801 "%main_lab = OpLabel\n" +
2802 "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
2803 "OpReturn\n" +
2804 "OpFunctionEnd",
2805 2, true),
2806 // Test case 3: fold 1.0 > 2.0
2807 InstructionFoldingCase<bool>(
2808 Header() + "%main = OpFunction %void None %void_func\n" +
2809 "%main_lab = OpLabel\n" +
2810 "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
2811 "OpReturn\n" +
2812 "OpFunctionEnd",
2813 2, false),
2814 // Test case 4: fold 1.0 <= 2.0
2815 InstructionFoldingCase<bool>(
2816 Header() + "%main = OpFunction %void None %void_func\n" +
2817 "%main_lab = OpLabel\n" +
2818 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
2819 "OpReturn\n" +
2820 "OpFunctionEnd",
2821 2, true),
2822 // Test case 5: fold 1.0 >= 2.0
2823 InstructionFoldingCase<bool>(
2824 Header() + "%main = OpFunction %void None %void_func\n" +
2825 "%main_lab = OpLabel\n" +
2826 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
2827 "OpReturn\n" +
2828 "OpFunctionEnd",
2829 2, false),
2830 // Test case 6: fold 1.0 == 1.0
2831 InstructionFoldingCase<bool>(
2832 Header() + "%main = OpFunction %void None %void_func\n" +
2833 "%main_lab = OpLabel\n" +
2834 "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
2835 "OpReturn\n" +
2836 "OpFunctionEnd",
2837 2, true),
2838 // Test case 7: fold 1.0 != 1.0
2839 InstructionFoldingCase<bool>(
2840 Header() + "%main = OpFunction %void None %void_func\n" +
2841 "%main_lab = OpLabel\n" +
2842 "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
2843 "OpReturn\n" +
2844 "OpFunctionEnd",
2845 2, false),
2846 // Test case 8: fold 1.0 < 1.0
2847 InstructionFoldingCase<bool>(
2848 Header() + "%main = OpFunction %void None %void_func\n" +
2849 "%main_lab = OpLabel\n" +
2850 "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
2851 "OpReturn\n" +
2852 "OpFunctionEnd",
2853 2, false),
2854 // Test case 9: fold 1.0 > 1.0
2855 InstructionFoldingCase<bool>(
2856 Header() + "%main = OpFunction %void None %void_func\n" +
2857 "%main_lab = OpLabel\n" +
2858 "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
2859 "OpReturn\n" +
2860 "OpFunctionEnd",
2861 2, false),
2862 // Test case 10: fold 1.0 <= 1.0
2863 InstructionFoldingCase<bool>(
2864 Header() + "%main = OpFunction %void None %void_func\n" +
2865 "%main_lab = OpLabel\n" +
2866 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
2867 "OpReturn\n" +
2868 "OpFunctionEnd",
2869 2, true),
2870 // Test case 11: fold 1.0 >= 1.0
2871 InstructionFoldingCase<bool>(
2872 Header() + "%main = OpFunction %void None %void_func\n" +
2873 "%main_lab = OpLabel\n" +
2874 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
2875 "OpReturn\n" +
2876 "OpFunctionEnd",
2877 2, true),
2878 // Test case 12: fold 2.0 < 1.0
2879 InstructionFoldingCase<bool>(
2880 Header() + "%main = OpFunction %void None %void_func\n" +
2881 "%main_lab = OpLabel\n" +
2882 "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
2883 "OpReturn\n" +
2884 "OpFunctionEnd",
2885 2, false),
2886 // Test case 13: fold 2.0 > 1.0
2887 InstructionFoldingCase<bool>(
2888 Header() + "%main = OpFunction %void None %void_func\n" +
2889 "%main_lab = OpLabel\n" +
2890 "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
2891 "OpReturn\n" +
2892 "OpFunctionEnd",
2893 2, true),
2894 // Test case 14: fold 2.0 <= 1.0
2895 InstructionFoldingCase<bool>(
2896 Header() + "%main = OpFunction %void None %void_func\n" +
2897 "%main_lab = OpLabel\n" +
2898 "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
2899 "OpReturn\n" +
2900 "OpFunctionEnd",
2901 2, false),
2902 // Test case 15: fold 2.0 >= 1.0
2903 InstructionFoldingCase<bool>(
2904 Header() + "%main = OpFunction %void None %void_func\n" +
2905 "%main_lab = OpLabel\n" +
2906 "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
2907 "OpReturn\n" +
2908 "OpFunctionEnd",
2909 2, true)
2910 ));
2911
2912 INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2913 ::testing::Values(
2914 // Test case 0: fold 1.0 == 2.0
2915 InstructionFoldingCase<bool>(
2916 Header() + "%main = OpFunction %void None %void_func\n" +
2917 "%main_lab = OpLabel\n" +
2918 "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
2919 "OpReturn\n" +
2920 "OpFunctionEnd",
2921 2, false),
2922 // Test case 1: fold 1.0 != 2.0
2923 InstructionFoldingCase<bool>(
2924 Header() + "%main = OpFunction %void None %void_func\n" +
2925 "%main_lab = OpLabel\n" +
2926 "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
2927 "OpReturn\n" +
2928 "OpFunctionEnd",
2929 2, true),
2930 // Test case 2: fold 1.0 < 2.0
2931 InstructionFoldingCase<bool>(
2932 Header() + "%main = OpFunction %void None %void_func\n" +
2933 "%main_lab = OpLabel\n" +
2934 "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
2935 "OpReturn\n" +
2936 "OpFunctionEnd",
2937 2, true),
2938 // Test case 3: fold 1.0 > 2.0
2939 InstructionFoldingCase<bool>(
2940 Header() + "%main = OpFunction %void None %void_func\n" +
2941 "%main_lab = OpLabel\n" +
2942 "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
2943 "OpReturn\n" +
2944 "OpFunctionEnd",
2945 2, false),
2946 // Test case 4: fold 1.0 <= 2.0
2947 InstructionFoldingCase<bool>(
2948 Header() + "%main = OpFunction %void None %void_func\n" +
2949 "%main_lab = OpLabel\n" +
2950 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
2951 "OpReturn\n" +
2952 "OpFunctionEnd",
2953 2, true),
2954 // Test case 5: fold 1.0 >= 2.0
2955 InstructionFoldingCase<bool>(
2956 Header() + "%main = OpFunction %void None %void_func\n" +
2957 "%main_lab = OpLabel\n" +
2958 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
2959 "OpReturn\n" +
2960 "OpFunctionEnd",
2961 2, false),
2962 // Test case 6: fold 1.0 == 1.0
2963 InstructionFoldingCase<bool>(
2964 Header() + "%main = OpFunction %void None %void_func\n" +
2965 "%main_lab = OpLabel\n" +
2966 "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
2967 "OpReturn\n" +
2968 "OpFunctionEnd",
2969 2, true),
2970 // Test case 7: fold 1.0 != 1.0
2971 InstructionFoldingCase<bool>(
2972 Header() + "%main = OpFunction %void None %void_func\n" +
2973 "%main_lab = OpLabel\n" +
2974 "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
2975 "OpReturn\n" +
2976 "OpFunctionEnd",
2977 2, false),
2978 // Test case 8: fold 1.0 < 1.0
2979 InstructionFoldingCase<bool>(
2980 Header() + "%main = OpFunction %void None %void_func\n" +
2981 "%main_lab = OpLabel\n" +
2982 "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
2983 "OpReturn\n" +
2984 "OpFunctionEnd",
2985 2, false),
2986 // Test case 9: fold 1.0 > 1.0
2987 InstructionFoldingCase<bool>(
2988 Header() + "%main = OpFunction %void None %void_func\n" +
2989 "%main_lab = OpLabel\n" +
2990 "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
2991 "OpReturn\n" +
2992 "OpFunctionEnd",
2993 2, false),
2994 // Test case 10: fold 1.0 <= 1.0
2995 InstructionFoldingCase<bool>(
2996 Header() + "%main = OpFunction %void None %void_func\n" +
2997 "%main_lab = OpLabel\n" +
2998 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
2999 "OpReturn\n" +
3000 "OpFunctionEnd",
3001 2, true),
3002 // Test case 11: fold 1.0 >= 1.0
3003 InstructionFoldingCase<bool>(
3004 Header() + "%main = OpFunction %void None %void_func\n" +
3005 "%main_lab = OpLabel\n" +
3006 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
3007 "OpReturn\n" +
3008 "OpFunctionEnd",
3009 2, true),
3010 // Test case 12: fold 2.0 < 1.0
3011 InstructionFoldingCase<bool>(
3012 Header() + "%main = OpFunction %void None %void_func\n" +
3013 "%main_lab = OpLabel\n" +
3014 "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
3015 "OpReturn\n" +
3016 "OpFunctionEnd",
3017 2, false),
3018 // Test case 13: fold 2.0 > 1.0
3019 InstructionFoldingCase<bool>(
3020 Header() + "%main = OpFunction %void None %void_func\n" +
3021 "%main_lab = OpLabel\n" +
3022 "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
3023 "OpReturn\n" +
3024 "OpFunctionEnd",
3025 2, true),
3026 // Test case 14: fold 2.0 <= 1.0
3027 InstructionFoldingCase<bool>(
3028 Header() + "%main = OpFunction %void None %void_func\n" +
3029 "%main_lab = OpLabel\n" +
3030 "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
3031 "OpReturn\n" +
3032 "OpFunctionEnd",
3033 2, false),
3034 // Test case 15: fold 2.0 >= 1.0
3035 InstructionFoldingCase<bool>(
3036 Header() + "%main = OpFunction %void None %void_func\n" +
3037 "%main_lab = OpLabel\n" +
3038 "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
3039 "OpReturn\n" +
3040 "OpFunctionEnd",
3041 2, true)
3042 ));
3043
3044 INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3045 ::testing::Values(
3046 // Test case 0: fold 1.0 == 2.0
3047 InstructionFoldingCase<bool>(
3048 Header() + "%main = OpFunction %void None %void_func\n" +
3049 "%main_lab = OpLabel\n" +
3050 "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
3051 "OpReturn\n" +
3052 "OpFunctionEnd",
3053 2, false),
3054 // Test case 1: fold 1.0 != 2.0
3055 InstructionFoldingCase<bool>(
3056 Header() + "%main = OpFunction %void None %void_func\n" +
3057 "%main_lab = OpLabel\n" +
3058 "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
3059 "OpReturn\n" +
3060 "OpFunctionEnd",
3061 2, true),
3062 // Test case 2: fold 1.0 < 2.0
3063 InstructionFoldingCase<bool>(
3064 Header() + "%main = OpFunction %void None %void_func\n" +
3065 "%main_lab = OpLabel\n" +
3066 "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
3067 "OpReturn\n" +
3068 "OpFunctionEnd",
3069 2, true),
3070 // Test case 3: fold 1.0 > 2.0
3071 InstructionFoldingCase<bool>(
3072 Header() + "%main = OpFunction %void None %void_func\n" +
3073 "%main_lab = OpLabel\n" +
3074 "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
3075 "OpReturn\n" +
3076 "OpFunctionEnd",
3077 2, false),
3078 // Test case 4: fold 1.0 <= 2.0
3079 InstructionFoldingCase<bool>(
3080 Header() + "%main = OpFunction %void None %void_func\n" +
3081 "%main_lab = OpLabel\n" +
3082 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
3083 "OpReturn\n" +
3084 "OpFunctionEnd",
3085 2, true),
3086 // Test case 5: fold 1.0 >= 2.0
3087 InstructionFoldingCase<bool>(
3088 Header() + "%main = OpFunction %void None %void_func\n" +
3089 "%main_lab = OpLabel\n" +
3090 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
3091 "OpReturn\n" +
3092 "OpFunctionEnd",
3093 2, false),
3094 // Test case 6: fold 1.0 == 1.0
3095 InstructionFoldingCase<bool>(
3096 Header() + "%main = OpFunction %void None %void_func\n" +
3097 "%main_lab = OpLabel\n" +
3098 "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
3099 "OpReturn\n" +
3100 "OpFunctionEnd",
3101 2, true),
3102 // Test case 7: fold 1.0 != 1.0
3103 InstructionFoldingCase<bool>(
3104 Header() + "%main = OpFunction %void None %void_func\n" +
3105 "%main_lab = OpLabel\n" +
3106 "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
3107 "OpReturn\n" +
3108 "OpFunctionEnd",
3109 2, false),
3110 // Test case 8: fold 1.0 < 1.0
3111 InstructionFoldingCase<bool>(
3112 Header() + "%main = OpFunction %void None %void_func\n" +
3113 "%main_lab = OpLabel\n" +
3114 "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
3115 "OpReturn\n" +
3116 "OpFunctionEnd",
3117 2, false),
3118 // Test case 9: fold 1.0 > 1.0
3119 InstructionFoldingCase<bool>(
3120 Header() + "%main = OpFunction %void None %void_func\n" +
3121 "%main_lab = OpLabel\n" +
3122 "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
3123 "OpReturn\n" +
3124 "OpFunctionEnd",
3125 2, false),
3126 // Test case 10: fold 1.0 <= 1.0
3127 InstructionFoldingCase<bool>(
3128 Header() + "%main = OpFunction %void None %void_func\n" +
3129 "%main_lab = OpLabel\n" +
3130 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
3131 "OpReturn\n" +
3132 "OpFunctionEnd",
3133 2, true),
3134 // Test case 11: fold 1.0 >= 1.0
3135 InstructionFoldingCase<bool>(
3136 Header() + "%main = OpFunction %void None %void_func\n" +
3137 "%main_lab = OpLabel\n" +
3138 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
3139 "OpReturn\n" +
3140 "OpFunctionEnd",
3141 2, true),
3142 // Test case 12: fold 2.0 < 1.0
3143 InstructionFoldingCase<bool>(
3144 Header() + "%main = OpFunction %void None %void_func\n" +
3145 "%main_lab = OpLabel\n" +
3146 "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
3147 "OpReturn\n" +
3148 "OpFunctionEnd",
3149 2, false),
3150 // Test case 13: fold 2.0 > 1.0
3151 InstructionFoldingCase<bool>(
3152 Header() + "%main = OpFunction %void None %void_func\n" +
3153 "%main_lab = OpLabel\n" +
3154 "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
3155 "OpReturn\n" +
3156 "OpFunctionEnd",
3157 2, true),
3158 // Test case 14: fold 2.0 <= 1.0
3159 InstructionFoldingCase<bool>(
3160 Header() + "%main = OpFunction %void None %void_func\n" +
3161 "%main_lab = OpLabel\n" +
3162 "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
3163 "OpReturn\n" +
3164 "OpFunctionEnd",
3165 2, false),
3166 // Test case 15: fold 2.0 >= 1.0
3167 InstructionFoldingCase<bool>(
3168 Header() + "%main = OpFunction %void None %void_func\n" +
3169 "%main_lab = OpLabel\n" +
3170 "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
3171 "OpReturn\n" +
3172 "OpFunctionEnd",
3173 2, true)
3174 ));
3175
3176 INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3177 ::testing::Values(
3178 // Test case 0: fold 1.0 == 2.0
3179 InstructionFoldingCase<bool>(
3180 Header() + "%main = OpFunction %void None %void_func\n" +
3181 "%main_lab = OpLabel\n" +
3182 "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
3183 "OpReturn\n" +
3184 "OpFunctionEnd",
3185 2, false),
3186 // Test case 1: fold 1.0 != 2.0
3187 InstructionFoldingCase<bool>(
3188 Header() + "%main = OpFunction %void None %void_func\n" +
3189 "%main_lab = OpLabel\n" +
3190 "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
3191 "OpReturn\n" +
3192 "OpFunctionEnd",
3193 2, true),
3194 // Test case 2: fold 1.0 < 2.0
3195 InstructionFoldingCase<bool>(
3196 Header() + "%main = OpFunction %void None %void_func\n" +
3197 "%main_lab = OpLabel\n" +
3198 "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
3199 "OpReturn\n" +
3200 "OpFunctionEnd",
3201 2, true),
3202 // Test case 3: fold 1.0 > 2.0
3203 InstructionFoldingCase<bool>(
3204 Header() + "%main = OpFunction %void None %void_func\n" +
3205 "%main_lab = OpLabel\n" +
3206 "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
3207 "OpReturn\n" +
3208 "OpFunctionEnd",
3209 2, false),
3210 // Test case 4: fold 1.0 <= 2.0
3211 InstructionFoldingCase<bool>(
3212 Header() + "%main = OpFunction %void None %void_func\n" +
3213 "%main_lab = OpLabel\n" +
3214 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
3215 "OpReturn\n" +
3216 "OpFunctionEnd",
3217 2, true),
3218 // Test case 5: fold 1.0 >= 2.0
3219 InstructionFoldingCase<bool>(
3220 Header() + "%main = OpFunction %void None %void_func\n" +
3221 "%main_lab = OpLabel\n" +
3222 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
3223 "OpReturn\n" +
3224 "OpFunctionEnd",
3225 2, false),
3226 // Test case 6: fold 1.0 == 1.0
3227 InstructionFoldingCase<bool>(
3228 Header() + "%main = OpFunction %void None %void_func\n" +
3229 "%main_lab = OpLabel\n" +
3230 "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
3231 "OpReturn\n" +
3232 "OpFunctionEnd",
3233 2, true),
3234 // Test case 7: fold 1.0 != 1.0
3235 InstructionFoldingCase<bool>(
3236 Header() + "%main = OpFunction %void None %void_func\n" +
3237 "%main_lab = OpLabel\n" +
3238 "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
3239 "OpReturn\n" +
3240 "OpFunctionEnd",
3241 2, false),
3242 // Test case 8: fold 1.0 < 1.0
3243 InstructionFoldingCase<bool>(
3244 Header() + "%main = OpFunction %void None %void_func\n" +
3245 "%main_lab = OpLabel\n" +
3246 "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
3247 "OpReturn\n" +
3248 "OpFunctionEnd",
3249 2, false),
3250 // Test case 9: fold 1.0 > 1.0
3251 InstructionFoldingCase<bool>(
3252 Header() + "%main = OpFunction %void None %void_func\n" +
3253 "%main_lab = OpLabel\n" +
3254 "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
3255 "OpReturn\n" +
3256 "OpFunctionEnd",
3257 2, false),
3258 // Test case 10: fold 1.0 <= 1.0
3259 InstructionFoldingCase<bool>(
3260 Header() + "%main = OpFunction %void None %void_func\n" +
3261 "%main_lab = OpLabel\n" +
3262 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
3263 "OpReturn\n" +
3264 "OpFunctionEnd",
3265 2, true),
3266 // Test case 11: fold 1.0 >= 1.0
3267 InstructionFoldingCase<bool>(
3268 Header() + "%main = OpFunction %void None %void_func\n" +
3269 "%main_lab = OpLabel\n" +
3270 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
3271 "OpReturn\n" +
3272 "OpFunctionEnd",
3273 2, true),
3274 // Test case 12: fold 2.0 < 1.0
3275 InstructionFoldingCase<bool>(
3276 Header() + "%main = OpFunction %void None %void_func\n" +
3277 "%main_lab = OpLabel\n" +
3278 "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
3279 "OpReturn\n" +
3280 "OpFunctionEnd",
3281 2, false),
3282 // Test case 13: fold 2.0 > 1.0
3283 InstructionFoldingCase<bool>(
3284 Header() + "%main = OpFunction %void None %void_func\n" +
3285 "%main_lab = OpLabel\n" +
3286 "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
3287 "OpReturn\n" +
3288 "OpFunctionEnd",
3289 2, true),
3290 // Test case 14: fold 2.0 <= 1.0
3291 InstructionFoldingCase<bool>(
3292 Header() + "%main = OpFunction %void None %void_func\n" +
3293 "%main_lab = OpLabel\n" +
3294 "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
3295 "OpReturn\n" +
3296 "OpFunctionEnd",
3297 2, false),
3298 // Test case 15: fold 2.0 >= 1.0
3299 InstructionFoldingCase<bool>(
3300 Header() + "%main = OpFunction %void None %void_func\n" +
3301 "%main_lab = OpLabel\n" +
3302 "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
3303 "OpReturn\n" +
3304 "OpFunctionEnd",
3305 2, true)
3306 ));
3307
3308 INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3309 ::testing::Values(
3310 // Test case 0: fold NaN == 0 (ord)
3311 InstructionFoldingCase<bool>(
3312 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3313 "%main_lab = OpLabel\n" +
3314 "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
3315 "OpReturn\n" +
3316 "OpFunctionEnd",
3317 2, false),
3318 // Test case 1: fold NaN == NaN (unord)
3319 InstructionFoldingCase<bool>(
3320 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3321 "%main_lab = OpLabel\n" +
3322 "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
3323 "OpReturn\n" +
3324 "OpFunctionEnd",
3325 2, true),
3326 // Test case 2: fold NaN != NaN (ord)
3327 InstructionFoldingCase<bool>(
3328 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3329 "%main_lab = OpLabel\n" +
3330 "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
3331 "OpReturn\n" +
3332 "OpFunctionEnd",
3333 2, false),
3334 // Test case 3: fold NaN != NaN (unord)
3335 InstructionFoldingCase<bool>(
3336 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3337 "%main_lab = OpLabel\n" +
3338 "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
3339 "OpReturn\n" +
3340 "OpFunctionEnd",
3341 2, true)
3342 ));
3343
3344 INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3345 ::testing::Values(
3346 // Test case 0: fold NaN == 0 (ord)
3347 InstructionFoldingCase<bool>(
3348 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3349 "%main_lab = OpLabel\n" +
3350 "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
3351 "OpReturn\n" +
3352 "OpFunctionEnd",
3353 2, false),
3354 // Test case 1: fold NaN == NaN (unord)
3355 InstructionFoldingCase<bool>(
3356 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3357 "%main_lab = OpLabel\n" +
3358 "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
3359 "OpReturn\n" +
3360 "OpFunctionEnd",
3361 2, true),
3362 // Test case 2: fold NaN != NaN (ord)
3363 InstructionFoldingCase<bool>(
3364 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3365 "%main_lab = OpLabel\n" +
3366 "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
3367 "OpReturn\n" +
3368 "OpFunctionEnd",
3369 2, false),
3370 // Test case 3: fold NaN != NaN (unord)
3371 InstructionFoldingCase<bool>(
3372 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3373 "%main_lab = OpLabel\n" +
3374 "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
3375 "OpReturn\n" +
3376 "OpFunctionEnd",
3377 2, true)
3378 ));
3379 // clang-format on
3380
3381 template <class ResultType>
3382 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anon26957::InstructionFoldingCaseWithMap3383 InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
3384 ResultType result,
3385 std::function<uint32_t(uint32_t)> map)
3386 : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
3387
3388 std::string test_body;
3389 uint32_t id_to_fold;
3390 ResultType expected_result;
3391 std::function<uint32_t(uint32_t)> id_map;
3392 };
3393
3394 using IntegerInstructionFoldingTestWithMap =
3395 ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
3396
TEST_P(IntegerInstructionFoldingTestWithMap, Case)3397 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
3398 const auto& tc = GetParam();
3399
3400 // Build module.
3401 std::unique_ptr<IRContext> context =
3402 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3403 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3404 ASSERT_NE(nullptr, context);
3405
3406 // Fold the instruction to test.
3407 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3408 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3409 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3410 tc.id_map);
3411
3412 // Make sure the instruction folded as expected.
3413 EXPECT_NE(inst, nullptr);
3414 if (inst != nullptr) {
3415 EXPECT_EQ(inst->opcode(), spv::Op::OpConstant);
3416 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3417 const analysis::IntConstant* result =
3418 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
3419 EXPECT_NE(result, nullptr);
3420 if (result != nullptr) {
3421 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
3422 }
3423 }
3424 }
3425 // clang-format off
3426 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
3427 ::testing::Values(
3428 // Test case 0: fold %3 = 0; %3 * n
3429 InstructionFoldingCaseWithMap<uint32_t>(
3430 Header() + "%main = OpFunction %void None %void_func\n" +
3431 "%main_lab = OpLabel\n" +
3432 "%n = OpVariable %_ptr_int Function\n" +
3433 "%load = OpLoad %int %n\n" +
3434 "%3 = OpCopyObject %int %int_0\n"
3435 "%2 = OpIMul %int %3 %load\n" +
3436 "OpReturn\n" +
3437 "OpFunctionEnd",
3438 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
3439 ));
3440 // clang-format on
3441
3442 using BooleanInstructionFoldingTestWithMap =
3443 ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
3444
TEST_P(BooleanInstructionFoldingTestWithMap, Case)3445 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
3446 const auto& tc = GetParam();
3447
3448 // Build module.
3449 std::unique_ptr<IRContext> context =
3450 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3451 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3452 ASSERT_NE(nullptr, context);
3453
3454 // Fold the instruction to test.
3455 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3456 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3457 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3458 tc.id_map);
3459
3460 // Make sure the instruction folded as expected.
3461 EXPECT_NE(inst, nullptr);
3462 if (inst != nullptr) {
3463 std::vector<spv::Op> bool_opcodes = {spv::Op::OpConstantTrue,
3464 spv::Op::OpConstantFalse};
3465 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
3466 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3467 const analysis::BoolConstant* result =
3468 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
3469 EXPECT_NE(result, nullptr);
3470 if (result != nullptr) {
3471 EXPECT_EQ(result->value(), tc.expected_result);
3472 }
3473 }
3474 }
3475
3476 // clang-format off
3477 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap,
3478 ::testing::Values(
3479 // Test case 0: fold %3 = true; %3 || n
3480 InstructionFoldingCaseWithMap<bool>(
3481 Header() + "%main = OpFunction %void None %void_func\n" +
3482 "%main_lab = OpLabel\n" +
3483 "%n = OpVariable %_ptr_bool Function\n" +
3484 "%load = OpLoad %bool %n\n" +
3485 "%3 = OpCopyObject %bool %true\n" +
3486 "%2 = OpLogicalOr %bool %3 %load\n" +
3487 "OpReturn\n" +
3488 "OpFunctionEnd",
3489 2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
3490 ));
3491 // clang-format on
3492
3493 using GeneralInstructionFoldingTest =
3494 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
3495
TEST_P(GeneralInstructionFoldingTest, Case)3496 TEST_P(GeneralInstructionFoldingTest, Case) {
3497 const auto& tc = GetParam();
3498
3499 // Build module.
3500 std::unique_ptr<IRContext> context =
3501 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3502 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3503 ASSERT_NE(nullptr, context);
3504
3505 // Fold the instruction to test.
3506 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3507 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3508 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
3509 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
3510
3511 // Make sure the instruction folded as expected.
3512 EXPECT_EQ(inst->result_id(), original_inst->result_id());
3513 EXPECT_EQ(inst->type_id(), original_inst->type_id());
3514 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
3515 if (succeeded) {
3516 EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject);
3517 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
3518 } else {
3519 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
3520 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
3521 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
3522 }
3523 }
3524 }
3525
3526 // clang-format off
3527 INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
3528 ::testing::Values(
3529 // Test case 0: Don't fold n * m
3530 InstructionFoldingCase<uint32_t>(
3531 Header() + "%main = OpFunction %void None %void_func\n" +
3532 "%main_lab = OpLabel\n" +
3533 "%n = OpVariable %_ptr_int Function\n" +
3534 "%m = OpVariable %_ptr_int Function\n" +
3535 "%load_n = OpLoad %int %n\n" +
3536 "%load_m = OpLoad %int %m\n" +
3537 "%2 = OpIMul %int %load_n %load_m\n" +
3538 "OpReturn\n" +
3539 "OpFunctionEnd",
3540 2, 0),
3541 // Test case 1: Don't fold n / m (unsigned)
3542 InstructionFoldingCase<uint32_t>(
3543 Header() + "%main = OpFunction %void None %void_func\n" +
3544 "%main_lab = OpLabel\n" +
3545 "%n = OpVariable %_ptr_uint Function\n" +
3546 "%m = OpVariable %_ptr_uint Function\n" +
3547 "%load_n = OpLoad %uint %n\n" +
3548 "%load_m = OpLoad %uint %m\n" +
3549 "%2 = OpUDiv %uint %load_n %load_m\n" +
3550 "OpReturn\n" +
3551 "OpFunctionEnd",
3552 2, 0),
3553 // Test case 2: Don't fold n / m (signed)
3554 InstructionFoldingCase<uint32_t>(
3555 Header() + "%main = OpFunction %void None %void_func\n" +
3556 "%main_lab = OpLabel\n" +
3557 "%n = OpVariable %_ptr_int Function\n" +
3558 "%m = OpVariable %_ptr_int Function\n" +
3559 "%load_n = OpLoad %int %n\n" +
3560 "%load_m = OpLoad %int %m\n" +
3561 "%2 = OpSDiv %int %load_n %load_m\n" +
3562 "OpReturn\n" +
3563 "OpFunctionEnd",
3564 2, 0),
3565 // Test case 3: Don't fold n remainder m
3566 InstructionFoldingCase<uint32_t>(
3567 Header() + "%main = OpFunction %void None %void_func\n" +
3568 "%main_lab = OpLabel\n" +
3569 "%n = OpVariable %_ptr_int Function\n" +
3570 "%m = OpVariable %_ptr_int Function\n" +
3571 "%load_n = OpLoad %int %n\n" +
3572 "%load_m = OpLoad %int %m\n" +
3573 "%2 = OpSRem %int %load_n %load_m\n" +
3574 "OpReturn\n" +
3575 "OpFunctionEnd",
3576 2, 0),
3577 // Test case 4: Don't fold n % m (signed)
3578 InstructionFoldingCase<uint32_t>(
3579 Header() + "%main = OpFunction %void None %void_func\n" +
3580 "%main_lab = OpLabel\n" +
3581 "%n = OpVariable %_ptr_int Function\n" +
3582 "%m = OpVariable %_ptr_int Function\n" +
3583 "%load_n = OpLoad %int %n\n" +
3584 "%load_m = OpLoad %int %m\n" +
3585 "%2 = OpSMod %int %load_n %load_m\n" +
3586 "OpReturn\n" +
3587 "OpFunctionEnd",
3588 2, 0),
3589 // Test case 5: Don't fold n % m (unsigned)
3590 InstructionFoldingCase<uint32_t>(
3591 Header() + "%main = OpFunction %void None %void_func\n" +
3592 "%main_lab = OpLabel\n" +
3593 "%n = OpVariable %_ptr_uint Function\n" +
3594 "%m = OpVariable %_ptr_uint Function\n" +
3595 "%load_n = OpLoad %uint %n\n" +
3596 "%load_m = OpLoad %uint %m\n" +
3597 "%2 = OpUMod %int %load_n %load_m\n" +
3598 "OpReturn\n" +
3599 "OpFunctionEnd",
3600 2, 0),
3601 // Test case 6: Don't fold n << m
3602 InstructionFoldingCase<uint32_t>(
3603 Header() + "%main = OpFunction %void None %void_func\n" +
3604 "%main_lab = OpLabel\n" +
3605 "%n = OpVariable %_ptr_uint Function\n" +
3606 "%m = OpVariable %_ptr_uint Function\n" +
3607 "%load_n = OpLoad %uint %n\n" +
3608 "%load_m = OpLoad %uint %m\n" +
3609 "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
3610 "OpReturn\n" +
3611 "OpFunctionEnd",
3612 2, 0),
3613 // Test case 7: Don't fold n >> m
3614 InstructionFoldingCase<uint32_t>(
3615 Header() + "%main = OpFunction %void None %void_func\n" +
3616 "%main_lab = OpLabel\n" +
3617 "%n = OpVariable %_ptr_uint Function\n" +
3618 "%m = OpVariable %_ptr_uint Function\n" +
3619 "%load_n = OpLoad %uint %n\n" +
3620 "%load_m = OpLoad %uint %m\n" +
3621 "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
3622 "OpReturn\n" +
3623 "OpFunctionEnd",
3624 2, 0),
3625 // Test case 8: Don't fold n | m
3626 InstructionFoldingCase<uint32_t>(
3627 Header() + "%main = OpFunction %void None %void_func\n" +
3628 "%main_lab = OpLabel\n" +
3629 "%n = OpVariable %_ptr_uint Function\n" +
3630 "%m = OpVariable %_ptr_uint Function\n" +
3631 "%load_n = OpLoad %uint %n\n" +
3632 "%load_m = OpLoad %uint %m\n" +
3633 "%2 = OpBitwiseOr %int %load_n %load_m\n" +
3634 "OpReturn\n" +
3635 "OpFunctionEnd",
3636 2, 0),
3637 // Test case 9: Don't fold n & m
3638 InstructionFoldingCase<uint32_t>(
3639 Header() + "%main = OpFunction %void None %void_func\n" +
3640 "%main_lab = OpLabel\n" +
3641 "%n = OpVariable %_ptr_uint Function\n" +
3642 "%m = OpVariable %_ptr_uint Function\n" +
3643 "%load_n = OpLoad %uint %n\n" +
3644 "%load_m = OpLoad %uint %m\n" +
3645 "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
3646 "OpReturn\n" +
3647 "OpFunctionEnd",
3648 2, 0),
3649 // Test case 10: Don't fold n < m (unsigned)
3650 InstructionFoldingCase<uint32_t>(
3651 Header() + "%main = OpFunction %void None %void_func\n" +
3652 "%main_lab = OpLabel\n" +
3653 "%n = OpVariable %_ptr_uint Function\n" +
3654 "%m = OpVariable %_ptr_uint Function\n" +
3655 "%load_n = OpLoad %uint %n\n" +
3656 "%load_m = OpLoad %uint %m\n" +
3657 "%2 = OpULessThan %bool %load_n %load_m\n" +
3658 "OpReturn\n" +
3659 "OpFunctionEnd",
3660 2, 0),
3661 // Test case 11: Don't fold n > m (unsigned)
3662 InstructionFoldingCase<uint32_t>(
3663 Header() + "%main = OpFunction %void None %void_func\n" +
3664 "%main_lab = OpLabel\n" +
3665 "%n = OpVariable %_ptr_uint Function\n" +
3666 "%m = OpVariable %_ptr_uint Function\n" +
3667 "%load_n = OpLoad %uint %n\n" +
3668 "%load_m = OpLoad %uint %m\n" +
3669 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3670 "OpReturn\n" +
3671 "OpFunctionEnd",
3672 2, 0),
3673 // Test case 12: Don't fold n <= m (unsigned)
3674 InstructionFoldingCase<uint32_t>(
3675 Header() + "%main = OpFunction %void None %void_func\n" +
3676 "%main_lab = OpLabel\n" +
3677 "%n = OpVariable %_ptr_uint Function\n" +
3678 "%m = OpVariable %_ptr_uint Function\n" +
3679 "%load_n = OpLoad %uint %n\n" +
3680 "%load_m = OpLoad %uint %m\n" +
3681 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3682 "OpReturn\n" +
3683 "OpFunctionEnd",
3684 2, 0),
3685 // Test case 13: Don't fold n >= m (unsigned)
3686 InstructionFoldingCase<uint32_t>(
3687 Header() + "%main = OpFunction %void None %void_func\n" +
3688 "%main_lab = OpLabel\n" +
3689 "%n = OpVariable %_ptr_uint Function\n" +
3690 "%m = OpVariable %_ptr_uint Function\n" +
3691 "%load_n = OpLoad %uint %n\n" +
3692 "%load_m = OpLoad %uint %m\n" +
3693 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3694 "OpReturn\n" +
3695 "OpFunctionEnd",
3696 2, 0),
3697 // Test case 14: Don't fold n < m (signed)
3698 InstructionFoldingCase<uint32_t>(
3699 Header() + "%main = OpFunction %void None %void_func\n" +
3700 "%main_lab = OpLabel\n" +
3701 "%n = OpVariable %_ptr_int Function\n" +
3702 "%m = OpVariable %_ptr_int Function\n" +
3703 "%load_n = OpLoad %int %n\n" +
3704 "%load_m = OpLoad %int %m\n" +
3705 "%2 = OpULessThan %bool %load_n %load_m\n" +
3706 "OpReturn\n" +
3707 "OpFunctionEnd",
3708 2, 0),
3709 // Test case 15: Don't fold n > m (signed)
3710 InstructionFoldingCase<uint32_t>(
3711 Header() + "%main = OpFunction %void None %void_func\n" +
3712 "%main_lab = OpLabel\n" +
3713 "%n = OpVariable %_ptr_int Function\n" +
3714 "%m = OpVariable %_ptr_int Function\n" +
3715 "%load_n = OpLoad %int %n\n" +
3716 "%load_m = OpLoad %int %m\n" +
3717 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3718 "OpReturn\n" +
3719 "OpFunctionEnd",
3720 2, 0),
3721 // Test case 16: Don't fold n <= m (signed)
3722 InstructionFoldingCase<uint32_t>(
3723 Header() + "%main = OpFunction %void None %void_func\n" +
3724 "%main_lab = OpLabel\n" +
3725 "%n = OpVariable %_ptr_int Function\n" +
3726 "%m = OpVariable %_ptr_int Function\n" +
3727 "%load_n = OpLoad %int %n\n" +
3728 "%load_m = OpLoad %int %m\n" +
3729 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3730 "OpReturn\n" +
3731 "OpFunctionEnd",
3732 2, 0),
3733 // Test case 17: Don't fold n >= m (signed)
3734 InstructionFoldingCase<uint32_t>(
3735 Header() + "%main = OpFunction %void None %void_func\n" +
3736 "%main_lab = OpLabel\n" +
3737 "%n = OpVariable %_ptr_int Function\n" +
3738 "%m = OpVariable %_ptr_int Function\n" +
3739 "%load_n = OpLoad %int %n\n" +
3740 "%load_m = OpLoad %int %m\n" +
3741 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3742 "OpReturn\n" +
3743 "OpFunctionEnd",
3744 2, 0),
3745 // Test case 18: Don't fold n || m
3746 InstructionFoldingCase<uint32_t>(
3747 Header() + "%main = OpFunction %void None %void_func\n" +
3748 "%main_lab = OpLabel\n" +
3749 "%n = OpVariable %_ptr_bool Function\n" +
3750 "%m = OpVariable %_ptr_bool Function\n" +
3751 "%load_n = OpLoad %bool %n\n" +
3752 "%load_m = OpLoad %bool %m\n" +
3753 "%2 = OpLogicalOr %bool %load_n %load_m\n" +
3754 "OpReturn\n" +
3755 "OpFunctionEnd",
3756 2, 0),
3757 // Test case 19: Don't fold n && m
3758 InstructionFoldingCase<uint32_t>(
3759 Header() + "%main = OpFunction %void None %void_func\n" +
3760 "%main_lab = OpLabel\n" +
3761 "%n = OpVariable %_ptr_bool Function\n" +
3762 "%m = OpVariable %_ptr_bool Function\n" +
3763 "%load_n = OpLoad %bool %n\n" +
3764 "%load_m = OpLoad %bool %m\n" +
3765 "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
3766 "OpReturn\n" +
3767 "OpFunctionEnd",
3768 2, 0),
3769 // Test case 20: Don't fold n * 3
3770 InstructionFoldingCase<uint32_t>(
3771 Header() + "%main = OpFunction %void None %void_func\n" +
3772 "%main_lab = OpLabel\n" +
3773 "%n = OpVariable %_ptr_int Function\n" +
3774 "%load_n = OpLoad %int %n\n" +
3775 "%2 = OpIMul %int %load_n %int_3\n" +
3776 "OpReturn\n" +
3777 "OpFunctionEnd",
3778 2, 0),
3779 // Test case 21: Don't fold n / 3 (unsigned)
3780 InstructionFoldingCase<uint32_t>(
3781 Header() + "%main = OpFunction %void None %void_func\n" +
3782 "%main_lab = OpLabel\n" +
3783 "%n = OpVariable %_ptr_uint Function\n" +
3784 "%load_n = OpLoad %uint %n\n" +
3785 "%2 = OpUDiv %uint %load_n %uint_3\n" +
3786 "OpReturn\n" +
3787 "OpFunctionEnd",
3788 2, 0),
3789 // Test case 22: Don't fold n / 3 (signed)
3790 InstructionFoldingCase<uint32_t>(
3791 Header() + "%main = OpFunction %void None %void_func\n" +
3792 "%main_lab = OpLabel\n" +
3793 "%n = OpVariable %_ptr_int Function\n" +
3794 "%load_n = OpLoad %int %n\n" +
3795 "%2 = OpSDiv %int %load_n %int_3\n" +
3796 "OpReturn\n" +
3797 "OpFunctionEnd",
3798 2, 0),
3799 // Test case 23: Don't fold n remainder 3
3800 InstructionFoldingCase<uint32_t>(
3801 Header() + "%main = OpFunction %void None %void_func\n" +
3802 "%main_lab = OpLabel\n" +
3803 "%n = OpVariable %_ptr_int Function\n" +
3804 "%load_n = OpLoad %int %n\n" +
3805 "%2 = OpSRem %int %load_n %int_3\n" +
3806 "OpReturn\n" +
3807 "OpFunctionEnd",
3808 2, 0),
3809 // Test case 24: Don't fold n % 3 (signed)
3810 InstructionFoldingCase<uint32_t>(
3811 Header() + "%main = OpFunction %void None %void_func\n" +
3812 "%main_lab = OpLabel\n" +
3813 "%n = OpVariable %_ptr_int Function\n" +
3814 "%load_n = OpLoad %int %n\n" +
3815 "%2 = OpSMod %int %load_n %int_3\n" +
3816 "OpReturn\n" +
3817 "OpFunctionEnd",
3818 2, 0),
3819 // Test case 25: Don't fold n % 3 (unsigned)
3820 InstructionFoldingCase<uint32_t>(
3821 Header() + "%main = OpFunction %void None %void_func\n" +
3822 "%main_lab = OpLabel\n" +
3823 "%n = OpVariable %_ptr_uint Function\n" +
3824 "%load_n = OpLoad %uint %n\n" +
3825 "%2 = OpUMod %int %load_n %int_3\n" +
3826 "OpReturn\n" +
3827 "OpFunctionEnd",
3828 2, 0),
3829 // Test case 26: Don't fold n << 3
3830 InstructionFoldingCase<uint32_t>(
3831 Header() + "%main = OpFunction %void None %void_func\n" +
3832 "%main_lab = OpLabel\n" +
3833 "%n = OpVariable %_ptr_uint Function\n" +
3834 "%load_n = OpLoad %uint %n\n" +
3835 "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
3836 "OpReturn\n" +
3837 "OpFunctionEnd",
3838 2, 0),
3839 // Test case 27: Don't fold n >> 3
3840 InstructionFoldingCase<uint32_t>(
3841 Header() + "%main = OpFunction %void None %void_func\n" +
3842 "%main_lab = OpLabel\n" +
3843 "%n = OpVariable %_ptr_uint Function\n" +
3844 "%load_n = OpLoad %uint %n\n" +
3845 "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
3846 "OpReturn\n" +
3847 "OpFunctionEnd",
3848 2, 0),
3849 // Test case 28: Don't fold n | 3
3850 InstructionFoldingCase<uint32_t>(
3851 Header() + "%main = OpFunction %void None %void_func\n" +
3852 "%main_lab = OpLabel\n" +
3853 "%n = OpVariable %_ptr_uint Function\n" +
3854 "%load_n = OpLoad %uint %n\n" +
3855 "%2 = OpBitwiseOr %int %load_n %int_3\n" +
3856 "OpReturn\n" +
3857 "OpFunctionEnd",
3858 2, 0),
3859 // Test case 29: Don't fold n & 3
3860 InstructionFoldingCase<uint32_t>(
3861 Header() + "%main = OpFunction %void None %void_func\n" +
3862 "%main_lab = OpLabel\n" +
3863 "%n = OpVariable %_ptr_uint Function\n" +
3864 "%load_n = OpLoad %uint %n\n" +
3865 "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
3866 "OpReturn\n" +
3867 "OpFunctionEnd",
3868 2, 0),
3869 // Test case 30: Don't fold n < 3 (unsigned)
3870 InstructionFoldingCase<uint32_t>(
3871 Header() + "%main = OpFunction %void None %void_func\n" +
3872 "%main_lab = OpLabel\n" +
3873 "%n = OpVariable %_ptr_uint Function\n" +
3874 "%load_n = OpLoad %uint %n\n" +
3875 "%2 = OpULessThan %bool %load_n %uint_3\n" +
3876 "OpReturn\n" +
3877 "OpFunctionEnd",
3878 2, 0),
3879 // Test case 31: Don't fold n > 3 (unsigned)
3880 InstructionFoldingCase<uint32_t>(
3881 Header() + "%main = OpFunction %void None %void_func\n" +
3882 "%main_lab = OpLabel\n" +
3883 "%n = OpVariable %_ptr_uint Function\n" +
3884 "%load_n = OpLoad %uint %n\n" +
3885 "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
3886 "OpReturn\n" +
3887 "OpFunctionEnd",
3888 2, 0),
3889 // Test case 32: Don't fold n <= 3 (unsigned)
3890 InstructionFoldingCase<uint32_t>(
3891 Header() + "%main = OpFunction %void None %void_func\n" +
3892 "%main_lab = OpLabel\n" +
3893 "%n = OpVariable %_ptr_uint Function\n" +
3894 "%load_n = OpLoad %uint %n\n" +
3895 "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
3896 "OpReturn\n" +
3897 "OpFunctionEnd",
3898 2, 0),
3899 // Test case 33: Don't fold n >= 3 (unsigned)
3900 InstructionFoldingCase<uint32_t>(
3901 Header() + "%main = OpFunction %void None %void_func\n" +
3902 "%main_lab = OpLabel\n" +
3903 "%n = OpVariable %_ptr_uint Function\n" +
3904 "%load_n = OpLoad %uint %n\n" +
3905 "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
3906 "OpReturn\n" +
3907 "OpFunctionEnd",
3908 2, 0),
3909 // Test case 34: Don't fold n < 3 (signed)
3910 InstructionFoldingCase<uint32_t>(
3911 Header() + "%main = OpFunction %void None %void_func\n" +
3912 "%main_lab = OpLabel\n" +
3913 "%n = OpVariable %_ptr_int Function\n" +
3914 "%load_n = OpLoad %int %n\n" +
3915 "%2 = OpULessThan %bool %load_n %int_3\n" +
3916 "OpReturn\n" +
3917 "OpFunctionEnd",
3918 2, 0),
3919 // Test case 35: Don't fold n > 3 (signed)
3920 InstructionFoldingCase<uint32_t>(
3921 Header() + "%main = OpFunction %void None %void_func\n" +
3922 "%main_lab = OpLabel\n" +
3923 "%n = OpVariable %_ptr_int Function\n" +
3924 "%load_n = OpLoad %int %n\n" +
3925 "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
3926 "OpReturn\n" +
3927 "OpFunctionEnd",
3928 2, 0),
3929 // Test case 36: Don't fold n <= 3 (signed)
3930 InstructionFoldingCase<uint32_t>(
3931 Header() + "%main = OpFunction %void None %void_func\n" +
3932 "%main_lab = OpLabel\n" +
3933 "%n = OpVariable %_ptr_int Function\n" +
3934 "%load_n = OpLoad %int %n\n" +
3935 "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
3936 "OpReturn\n" +
3937 "OpFunctionEnd",
3938 2, 0),
3939 // Test case 37: Don't fold n >= 3 (signed)
3940 InstructionFoldingCase<uint32_t>(
3941 Header() + "%main = OpFunction %void None %void_func\n" +
3942 "%main_lab = OpLabel\n" +
3943 "%n = OpVariable %_ptr_int Function\n" +
3944 "%load_n = OpLoad %int %n\n" +
3945 "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
3946 "OpReturn\n" +
3947 "OpFunctionEnd",
3948 2, 0),
3949 // Test case 38: Don't fold 2 + 3 (long), bad length
3950 InstructionFoldingCase<uint32_t>(
3951 Header() + "%main = OpFunction %void None %void_func\n" +
3952 "%main_lab = OpLabel\n" +
3953 "%2 = OpIAdd %long %long_2 %long_3\n" +
3954 "OpReturn\n" +
3955 "OpFunctionEnd",
3956 2, 0),
3957 // Test case 39: Don't fold 2 + 3 (short), bad length
3958 InstructionFoldingCase<uint32_t>(
3959 Header() + "%main = OpFunction %void None %void_func\n" +
3960 "%main_lab = OpLabel\n" +
3961 "%2 = OpIAdd %short %short_2 %short_3\n" +
3962 "OpReturn\n" +
3963 "OpFunctionEnd",
3964 2, 0),
3965 // Test case 40: fold 1*n
3966 InstructionFoldingCase<uint32_t>(
3967 Header() + "%main = OpFunction %void None %void_func\n" +
3968 "%main_lab = OpLabel\n" +
3969 "%n = OpVariable %_ptr_int Function\n" +
3970 "%3 = OpLoad %int %n\n" +
3971 "%2 = OpIMul %int %int_1 %3\n" +
3972 "OpReturn\n" +
3973 "OpFunctionEnd",
3974 2, 3),
3975 // Test case 41: fold n*1
3976 InstructionFoldingCase<uint32_t>(
3977 Header() + "%main = OpFunction %void None %void_func\n" +
3978 "%main_lab = OpLabel\n" +
3979 "%n = OpVariable %_ptr_int Function\n" +
3980 "%3 = OpLoad %int %n\n" +
3981 "%2 = OpIMul %int %3 %int_1\n" +
3982 "OpReturn\n" +
3983 "OpFunctionEnd",
3984 2, 3),
3985 // Test case 42: Don't fold comparisons of 64-bit types
3986 // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
3987 InstructionFoldingCase<uint32_t>(
3988 Header() + "%main = OpFunction %void None %void_func\n" +
3989 "%main_lab = OpLabel\n" +
3990 "%2 = OpSLessThan %bool %long_0 %long_2\n" +
3991 "OpReturn\n" +
3992 "OpFunctionEnd",
3993 2, 0)
3994 ));
3995
3996 INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
3997 ::testing::Values(
3998 // Test case 0: fold Insert feeding extract
3999 InstructionFoldingCase<uint32_t>(
4000 Header() + "%main = OpFunction %void None %void_func\n" +
4001 "%main_lab = OpLabel\n" +
4002 "%n = OpVariable %_ptr_int Function\n" +
4003 "%2 = OpLoad %int %n\n" +
4004 "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
4005 "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
4006 "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
4007 "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
4008 "%7 = OpCompositeExtract %int %6 0\n" +
4009 "OpReturn\n" +
4010 "OpFunctionEnd",
4011 7, 2),
4012 // Test case 1: fold Composite construct feeding extract (position 0)
4013 InstructionFoldingCase<uint32_t>(
4014 Header() + "%main = OpFunction %void None %void_func\n" +
4015 "%main_lab = OpLabel\n" +
4016 "%n = OpVariable %_ptr_int Function\n" +
4017 "%2 = OpLoad %int %n\n" +
4018 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
4019 "%4 = OpCompositeExtract %int %3 0\n" +
4020 "OpReturn\n" +
4021 "OpFunctionEnd",
4022 4, 2),
4023 // Test case 2: fold Composite construct feeding extract (position 3)
4024 InstructionFoldingCase<uint32_t>(
4025 Header() + "%main = OpFunction %void None %void_func\n" +
4026 "%main_lab = OpLabel\n" +
4027 "%n = OpVariable %_ptr_int Function\n" +
4028 "%2 = OpLoad %int %n\n" +
4029 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
4030 "%4 = OpCompositeExtract %int %3 3\n" +
4031 "OpReturn\n" +
4032 "OpFunctionEnd",
4033 4, INT_0_ID),
4034 // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
4035 InstructionFoldingCase<uint32_t>(
4036 Header() + "%main = OpFunction %void None %void_func\n" +
4037 "%main_lab = OpLabel\n" +
4038 "%n = OpVariable %_ptr_int Function\n" +
4039 "%2 = OpLoad %int %n\n" +
4040 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4041 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4042 "%5 = OpCompositeExtract %int %4 3\n" +
4043 "OpReturn\n" +
4044 "OpFunctionEnd",
4045 5, INT_0_ID),
4046 // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
4047 InstructionFoldingCase<uint32_t>(
4048 Header() + "%main = OpFunction %void None %void_func\n" +
4049 "%main_lab = OpLabel\n" +
4050 "%n = OpVariable %_ptr_int Function\n" +
4051 "%2 = OpLoad %int %n\n" +
4052 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
4053 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4054 "%5 = OpCompositeExtract %int %4 0\n" +
4055 "OpReturn\n" +
4056 "OpFunctionEnd",
4057 5, 2),
4058 // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
4059 InstructionFoldingCase<uint32_t>(
4060 Header() + "%main = OpFunction %void None %void_func\n" +
4061 "%main_lab = OpLabel\n" +
4062 "%n = OpVariable %_ptr_int Function\n" +
4063 "%2 = OpLoad %int %n\n" +
4064 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4065 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
4066 "%5 = OpCompositeExtract %int %4 1\n" +
4067 "OpReturn\n" +
4068 "OpFunctionEnd",
4069 5, 2),
4070 // Test case 6: fold Composite construct with multiple indices.
4071 InstructionFoldingCase<uint32_t>(
4072 Header() + "%main = OpFunction %void None %void_func\n" +
4073 "%main_lab = OpLabel\n" +
4074 "%n = OpVariable %_ptr_int Function\n" +
4075 "%2 = OpLoad %int %n\n" +
4076 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
4077 "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
4078 "%5 = OpCompositeExtract %int %4 0 1\n" +
4079 "OpReturn\n" +
4080 "OpFunctionEnd",
4081 5, 2),
4082 // Test case 7: fold constant extract.
4083 InstructionFoldingCase<uint32_t>(
4084 Header() + "%main = OpFunction %void None %void_func\n" +
4085 "%main_lab = OpLabel\n" +
4086 "%2 = OpCompositeExtract %int %102 1\n" +
4087 "OpReturn\n" +
4088 "OpFunctionEnd",
4089 2, INT_7_ID),
4090 // Test case 8: constant struct has OpUndef
4091 InstructionFoldingCase<uint32_t>(
4092 Header() + "%main = OpFunction %void None %void_func\n" +
4093 "%main_lab = OpLabel\n" +
4094 "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
4095 "OpReturn\n" +
4096 "OpFunctionEnd",
4097 2, 0),
4098 // Test case 9: Extracting a member of element inserted via Insert
4099 InstructionFoldingCase<uint32_t>(
4100 Header() + "%main = OpFunction %void None %void_func\n" +
4101 "%main_lab = OpLabel\n" +
4102 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4103 "%2 = OpLoad %struct_v2int_int_int %n\n" +
4104 "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
4105 "%4 = OpCompositeExtract %int %3 0 1\n" +
4106 "OpReturn\n" +
4107 "OpFunctionEnd",
4108 4, 103),
4109 // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
4110 InstructionFoldingCase<uint32_t>(
4111 Header() + "%main = OpFunction %void None %void_func\n" +
4112 "%main_lab = OpLabel\n" +
4113 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
4114 "%2 = OpLoad %struct_v2int_int_int %n\n" +
4115 "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
4116 "%4 = OpCompositeExtract %v2int %3 0\n" +
4117 "OpReturn\n" +
4118 "OpFunctionEnd",
4119 4, 0),
4120 // Test case 11: Extracting from result of vector shuffle (first input)
4121 InstructionFoldingCase<uint32_t>(
4122 Header() + "%main = OpFunction %void None %void_func\n" +
4123 "%main_lab = OpLabel\n" +
4124 "%n = OpVariable %_ptr_v2int Function\n" +
4125 "%2 = OpLoad %v2int %n\n" +
4126 "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
4127 "%4 = OpCompositeExtract %int %3 1\n" +
4128 "OpReturn\n" +
4129 "OpFunctionEnd",
4130 4, INT_7_ID),
4131 // Test case 12: Extracting from result of vector shuffle (second input)
4132 InstructionFoldingCase<uint32_t>(
4133 Header() + "%main = OpFunction %void None %void_func\n" +
4134 "%main_lab = OpLabel\n" +
4135 "%n = OpVariable %_ptr_v2int Function\n" +
4136 "%2 = OpLoad %v2int %n\n" +
4137 "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
4138 "%4 = OpCompositeExtract %int %3 0\n" +
4139 "OpReturn\n" +
4140 "OpFunctionEnd",
4141 4, INT_7_ID),
4142 // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608
4143 // Out of bounds access. Do not fold.
4144 InstructionFoldingCase<uint32_t>(
4145 Header() + "%main = OpFunction %void None %void_func\n" +
4146 "%main_lab = OpLabel\n" +
4147 "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" +
4148 "%3 = OpCompositeExtract %float %2 4\n" +
4149 "OpReturn\n" +
4150 "OpFunctionEnd",
4151 3, 0),
4152 // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631
4153 // Extract the component right after the vector constituent.
4154 InstructionFoldingCase<uint32_t>(
4155 Header() + "%main = OpFunction %void None %void_func\n" +
4156 "%main_lab = OpLabel\n" +
4157 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4158 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4159 "%4 = OpCompositeExtract %int %3 2\n" +
4160 "OpReturn\n" +
4161 "OpFunctionEnd",
4162 4, INT_0_ID),
4163 // Test case 15:
4164 // Don't fold extract fed by construct with vector result if the index is
4165 // past the last element.
4166 InstructionFoldingCase<uint32_t>(
4167 Header() + "%main = OpFunction %void None %void_func\n" +
4168 "%main_lab = OpLabel\n" +
4169 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
4170 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
4171 "%4 = OpCompositeExtract %int %3 4\n" +
4172 "OpReturn\n" +
4173 "OpFunctionEnd",
4174 4, 0)
4175 ));
4176
4177 INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
4178 ::testing::Values(
4179 // Test case 0: fold Extracts feeding construct
4180 InstructionFoldingCase<uint32_t>(
4181 Header() + "%main = OpFunction %void None %void_func\n" +
4182 "%main_lab = OpLabel\n" +
4183 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4184 "%3 = OpCompositeExtract %int %2 0\n" +
4185 "%4 = OpCompositeExtract %int %2 1\n" +
4186 "%5 = OpCompositeExtract %int %2 2\n" +
4187 "%6 = OpCompositeExtract %int %2 3\n" +
4188 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4189 "OpReturn\n" +
4190 "OpFunctionEnd",
4191 7, 2),
4192 // Test case 1: Don't fold Extracts feeding construct (Different source)
4193 InstructionFoldingCase<uint32_t>(
4194 Header() + "%main = OpFunction %void None %void_func\n" +
4195 "%main_lab = OpLabel\n" +
4196 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4197 "%3 = OpCompositeExtract %int %2 0\n" +
4198 "%4 = OpCompositeExtract %int %2 1\n" +
4199 "%5 = OpCompositeExtract %int %2 2\n" +
4200 "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
4201 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4202 "OpReturn\n" +
4203 "OpFunctionEnd",
4204 7, 0),
4205 // Test case 2: Don't fold Extracts feeding construct (bad indices)
4206 InstructionFoldingCase<uint32_t>(
4207 Header() + "%main = OpFunction %void None %void_func\n" +
4208 "%main_lab = OpLabel\n" +
4209 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
4210 "%3 = OpCompositeExtract %int %2 0\n" +
4211 "%4 = OpCompositeExtract %int %2 0\n" +
4212 "%5 = OpCompositeExtract %int %2 2\n" +
4213 "%6 = OpCompositeExtract %int %2 3\n" +
4214 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
4215 "OpReturn\n" +
4216 "OpFunctionEnd",
4217 7, 0),
4218 // Test case 3: Don't fold Extracts feeding construct (different type)
4219 InstructionFoldingCase<uint32_t>(
4220 Header() + "%main = OpFunction %void None %void_func\n" +
4221 "%main_lab = OpLabel\n" +
4222 "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
4223 "%3 = OpCompositeExtract %v2int %2 0\n" +
4224 "%4 = OpCompositeExtract %int %2 1\n" +
4225 "%5 = OpCompositeExtract %int %2 2\n" +
4226 "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
4227 "OpReturn\n" +
4228 "OpFunctionEnd",
4229 7, 0),
4230 // Test case 4: Fold construct with constants to constant.
4231 InstructionFoldingCase<uint32_t>(
4232 Header() + "%main = OpFunction %void None %void_func\n" +
4233 "%main_lab = OpLabel\n" +
4234 "%2 = OpCompositeConstruct %v2int %103 %103\n" +
4235 "OpReturn\n" +
4236 "OpFunctionEnd",
4237 2, VEC2_0_ID),
4238 // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct
4239 // for an empty struct, and we reached the id limit.
4240 InstructionFoldingCase<uint32_t>(
4241 Header() + "%empty_struct = OpTypeStruct\n" +
4242 "%main = OpFunction %void None %void_func\n" +
4243 "%main_lab = OpLabel\n" +
4244 "%4194303 = OpCompositeConstruct %empty_struct\n" +
4245 "OpReturn\n" +
4246 "OpFunctionEnd",
4247 4194303, 0)
4248 ));
4249
4250 INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
4251 ::testing::Values(
4252 // Test case 0: Fold phi with the same values for all edges.
4253 InstructionFoldingCase<uint32_t>(
4254 Header() + "%main = OpFunction %void None %void_func\n" +
4255 "%main_lab = OpLabel\n" +
4256 " OpBranchConditional %true %l1 %l2\n" +
4257 "%l1 = OpLabel\n" +
4258 " OpBranch %merge_lab\n" +
4259 "%l2 = OpLabel\n" +
4260 " OpBranch %merge_lab\n" +
4261 "%merge_lab = OpLabel\n" +
4262 "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
4263 "OpReturn\n" +
4264 "OpFunctionEnd",
4265 2, INT_0_ID),
4266 // Test case 1: Fold phi in pass through loop.
4267 InstructionFoldingCase<uint32_t>(
4268 Header() + "%main = OpFunction %void None %void_func\n" +
4269 "%main_lab = OpLabel\n" +
4270 " OpBranch %l1\n" +
4271 "%l1 = OpLabel\n" +
4272 "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
4273 " OpBranchConditional %true %l1 %merge_lab\n" +
4274 "%merge_lab = OpLabel\n" +
4275 "OpReturn\n" +
4276 "OpFunctionEnd",
4277 2, INT_0_ID),
4278 // Test case 2: Don't Fold phi because of different values.
4279 InstructionFoldingCase<uint32_t>(
4280 Header() + "%main = OpFunction %void None %void_func\n" +
4281 "%main_lab = OpLabel\n" +
4282 " OpBranch %l1\n" +
4283 "%l1 = OpLabel\n" +
4284 "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
4285 " OpBranchConditional %true %l1 %merge_lab\n" +
4286 "%merge_lab = OpLabel\n" +
4287 "OpReturn\n" +
4288 "OpFunctionEnd",
4289 2, 0)
4290 ));
4291
4292 INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
4293 ::testing::Values(
4294 // Test case 0: Don't fold n + 1.0
4295 InstructionFoldingCase<uint32_t>(
4296 Header() + "%main = OpFunction %void None %void_func\n" +
4297 "%main_lab = OpLabel\n" +
4298 "%n = OpVariable %_ptr_float Function\n" +
4299 "%3 = OpLoad %float %n\n" +
4300 "%2 = OpFAdd %float %3 %float_2\n" +
4301 "OpReturn\n" +
4302 "OpFunctionEnd",
4303 2, 0),
4304 // Test case 1: Don't fold n - 1.0
4305 InstructionFoldingCase<uint32_t>(
4306 Header() + "%main = OpFunction %void None %void_func\n" +
4307 "%main_lab = OpLabel\n" +
4308 "%n = OpVariable %_ptr_float Function\n" +
4309 "%3 = OpLoad %float %n\n" +
4310 "%2 = OpFSub %float %3 %float_2\n" +
4311 "OpReturn\n" +
4312 "OpFunctionEnd",
4313 2, 0),
4314 // Test case 2: Don't fold n * 2.0
4315 InstructionFoldingCase<uint32_t>(
4316 Header() + "%main = OpFunction %void None %void_func\n" +
4317 "%main_lab = OpLabel\n" +
4318 "%n = OpVariable %_ptr_float Function\n" +
4319 "%3 = OpLoad %float %n\n" +
4320 "%2 = OpFMul %float %3 %float_2\n" +
4321 "OpReturn\n" +
4322 "OpFunctionEnd",
4323 2, 0),
4324 // Test case 3: Fold n + 0.0
4325 InstructionFoldingCase<uint32_t>(
4326 Header() + "%main = OpFunction %void None %void_func\n" +
4327 "%main_lab = OpLabel\n" +
4328 "%n = OpVariable %_ptr_float Function\n" +
4329 "%3 = OpLoad %float %n\n" +
4330 "%2 = OpFAdd %float %3 %float_0\n" +
4331 "OpReturn\n" +
4332 "OpFunctionEnd",
4333 2, 3),
4334 // Test case 4: Fold 0.0 + n
4335 InstructionFoldingCase<uint32_t>(
4336 Header() + "%main = OpFunction %void None %void_func\n" +
4337 "%main_lab = OpLabel\n" +
4338 "%n = OpVariable %_ptr_float Function\n" +
4339 "%3 = OpLoad %float %n\n" +
4340 "%2 = OpFAdd %float %float_0 %3\n" +
4341 "OpReturn\n" +
4342 "OpFunctionEnd",
4343 2, 3),
4344 // Test case 5: Fold n - 0.0
4345 InstructionFoldingCase<uint32_t>(
4346 Header() + "%main = OpFunction %void None %void_func\n" +
4347 "%main_lab = OpLabel\n" +
4348 "%n = OpVariable %_ptr_float Function\n" +
4349 "%3 = OpLoad %float %n\n" +
4350 "%2 = OpFSub %float %3 %float_0\n" +
4351 "OpReturn\n" +
4352 "OpFunctionEnd",
4353 2, 3),
4354 // Test case 6: Fold n * 1.0
4355 InstructionFoldingCase<uint32_t>(
4356 Header() + "%main = OpFunction %void None %void_func\n" +
4357 "%main_lab = OpLabel\n" +
4358 "%n = OpVariable %_ptr_float Function\n" +
4359 "%3 = OpLoad %float %n\n" +
4360 "%2 = OpFMul %float %3 %float_1\n" +
4361 "OpReturn\n" +
4362 "OpFunctionEnd",
4363 2, 3),
4364 // Test case 7: Fold 1.0 * n
4365 InstructionFoldingCase<uint32_t>(
4366 Header() + "%main = OpFunction %void None %void_func\n" +
4367 "%main_lab = OpLabel\n" +
4368 "%n = OpVariable %_ptr_float Function\n" +
4369 "%3 = OpLoad %float %n\n" +
4370 "%2 = OpFMul %float %float_1 %3\n" +
4371 "OpReturn\n" +
4372 "OpFunctionEnd",
4373 2, 3),
4374 // Test case 8: Fold n / 1.0
4375 InstructionFoldingCase<uint32_t>(
4376 Header() + "%main = OpFunction %void None %void_func\n" +
4377 "%main_lab = OpLabel\n" +
4378 "%n = OpVariable %_ptr_float Function\n" +
4379 "%3 = OpLoad %float %n\n" +
4380 "%2 = OpFDiv %float %3 %float_1\n" +
4381 "OpReturn\n" +
4382 "OpFunctionEnd",
4383 2, 3),
4384 // Test case 9: Fold n * 0.0
4385 InstructionFoldingCase<uint32_t>(
4386 Header() + "%main = OpFunction %void None %void_func\n" +
4387 "%main_lab = OpLabel\n" +
4388 "%n = OpVariable %_ptr_float Function\n" +
4389 "%3 = OpLoad %float %n\n" +
4390 "%2 = OpFMul %float %3 %104\n" +
4391 "OpReturn\n" +
4392 "OpFunctionEnd",
4393 2, FLOAT_0_ID),
4394 // Test case 10: Fold 0.0 * n
4395 InstructionFoldingCase<uint32_t>(
4396 Header() + "%main = OpFunction %void None %void_func\n" +
4397 "%main_lab = OpLabel\n" +
4398 "%n = OpVariable %_ptr_float Function\n" +
4399 "%3 = OpLoad %float %n\n" +
4400 "%2 = OpFMul %float %104 %3\n" +
4401 "OpReturn\n" +
4402 "OpFunctionEnd",
4403 2, FLOAT_0_ID),
4404 // Test case 11: Fold 0.0 / n
4405 InstructionFoldingCase<uint32_t>(
4406 Header() + "%main = OpFunction %void None %void_func\n" +
4407 "%main_lab = OpLabel\n" +
4408 "%n = OpVariable %_ptr_float Function\n" +
4409 "%3 = OpLoad %float %n\n" +
4410 "%2 = OpFDiv %float %104 %3\n" +
4411 "OpReturn\n" +
4412 "OpFunctionEnd",
4413 2, FLOAT_0_ID),
4414 // Test case 12: Don't fold mix(a, b, 2.0)
4415 InstructionFoldingCase<uint32_t>(
4416 Header() + "%main = OpFunction %void None %void_func\n" +
4417 "%main_lab = OpLabel\n" +
4418 "%a = OpVariable %_ptr_float Function\n" +
4419 "%b = OpVariable %_ptr_float Function\n" +
4420 "%3 = OpLoad %float %a\n" +
4421 "%4 = OpLoad %float %b\n" +
4422 "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
4423 "OpReturn\n" +
4424 "OpFunctionEnd",
4425 2, 0),
4426 // Test case 13: Fold mix(a, b, 0.0)
4427 InstructionFoldingCase<uint32_t>(
4428 Header() + "%main = OpFunction %void None %void_func\n" +
4429 "%main_lab = OpLabel\n" +
4430 "%a = OpVariable %_ptr_float Function\n" +
4431 "%b = OpVariable %_ptr_float Function\n" +
4432 "%3 = OpLoad %float %a\n" +
4433 "%4 = OpLoad %float %b\n" +
4434 "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
4435 "OpReturn\n" +
4436 "OpFunctionEnd",
4437 2, 3),
4438 // Test case 14: Fold mix(a, b, 1.0)
4439 InstructionFoldingCase<uint32_t>(
4440 Header() + "%main = OpFunction %void None %void_func\n" +
4441 "%main_lab = OpLabel\n" +
4442 "%a = OpVariable %_ptr_float Function\n" +
4443 "%b = OpVariable %_ptr_float Function\n" +
4444 "%3 = OpLoad %float %a\n" +
4445 "%4 = OpLoad %float %b\n" +
4446 "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
4447 "OpReturn\n" +
4448 "OpFunctionEnd",
4449 2, 4),
4450 // Test case 15: Fold vector fadd with null
4451 InstructionFoldingCase<uint32_t>(
4452 Header() + "%main = OpFunction %void None %void_func\n" +
4453 "%main_lab = OpLabel\n" +
4454 "%a = OpVariable %_ptr_v2float Function\n" +
4455 "%2 = OpLoad %v2float %a\n" +
4456 "%3 = OpFAdd %v2float %2 %v2float_null\n" +
4457 "OpReturn\n" +
4458 "OpFunctionEnd",
4459 3, 2),
4460 // Test case 16: Fold vector fadd with null
4461 InstructionFoldingCase<uint32_t>(
4462 Header() + "%main = OpFunction %void None %void_func\n" +
4463 "%main_lab = OpLabel\n" +
4464 "%a = OpVariable %_ptr_v2float Function\n" +
4465 "%2 = OpLoad %v2float %a\n" +
4466 "%3 = OpFAdd %v2float %v2float_null %2\n" +
4467 "OpReturn\n" +
4468 "OpFunctionEnd",
4469 3, 2),
4470 // Test case 17: Fold vector fsub with null
4471 InstructionFoldingCase<uint32_t>(
4472 Header() + "%main = OpFunction %void None %void_func\n" +
4473 "%main_lab = OpLabel\n" +
4474 "%a = OpVariable %_ptr_v2float Function\n" +
4475 "%2 = OpLoad %v2float %a\n" +
4476 "%3 = OpFSub %v2float %2 %v2float_null\n" +
4477 "OpReturn\n" +
4478 "OpFunctionEnd",
4479 3, 2),
4480 // Test case 18: Fold 0.0(half) * n
4481 InstructionFoldingCase<uint32_t>(
4482 Header() + "%main = OpFunction %void None %void_func\n" +
4483 "%main_lab = OpLabel\n" +
4484 "%n = OpVariable %_ptr_half Function\n" +
4485 "%3 = OpLoad %half %n\n" +
4486 "%2 = OpFMul %half %108 %3\n" +
4487 "OpReturn\n" +
4488 "OpFunctionEnd",
4489 2, HALF_0_ID),
4490 // Test case 19: Don't fold 1.0(half) * n
4491 InstructionFoldingCase<uint32_t>(
4492 Header() + "%main = OpFunction %void None %void_func\n" +
4493 "%main_lab = OpLabel\n" +
4494 "%n = OpVariable %_ptr_half Function\n" +
4495 "%3 = OpLoad %half %n\n" +
4496 "%2 = OpFMul %half %half_1 %3\n" +
4497 "OpReturn\n" +
4498 "OpFunctionEnd",
4499 2, 0),
4500 // Test case 20: Don't fold 1.0 * 1.0 (half)
4501 InstructionFoldingCase<uint32_t>(
4502 Header() + "%main = OpFunction %void None %void_func\n" +
4503 "%main_lab = OpLabel\n" +
4504 "%2 = OpFMul %half %half_1 %half_1\n" +
4505 "OpReturn\n" +
4506 "OpFunctionEnd",
4507 2, 0),
4508 // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half)
4509 InstructionFoldingCase<uint32_t>(
4510 Header() + "%main = OpFunction %void None %void_func\n" +
4511 "%main_lab = OpLabel\n" +
4512 "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" +
4513 "OpReturn\n" +
4514 "OpFunctionEnd",
4515 2, 0),
4516 // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half)
4517 InstructionFoldingCase<uint32_t>(
4518 Header() + "%main = OpFunction %void None %void_func\n" +
4519 "%main_lab = OpLabel\n" +
4520 "%2 = OpDot %half %half_0_1 %half_0_1\n" +
4521 "OpReturn\n" +
4522 "OpFunctionEnd",
4523 2, 0),
4524 // Test case 23: Don't fold 1.0(half) / 2.0(half)
4525 // We do not have to code to emulate 16-bit float operations. Just make sure we do not crash.
4526 InstructionFoldingCase<uint32_t>(
4527 Header() + "%main = OpFunction %void None %void_func\n" +
4528 "%main_lab = OpLabel\n" +
4529 "%n = OpVariable %_ptr_half Function\n" +
4530 "%3 = OpLoad %half %n\n" +
4531 "%2 = OpFDiv %half %half_1 %half_2\n" +
4532 "OpReturn\n" +
4533 "OpFunctionEnd",
4534 2, 0)
4535 ));
4536
4537 INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
4538 ::testing::Values(
4539 // Test case 0: Don't fold n + 1.0
4540 InstructionFoldingCase<uint32_t>(
4541 Header() + "%main = OpFunction %void None %void_func\n" +
4542 "%main_lab = OpLabel\n" +
4543 "%n = OpVariable %_ptr_double Function\n" +
4544 "%3 = OpLoad %double %n\n" +
4545 "%2 = OpFAdd %double %3 %double_2\n" +
4546 "OpReturn\n" +
4547 "OpFunctionEnd",
4548 2, 0),
4549 // Test case 1: Don't fold n - 1.0
4550 InstructionFoldingCase<uint32_t>(
4551 Header() + "%main = OpFunction %void None %void_func\n" +
4552 "%main_lab = OpLabel\n" +
4553 "%n = OpVariable %_ptr_double Function\n" +
4554 "%3 = OpLoad %double %n\n" +
4555 "%2 = OpFSub %double %3 %double_2\n" +
4556 "OpReturn\n" +
4557 "OpFunctionEnd",
4558 2, 0),
4559 // Test case 2: Don't fold n * 2.0
4560 InstructionFoldingCase<uint32_t>(
4561 Header() + "%main = OpFunction %void None %void_func\n" +
4562 "%main_lab = OpLabel\n" +
4563 "%n = OpVariable %_ptr_double Function\n" +
4564 "%3 = OpLoad %double %n\n" +
4565 "%2 = OpFMul %double %3 %double_2\n" +
4566 "OpReturn\n" +
4567 "OpFunctionEnd",
4568 2, 0),
4569 // Test case 3: Fold n + 0.0
4570 InstructionFoldingCase<uint32_t>(
4571 Header() + "%main = OpFunction %void None %void_func\n" +
4572 "%main_lab = OpLabel\n" +
4573 "%n = OpVariable %_ptr_double Function\n" +
4574 "%3 = OpLoad %double %n\n" +
4575 "%2 = OpFAdd %double %3 %double_0\n" +
4576 "OpReturn\n" +
4577 "OpFunctionEnd",
4578 2, 3),
4579 // Test case 4: Fold 0.0 + n
4580 InstructionFoldingCase<uint32_t>(
4581 Header() + "%main = OpFunction %void None %void_func\n" +
4582 "%main_lab = OpLabel\n" +
4583 "%n = OpVariable %_ptr_double Function\n" +
4584 "%3 = OpLoad %double %n\n" +
4585 "%2 = OpFAdd %double %double_0 %3\n" +
4586 "OpReturn\n" +
4587 "OpFunctionEnd",
4588 2, 3),
4589 // Test case 5: Fold n - 0.0
4590 InstructionFoldingCase<uint32_t>(
4591 Header() + "%main = OpFunction %void None %void_func\n" +
4592 "%main_lab = OpLabel\n" +
4593 "%n = OpVariable %_ptr_double Function\n" +
4594 "%3 = OpLoad %double %n\n" +
4595 "%2 = OpFSub %double %3 %double_0\n" +
4596 "OpReturn\n" +
4597 "OpFunctionEnd",
4598 2, 3),
4599 // Test case 6: Fold n * 1.0
4600 InstructionFoldingCase<uint32_t>(
4601 Header() + "%main = OpFunction %void None %void_func\n" +
4602 "%main_lab = OpLabel\n" +
4603 "%n = OpVariable %_ptr_double Function\n" +
4604 "%3 = OpLoad %double %n\n" +
4605 "%2 = OpFMul %double %3 %double_1\n" +
4606 "OpReturn\n" +
4607 "OpFunctionEnd",
4608 2, 3),
4609 // Test case 7: Fold 1.0 * n
4610 InstructionFoldingCase<uint32_t>(
4611 Header() + "%main = OpFunction %void None %void_func\n" +
4612 "%main_lab = OpLabel\n" +
4613 "%n = OpVariable %_ptr_double Function\n" +
4614 "%3 = OpLoad %double %n\n" +
4615 "%2 = OpFMul %double %double_1 %3\n" +
4616 "OpReturn\n" +
4617 "OpFunctionEnd",
4618 2, 3),
4619 // Test case 8: Fold n / 1.0
4620 InstructionFoldingCase<uint32_t>(
4621 Header() + "%main = OpFunction %void None %void_func\n" +
4622 "%main_lab = OpLabel\n" +
4623 "%n = OpVariable %_ptr_double Function\n" +
4624 "%3 = OpLoad %double %n\n" +
4625 "%2 = OpFDiv %double %3 %double_1\n" +
4626 "OpReturn\n" +
4627 "OpFunctionEnd",
4628 2, 3),
4629 // Test case 9: Fold n * 0.0
4630 InstructionFoldingCase<uint32_t>(
4631 Header() + "%main = OpFunction %void None %void_func\n" +
4632 "%main_lab = OpLabel\n" +
4633 "%n = OpVariable %_ptr_double Function\n" +
4634 "%3 = OpLoad %double %n\n" +
4635 "%2 = OpFMul %double %3 %105\n" +
4636 "OpReturn\n" +
4637 "OpFunctionEnd",
4638 2, DOUBLE_0_ID),
4639 // Test case 10: Fold 0.0 * n
4640 InstructionFoldingCase<uint32_t>(
4641 Header() + "%main = OpFunction %void None %void_func\n" +
4642 "%main_lab = OpLabel\n" +
4643 "%n = OpVariable %_ptr_double Function\n" +
4644 "%3 = OpLoad %double %n\n" +
4645 "%2 = OpFMul %double %105 %3\n" +
4646 "OpReturn\n" +
4647 "OpFunctionEnd",
4648 2, DOUBLE_0_ID),
4649 // Test case 11: Fold 0.0 / n
4650 InstructionFoldingCase<uint32_t>(
4651 Header() + "%main = OpFunction %void None %void_func\n" +
4652 "%main_lab = OpLabel\n" +
4653 "%n = OpVariable %_ptr_double Function\n" +
4654 "%3 = OpLoad %double %n\n" +
4655 "%2 = OpFDiv %double %105 %3\n" +
4656 "OpReturn\n" +
4657 "OpFunctionEnd",
4658 2, DOUBLE_0_ID),
4659 // Test case 12: Don't fold mix(a, b, 2.0)
4660 InstructionFoldingCase<uint32_t>(
4661 Header() + "%main = OpFunction %void None %void_func\n" +
4662 "%main_lab = OpLabel\n" +
4663 "%a = OpVariable %_ptr_double Function\n" +
4664 "%b = OpVariable %_ptr_double Function\n" +
4665 "%3 = OpLoad %double %a\n" +
4666 "%4 = OpLoad %double %b\n" +
4667 "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
4668 "OpReturn\n" +
4669 "OpFunctionEnd",
4670 2, 0),
4671 // Test case 13: Fold mix(a, b, 0.0)
4672 InstructionFoldingCase<uint32_t>(
4673 Header() + "%main = OpFunction %void None %void_func\n" +
4674 "%main_lab = OpLabel\n" +
4675 "%a = OpVariable %_ptr_double Function\n" +
4676 "%b = OpVariable %_ptr_double Function\n" +
4677 "%3 = OpLoad %double %a\n" +
4678 "%4 = OpLoad %double %b\n" +
4679 "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
4680 "OpReturn\n" +
4681 "OpFunctionEnd",
4682 2, 3),
4683 // Test case 14: Fold mix(a, b, 1.0)
4684 InstructionFoldingCase<uint32_t>(
4685 Header() + "%main = OpFunction %void None %void_func\n" +
4686 "%main_lab = OpLabel\n" +
4687 "%a = OpVariable %_ptr_double Function\n" +
4688 "%b = OpVariable %_ptr_double Function\n" +
4689 "%3 = OpLoad %double %a\n" +
4690 "%4 = OpLoad %double %b\n" +
4691 "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
4692 "OpReturn\n" +
4693 "OpFunctionEnd",
4694 2, 4)
4695 ));
4696
4697 INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4698 ::testing::Values(
4699 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4700 InstructionFoldingCase<uint32_t>(
4701 Header() + "%main = OpFunction %void None %void_func\n" +
4702 "%main_lab = OpLabel\n" +
4703 "%n = OpVariable %_ptr_v4float Function\n" +
4704 "%3 = OpLoad %v4float %n\n" +
4705 "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
4706 "OpReturn\n" +
4707 "OpFunctionEnd",
4708 2, 0),
4709 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4710 InstructionFoldingCase<uint32_t>(
4711 Header() + "%main = OpFunction %void None %void_func\n" +
4712 "%main_lab = OpLabel\n" +
4713 "%n = OpVariable %_ptr_v4float Function\n" +
4714 "%3 = OpLoad %v4float %n\n" +
4715 "%2 = OpFMul %v4float %3 %106\n" +
4716 "OpReturn\n" +
4717 "OpFunctionEnd",
4718 2, VEC4_0_ID),
4719 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4720 InstructionFoldingCase<uint32_t>(
4721 Header() + "%main = OpFunction %void None %void_func\n" +
4722 "%main_lab = OpLabel\n" +
4723 "%n = OpVariable %_ptr_v4float Function\n" +
4724 "%3 = OpLoad %v4float %n\n" +
4725 "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
4726 "OpReturn\n" +
4727 "OpFunctionEnd",
4728 2, 3)
4729 ));
4730
4731 INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4732 ::testing::Values(
4733 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4734 InstructionFoldingCase<uint32_t>(
4735 Header() + "%main = OpFunction %void None %void_func\n" +
4736 "%main_lab = OpLabel\n" +
4737 "%n = OpVariable %_ptr_v4double Function\n" +
4738 "%3 = OpLoad %v4double %n\n" +
4739 "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
4740 "OpReturn\n" +
4741 "OpFunctionEnd",
4742 2, 0),
4743 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4744 InstructionFoldingCase<uint32_t>(
4745 Header() + "%main = OpFunction %void None %void_func\n" +
4746 "%main_lab = OpLabel\n" +
4747 "%n = OpVariable %_ptr_v4double Function\n" +
4748 "%3 = OpLoad %v4double %n\n" +
4749 "%2 = OpFMul %v4double %3 %106\n" +
4750 "OpReturn\n" +
4751 "OpFunctionEnd",
4752 2, DVEC4_0_ID),
4753 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4754 InstructionFoldingCase<uint32_t>(
4755 Header() + "%main = OpFunction %void None %void_func\n" +
4756 "%main_lab = OpLabel\n" +
4757 "%n = OpVariable %_ptr_v4double Function\n" +
4758 "%3 = OpLoad %v4double %n\n" +
4759 "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
4760 "OpReturn\n" +
4761 "OpFunctionEnd",
4762 2, 3)
4763 ));
4764
4765 INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
4766 ::testing::Values(
4767 // Test case 0: Don't fold n + 1
4768 InstructionFoldingCase<uint32_t>(
4769 Header() + "%main = OpFunction %void None %void_func\n" +
4770 "%main_lab = OpLabel\n" +
4771 "%n = OpVariable %_ptr_uint Function\n" +
4772 "%3 = OpLoad %uint %n\n" +
4773 "%2 = OpIAdd %uint %3 %uint_1\n" +
4774 "OpReturn\n" +
4775 "OpFunctionEnd",
4776 2, 0),
4777 // Test case 1: Don't fold 1 + n
4778 InstructionFoldingCase<uint32_t>(
4779 Header() + "%main = OpFunction %void None %void_func\n" +
4780 "%main_lab = OpLabel\n" +
4781 "%n = OpVariable %_ptr_uint Function\n" +
4782 "%3 = OpLoad %uint %n\n" +
4783 "%2 = OpIAdd %uint %uint_1 %3\n" +
4784 "OpReturn\n" +
4785 "OpFunctionEnd",
4786 2, 0),
4787 // Test case 2: Fold n + 0
4788 InstructionFoldingCase<uint32_t>(
4789 Header() + "%main = OpFunction %void None %void_func\n" +
4790 "%main_lab = OpLabel\n" +
4791 "%n = OpVariable %_ptr_uint Function\n" +
4792 "%3 = OpLoad %uint %n\n" +
4793 "%2 = OpIAdd %uint %3 %uint_0\n" +
4794 "OpReturn\n" +
4795 "OpFunctionEnd",
4796 2, 3),
4797 // Test case 3: Fold 0 + n
4798 InstructionFoldingCase<uint32_t>(
4799 Header() + "%main = OpFunction %void None %void_func\n" +
4800 "%main_lab = OpLabel\n" +
4801 "%n = OpVariable %_ptr_uint Function\n" +
4802 "%3 = OpLoad %uint %n\n" +
4803 "%2 = OpIAdd %uint %uint_0 %3\n" +
4804 "OpReturn\n" +
4805 "OpFunctionEnd",
4806 2, 3),
4807 // Test case 4: Don't fold n + (1,0)
4808 InstructionFoldingCase<uint32_t>(
4809 Header() + "%main = OpFunction %void None %void_func\n" +
4810 "%main_lab = OpLabel\n" +
4811 "%n = OpVariable %_ptr_v2int Function\n" +
4812 "%3 = OpLoad %v2int %n\n" +
4813 "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
4814 "OpReturn\n" +
4815 "OpFunctionEnd",
4816 2, 0),
4817 // Test case 5: Don't fold (1,0) + n
4818 InstructionFoldingCase<uint32_t>(
4819 Header() + "%main = OpFunction %void None %void_func\n" +
4820 "%main_lab = OpLabel\n" +
4821 "%n = OpVariable %_ptr_v2int Function\n" +
4822 "%3 = OpLoad %v2int %n\n" +
4823 "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
4824 "OpReturn\n" +
4825 "OpFunctionEnd",
4826 2, 0),
4827 // Test case 6: Fold n + (0,0)
4828 InstructionFoldingCase<uint32_t>(
4829 Header() + "%main = OpFunction %void None %void_func\n" +
4830 "%main_lab = OpLabel\n" +
4831 "%n = OpVariable %_ptr_v2int Function\n" +
4832 "%3 = OpLoad %v2int %n\n" +
4833 "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
4834 "OpReturn\n" +
4835 "OpFunctionEnd",
4836 2, 3),
4837 // Test case 7: Fold (0,0) + n
4838 InstructionFoldingCase<uint32_t>(
4839 Header() + "%main = OpFunction %void None %void_func\n" +
4840 "%main_lab = OpLabel\n" +
4841 "%n = OpVariable %_ptr_v2int Function\n" +
4842 "%3 = OpLoad %v2int %n\n" +
4843 "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
4844 "OpReturn\n" +
4845 "OpFunctionEnd",
4846 2, 3)
4847 ));
4848
4849 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
4850 ::testing::Values(
4851 // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
4852 InstructionFoldingCase<uint32_t>(
4853 Header() + "%main = OpFunction %void None %void_func\n" +
4854 "%main_lab = OpLabel\n" +
4855 "%n = OpVariable %_ptr_float Function\n" +
4856 "%ld = OpLoad %float %n\n" +
4857 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4858 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4859 "OpReturn\n" +
4860 "OpFunctionEnd",
4861 2, 0),
4862 // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
4863 InstructionFoldingCase<uint32_t>(
4864 Header() + "%main = OpFunction %void None %void_func\n" +
4865 "%main_lab = OpLabel\n" +
4866 "%n = OpVariable %_ptr_float Function\n" +
4867 "%ld = OpLoad %float %n\n" +
4868 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4869 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4870 "OpReturn\n" +
4871 "OpFunctionEnd",
4872 2, 0),
4873 // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
4874 InstructionFoldingCase<uint32_t>(
4875 Header() + "%main = OpFunction %void None %void_func\n" +
4876 "%main_lab = OpLabel\n" +
4877 "%n = OpVariable %_ptr_float Function\n" +
4878 "%ld = OpLoad %float %n\n" +
4879 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4880 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
4881 "OpReturn\n" +
4882 "OpFunctionEnd",
4883 2, 0),
4884 // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
4885 InstructionFoldingCase<uint32_t>(
4886 Header() + "%main = OpFunction %void None %void_func\n" +
4887 "%main_lab = OpLabel\n" +
4888 "%n = OpVariable %_ptr_float Function\n" +
4889 "%ld = OpLoad %float %n\n" +
4890 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4891 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
4892 "OpReturn\n" +
4893 "OpFunctionEnd",
4894 2, 0),
4895 // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
4896 InstructionFoldingCase<uint32_t>(
4897 Header() + "%main = OpFunction %void None %void_func\n" +
4898 "%main_lab = OpLabel\n" +
4899 "%n = OpVariable %_ptr_float Function\n" +
4900 "%ld = OpLoad %float %n\n" +
4901 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4902 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4903 "OpReturn\n" +
4904 "OpFunctionEnd",
4905 2, 0),
4906 // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
4907 InstructionFoldingCase<uint32_t>(
4908 Header() + "%main = OpFunction %void None %void_func\n" +
4909 "%main_lab = OpLabel\n" +
4910 "%n = OpVariable %_ptr_float Function\n" +
4911 "%ld = OpLoad %float %n\n" +
4912 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4913 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4914 "OpReturn\n" +
4915 "OpFunctionEnd",
4916 2, 0),
4917 // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
4918 InstructionFoldingCase<uint32_t>(
4919 Header() + "%main = OpFunction %void None %void_func\n" +
4920 "%main_lab = OpLabel\n" +
4921 "%n = OpVariable %_ptr_float Function\n" +
4922 "%ld = OpLoad %float %n\n" +
4923 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4924 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
4925 "OpReturn\n" +
4926 "OpFunctionEnd",
4927 2, 0),
4928 // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
4929 InstructionFoldingCase<uint32_t>(
4930 Header() + "%main = OpFunction %void None %void_func\n" +
4931 "%main_lab = OpLabel\n" +
4932 "%n = OpVariable %_ptr_float Function\n" +
4933 "%ld = OpLoad %float %n\n" +
4934 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4935 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
4936 "OpReturn\n" +
4937 "OpFunctionEnd",
4938 2, 0),
4939 // Test case 8: Don't Fold 0.0 < clamp(0, 1)
4940 InstructionFoldingCase<uint32_t>(
4941 Header() + "%main = OpFunction %void None %void_func\n" +
4942 "%main_lab = OpLabel\n" +
4943 "%n = OpVariable %_ptr_float Function\n" +
4944 "%ld = OpLoad %float %n\n" +
4945 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4946 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4947 "OpReturn\n" +
4948 "OpFunctionEnd",
4949 2, 0),
4950 // Test case 9: Don't Fold 0.0 < clamp(0, 1)
4951 InstructionFoldingCase<uint32_t>(
4952 Header() + "%main = OpFunction %void None %void_func\n" +
4953 "%main_lab = OpLabel\n" +
4954 "%n = OpVariable %_ptr_float Function\n" +
4955 "%ld = OpLoad %float %n\n" +
4956 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4957 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4958 "OpReturn\n" +
4959 "OpFunctionEnd",
4960 2, 0),
4961 // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
4962 InstructionFoldingCase<uint32_t>(
4963 Header() + "%main = OpFunction %void None %void_func\n" +
4964 "%main_lab = OpLabel\n" +
4965 "%n = OpVariable %_ptr_float Function\n" +
4966 "%ld = OpLoad %float %n\n" +
4967 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4968 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4969 "OpReturn\n" +
4970 "OpFunctionEnd",
4971 2, 0),
4972 // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
4973 InstructionFoldingCase<uint32_t>(
4974 Header() + "%main = OpFunction %void None %void_func\n" +
4975 "%main_lab = OpLabel\n" +
4976 "%n = OpVariable %_ptr_float Function\n" +
4977 "%ld = OpLoad %float %n\n" +
4978 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4979 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4980 "OpReturn\n" +
4981 "OpFunctionEnd",
4982 2, 0)
4983 ));
4984
4985 INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
4986 ::testing::Values(
4987 // Test case 0: Don't Fold clamp(-1, 1) < 0.0
4988 InstructionFoldingCase<uint32_t>(
4989 Header() + "%main = OpFunction %void None %void_func\n" +
4990 "%main_lab = OpLabel\n" +
4991 "%n = OpVariable %_ptr_float Function\n" +
4992 "%ld = OpLoad %float %n\n" +
4993 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4994 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4995 "OpReturn\n" +
4996 "OpFunctionEnd",
4997 2, 0),
4998 // Test case 1: Don't Fold clamp(-1, 1) < 0.0
4999 InstructionFoldingCase<uint32_t>(
5000 Header() + "%main = OpFunction %void None %void_func\n" +
5001 "%main_lab = OpLabel\n" +
5002 "%n = OpVariable %_ptr_float Function\n" +
5003 "%ld = OpLoad %float %n\n" +
5004 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5005 "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
5006 "OpReturn\n" +
5007 "OpFunctionEnd",
5008 2, 0),
5009 // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
5010 InstructionFoldingCase<uint32_t>(
5011 Header() + "%main = OpFunction %void None %void_func\n" +
5012 "%main_lab = OpLabel\n" +
5013 "%n = OpVariable %_ptr_float Function\n" +
5014 "%ld = OpLoad %float %n\n" +
5015 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5016 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
5017 "OpReturn\n" +
5018 "OpFunctionEnd",
5019 2, 0),
5020 // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
5021 InstructionFoldingCase<uint32_t>(
5022 Header() + "%main = OpFunction %void None %void_func\n" +
5023 "%main_lab = OpLabel\n" +
5024 "%n = OpVariable %_ptr_float Function\n" +
5025 "%ld = OpLoad %float %n\n" +
5026 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5027 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
5028 "OpReturn\n" +
5029 "OpFunctionEnd",
5030 2, 0),
5031 // Test case 4: Don't Fold clamp(-1, 1) > 0.0
5032 InstructionFoldingCase<uint32_t>(
5033 Header() + "%main = OpFunction %void None %void_func\n" +
5034 "%main_lab = OpLabel\n" +
5035 "%n = OpVariable %_ptr_float Function\n" +
5036 "%ld = OpLoad %float %n\n" +
5037 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5038 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
5039 "OpReturn\n" +
5040 "OpFunctionEnd",
5041 2, 0),
5042 // Test case 5: Don't Fold clamp(-1, 1) > 0.0
5043 InstructionFoldingCase<uint32_t>(
5044 Header() + "%main = OpFunction %void None %void_func\n" +
5045 "%main_lab = OpLabel\n" +
5046 "%n = OpVariable %_ptr_float Function\n" +
5047 "%ld = OpLoad %float %n\n" +
5048 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5049 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
5050 "OpReturn\n" +
5051 "OpFunctionEnd",
5052 2, 0),
5053 // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
5054 InstructionFoldingCase<uint32_t>(
5055 Header() + "%main = OpFunction %void None %void_func\n" +
5056 "%main_lab = OpLabel\n" +
5057 "%n = OpVariable %_ptr_float Function\n" +
5058 "%ld = OpLoad %float %n\n" +
5059 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5060 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
5061 "OpReturn\n" +
5062 "OpFunctionEnd",
5063 2, 0),
5064 // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
5065 InstructionFoldingCase<uint32_t>(
5066 Header() + "%main = OpFunction %void None %void_func\n" +
5067 "%main_lab = OpLabel\n" +
5068 "%n = OpVariable %_ptr_float Function\n" +
5069 "%ld = OpLoad %float %n\n" +
5070 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
5071 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
5072 "OpReturn\n" +
5073 "OpFunctionEnd",
5074 2, 0),
5075 // Test case 8: Don't Fold clamp(-1, 0) < 0.0
5076 InstructionFoldingCase<uint32_t>(
5077 Header() + "%main = OpFunction %void None %void_func\n" +
5078 "%main_lab = OpLabel\n" +
5079 "%n = OpVariable %_ptr_float Function\n" +
5080 "%ld = OpLoad %float %n\n" +
5081 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5082 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
5083 "OpReturn\n" +
5084 "OpFunctionEnd",
5085 2, 0),
5086 // Test case 9: Don't Fold clamp(0, 1) < 1
5087 InstructionFoldingCase<uint32_t>(
5088 Header() + "%main = OpFunction %void None %void_func\n" +
5089 "%main_lab = OpLabel\n" +
5090 "%n = OpVariable %_ptr_float Function\n" +
5091 "%ld = OpLoad %float %n\n" +
5092 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
5093 "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
5094 "OpReturn\n" +
5095 "OpFunctionEnd",
5096 2, 0),
5097 // Test case 10: Don't Fold clamp(-1, 0) > -1
5098 InstructionFoldingCase<uint32_t>(
5099 Header() + "%main = OpFunction %void None %void_func\n" +
5100 "%main_lab = OpLabel\n" +
5101 "%n = OpVariable %_ptr_float Function\n" +
5102 "%ld = OpLoad %float %n\n" +
5103 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5104 "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
5105 "OpReturn\n" +
5106 "OpFunctionEnd",
5107 2, 0),
5108 // Test case 11: Don't Fold clamp(-1, 0) > -1
5109 InstructionFoldingCase<uint32_t>(
5110 Header() + "%main = OpFunction %void None %void_func\n" +
5111 "%main_lab = OpLabel\n" +
5112 "%n = OpVariable %_ptr_float Function\n" +
5113 "%ld = OpLoad %float %n\n" +
5114 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
5115 "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
5116 "OpReturn\n" +
5117 "OpFunctionEnd",
5118 2, 0)
5119 ));
5120
5121 INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
5122 ::testing::Values(
5123 // Test case 0: Fold int(3.0)
5124 InstructionFoldingCase<uint32_t>(
5125 Header() + "%main = OpFunction %void None %void_func\n" +
5126 "%main_lab = OpLabel\n" +
5127 "%2 = OpConvertFToS %int %float_3\n" +
5128 "OpReturn\n" +
5129 "OpFunctionEnd",
5130 2, 3),
5131 // Test case 1: Fold uint(3.0)
5132 InstructionFoldingCase<uint32_t>(
5133 Header() + "%main = OpFunction %void None %void_func\n" +
5134 "%main_lab = OpLabel\n" +
5135 "%2 = OpConvertFToU %int %float_3\n" +
5136 "OpReturn\n" +
5137 "OpFunctionEnd",
5138 2, 3)
5139 ));
5140
5141 INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
5142 ::testing::Values(
5143 // Test case 0: Fold float(3)
5144 InstructionFoldingCase<float>(
5145 Header() + "%main = OpFunction %void None %void_func\n" +
5146 "%main_lab = OpLabel\n" +
5147 "%2 = OpConvertSToF %float %int_3\n" +
5148 "OpReturn\n" +
5149 "OpFunctionEnd",
5150 2, 3.0),
5151 // Test case 1: Fold float(3u)
5152 InstructionFoldingCase<float>(
5153 Header() + "%main = OpFunction %void None %void_func\n" +
5154 "%main_lab = OpLabel\n" +
5155 "%2 = OpConvertUToF %float %uint_3\n" +
5156 "OpReturn\n" +
5157 "OpFunctionEnd",
5158 2, 3.0)
5159 ));
5160 // clang-format on
5161
5162 using ToNegateFoldingTest =
5163 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
5164
TEST_P(ToNegateFoldingTest, Case)5165 TEST_P(ToNegateFoldingTest, Case) {
5166 const auto& tc = GetParam();
5167
5168 // Build module.
5169 std::unique_ptr<IRContext> context =
5170 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5171 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5172 ASSERT_NE(nullptr, context);
5173
5174 // Fold the instruction to test.
5175 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
5176 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
5177 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5178 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5179
5180 // Make sure the instruction folded as expected.
5181 EXPECT_EQ(inst->result_id(), original_inst->result_id());
5182 EXPECT_EQ(inst->type_id(), original_inst->type_id());
5183 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
5184 if (succeeded) {
5185 EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate);
5186 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
5187 } else {
5188 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
5189 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
5190 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
5191 }
5192 }
5193 }
5194
5195 // clang-format off
5196 INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
5197 ::testing::Values(
5198 // Test case 0: Don't fold 1.0 - n
5199 InstructionFoldingCase<uint32_t>(
5200 Header() + "%main = OpFunction %void None %void_func\n" +
5201 "%main_lab = OpLabel\n" +
5202 "%n = OpVariable %_ptr_float Function\n" +
5203 "%3 = OpLoad %float %n\n" +
5204 "%2 = OpFSub %float %float_1 %3\n" +
5205 "OpReturn\n" +
5206 "OpFunctionEnd",
5207 2, 0),
5208 // Test case 1: Fold 0.0 - n
5209 InstructionFoldingCase<uint32_t>(
5210 Header() + "%main = OpFunction %void None %void_func\n" +
5211 "%main_lab = OpLabel\n" +
5212 "%n = OpVariable %_ptr_float Function\n" +
5213 "%3 = OpLoad %float %n\n" +
5214 "%2 = OpFSub %float %float_0 %3\n" +
5215 "OpReturn\n" +
5216 "OpFunctionEnd",
5217 2, 3),
5218 // Test case 2: Don't fold (0,0,0,1) - n
5219 InstructionFoldingCase<uint32_t>(
5220 Header() + "%main = OpFunction %void None %void_func\n" +
5221 "%main_lab = OpLabel\n" +
5222 "%n = OpVariable %_ptr_v4float Function\n" +
5223 "%3 = OpLoad %v4float %n\n" +
5224 "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
5225 "OpReturn\n" +
5226 "OpFunctionEnd",
5227 2, 0),
5228 // Test case 3: Fold (0,0,0,0) - n
5229 InstructionFoldingCase<uint32_t>(
5230 Header() + "%main = OpFunction %void None %void_func\n" +
5231 "%main_lab = OpLabel\n" +
5232 "%n = OpVariable %_ptr_v4float Function\n" +
5233 "%3 = OpLoad %v4float %n\n" +
5234 "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
5235 "OpReturn\n" +
5236 "OpFunctionEnd",
5237 2, 3)
5238 ));
5239
5240 INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
5241 ::testing::Values(
5242 // Test case 0: Don't fold 1.0 - n
5243 InstructionFoldingCase<uint32_t>(
5244 Header() + "%main = OpFunction %void None %void_func\n" +
5245 "%main_lab = OpLabel\n" +
5246 "%n = OpVariable %_ptr_double Function\n" +
5247 "%3 = OpLoad %double %n\n" +
5248 "%2 = OpFSub %double %double_1 %3\n" +
5249 "OpReturn\n" +
5250 "OpFunctionEnd",
5251 2, 0),
5252 // Test case 1: Fold 0.0 - n
5253 InstructionFoldingCase<uint32_t>(
5254 Header() + "%main = OpFunction %void None %void_func\n" +
5255 "%main_lab = OpLabel\n" +
5256 "%n = OpVariable %_ptr_double Function\n" +
5257 "%3 = OpLoad %double %n\n" +
5258 "%2 = OpFSub %double %double_0 %3\n" +
5259 "OpReturn\n" +
5260 "OpFunctionEnd",
5261 2, 3),
5262 // Test case 2: Don't fold (0,0,0,1) - n
5263 InstructionFoldingCase<uint32_t>(
5264 Header() + "%main = OpFunction %void None %void_func\n" +
5265 "%main_lab = OpLabel\n" +
5266 "%n = OpVariable %_ptr_v4double Function\n" +
5267 "%3 = OpLoad %v4double %n\n" +
5268 "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
5269 "OpReturn\n" +
5270 "OpFunctionEnd",
5271 2, 0),
5272 // Test case 3: Fold (0,0,0,0) - n
5273 InstructionFoldingCase<uint32_t>(
5274 Header() + "%main = OpFunction %void None %void_func\n" +
5275 "%main_lab = OpLabel\n" +
5276 "%n = OpVariable %_ptr_v4double Function\n" +
5277 "%3 = OpLoad %v4double %n\n" +
5278 "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
5279 "OpReturn\n" +
5280 "OpFunctionEnd",
5281 2, 3)
5282 ));
5283
5284 using MatchingInstructionFoldingTest =
5285 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
5286
TEST_P(MatchingInstructionFoldingTest, Case)5287 TEST_P(MatchingInstructionFoldingTest, Case) {
5288 const auto& tc = GetParam();
5289
5290 // Build module.
5291 std::unique_ptr<IRContext> context =
5292 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5293 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5294 ASSERT_NE(nullptr, context);
5295
5296 // Fold the instruction to test.
5297 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
5298 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
5299 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5300 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5301 EXPECT_EQ(succeeded, tc.expected_result);
5302 if (succeeded) {
5303 Match(tc.test_body, context.get());
5304 }
5305 }
5306
5307 INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
5308 ::testing::Values(
5309 // Test case 0: Fold 0 + n (change sign)
5310 InstructionFoldingCase<bool>(
5311 Header() +
5312 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5313 "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
5314 "%main = OpFunction %void None %void_func\n" +
5315 "%main_lab = OpLabel\n" +
5316 "%n = OpVariable %_ptr_int Function\n" +
5317 "%3 = OpLoad %uint %n\n" +
5318 "%2 = OpIAdd %uint %int_0 %3\n" +
5319 "OpReturn\n" +
5320 "OpFunctionEnd\n",
5321 2, true),
5322 // Test case 0: Fold 0 + n (change sign)
5323 InstructionFoldingCase<bool>(
5324 Header() +
5325 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5326 "; CHECK: %2 = OpBitcast [[int]] %3\n" +
5327 "%main = OpFunction %void None %void_func\n" +
5328 "%main_lab = OpLabel\n" +
5329 "%n = OpVariable %_ptr_int Function\n" +
5330 "%3 = OpLoad %int %n\n" +
5331 "%2 = OpIAdd %int %uint_0 %3\n" +
5332 "OpReturn\n" +
5333 "OpFunctionEnd\n",
5334 2, true)
5335 ));
5336
5337 INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest,
5338 ::testing::Values(
5339 // Test case 0: fold consecutive fnegate
5340 // -(-x) = x
5341 InstructionFoldingCase<bool>(
5342 Header() +
5343 "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
5344 "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
5345 "%main = OpFunction %void None %void_func\n" +
5346 "%main_lab = OpLabel\n" +
5347 "%var = OpVariable %_ptr_float Function\n" +
5348 "%2 = OpLoad %float %var\n" +
5349 "%3 = OpFNegate %float %2\n" +
5350 "%4 = OpFNegate %float %3\n" +
5351 "OpReturn\n" +
5352 "OpFunctionEnd",
5353 4, true),
5354 // Test case 1: fold fnegate(fmul with const).
5355 // -(x * 2.0) = x * -2.0
5356 InstructionFoldingCase<bool>(
5357 Header() +
5358 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5359 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5360 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5361 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5362 "%main = OpFunction %void None %void_func\n" +
5363 "%main_lab = OpLabel\n" +
5364 "%var = OpVariable %_ptr_float Function\n" +
5365 "%2 = OpLoad %float %var\n" +
5366 "%3 = OpFMul %float %2 %float_2\n" +
5367 "%4 = OpFNegate %float %3\n" +
5368 "OpReturn\n" +
5369 "OpFunctionEnd",
5370 4, true),
5371 // Test case 2: fold fnegate(fmul with const).
5372 // -(2.0 * x) = x * 2.0
5373 InstructionFoldingCase<bool>(
5374 Header() +
5375 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5376 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5377 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5378 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5379 "%main = OpFunction %void None %void_func\n" +
5380 "%main_lab = OpLabel\n" +
5381 "%var = OpVariable %_ptr_float Function\n" +
5382 "%2 = OpLoad %float %var\n" +
5383 "%3 = OpFMul %float %float_2 %2\n" +
5384 "%4 = OpFNegate %float %3\n" +
5385 "OpReturn\n" +
5386 "OpFunctionEnd",
5387 4, true),
5388 // Test case 3: fold fnegate(fdiv with const).
5389 // -(x / 2.0) = x * -0.5
5390 InstructionFoldingCase<bool>(
5391 Header() +
5392 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5393 "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
5394 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5395 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
5396 "%main = OpFunction %void None %void_func\n" +
5397 "%main_lab = OpLabel\n" +
5398 "%var = OpVariable %_ptr_float Function\n" +
5399 "%2 = OpLoad %float %var\n" +
5400 "%3 = OpFDiv %float %2 %float_2\n" +
5401 "%4 = OpFNegate %float %3\n" +
5402 "OpReturn\n" +
5403 "OpFunctionEnd",
5404 4, true),
5405 // Test case 4: fold fnegate(fdiv with const).
5406 // -(2.0 / x) = -2.0 / x
5407 InstructionFoldingCase<bool>(
5408 Header() +
5409 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5410 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5411 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5412 "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
5413 "%main = OpFunction %void None %void_func\n" +
5414 "%main_lab = OpLabel\n" +
5415 "%var = OpVariable %_ptr_float Function\n" +
5416 "%2 = OpLoad %float %var\n" +
5417 "%3 = OpFDiv %float %float_2 %2\n" +
5418 "%4 = OpFNegate %float %3\n" +
5419 "OpReturn\n" +
5420 "OpFunctionEnd",
5421 4, true),
5422 // Test case 5: fold fnegate(fadd with const).
5423 // -(2.0 + x) = -2.0 - x
5424 InstructionFoldingCase<bool>(
5425 Header() +
5426 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5427 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5428 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5429 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5430 "%main = OpFunction %void None %void_func\n" +
5431 "%main_lab = OpLabel\n" +
5432 "%var = OpVariable %_ptr_float Function\n" +
5433 "%2 = OpLoad %float %var\n" +
5434 "%3 = OpFAdd %float %float_2 %2\n" +
5435 "%4 = OpFNegate %float %3\n" +
5436 "OpReturn\n" +
5437 "OpFunctionEnd",
5438 4, true),
5439 // Test case 6: fold fnegate(fadd with const).
5440 // -(x + 2.0) = -2.0 - x
5441 InstructionFoldingCase<bool>(
5442 Header() +
5443 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5444 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5445 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5446 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5447 "%main = OpFunction %void None %void_func\n" +
5448 "%main_lab = OpLabel\n" +
5449 "%var = OpVariable %_ptr_float Function\n" +
5450 "%2 = OpLoad %float %var\n" +
5451 "%3 = OpFAdd %float %2 %float_2\n" +
5452 "%4 = OpFNegate %float %3\n" +
5453 "OpReturn\n" +
5454 "OpFunctionEnd",
5455 4, true),
5456 // Test case 7: fold fnegate(fsub with const).
5457 // -(2.0 - x) = x - 2.0
5458 InstructionFoldingCase<bool>(
5459 Header() +
5460 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5461 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5462 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5463 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
5464 "%main = OpFunction %void None %void_func\n" +
5465 "%main_lab = OpLabel\n" +
5466 "%var = OpVariable %_ptr_float Function\n" +
5467 "%2 = OpLoad %float %var\n" +
5468 "%3 = OpFSub %float %float_2 %2\n" +
5469 "%4 = OpFNegate %float %3\n" +
5470 "OpReturn\n" +
5471 "OpFunctionEnd",
5472 4, true),
5473 // Test case 8: fold fnegate(fsub with const).
5474 // -(x - 2.0) = 2.0 - x
5475 InstructionFoldingCase<bool>(
5476 Header() +
5477 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5478 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5479 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5480 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5481 "%main = OpFunction %void None %void_func\n" +
5482 "%main_lab = OpLabel\n" +
5483 "%var = OpVariable %_ptr_float Function\n" +
5484 "%2 = OpLoad %float %var\n" +
5485 "%3 = OpFSub %float %2 %float_2\n" +
5486 "%4 = OpFNegate %float %3\n" +
5487 "OpReturn\n" +
5488 "OpFunctionEnd",
5489 4, true),
5490 // Test case 9: fold consecutive snegate
5491 // -(-x) = x
5492 InstructionFoldingCase<bool>(
5493 Header() +
5494 "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
5495 "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
5496 "%main = OpFunction %void None %void_func\n" +
5497 "%main_lab = OpLabel\n" +
5498 "%var = OpVariable %_ptr_int Function\n" +
5499 "%2 = OpLoad %int %var\n" +
5500 "%3 = OpSNegate %int %2\n" +
5501 "%4 = OpSNegate %int %3\n" +
5502 "OpReturn\n" +
5503 "OpFunctionEnd",
5504 4, true),
5505 // Test case 10: fold consecutive vector negate
5506 // -(-x) = x
5507 InstructionFoldingCase<bool>(
5508 Header() +
5509 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
5510 "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
5511 "%main = OpFunction %void None %void_func\n" +
5512 "%main_lab = OpLabel\n" +
5513 "%var = OpVariable %_ptr_v2float Function\n" +
5514 "%2 = OpLoad %v2float %var\n" +
5515 "%3 = OpFNegate %v2float %2\n" +
5516 "%4 = OpFNegate %v2float %3\n" +
5517 "OpReturn\n" +
5518 "OpFunctionEnd",
5519 4, true),
5520 // Test case 11: fold snegate(iadd with const).
5521 // -(2 + x) = -2 - x
5522 InstructionFoldingCase<bool>(
5523 Header() +
5524 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5525 "; CHECK: OpConstant [[int]] -2147483648\n" +
5526 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5527 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5528 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5529 "%main = OpFunction %void None %void_func\n" +
5530 "%main_lab = OpLabel\n" +
5531 "%var = OpVariable %_ptr_int Function\n" +
5532 "%2 = OpLoad %int %var\n" +
5533 "%3 = OpIAdd %int %int_2 %2\n" +
5534 "%4 = OpSNegate %int %3\n" +
5535 "OpReturn\n" +
5536 "OpFunctionEnd",
5537 4, true),
5538 // Test case 12: fold snegate(iadd with const).
5539 // -(x + 2) = -2 - x
5540 InstructionFoldingCase<bool>(
5541 Header() +
5542 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5543 "; CHECK: OpConstant [[int]] -2147483648\n" +
5544 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5545 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5546 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5547 "%main = OpFunction %void None %void_func\n" +
5548 "%main_lab = OpLabel\n" +
5549 "%var = OpVariable %_ptr_int Function\n" +
5550 "%2 = OpLoad %int %var\n" +
5551 "%3 = OpIAdd %int %2 %int_2\n" +
5552 "%4 = OpSNegate %int %3\n" +
5553 "OpReturn\n" +
5554 "OpFunctionEnd",
5555 4, true),
5556 // Test case 13: fold snegate(isub with const).
5557 // -(2 - x) = x - 2
5558 InstructionFoldingCase<bool>(
5559 Header() +
5560 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5561 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5562 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5563 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
5564 "%main = OpFunction %void None %void_func\n" +
5565 "%main_lab = OpLabel\n" +
5566 "%var = OpVariable %_ptr_int Function\n" +
5567 "%2 = OpLoad %int %var\n" +
5568 "%3 = OpISub %int %int_2 %2\n" +
5569 "%4 = OpSNegate %int %3\n" +
5570 "OpReturn\n" +
5571 "OpFunctionEnd",
5572 4, true),
5573 // Test case 14: fold snegate(isub with const).
5574 // -(x - 2) = 2 - x
5575 InstructionFoldingCase<bool>(
5576 Header() +
5577 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5578 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5579 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5580 "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
5581 "%main = OpFunction %void None %void_func\n" +
5582 "%main_lab = OpLabel\n" +
5583 "%var = OpVariable %_ptr_int Function\n" +
5584 "%2 = OpLoad %int %var\n" +
5585 "%3 = OpISub %int %2 %int_2\n" +
5586 "%4 = OpSNegate %int %3\n" +
5587 "OpReturn\n" +
5588 "OpFunctionEnd",
5589 4, true),
5590 // Test case 15: fold snegate(iadd with const).
5591 // -(x + 2) = -2 - x
5592 InstructionFoldingCase<bool>(
5593 Header() +
5594 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5595 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
5596 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5597 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5598 "%main = OpFunction %void None %void_func\n" +
5599 "%main_lab = OpLabel\n" +
5600 "%var = OpVariable %_ptr_long Function\n" +
5601 "%2 = OpLoad %long %var\n" +
5602 "%3 = OpIAdd %long %2 %long_2\n" +
5603 "%4 = OpSNegate %long %3\n" +
5604 "OpReturn\n" +
5605 "OpFunctionEnd",
5606 4, true),
5607 // Test case 16: fold snegate(isub with const).
5608 // -(2 - x) = x - 2
5609 InstructionFoldingCase<bool>(
5610 Header() +
5611 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5612 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5613 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5614 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
5615 "%main = OpFunction %void None %void_func\n" +
5616 "%main_lab = OpLabel\n" +
5617 "%var = OpVariable %_ptr_long Function\n" +
5618 "%2 = OpLoad %long %var\n" +
5619 "%3 = OpISub %long %long_2 %2\n" +
5620 "%4 = OpSNegate %long %3\n" +
5621 "OpReturn\n" +
5622 "OpFunctionEnd",
5623 4, true),
5624 // Test case 17: fold snegate(isub with const).
5625 // -(x - 2) = 2 - x
5626 InstructionFoldingCase<bool>(
5627 Header() +
5628 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5629 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5630 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5631 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5632 "%main = OpFunction %void None %void_func\n" +
5633 "%main_lab = OpLabel\n" +
5634 "%var = OpVariable %_ptr_long Function\n" +
5635 "%2 = OpLoad %long %var\n" +
5636 "%3 = OpISub %long %2 %long_2\n" +
5637 "%4 = OpSNegate %long %3\n" +
5638 "OpReturn\n" +
5639 "OpFunctionEnd",
5640 4, true),
5641 // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
5642 InstructionFoldingCase<bool>(
5643 Header() +
5644 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5645 "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" +
5646 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" +
5647 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" +
5648 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5649 "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" +
5650 "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
5651 "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
5652 "%main = OpFunction %void None %void_func\n" +
5653 "%main_lab = OpLabel\n" +
5654 "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
5655 "OpReturn\n" +
5656 "OpFunctionEnd",
5657 2, true),
5658 // Test case 19: fold vector fnegate with null
5659 InstructionFoldingCase<bool>(
5660 Header() +
5661 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5662 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5663 "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
5664 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
5665 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5666 "%main = OpFunction %void None %void_func\n" +
5667 "%main_lab = OpLabel\n" +
5668 "%2 = OpFNegate %v2double %v2double_null\n" +
5669 "OpReturn\n" +
5670 "OpFunctionEnd",
5671 2, true)
5672 ));
5673
5674 INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
5675 ::testing::Values(
5676 // Test case 0: scalar reicprocal
5677 // x / 0.5 = x * 2.0
5678 InstructionFoldingCase<bool>(
5679 Header() +
5680 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5681 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5682 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5683 "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
5684 "%main = OpFunction %void None %void_func\n" +
5685 "%main_lab = OpLabel\n" +
5686 "%var = OpVariable %_ptr_float Function\n" +
5687 "%2 = OpLoad %float %var\n" +
5688 "%3 = OpFDiv %float %2 %float_0p5\n" +
5689 "OpReturn\n" +
5690 "OpFunctionEnd\n",
5691 3, true),
5692 // Test case 1: Unfoldable
5693 InstructionFoldingCase<bool>(
5694 Header() +
5695 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5696 "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
5697 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5698 "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
5699 "%main = OpFunction %void None %void_func\n" +
5700 "%main_lab = OpLabel\n" +
5701 "%var = OpVariable %_ptr_float Function\n" +
5702 "%2 = OpLoad %float %var\n" +
5703 "%3 = OpFDiv %float %2 %104\n" +
5704 "OpReturn\n" +
5705 "OpFunctionEnd\n",
5706 3, false),
5707 // Test case 2: Vector reciprocal
5708 // x / {2.0, 0.5} = x * {0.5, 2.0}
5709 InstructionFoldingCase<bool>(
5710 Header() +
5711 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5712 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5713 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5714 "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
5715 "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
5716 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5717 "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
5718 "%main = OpFunction %void None %void_func\n" +
5719 "%main_lab = OpLabel\n" +
5720 "%var = OpVariable %_ptr_v2float Function\n" +
5721 "%2 = OpLoad %v2float %var\n" +
5722 "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
5723 "OpReturn\n" +
5724 "OpFunctionEnd\n",
5725 3, true),
5726 // Test case 3: double reciprocal
5727 // x / 2.0 = x * 0.5
5728 InstructionFoldingCase<bool>(
5729 Header() +
5730 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5731 "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
5732 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5733 "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
5734 "%main = OpFunction %void None %void_func\n" +
5735 "%main_lab = OpLabel\n" +
5736 "%var = OpVariable %_ptr_double Function\n" +
5737 "%2 = OpLoad %double %var\n" +
5738 "%3 = OpFDiv %double %2 %double_2\n" +
5739 "OpReturn\n" +
5740 "OpFunctionEnd\n",
5741 3, true),
5742 // Test case 4: don't fold x / 0.
5743 InstructionFoldingCase<bool>(
5744 Header() +
5745 "%main = OpFunction %void None %void_func\n" +
5746 "%main_lab = OpLabel\n" +
5747 "%var = OpVariable %_ptr_v2float Function\n" +
5748 "%2 = OpLoad %v2float %var\n" +
5749 "%3 = OpFDiv %v2float %2 %v2float_null\n" +
5750 "OpReturn\n" +
5751 "OpFunctionEnd\n",
5752 3, false)
5753 ));
5754
5755 INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest,
5756 ::testing::Values(
5757 // Test case 0: fold consecutive fmuls
5758 // (x * 3.0) * 2.0 = x * 6.0
5759 InstructionFoldingCase<bool>(
5760 Header() +
5761 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5762 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5763 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5764 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5765 "%main = OpFunction %void None %void_func\n" +
5766 "%main_lab = OpLabel\n" +
5767 "%var = OpVariable %_ptr_float Function\n" +
5768 "%2 = OpLoad %float %var\n" +
5769 "%3 = OpFMul %float %2 %float_3\n" +
5770 "%4 = OpFMul %float %3 %float_2\n" +
5771 "OpReturn\n" +
5772 "OpFunctionEnd\n",
5773 4, true),
5774 // Test case 1: fold consecutive fmuls
5775 // 2.0 * (x * 3.0) = x * 6.0
5776 InstructionFoldingCase<bool>(
5777 Header() +
5778 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5779 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5780 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5781 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5782 "%main = OpFunction %void None %void_func\n" +
5783 "%main_lab = OpLabel\n" +
5784 "%var = OpVariable %_ptr_float Function\n" +
5785 "%2 = OpLoad %float %var\n" +
5786 "%3 = OpFMul %float %2 %float_3\n" +
5787 "%4 = OpFMul %float %float_2 %3\n" +
5788 "OpReturn\n" +
5789 "OpFunctionEnd\n",
5790 4, true),
5791 // Test case 2: fold consecutive fmuls
5792 // (3.0 * x) * 2.0 = x * 6.0
5793 InstructionFoldingCase<bool>(
5794 Header() +
5795 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5796 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5797 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5798 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5799 "%main = OpFunction %void None %void_func\n" +
5800 "%main_lab = OpLabel\n" +
5801 "%var = OpVariable %_ptr_float Function\n" +
5802 "%2 = OpLoad %float %var\n" +
5803 "%3 = OpFMul %float %float_3 %2\n" +
5804 "%4 = OpFMul %float %float_2 %3\n" +
5805 "OpReturn\n" +
5806 "OpFunctionEnd\n",
5807 4, true),
5808 // Test case 3: fold vector fmul
5809 InstructionFoldingCase<bool>(
5810 Header() +
5811 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5812 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5813 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5814 "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
5815 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5816 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
5817 "%main = OpFunction %void None %void_func\n" +
5818 "%main_lab = OpLabel\n" +
5819 "%var = OpVariable %_ptr_v2float Function\n" +
5820 "%2 = OpLoad %v2float %var\n" +
5821 "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
5822 "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
5823 "OpReturn\n" +
5824 "OpFunctionEnd\n",
5825 4, true),
5826 // Test case 4: fold double fmuls
5827 // (x * 3.0) * 2.0 = x * 6.0
5828 InstructionFoldingCase<bool>(
5829 Header() +
5830 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5831 "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
5832 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5833 "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
5834 "%main = OpFunction %void None %void_func\n" +
5835 "%main_lab = OpLabel\n" +
5836 "%var = OpVariable %_ptr_double Function\n" +
5837 "%2 = OpLoad %double %var\n" +
5838 "%3 = OpFMul %double %2 %double_3\n" +
5839 "%4 = OpFMul %double %3 %double_2\n" +
5840 "OpReturn\n" +
5841 "OpFunctionEnd\n",
5842 4, true),
5843 // Test case 5: fold 32 bit imuls
5844 // (x * 3) * 2 = x * 6
5845 InstructionFoldingCase<bool>(
5846 Header() +
5847 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5848 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5849 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5850 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
5851 "%main = OpFunction %void None %void_func\n" +
5852 "%main_lab = OpLabel\n" +
5853 "%var = OpVariable %_ptr_int Function\n" +
5854 "%2 = OpLoad %int %var\n" +
5855 "%3 = OpIMul %int %2 %int_3\n" +
5856 "%4 = OpIMul %int %3 %int_2\n" +
5857 "OpReturn\n" +
5858 "OpFunctionEnd\n",
5859 4, true),
5860 // Test case 6: fold 64 bit imuls
5861 // (x * 3) * 2 = x * 6
5862 InstructionFoldingCase<bool>(
5863 Header() +
5864 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5865 "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
5866 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5867 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
5868 "%main = OpFunction %void None %void_func\n" +
5869 "%main_lab = OpLabel\n" +
5870 "%var = OpVariable %_ptr_long Function\n" +
5871 "%2 = OpLoad %long %var\n" +
5872 "%3 = OpIMul %long %2 %long_3\n" +
5873 "%4 = OpIMul %long %3 %long_2\n" +
5874 "OpReturn\n" +
5875 "OpFunctionEnd\n",
5876 4, true),
5877 // Test case 7: merge vector integer mults
5878 InstructionFoldingCase<bool>(
5879 Header() +
5880 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5881 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5882 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5883 "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
5884 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5885 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
5886 "%main = OpFunction %void None %void_func\n" +
5887 "%main_lab = OpLabel\n" +
5888 "%var = OpVariable %_ptr_v2int Function\n" +
5889 "%2 = OpLoad %v2int %var\n" +
5890 "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
5891 "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
5892 "OpReturn\n" +
5893 "OpFunctionEnd\n",
5894 4, true),
5895 // Test case 8: merge fmul of fdiv
5896 // 2.0 * (2.0 / x) = 4.0 / x
5897 InstructionFoldingCase<bool>(
5898 Header() +
5899 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5900 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5901 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5902 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5903 "%main = OpFunction %void None %void_func\n" +
5904 "%main_lab = OpLabel\n" +
5905 "%var = OpVariable %_ptr_float Function\n" +
5906 "%2 = OpLoad %float %var\n" +
5907 "%3 = OpFDiv %float %float_2 %2\n" +
5908 "%4 = OpFMul %float %float_2 %3\n" +
5909 "OpReturn\n" +
5910 "OpFunctionEnd\n",
5911 4, true),
5912 // Test case 9: merge fmul of fdiv
5913 // (2.0 / x) * 2.0 = 4.0 / x
5914 InstructionFoldingCase<bool>(
5915 Header() +
5916 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5917 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5918 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5919 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5920 "%main = OpFunction %void None %void_func\n" +
5921 "%main_lab = OpLabel\n" +
5922 "%var = OpVariable %_ptr_float Function\n" +
5923 "%2 = OpLoad %float %var\n" +
5924 "%3 = OpFDiv %float %float_2 %2\n" +
5925 "%4 = OpFMul %float %3 %float_2\n" +
5926 "OpReturn\n" +
5927 "OpFunctionEnd\n",
5928 4, true),
5929 // Test case 10: Do not merge imul of sdiv
5930 // 4 * (x / 2)
5931 InstructionFoldingCase<bool>(
5932 Header() +
5933 "%main = OpFunction %void None %void_func\n" +
5934 "%main_lab = OpLabel\n" +
5935 "%var = OpVariable %_ptr_int Function\n" +
5936 "%2 = OpLoad %int %var\n" +
5937 "%3 = OpSDiv %int %2 %int_2\n" +
5938 "%4 = OpIMul %int %int_4 %3\n" +
5939 "OpReturn\n" +
5940 "OpFunctionEnd\n",
5941 4, false),
5942 // Test case 11: Do not merge imul of sdiv
5943 // (x / 2) * 4
5944 InstructionFoldingCase<bool>(
5945 Header() +
5946 "%main = OpFunction %void None %void_func\n" +
5947 "%main_lab = OpLabel\n" +
5948 "%var = OpVariable %_ptr_int Function\n" +
5949 "%2 = OpLoad %int %var\n" +
5950 "%3 = OpSDiv %int %2 %int_2\n" +
5951 "%4 = OpIMul %int %3 %int_4\n" +
5952 "OpReturn\n" +
5953 "OpFunctionEnd\n",
5954 4, false),
5955 // Test case 12: Do not merge imul of udiv
5956 // 4 * (x / 2)
5957 InstructionFoldingCase<bool>(
5958 Header() +
5959 "%main = OpFunction %void None %void_func\n" +
5960 "%main_lab = OpLabel\n" +
5961 "%var = OpVariable %_ptr_uint Function\n" +
5962 "%2 = OpLoad %uint %var\n" +
5963 "%3 = OpUDiv %uint %2 %uint_2\n" +
5964 "%4 = OpIMul %uint %uint_4 %3\n" +
5965 "OpReturn\n" +
5966 "OpFunctionEnd\n",
5967 4, false),
5968 // Test case 13: Do not merge imul of udiv
5969 // (x / 2) * 4
5970 InstructionFoldingCase<bool>(
5971 Header() +
5972 "%main = OpFunction %void None %void_func\n" +
5973 "%main_lab = OpLabel\n" +
5974 "%var = OpVariable %_ptr_uint Function\n" +
5975 "%2 = OpLoad %uint %var\n" +
5976 "%3 = OpUDiv %uint %2 %uint_2\n" +
5977 "%4 = OpIMul %uint %3 %uint_4\n" +
5978 "OpReturn\n" +
5979 "OpFunctionEnd\n",
5980 4, false),
5981 // Test case 14: Don't fold
5982 // (x / 3) * 4
5983 InstructionFoldingCase<bool>(
5984 Header() +
5985 "%main = OpFunction %void None %void_func\n" +
5986 "%main_lab = OpLabel\n" +
5987 "%var = OpVariable %_ptr_uint Function\n" +
5988 "%2 = OpLoad %uint %var\n" +
5989 "%3 = OpUDiv %uint %2 %uint_3\n" +
5990 "%4 = OpIMul %uint %3 %uint_4\n" +
5991 "OpReturn\n" +
5992 "OpFunctionEnd\n",
5993 4, false),
5994 // Test case 15: merge vector fmul of fdiv
5995 // (x / {2,2}) * {4,4} = x * {2,2}
5996 InstructionFoldingCase<bool>(
5997 Header() +
5998 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5999 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6000 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6001 "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
6002 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
6003 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
6004 "%main = OpFunction %void None %void_func\n" +
6005 "%main_lab = OpLabel\n" +
6006 "%var = OpVariable %_ptr_v2float Function\n" +
6007 "%2 = OpLoad %v2float %var\n" +
6008 "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
6009 "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
6010 "OpReturn\n" +
6011 "OpFunctionEnd\n",
6012 4, true),
6013 // Test case 16: merge vector imul of snegate
6014 // (-x) * {2,2} = x * {-2,-2}
6015 InstructionFoldingCase<bool>(
6016 Header() +
6017 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6018 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6019 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6020 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6021 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6022 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6023 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6024 "%main = OpFunction %void None %void_func\n" +
6025 "%main_lab = OpLabel\n" +
6026 "%var = OpVariable %_ptr_v2int Function\n" +
6027 "%2 = OpLoad %v2int %var\n" +
6028 "%3 = OpSNegate %v2int %2\n" +
6029 "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
6030 "OpReturn\n" +
6031 "OpFunctionEnd\n",
6032 4, true),
6033 // Test case 17: merge vector imul of snegate
6034 // {2,2} * (-x) = x * {-2,-2}
6035 InstructionFoldingCase<bool>(
6036 Header() +
6037 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6038 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
6039 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
6040 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
6041 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
6042 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
6043 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
6044 "%main = OpFunction %void None %void_func\n" +
6045 "%main_lab = OpLabel\n" +
6046 "%var = OpVariable %_ptr_v2int Function\n" +
6047 "%2 = OpLoad %v2int %var\n" +
6048 "%3 = OpSNegate %v2int %2\n" +
6049 "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
6050 "OpReturn\n" +
6051 "OpFunctionEnd\n",
6052 4, true),
6053 // Test case 18: Fold OpVectorTimesScalar
6054 // {4,4} = OpVectorTimesScalar v2float {2,2} 2
6055 InstructionFoldingCase<bool>(
6056 Header() +
6057 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6058 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6059 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
6060 "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
6061 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
6062 "%main = OpFunction %void None %void_func\n" +
6063 "%main_lab = OpLabel\n" +
6064 "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
6065 "OpReturn\n" +
6066 "OpFunctionEnd",
6067 2, true),
6068 // Test case 19: Fold OpVectorTimesScalar
6069 // {0,0} = OpVectorTimesScalar v2float v2float_null -1
6070 InstructionFoldingCase<bool>(
6071 Header() +
6072 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6073 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
6074 "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
6075 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
6076 "%main = OpFunction %void None %void_func\n" +
6077 "%main_lab = OpLabel\n" +
6078 "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
6079 "OpReturn\n" +
6080 "OpFunctionEnd",
6081 2, true),
6082 // Test case 20: Fold OpVectorTimesScalar
6083 // {4,4} = OpVectorTimesScalar v2double {2,2} 2
6084 InstructionFoldingCase<bool>(
6085 Header() +
6086 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6087 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6088 "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
6089 "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
6090 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
6091 "%main = OpFunction %void None %void_func\n" +
6092 "%main_lab = OpLabel\n" +
6093 "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
6094 "OpReturn\n" +
6095 "OpFunctionEnd",
6096 2, true),
6097 // Test case 21: Fold OpVectorTimesScalar
6098 // {0,0} = OpVectorTimesScalar v2double {0,0} n
6099 InstructionFoldingCase<bool>(
6100 Header() +
6101 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6102 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6103 "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
6104 "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
6105 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
6106 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
6107 "%main = OpFunction %void None %void_func\n" +
6108 "%main_lab = OpLabel\n" +
6109 "%n = OpVariable %_ptr_double Function\n" +
6110 "%load = OpLoad %double %n\n" +
6111 "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
6112 "OpReturn\n" +
6113 "OpFunctionEnd",
6114 2, true),
6115 // Test case 22: Fold OpVectorTimesScalar
6116 // {0,0} = OpVectorTimesScalar v2double n 0
6117 InstructionFoldingCase<bool>(
6118 Header() +
6119 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6120 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
6121 "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
6122 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
6123 "%main = OpFunction %void None %void_func\n" +
6124 "%main_lab = OpLabel\n" +
6125 "%n = OpVariable %_ptr_v2double Function\n" +
6126 "%load = OpLoad %v2double %n\n" +
6127 "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
6128 "OpReturn\n" +
6129 "OpFunctionEnd",
6130 2, true),
6131 // Test case 23: merge fmul of fdiv
6132 // x * (y / x) = y
6133 InstructionFoldingCase<bool>(
6134 Header() +
6135 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6136 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6137 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6138 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6139 "%main = OpFunction %void None %void_func\n" +
6140 "%main_lab = OpLabel\n" +
6141 "%x = OpVariable %_ptr_float Function\n" +
6142 "%y = OpVariable %_ptr_float Function\n" +
6143 "%2 = OpLoad %float %x\n" +
6144 "%3 = OpLoad %float %y\n" +
6145 "%4 = OpFDiv %float %3 %2\n" +
6146 "%5 = OpFMul %float %2 %4\n" +
6147 "OpReturn\n" +
6148 "OpFunctionEnd\n",
6149 5, true),
6150 // Test case 24: merge fmul of fdiv
6151 // (y / x) * x = y
6152 InstructionFoldingCase<bool>(
6153 Header() +
6154 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6155 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6156 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6157 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6158 "%main = OpFunction %void None %void_func\n" +
6159 "%main_lab = OpLabel\n" +
6160 "%x = OpVariable %_ptr_float Function\n" +
6161 "%y = OpVariable %_ptr_float Function\n" +
6162 "%2 = OpLoad %float %x\n" +
6163 "%3 = OpLoad %float %y\n" +
6164 "%4 = OpFDiv %float %3 %2\n" +
6165 "%5 = OpFMul %float %4 %2\n" +
6166 "OpReturn\n" +
6167 "OpFunctionEnd\n",
6168 5, true),
6169 // Test case 25: fold overflowing signed 32 bit imuls
6170 // (x * 1073741824) * 2 = x * int_min
6171 InstructionFoldingCase<bool>(
6172 Header() +
6173 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6174 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6175 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6176 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" +
6177 "%main = OpFunction %void None %void_func\n" +
6178 "%main_lab = OpLabel\n" +
6179 "%var = OpVariable %_ptr_int Function\n" +
6180 "%2 = OpLoad %int %var\n" +
6181 "%3 = OpIMul %int %2 %int_1073741824\n" +
6182 "%4 = OpIMul %int %3 %int_2\n" +
6183 "OpReturn\n" +
6184 "OpFunctionEnd\n",
6185 4, true),
6186 // Test case 26: fold overflowing signed 64 bit imuls
6187 // (x * 4611686018427387904) * 2 = x * long_min
6188 InstructionFoldingCase<bool>(
6189 Header() +
6190 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6191 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6192 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6193 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" +
6194 "%main = OpFunction %void None %void_func\n" +
6195 "%main_lab = OpLabel\n" +
6196 "%var = OpVariable %_ptr_long Function\n" +
6197 "%2 = OpLoad %long %var\n" +
6198 "%3 = OpIMul %long %2 %long_4611686018427387904\n" +
6199 "%4 = OpIMul %long %3 %long_2\n" +
6200 "OpReturn\n" +
6201 "OpFunctionEnd\n",
6202 4, true),
6203 // Test case 27: fold overflowing 32 bit unsigned imuls
6204 // (x * 2147483649) * 2 = x * 2
6205 InstructionFoldingCase<bool>(
6206 Header() +
6207 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6208 "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" +
6209 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6210 "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" +
6211 "%main = OpFunction %void None %void_func\n" +
6212 "%main_lab = OpLabel\n" +
6213 "%var = OpVariable %_ptr_uint Function\n" +
6214 "%2 = OpLoad %uint %var\n" +
6215 "%3 = OpIMul %uint %2 %uint_2147483649\n" +
6216 "%4 = OpIMul %uint %3 %uint_2\n" +
6217 "OpReturn\n" +
6218 "OpFunctionEnd\n",
6219 4, true),
6220 // Test case 28: fold overflowing 64 bit unsigned imuls
6221 // (x * 9223372036854775809) * 2 = x * 2
6222 InstructionFoldingCase<bool>(
6223 Header() +
6224 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6225 "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" +
6226 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6227 "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" +
6228 "%main = OpFunction %void None %void_func\n" +
6229 "%main_lab = OpLabel\n" +
6230 "%var = OpVariable %_ptr_ulong Function\n" +
6231 "%2 = OpLoad %ulong %var\n" +
6232 "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" +
6233 "%4 = OpIMul %ulong %3 %ulong_2\n" +
6234 "OpReturn\n" +
6235 "OpFunctionEnd\n",
6236 4, true),
6237 // Test case 29: fold underflowing signed 32 bit imuls
6238 // (x * (-858993459)) * 10 = x * 2
6239 InstructionFoldingCase<bool>(
6240 Header() +
6241 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6242 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
6243 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6244 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" +
6245 "%main = OpFunction %void None %void_func\n" +
6246 "%main_lab = OpLabel\n" +
6247 "%var = OpVariable %_ptr_int Function\n" +
6248 "%2 = OpLoad %int %var\n" +
6249 "%3 = OpIMul %int %2 %int_n858993459\n" +
6250 "%4 = OpIMul %int %3 %int_10\n" +
6251 "OpReturn\n" +
6252 "OpFunctionEnd\n",
6253 4, true),
6254 // Test case 30: fold underflowing signed 64 bit imuls
6255 // (x * (-3689348814741910323)) * 10 = x * 2
6256 InstructionFoldingCase<bool>(
6257 Header() +
6258 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6259 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6260 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6261 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" +
6262 "%main = OpFunction %void None %void_func\n" +
6263 "%main_lab = OpLabel\n" +
6264 "%var = OpVariable %_ptr_long Function\n" +
6265 "%2 = OpLoad %long %var\n" +
6266 "%3 = OpIMul %long %2 %long_n3689348814741910323\n" +
6267 "%4 = OpIMul %long %3 %long_10\n" +
6268 "OpReturn\n" +
6269 "OpFunctionEnd\n",
6270 4, true)
6271 ));
6272
6273 INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest,
6274 ::testing::Values(
6275 // Test case 0: merge consecutive fdiv
6276 // 4.0 / (2.0 / x) = 2.0 * x
6277 InstructionFoldingCase<bool>(
6278 Header() +
6279 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6280 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6281 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6282 "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
6283 "%main = OpFunction %void None %void_func\n" +
6284 "%main_lab = OpLabel\n" +
6285 "%var = OpVariable %_ptr_float Function\n" +
6286 "%2 = OpLoad %float %var\n" +
6287 "%3 = OpFDiv %float %float_2 %2\n" +
6288 "%4 = OpFDiv %float %float_4 %3\n" +
6289 "OpReturn\n" +
6290 "OpFunctionEnd\n",
6291 4, true),
6292 // Test case 1: merge consecutive fdiv
6293 // 4.0 / (x / 2.0) = 8.0 / x
6294 InstructionFoldingCase<bool>(
6295 Header() +
6296 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6297 "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
6298 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6299 "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
6300 "%main = OpFunction %void None %void_func\n" +
6301 "%main_lab = OpLabel\n" +
6302 "%var = OpVariable %_ptr_float Function\n" +
6303 "%2 = OpLoad %float %var\n" +
6304 "%3 = OpFDiv %float %2 %float_2\n" +
6305 "%4 = OpFDiv %float %float_4 %3\n" +
6306 "OpReturn\n" +
6307 "OpFunctionEnd\n",
6308 4, true),
6309 // Test case 2: merge consecutive fdiv
6310 // (4.0 / x) / 2.0 = 2.0 / x
6311 InstructionFoldingCase<bool>(
6312 Header() +
6313 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6314 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6315 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6316 "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
6317 "%main = OpFunction %void None %void_func\n" +
6318 "%main_lab = OpLabel\n" +
6319 "%var = OpVariable %_ptr_float Function\n" +
6320 "%2 = OpLoad %float %var\n" +
6321 "%3 = OpFDiv %float %float_4 %2\n" +
6322 "%4 = OpFDiv %float %3 %float_2\n" +
6323 "OpReturn\n" +
6324 "OpFunctionEnd\n",
6325 4, true),
6326 // Test case 3: Do not merge consecutive sdiv
6327 // 4 / (2 / x)
6328 InstructionFoldingCase<bool>(
6329 Header() +
6330 "%main = OpFunction %void None %void_func\n" +
6331 "%main_lab = OpLabel\n" +
6332 "%var = OpVariable %_ptr_int Function\n" +
6333 "%2 = OpLoad %int %var\n" +
6334 "%3 = OpSDiv %int %int_2 %2\n" +
6335 "%4 = OpSDiv %int %int_4 %3\n" +
6336 "OpReturn\n" +
6337 "OpFunctionEnd\n",
6338 4, false),
6339 // Test case 4: Do not merge consecutive sdiv
6340 // 4 / (x / 2)
6341 InstructionFoldingCase<bool>(
6342 Header() +
6343 "%main = OpFunction %void None %void_func\n" +
6344 "%main_lab = OpLabel\n" +
6345 "%var = OpVariable %_ptr_int Function\n" +
6346 "%2 = OpLoad %int %var\n" +
6347 "%3 = OpSDiv %int %2 %int_2\n" +
6348 "%4 = OpSDiv %int %int_4 %3\n" +
6349 "OpReturn\n" +
6350 "OpFunctionEnd\n",
6351 4, false),
6352 // Test case 5: Do not merge consecutive sdiv
6353 // (4 / x) / 2
6354 InstructionFoldingCase<bool>(
6355 Header() +
6356 "%main = OpFunction %void None %void_func\n" +
6357 "%main_lab = OpLabel\n" +
6358 "%var = OpVariable %_ptr_int Function\n" +
6359 "%2 = OpLoad %int %var\n" +
6360 "%3 = OpSDiv %int %int_4 %2\n" +
6361 "%4 = OpSDiv %int %3 %int_2\n" +
6362 "OpReturn\n" +
6363 "OpFunctionEnd\n",
6364 4, false),
6365 // Test case 6: Do not merge consecutive sdiv
6366 // (x / 4) / 2
6367 InstructionFoldingCase<bool>(
6368 Header() +
6369 "%main = OpFunction %void None %void_func\n" +
6370 "%main_lab = OpLabel\n" +
6371 "%var = OpVariable %_ptr_int Function\n" +
6372 "%2 = OpLoad %int %var\n" +
6373 "%3 = OpSDiv %int %2 %int_4\n" +
6374 "%4 = OpSDiv %int %3 %int_2\n" +
6375 "OpReturn\n" +
6376 "OpFunctionEnd\n",
6377 4, false),
6378 // Test case 7: Do not merge sdiv of imul
6379 // 4 / (2 * x)
6380 InstructionFoldingCase<bool>(
6381 Header() +
6382 "%main = OpFunction %void None %void_func\n" +
6383 "%main_lab = OpLabel\n" +
6384 "%var = OpVariable %_ptr_int Function\n" +
6385 "%2 = OpLoad %int %var\n" +
6386 "%3 = OpIMul %int %int_2 %2\n" +
6387 "%4 = OpSDiv %int %int_4 %3\n" +
6388 "OpReturn\n" +
6389 "OpFunctionEnd\n",
6390 4, false),
6391 // Test case 8: Do not merge sdiv of imul
6392 // 4 / (x * 2)
6393 InstructionFoldingCase<bool>(
6394 Header() +
6395 "%main = OpFunction %void None %void_func\n" +
6396 "%main_lab = OpLabel\n" +
6397 "%var = OpVariable %_ptr_int Function\n" +
6398 "%2 = OpLoad %int %var\n" +
6399 "%3 = OpIMul %int %2 %int_2\n" +
6400 "%4 = OpSDiv %int %int_4 %3\n" +
6401 "OpReturn\n" +
6402 "OpFunctionEnd\n",
6403 4, false),
6404 // Test case 9: Do not merge sdiv of imul
6405 // (4 * x) / 2
6406 InstructionFoldingCase<bool>(
6407 Header() +
6408 "%main = OpFunction %void None %void_func\n" +
6409 "%main_lab = OpLabel\n" +
6410 "%var = OpVariable %_ptr_int Function\n" +
6411 "%2 = OpLoad %int %var\n" +
6412 "%3 = OpIMul %int %int_4 %2\n" +
6413 "%4 = OpSDiv %int %3 %int_2\n" +
6414 "OpReturn\n" +
6415 "OpFunctionEnd\n",
6416 4, false),
6417 // Test case 10: Do not merge sdiv of imul
6418 // (x * 4) / 2
6419 InstructionFoldingCase<bool>(
6420 Header() +
6421 "%main = OpFunction %void None %void_func\n" +
6422 "%main_lab = OpLabel\n" +
6423 "%var = OpVariable %_ptr_int Function\n" +
6424 "%2 = OpLoad %int %var\n" +
6425 "%3 = OpIMul %int %2 %int_4\n" +
6426 "%4 = OpSDiv %int %3 %int_2\n" +
6427 "OpReturn\n" +
6428 "OpFunctionEnd\n",
6429 4, false),
6430 // Test case 11: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
6431 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
6432 // Specifically, (-INT_MIN) / 2 != INT_MIN / -2.
6433 InstructionFoldingCase<bool>(
6434 Header() +
6435 "%main = OpFunction %void None %void_func\n" +
6436 "%main_lab = OpLabel\n" +
6437 "%var = OpVariable %_ptr_int Function\n" +
6438 "%2 = OpLoad %int %var\n" +
6439 "%3 = OpSNegate %int %2\n" +
6440 "%4 = OpSDiv %int %3 %int_2\n" +
6441 "OpReturn\n" +
6442 "OpFunctionEnd\n",
6443 4, false),
6444 // Test case 12: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
6445 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
6446 // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN.
6447 InstructionFoldingCase<bool>(
6448 Header() +
6449 "%main = OpFunction %void None %void_func\n" +
6450 "%main_lab = OpLabel\n" +
6451 "%var = OpVariable %_ptr_int Function\n" +
6452 "%2 = OpLoad %int %var\n" +
6453 "%3 = OpSNegate %int %2\n" +
6454 "%4 = OpSDiv %int %int_2 %3\n" +
6455 "OpReturn\n" +
6456 "OpFunctionEnd\n",
6457 4, false),
6458 // Test case 13: Don't merge
6459 // (x / {null}) / {null}
6460 InstructionFoldingCase<bool>(
6461 Header() +
6462 "%main = OpFunction %void None %void_func\n" +
6463 "%main_lab = OpLabel\n" +
6464 "%var = OpVariable %_ptr_v2float Function\n" +
6465 "%2 = OpLoad %float %var\n" +
6466 "%3 = OpFDiv %float %2 %v2float_null\n" +
6467 "%4 = OpFDiv %float %3 %v2float_null\n" +
6468 "OpReturn\n" +
6469 "OpFunctionEnd\n",
6470 4, false),
6471 // Test case 14: merge fmul of fdiv
6472 // (y * x) / x = y
6473 InstructionFoldingCase<bool>(
6474 Header() +
6475 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6476 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6477 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6478 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6479 "%main = OpFunction %void None %void_func\n" +
6480 "%main_lab = OpLabel\n" +
6481 "%x = OpVariable %_ptr_float Function\n" +
6482 "%y = OpVariable %_ptr_float Function\n" +
6483 "%2 = OpLoad %float %x\n" +
6484 "%3 = OpLoad %float %y\n" +
6485 "%4 = OpFMul %float %3 %2\n" +
6486 "%5 = OpFDiv %float %4 %2\n" +
6487 "OpReturn\n" +
6488 "OpFunctionEnd\n",
6489 5, true),
6490 // Test case 15: merge fmul of fdiv
6491 // (x * y) / x = y
6492 InstructionFoldingCase<bool>(
6493 Header() +
6494 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6495 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6496 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6497 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6498 "%main = OpFunction %void None %void_func\n" +
6499 "%main_lab = OpLabel\n" +
6500 "%x = OpVariable %_ptr_float Function\n" +
6501 "%y = OpVariable %_ptr_float Function\n" +
6502 "%2 = OpLoad %float %x\n" +
6503 "%3 = OpLoad %float %y\n" +
6504 "%4 = OpFMul %float %2 %3\n" +
6505 "%5 = OpFDiv %float %4 %2\n" +
6506 "OpReturn\n" +
6507 "OpFunctionEnd\n",
6508 5, true),
6509 // Test case 16: Do not merge udiv of snegate
6510 // (-x) / 2u
6511 InstructionFoldingCase<bool>(
6512 Header() +
6513 "%main = OpFunction %void None %void_func\n" +
6514 "%main_lab = OpLabel\n" +
6515 "%var = OpVariable %_ptr_uint Function\n" +
6516 "%2 = OpLoad %uint %var\n" +
6517 "%3 = OpSNegate %uint %2\n" +
6518 "%4 = OpUDiv %uint %3 %uint_2\n" +
6519 "OpReturn\n" +
6520 "OpFunctionEnd\n",
6521 4, false),
6522 // Test case 17: Do not merge udiv of snegate
6523 // 2u / (-x)
6524 InstructionFoldingCase<bool>(
6525 Header() +
6526 "%main = OpFunction %void None %void_func\n" +
6527 "%main_lab = OpLabel\n" +
6528 "%var = OpVariable %_ptr_uint Function\n" +
6529 "%2 = OpLoad %uint %var\n" +
6530 "%3 = OpSNegate %uint %2\n" +
6531 "%4 = OpUDiv %uint %uint_2 %3\n" +
6532 "OpReturn\n" +
6533 "OpFunctionEnd\n",
6534 4, false)
6535 ));
6536
6537 INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest,
6538 ::testing::Values(
6539 // Test case 0: merge add of negate
6540 // (-x) + 2 = 2 - x
6541 InstructionFoldingCase<bool>(
6542 Header() +
6543 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6544 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6545 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6546 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6547 "%main = OpFunction %void None %void_func\n" +
6548 "%main_lab = OpLabel\n" +
6549 "%var = OpVariable %_ptr_float Function\n" +
6550 "%2 = OpLoad %float %var\n" +
6551 "%3 = OpFNegate %float %2\n" +
6552 "%4 = OpFAdd %float %3 %float_2\n" +
6553 "OpReturn\n" +
6554 "OpFunctionEnd\n",
6555 4, true),
6556 // Test case 1: merge add of negate
6557 // 2 + (-x) = 2 - x
6558 InstructionFoldingCase<bool>(
6559 Header() +
6560 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6561 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6562 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6563 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6564 "%main = OpFunction %void None %void_func\n" +
6565 "%main_lab = OpLabel\n" +
6566 "%var = OpVariable %_ptr_float Function\n" +
6567 "%2 = OpLoad %float %var\n" +
6568 "%3 = OpSNegate %float %2\n" +
6569 "%4 = OpIAdd %float %float_2 %3\n" +
6570 "OpReturn\n" +
6571 "OpFunctionEnd\n",
6572 4, true),
6573 // Test case 2: merge add of negate
6574 // (-x) + 2 = 2 - x
6575 InstructionFoldingCase<bool>(
6576 Header() +
6577 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6578 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6579 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6580 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6581 "%main = OpFunction %void None %void_func\n" +
6582 "%main_lab = OpLabel\n" +
6583 "%var = OpVariable %_ptr_long Function\n" +
6584 "%2 = OpLoad %long %var\n" +
6585 "%3 = OpSNegate %long %2\n" +
6586 "%4 = OpIAdd %long %3 %long_2\n" +
6587 "OpReturn\n" +
6588 "OpFunctionEnd\n",
6589 4, true),
6590 // Test case 3: merge add of negate
6591 // 2 + (-x) = 2 - x
6592 InstructionFoldingCase<bool>(
6593 Header() +
6594 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6595 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6596 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6597 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6598 "%main = OpFunction %void None %void_func\n" +
6599 "%main_lab = OpLabel\n" +
6600 "%var = OpVariable %_ptr_long Function\n" +
6601 "%2 = OpLoad %long %var\n" +
6602 "%3 = OpSNegate %long %2\n" +
6603 "%4 = OpIAdd %long %long_2 %3\n" +
6604 "OpReturn\n" +
6605 "OpFunctionEnd\n",
6606 4, true),
6607 // Test case 4: merge add of subtract
6608 // (x - 1) + 2 = x + 1
6609 InstructionFoldingCase<bool>(
6610 Header() +
6611 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6612 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6613 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6614 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6615 "%main = OpFunction %void None %void_func\n" +
6616 "%main_lab = OpLabel\n" +
6617 "%var = OpVariable %_ptr_float Function\n" +
6618 "%2 = OpLoad %float %var\n" +
6619 "%3 = OpFSub %float %2 %float_1\n" +
6620 "%4 = OpFAdd %float %3 %float_2\n" +
6621 "OpReturn\n" +
6622 "OpFunctionEnd\n",
6623 4, true),
6624 // Test case 5: merge add of subtract
6625 // (1 - x) + 2 = 3 - x
6626 InstructionFoldingCase<bool>(
6627 Header() +
6628 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6629 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6630 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6631 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6632 "%main = OpFunction %void None %void_func\n" +
6633 "%main_lab = OpLabel\n" +
6634 "%var = OpVariable %_ptr_float Function\n" +
6635 "%2 = OpLoad %float %var\n" +
6636 "%3 = OpFSub %float %float_1 %2\n" +
6637 "%4 = OpFAdd %float %3 %float_2\n" +
6638 "OpReturn\n" +
6639 "OpFunctionEnd\n",
6640 4, true),
6641 // Test case 6: merge add of subtract
6642 // 2 + (x - 1) = x + 1
6643 InstructionFoldingCase<bool>(
6644 Header() +
6645 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6646 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6647 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6648 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6649 "%main = OpFunction %void None %void_func\n" +
6650 "%main_lab = OpLabel\n" +
6651 "%var = OpVariable %_ptr_float Function\n" +
6652 "%2 = OpLoad %float %var\n" +
6653 "%3 = OpFSub %float %2 %float_1\n" +
6654 "%4 = OpFAdd %float %float_2 %3\n" +
6655 "OpReturn\n" +
6656 "OpFunctionEnd\n",
6657 4, true),
6658 // Test case 7: merge add of subtract
6659 // 2 + (1 - x) = 3 - x
6660 InstructionFoldingCase<bool>(
6661 Header() +
6662 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6663 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6664 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6665 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6666 "%main = OpFunction %void None %void_func\n" +
6667 "%main_lab = OpLabel\n" +
6668 "%var = OpVariable %_ptr_float Function\n" +
6669 "%2 = OpLoad %float %var\n" +
6670 "%3 = OpFSub %float %float_1 %2\n" +
6671 "%4 = OpFAdd %float %float_2 %3\n" +
6672 "OpReturn\n" +
6673 "OpFunctionEnd\n",
6674 4, true),
6675 // Test case 8: merge add of add
6676 // (x + 1) + 2 = x + 3
6677 InstructionFoldingCase<bool>(
6678 Header() +
6679 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6680 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6681 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6682 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6683 "%main = OpFunction %void None %void_func\n" +
6684 "%main_lab = OpLabel\n" +
6685 "%var = OpVariable %_ptr_float Function\n" +
6686 "%2 = OpLoad %float %var\n" +
6687 "%3 = OpFAdd %float %2 %float_1\n" +
6688 "%4 = OpFAdd %float %3 %float_2\n" +
6689 "OpReturn\n" +
6690 "OpFunctionEnd\n",
6691 4, true),
6692 // Test case 9: merge add of add
6693 // (1 + x) + 2 = 3 + x
6694 InstructionFoldingCase<bool>(
6695 Header() +
6696 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6697 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6698 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6699 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6700 "%main = OpFunction %void None %void_func\n" +
6701 "%main_lab = OpLabel\n" +
6702 "%var = OpVariable %_ptr_float Function\n" +
6703 "%2 = OpLoad %float %var\n" +
6704 "%3 = OpFAdd %float %float_1 %2\n" +
6705 "%4 = OpFAdd %float %3 %float_2\n" +
6706 "OpReturn\n" +
6707 "OpFunctionEnd\n",
6708 4, true),
6709 // Test case 10: merge add of add
6710 // 2 + (x + 1) = x + 1
6711 InstructionFoldingCase<bool>(
6712 Header() +
6713 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6714 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6715 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6716 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6717 "%main = OpFunction %void None %void_func\n" +
6718 "%main_lab = OpLabel\n" +
6719 "%var = OpVariable %_ptr_float Function\n" +
6720 "%2 = OpLoad %float %var\n" +
6721 "%3 = OpFAdd %float %2 %float_1\n" +
6722 "%4 = OpFAdd %float %float_2 %3\n" +
6723 "OpReturn\n" +
6724 "OpFunctionEnd\n",
6725 4, true),
6726 // Test case 11: merge add of add
6727 // 2 + (1 + x) = 3 - x
6728 InstructionFoldingCase<bool>(
6729 Header() +
6730 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6731 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6732 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6733 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6734 "%main = OpFunction %void None %void_func\n" +
6735 "%main_lab = OpLabel\n" +
6736 "%var = OpVariable %_ptr_float Function\n" +
6737 "%2 = OpLoad %float %var\n" +
6738 "%3 = OpFAdd %float %float_1 %2\n" +
6739 "%4 = OpFAdd %float %float_2 %3\n" +
6740 "OpReturn\n" +
6741 "OpFunctionEnd\n",
6742 4, true),
6743 // Test case 12: fold overflowing signed 32 bit iadds
6744 // (x + int_max) + 1 = x + int_min
6745 InstructionFoldingCase<bool>(
6746 Header() +
6747 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6748 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6749 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6750 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" +
6751 "%main = OpFunction %void None %void_func\n" +
6752 "%main_lab = OpLabel\n" +
6753 "%var = OpVariable %_ptr_int Function\n" +
6754 "%2 = OpLoad %int %var\n" +
6755 "%3 = OpIAdd %int %2 %int_max\n" +
6756 "%4 = OpIAdd %int %3 %int_1\n" +
6757 "OpReturn\n" +
6758 "OpFunctionEnd\n",
6759 4, true),
6760 // Test case 13: fold overflowing signed 64 bit iadds
6761 // (x + long_max) + 1 = x + long_min
6762 InstructionFoldingCase<bool>(
6763 Header() +
6764 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6765 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6766 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6767 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" +
6768 "%main = OpFunction %void None %void_func\n" +
6769 "%main_lab = OpLabel\n" +
6770 "%var = OpVariable %_ptr_long Function\n" +
6771 "%2 = OpLoad %long %var\n" +
6772 "%3 = OpIAdd %long %2 %long_max\n" +
6773 "%4 = OpIAdd %long %3 %long_1\n" +
6774 "OpReturn\n" +
6775 "OpFunctionEnd\n",
6776 4, true),
6777 // Test case 14: fold overflowing 32 bit unsigned iadds
6778 // (x + uint_max) + 2 = x + 1
6779 InstructionFoldingCase<bool>(
6780 Header() +
6781 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6782 "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
6783 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6784 "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" +
6785 "%main = OpFunction %void None %void_func\n" +
6786 "%main_lab = OpLabel\n" +
6787 "%var = OpVariable %_ptr_uint Function\n" +
6788 "%2 = OpLoad %uint %var\n" +
6789 "%3 = OpIAdd %uint %2 %uint_max\n" +
6790 "%4 = OpIAdd %uint %3 %uint_2\n" +
6791 "OpReturn\n" +
6792 "OpFunctionEnd\n",
6793 4, true),
6794 // Test case 15: fold overflowing 64 bit unsigned iadds
6795 // (x + ulong_max) + 2 = x + 1
6796 InstructionFoldingCase<bool>(
6797 Header() +
6798 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6799 "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" +
6800 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6801 "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" +
6802 "%main = OpFunction %void None %void_func\n" +
6803 "%main_lab = OpLabel\n" +
6804 "%var = OpVariable %_ptr_ulong Function\n" +
6805 "%2 = OpLoad %ulong %var\n" +
6806 "%3 = OpIAdd %ulong %2 %ulong_max\n" +
6807 "%4 = OpIAdd %ulong %3 %ulong_2\n" +
6808 "OpReturn\n" +
6809 "OpFunctionEnd\n",
6810 4, true),
6811 // Test case 16: fold underflowing signed 32 bit iadds
6812 // (x + int_min) + (-1) = x + int_max
6813 InstructionFoldingCase<bool>(
6814 Header() +
6815 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6816 "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" +
6817 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6818 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" +
6819 "%main = OpFunction %void None %void_func\n" +
6820 "%main_lab = OpLabel\n" +
6821 "%var = OpVariable %_ptr_int Function\n" +
6822 "%2 = OpLoad %int %var\n" +
6823 "%3 = OpIAdd %int %2 %int_min\n" +
6824 "%4 = OpIAdd %int %3 %int_n1\n" +
6825 "OpReturn\n" +
6826 "OpFunctionEnd\n",
6827 4, true),
6828 // Test case 17: fold underflowing signed 64 bit iadds
6829 // (x + long_min) + (-1) = x + long_max
6830 InstructionFoldingCase<bool>(
6831 Header() +
6832 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6833 "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" +
6834 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6835 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" +
6836 "%main = OpFunction %void None %void_func\n" +
6837 "%main_lab = OpLabel\n" +
6838 "%var = OpVariable %_ptr_long Function\n" +
6839 "%2 = OpLoad %long %var\n" +
6840 "%3 = OpIAdd %long %2 %long_min\n" +
6841 "%4 = OpIAdd %long %3 %long_n1\n" +
6842 "OpReturn\n" +
6843 "OpFunctionEnd\n",
6844 4, true)
6845 ));
6846
6847 INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
6848 ::testing::Values(
6849 // Test case 0: merge of add of sub
6850 // (a - b) + b => a
6851 InstructionFoldingCase<bool>(
6852 Header() +
6853 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6854 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6855 "%main = OpFunction %void None %void_func\n" +
6856 "%main_lab = OpLabel\n" +
6857 "%var0 = OpVariable %_ptr_float Function\n" +
6858 "%var1 = OpVariable %_ptr_float Function\n" +
6859 "%3 = OpLoad %float %var0\n" +
6860 "%4 = OpLoad %float %var1\n" +
6861 "%5 = OpFSub %float %3 %4\n" +
6862 "%6 = OpFAdd %float %5 %4\n" +
6863 "OpReturn\n" +
6864 "OpFunctionEnd\n",
6865 6, true),
6866 // Test case 1: merge of add of sub
6867 // b + (a - b) => a
6868 InstructionFoldingCase<bool>(
6869 Header() +
6870 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6871 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6872 "%main = OpFunction %void None %void_func\n" +
6873 "%main_lab = OpLabel\n" +
6874 "%var0 = OpVariable %_ptr_float Function\n" +
6875 "%var1 = OpVariable %_ptr_float Function\n" +
6876 "%3 = OpLoad %float %var0\n" +
6877 "%4 = OpLoad %float %var1\n" +
6878 "%5 = OpFSub %float %3 %4\n" +
6879 "%6 = OpFAdd %float %4 %5\n" +
6880 "OpReturn\n" +
6881 "OpFunctionEnd\n",
6882 6, true)
6883 ));
6884
6885 INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
6886 ::testing::Values(
6887 // Test case 0: factor of add of muls
6888 // (a * b) + (a * c) => a * (b + c)
6889 InstructionFoldingCase<bool>(
6890 Header() +
6891 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6892 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6893 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6894 "%main = OpFunction %void None %void_func\n" +
6895 "%main_lab = OpLabel\n" +
6896 "%var0 = OpVariable %_ptr_float Function\n" +
6897 "%var1 = OpVariable %_ptr_float Function\n" +
6898 "%var2 = OpVariable %_ptr_float Function\n" +
6899 "%4 = OpLoad %float %var0\n" +
6900 "%5 = OpLoad %float %var1\n" +
6901 "%6 = OpLoad %float %var2\n" +
6902 "%7 = OpFMul %float %6 %4\n" +
6903 "%8 = OpFMul %float %6 %5\n" +
6904 "%9 = OpFAdd %float %7 %8\n" +
6905 "OpReturn\n" +
6906 "OpFunctionEnd\n",
6907 9, true),
6908 // Test case 1: factor of add of muls
6909 // (b * a) + (a * c) => a * (b + c)
6910 InstructionFoldingCase<bool>(
6911 Header() +
6912 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6913 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6914 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6915 "%main = OpFunction %void None %void_func\n" +
6916 "%main_lab = OpLabel\n" +
6917 "%var0 = OpVariable %_ptr_float Function\n" +
6918 "%var1 = OpVariable %_ptr_float Function\n" +
6919 "%var2 = OpVariable %_ptr_float Function\n" +
6920 "%4 = OpLoad %float %var0\n" +
6921 "%5 = OpLoad %float %var1\n" +
6922 "%6 = OpLoad %float %var2\n" +
6923 "%7 = OpFMul %float %4 %6\n" +
6924 "%8 = OpFMul %float %6 %5\n" +
6925 "%9 = OpFAdd %float %7 %8\n" +
6926 "OpReturn\n" +
6927 "OpFunctionEnd\n",
6928 9, true),
6929 // Test case 2: factor of add of muls
6930 // (a * b) + (c * a) => a * (b + c)
6931 InstructionFoldingCase<bool>(
6932 Header() +
6933 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6934 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6935 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6936 "%main = OpFunction %void None %void_func\n" +
6937 "%main_lab = OpLabel\n" +
6938 "%var0 = OpVariable %_ptr_float Function\n" +
6939 "%var1 = OpVariable %_ptr_float Function\n" +
6940 "%var2 = OpVariable %_ptr_float Function\n" +
6941 "%4 = OpLoad %float %var0\n" +
6942 "%5 = OpLoad %float %var1\n" +
6943 "%6 = OpLoad %float %var2\n" +
6944 "%7 = OpFMul %float %6 %4\n" +
6945 "%8 = OpFMul %float %5 %6\n" +
6946 "%9 = OpFAdd %float %7 %8\n" +
6947 "OpReturn\n" +
6948 "OpFunctionEnd\n",
6949 9, true),
6950 // Test case 3: factor of add of muls
6951 // (b * a) + (c * a) => a * (b + c)
6952 InstructionFoldingCase<bool>(
6953 Header() +
6954 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6955 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6956 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6957 "%main = OpFunction %void None %void_func\n" +
6958 "%main_lab = OpLabel\n" +
6959 "%var0 = OpVariable %_ptr_float Function\n" +
6960 "%var1 = OpVariable %_ptr_float Function\n" +
6961 "%var2 = OpVariable %_ptr_float Function\n" +
6962 "%4 = OpLoad %float %var0\n" +
6963 "%5 = OpLoad %float %var1\n" +
6964 "%6 = OpLoad %float %var2\n" +
6965 "%7 = OpFMul %float %4 %6\n" +
6966 "%8 = OpFMul %float %5 %6\n" +
6967 "%9 = OpFAdd %float %7 %8\n" +
6968 "OpReturn\n" +
6969 "OpFunctionEnd\n",
6970 9, true)
6971 ));
6972
6973 INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
6974 ::testing::Values(
6975 // Test case 0: merge sub of negate
6976 // (-x) - 2 = -2 - x
6977 InstructionFoldingCase<bool>(
6978 Header() +
6979 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6980 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
6981 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6982 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
6983 "%main = OpFunction %void None %void_func\n" +
6984 "%main_lab = OpLabel\n" +
6985 "%var = OpVariable %_ptr_float Function\n" +
6986 "%2 = OpLoad %float %var\n" +
6987 "%3 = OpFNegate %float %2\n" +
6988 "%4 = OpFSub %float %3 %float_2\n" +
6989 "OpReturn\n" +
6990 "OpFunctionEnd\n",
6991 4, true),
6992 // Test case 1: merge sub of negate
6993 // 2 - (-x) = x + 2
6994 InstructionFoldingCase<bool>(
6995 Header() +
6996 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6997 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6998 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6999 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
7000 "%main = OpFunction %void None %void_func\n" +
7001 "%main_lab = OpLabel\n" +
7002 "%var = OpVariable %_ptr_float Function\n" +
7003 "%2 = OpLoad %float %var\n" +
7004 "%3 = OpFNegate %float %2\n" +
7005 "%4 = OpFSub %float %float_2 %3\n" +
7006 "OpReturn\n" +
7007 "OpFunctionEnd\n",
7008 4, true),
7009 // Test case 2: merge sub of negate
7010 // (-x) - 2 = -2 - x
7011 InstructionFoldingCase<bool>(
7012 Header() +
7013 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7014 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
7015 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7016 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
7017 "%main = OpFunction %void None %void_func\n" +
7018 "%main_lab = OpLabel\n" +
7019 "%var = OpVariable %_ptr_long Function\n" +
7020 "%2 = OpLoad %long %var\n" +
7021 "%3 = OpSNegate %long %2\n" +
7022 "%4 = OpISub %long %3 %long_2\n" +
7023 "OpReturn\n" +
7024 "OpFunctionEnd\n",
7025 4, true),
7026 // Test case 3: merge sub of negate
7027 // 2 - (-x) = x + 2
7028 InstructionFoldingCase<bool>(
7029 Header() +
7030 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
7031 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
7032 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7033 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
7034 "%main = OpFunction %void None %void_func\n" +
7035 "%main_lab = OpLabel\n" +
7036 "%var = OpVariable %_ptr_long Function\n" +
7037 "%2 = OpLoad %long %var\n" +
7038 "%3 = OpSNegate %long %2\n" +
7039 "%4 = OpISub %long %long_2 %3\n" +
7040 "OpReturn\n" +
7041 "OpFunctionEnd\n",
7042 4, true),
7043 // Test case 4: merge add of subtract
7044 // (x + 2) - 1 = x + 1
7045 InstructionFoldingCase<bool>(
7046 Header() +
7047 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7048 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7049 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7050 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7051 "%main = OpFunction %void None %void_func\n" +
7052 "%main_lab = OpLabel\n" +
7053 "%var = OpVariable %_ptr_float Function\n" +
7054 "%2 = OpLoad %float %var\n" +
7055 "%3 = OpFAdd %float %2 %float_2\n" +
7056 "%4 = OpFSub %float %3 %float_1\n" +
7057 "OpReturn\n" +
7058 "OpFunctionEnd\n",
7059 4, true),
7060 // Test case 5: merge add of subtract
7061 // (2 + x) - 1 = x + 1
7062 InstructionFoldingCase<bool>(
7063 Header() +
7064 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7065 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7066 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7067 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7068 "%main = OpFunction %void None %void_func\n" +
7069 "%main_lab = OpLabel\n" +
7070 "%var = OpVariable %_ptr_float Function\n" +
7071 "%2 = OpLoad %float %var\n" +
7072 "%3 = OpFAdd %float %float_2 %2\n" +
7073 "%4 = OpFSub %float %3 %float_1\n" +
7074 "OpReturn\n" +
7075 "OpFunctionEnd\n",
7076 4, true),
7077 // Test case 6: merge add of subtract
7078 // 2 - (x + 1) = 1 - x
7079 InstructionFoldingCase<bool>(
7080 Header() +
7081 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7082 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7083 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7084 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7085 "%main = OpFunction %void None %void_func\n" +
7086 "%main_lab = OpLabel\n" +
7087 "%var = OpVariable %_ptr_float Function\n" +
7088 "%2 = OpLoad %float %var\n" +
7089 "%3 = OpFAdd %float %2 %float_1\n" +
7090 "%4 = OpFSub %float %float_2 %3\n" +
7091 "OpReturn\n" +
7092 "OpFunctionEnd\n",
7093 4, true),
7094 // Test case 7: merge add of subtract
7095 // 2 - (1 + x) = 1 - x
7096 InstructionFoldingCase<bool>(
7097 Header() +
7098 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7099 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7100 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7101 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7102 "%main = OpFunction %void None %void_func\n" +
7103 "%main_lab = OpLabel\n" +
7104 "%var = OpVariable %_ptr_float Function\n" +
7105 "%2 = OpLoad %float %var\n" +
7106 "%3 = OpFAdd %float %float_1 %2\n" +
7107 "%4 = OpFSub %float %float_2 %3\n" +
7108 "OpReturn\n" +
7109 "OpFunctionEnd\n",
7110 4, true),
7111 // Test case 8: merge subtract of subtract
7112 // (x - 2) - 1 = x - 3
7113 InstructionFoldingCase<bool>(
7114 Header() +
7115 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7116 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7117 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7118 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
7119 "%main = OpFunction %void None %void_func\n" +
7120 "%main_lab = OpLabel\n" +
7121 "%var = OpVariable %_ptr_float Function\n" +
7122 "%2 = OpLoad %float %var\n" +
7123 "%3 = OpFSub %float %2 %float_2\n" +
7124 "%4 = OpFSub %float %3 %float_1\n" +
7125 "OpReturn\n" +
7126 "OpFunctionEnd\n",
7127 4, true),
7128 // Test case 9: merge subtract of subtract
7129 // (2 - x) - 1 = 1 - x
7130 InstructionFoldingCase<bool>(
7131 Header() +
7132 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7133 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7134 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7135 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
7136 "%main = OpFunction %void None %void_func\n" +
7137 "%main_lab = OpLabel\n" +
7138 "%var = OpVariable %_ptr_float Function\n" +
7139 "%2 = OpLoad %float %var\n" +
7140 "%3 = OpFSub %float %float_2 %2\n" +
7141 "%4 = OpFSub %float %3 %float_1\n" +
7142 "OpReturn\n" +
7143 "OpFunctionEnd\n",
7144 4, true),
7145 // Test case 10: merge subtract of subtract
7146 // 2 - (x - 1) = 3 - x
7147 InstructionFoldingCase<bool>(
7148 Header() +
7149 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7150 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
7151 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7152 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
7153 "%main = OpFunction %void None %void_func\n" +
7154 "%main_lab = OpLabel\n" +
7155 "%var = OpVariable %_ptr_float Function\n" +
7156 "%2 = OpLoad %float %var\n" +
7157 "%3 = OpFSub %float %2 %float_1\n" +
7158 "%4 = OpFSub %float %float_2 %3\n" +
7159 "OpReturn\n" +
7160 "OpFunctionEnd\n",
7161 4, true),
7162 // Test case 11: merge subtract of subtract
7163 // 1 - (2 - x) = x + (-1)
7164 InstructionFoldingCase<bool>(
7165 Header() +
7166 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7167 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
7168 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7169 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
7170 "%main = OpFunction %void None %void_func\n" +
7171 "%main_lab = OpLabel\n" +
7172 "%var = OpVariable %_ptr_float Function\n" +
7173 "%2 = OpLoad %float %var\n" +
7174 "%3 = OpFSub %float %float_2 %2\n" +
7175 "%4 = OpFSub %float %float_1 %3\n" +
7176 "OpReturn\n" +
7177 "OpFunctionEnd\n",
7178 4, true),
7179 // Test case 12: merge subtract of subtract
7180 // 2 - (1 - x) = x + 1
7181 InstructionFoldingCase<bool>(
7182 Header() +
7183 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7184 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
7185 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
7186 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
7187 "%main = OpFunction %void None %void_func\n" +
7188 "%main_lab = OpLabel\n" +
7189 "%var = OpVariable %_ptr_float Function\n" +
7190 "%2 = OpLoad %float %var\n" +
7191 "%3 = OpFSub %float %float_1 %2\n" +
7192 "%4 = OpFSub %float %float_2 %3\n" +
7193 "OpReturn\n" +
7194 "OpFunctionEnd\n",
7195 4, true),
7196 // Test case 13: merge subtract of subtract with mixed types.
7197 // 2 - (1 - x) = x + 1
7198 InstructionFoldingCase<bool>(
7199 Header() +
7200 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7201 "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" +
7202 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7203 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" +
7204 "%main = OpFunction %void None %void_func\n" +
7205 "%main_lab = OpLabel\n" +
7206 "%var = OpVariable %_ptr_int Function\n" +
7207 "%2 = OpLoad %int %var\n" +
7208 "%3 = OpISub %int %uint_1 %2\n" +
7209 "%4 = OpISub %int %int_2 %3\n" +
7210 "OpReturn\n" +
7211 "OpFunctionEnd\n",
7212 4, true),
7213 // Test case 14: fold overflowing signed 32 bit isubs
7214 // (x - int_max) - 1 = x - int_min
7215 InstructionFoldingCase<bool>(
7216 Header() +
7217 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
7218 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
7219 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
7220 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" +
7221 "%main = OpFunction %void None %void_func\n" +
7222 "%main_lab = OpLabel\n" +
7223 "%var = OpVariable %_ptr_int Function\n" +
7224 "%2 = OpLoad %int %var\n" +
7225 "%3 = OpISub %int %2 %int_max\n" +
7226 "%4 = OpISub %int %3 %int_1\n" +
7227 "OpReturn\n" +
7228 "OpFunctionEnd\n",
7229 4, true),
7230 // Test case 15: fold overflowing signed 64 bit isubs
7231 // (x - long_max) - 1 = x - long_min
7232 InstructionFoldingCase<bool>(
7233 Header() +
7234 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
7235 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
7236 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
7237 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" +
7238 "%main = OpFunction %void None %void_func\n" +
7239 "%main_lab = OpLabel\n" +
7240 "%var = OpVariable %_ptr_long Function\n" +
7241 "%2 = OpLoad %long %var\n" +
7242 "%3 = OpISub %long %2 %long_max\n" +
7243 "%4 = OpISub %long %3 %long_1\n" +
7244 "OpReturn\n" +
7245 "OpFunctionEnd\n",
7246 4, true)
7247 ));
7248
7249 INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
7250 ::testing::Values(
7251 // Test case 0: Fold select with the same values for both sides
7252 InstructionFoldingCase<bool>(
7253 Header() +
7254 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7255 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7256 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7257 "%main = OpFunction %void None %void_func\n" +
7258 "%main_lab = OpLabel\n" +
7259 "%n = OpVariable %_ptr_bool Function\n" +
7260 "%load = OpLoad %bool %n\n" +
7261 "%2 = OpSelect %int %load %100 %100\n" +
7262 "OpReturn\n" +
7263 "OpFunctionEnd",
7264 2, true),
7265 // Test case 1: Fold select true to left side
7266 InstructionFoldingCase<bool>(
7267 Header() +
7268 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7269 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7270 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7271 "%main = OpFunction %void None %void_func\n" +
7272 "%main_lab = OpLabel\n" +
7273 "%n = OpVariable %_ptr_int Function\n" +
7274 "%load = OpLoad %bool %n\n" +
7275 "%2 = OpSelect %int %true %100 %n\n" +
7276 "OpReturn\n" +
7277 "OpFunctionEnd",
7278 2, true),
7279 // Test case 2: Fold select false to right side
7280 InstructionFoldingCase<bool>(
7281 Header() +
7282 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7283 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7284 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7285 "%main = OpFunction %void None %void_func\n" +
7286 "%main_lab = OpLabel\n" +
7287 "%n = OpVariable %_ptr_int Function\n" +
7288 "%load = OpLoad %bool %n\n" +
7289 "%2 = OpSelect %int %false %n %100\n" +
7290 "OpReturn\n" +
7291 "OpFunctionEnd",
7292 2, true),
7293 // Test case 3: Fold select null to right side
7294 InstructionFoldingCase<bool>(
7295 Header() +
7296 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7297 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7298 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7299 "%main = OpFunction %void None %void_func\n" +
7300 "%main_lab = OpLabel\n" +
7301 "%n = OpVariable %_ptr_int Function\n" +
7302 "%load = OpLoad %int %n\n" +
7303 "%2 = OpSelect %int %bool_null %load %100\n" +
7304 "OpReturn\n" +
7305 "OpFunctionEnd",
7306 2, true),
7307 // Test case 4: vector null
7308 InstructionFoldingCase<bool>(
7309 Header() +
7310 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7311 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7312 "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7313 "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
7314 "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
7315 "%main = OpFunction %void None %void_func\n" +
7316 "%main_lab = OpLabel\n" +
7317 "%n = OpVariable %_ptr_v2int Function\n" +
7318 "%load = OpLoad %v2int %n\n" +
7319 "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
7320 "OpReturn\n" +
7321 "OpFunctionEnd",
7322 2, true),
7323 // Test case 5: vector select
7324 InstructionFoldingCase<bool>(
7325 Header() +
7326 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7327 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7328 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
7329 "%main = OpFunction %void None %void_func\n" +
7330 "%main_lab = OpLabel\n" +
7331 "%m = OpVariable %_ptr_v2int Function\n" +
7332 "%n = OpVariable %_ptr_v2int Function\n" +
7333 "%2 = OpLoad %v2int %n\n" +
7334 "%3 = OpLoad %v2int %n\n" +
7335 "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
7336 "OpReturn\n" +
7337 "OpFunctionEnd",
7338 4, true),
7339 // Test case 6: vector select
7340 InstructionFoldingCase<bool>(
7341 Header() +
7342 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7343 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7344 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
7345 "%main = OpFunction %void None %void_func\n" +
7346 "%main_lab = OpLabel\n" +
7347 "%m = OpVariable %_ptr_v2int Function\n" +
7348 "%n = OpVariable %_ptr_v2int Function\n" +
7349 "%2 = OpLoad %v2int %n\n" +
7350 "%3 = OpLoad %v2int %n\n" +
7351 "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
7352 "OpReturn\n" +
7353 "OpFunctionEnd",
7354 4, true)
7355 ));
7356
7357 INSTANTIATE_TEST_SUITE_P(CompositeExtractOrInsertMatchingTest, MatchingInstructionFoldingTest,
7358 ::testing::Values(
7359 // Test case 0: Extracting from result of consecutive shuffles of differing
7360 // size.
7361 InstructionFoldingCase<bool>(
7362 Header() +
7363 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7364 "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
7365 "%main = OpFunction %void None %void_func\n" +
7366 "%main_lab = OpLabel\n" +
7367 "%n = OpVariable %_ptr_v4int Function\n" +
7368 "%2 = OpLoad %v4int %n\n" +
7369 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7370 "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
7371 "%5 = OpCompositeExtract %int %4 1\n" +
7372 "OpReturn\n" +
7373 "OpFunctionEnd",
7374 5, true),
7375 // Test case 1: Extracting from result of vector shuffle of differing
7376 // input and result sizes.
7377 InstructionFoldingCase<bool>(
7378 Header() +
7379 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7380 "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
7381 "%main = OpFunction %void None %void_func\n" +
7382 "%main_lab = OpLabel\n" +
7383 "%n = OpVariable %_ptr_v4int Function\n" +
7384 "%2 = OpLoad %v4int %n\n" +
7385 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7386 "%4 = OpCompositeExtract %int %3 0\n" +
7387 "OpReturn\n" +
7388 "OpFunctionEnd",
7389 4, true),
7390 // Test case 2: Extracting from result of vector shuffle of differing
7391 // input and result sizes.
7392 InstructionFoldingCase<bool>(
7393 Header() +
7394 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7395 "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
7396 "%main = OpFunction %void None %void_func\n" +
7397 "%main_lab = OpLabel\n" +
7398 "%n = OpVariable %_ptr_v4int Function\n" +
7399 "%2 = OpLoad %v4int %n\n" +
7400 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7401 "%4 = OpCompositeExtract %int %3 1\n" +
7402 "OpReturn\n" +
7403 "OpFunctionEnd",
7404 4, true),
7405 // Test case 3: Using fmix feeding extract with a 1 in the a position.
7406 InstructionFoldingCase<bool>(
7407 Header() +
7408 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7409 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7410 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7411 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7412 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7413 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
7414 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
7415 "%main = OpFunction %void None %void_func\n" +
7416 "%main_lab = OpLabel\n" +
7417 "%m = OpVariable %_ptr_v4double Function\n" +
7418 "%n = OpVariable %_ptr_v4double Function\n" +
7419 "%2 = OpLoad %v4double %m\n" +
7420 "%3 = OpLoad %v4double %n\n" +
7421 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7422 "%5 = OpCompositeExtract %double %4 1\n" +
7423 "OpReturn\n" +
7424 "OpFunctionEnd",
7425 5, true),
7426 // Test case 4: Using fmix feeding extract with a 0 in the a position.
7427 InstructionFoldingCase<bool>(
7428 Header() +
7429 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7430 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7431 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7432 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7433 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7434 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7435 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
7436 "%main = OpFunction %void None %void_func\n" +
7437 "%main_lab = OpLabel\n" +
7438 "%m = OpVariable %_ptr_v4double Function\n" +
7439 "%n = OpVariable %_ptr_v4double Function\n" +
7440 "%2 = OpLoad %v4double %m\n" +
7441 "%3 = OpLoad %v4double %n\n" +
7442 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7443 "%5 = OpCompositeExtract %double %4 2\n" +
7444 "OpReturn\n" +
7445 "OpFunctionEnd",
7446 5, true),
7447 // Test case 5: Using fmix feeding extract with a null for the alpha
7448 InstructionFoldingCase<bool>(
7449 Header() +
7450 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7451 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7452 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7453 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7454 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7455 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7456 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
7457 "%main = OpFunction %void None %void_func\n" +
7458 "%main_lab = OpLabel\n" +
7459 "%m = OpVariable %_ptr_v4double Function\n" +
7460 "%n = OpVariable %_ptr_v4double Function\n" +
7461 "%2 = OpLoad %v4double %m\n" +
7462 "%3 = OpLoad %v4double %n\n" +
7463 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
7464 "%5 = OpCompositeExtract %double %4 0\n" +
7465 "OpReturn\n" +
7466 "OpFunctionEnd",
7467 5, true),
7468 // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
7469 // position.
7470 InstructionFoldingCase<bool>(
7471 Header() +
7472 "%main = OpFunction %void None %void_func\n" +
7473 "%main_lab = OpLabel\n" +
7474 "%m = OpVariable %_ptr_v4double Function\n" +
7475 "%n = OpVariable %_ptr_v4double Function\n" +
7476 "%2 = OpLoad %v4double %m\n" +
7477 "%3 = OpLoad %v4double %n\n" +
7478 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
7479 "%5 = OpCompositeExtract %double %4 3\n" +
7480 "OpReturn\n" +
7481 "OpFunctionEnd",
7482 5, false),
7483 // Test case 7: Extracting the undefined literal value from a vector
7484 // shuffle.
7485 InstructionFoldingCase<bool>(
7486 Header() +
7487 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7488 "; CHECK: %4 = OpUndef [[int]]\n" +
7489 "%main = OpFunction %void None %void_func\n" +
7490 "%main_lab = OpLabel\n" +
7491 "%n = OpVariable %_ptr_v4int Function\n" +
7492 "%2 = OpLoad %v4int %n\n" +
7493 "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
7494 "%4 = OpCompositeExtract %int %3 1\n" +
7495 "OpReturn\n" +
7496 "OpFunctionEnd",
7497 4, true),
7498 // Test case 8: Inserting every element of a vector turns into a composite construct.
7499 InstructionFoldingCase<bool>(
7500 Header() +
7501 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7502 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7503 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7504 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7505 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7506 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7507 "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7508 "%main = OpFunction %void None %void_func\n" +
7509 "%main_lab = OpLabel\n" +
7510 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7511 "%3 = OpCompositeInsert %v4int %int_1 %2 1\n" +
7512 "%4 = OpCompositeInsert %v4int %int_2 %3 2\n" +
7513 "%5 = OpCompositeInsert %v4int %int_3 %4 3\n" +
7514 "OpReturn\n" +
7515 "OpFunctionEnd",
7516 5, true),
7517 // Test case 9: Inserting every element of a vector turns into a composite construct in a different order.
7518 InstructionFoldingCase<bool>(
7519 Header() +
7520 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7521 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7522 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7523 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7524 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7525 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7526 "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7527 "%main = OpFunction %void None %void_func\n" +
7528 "%main_lab = OpLabel\n" +
7529 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7530 "%4 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7531 "%3 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7532 "%5 = OpCompositeInsert %v4int %int_3 %3 3\n" +
7533 "OpReturn\n" +
7534 "OpFunctionEnd",
7535 5, true),
7536 // Test case 10: Check multiple inserts to the same position are handled correctly.
7537 InstructionFoldingCase<bool>(
7538 Header() +
7539 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7540 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7541 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7542 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7543 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7544 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7545 "; CHECK: %6 = OpCopyObject [[v4]] [[construct]]\n" +
7546 "%main = OpFunction %void None %void_func\n" +
7547 "%main_lab = OpLabel\n" +
7548 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7549 "%3 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7550 "%4 = OpCompositeInsert %v4int %int_4 %3 1\n" +
7551 "%5 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7552 "%6 = OpCompositeInsert %v4int %int_3 %5 3\n" +
7553 "OpReturn\n" +
7554 "OpFunctionEnd",
7555 6, true),
7556 // Test case 11: The last indexes are 0 and 1, but they have different first indexes. This should not be folded.
7557 InstructionFoldingCase<bool>(
7558 Header() +
7559 "%main = OpFunction %void None %void_func\n" +
7560 "%main_lab = OpLabel\n" +
7561 "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7562 "%3 = OpCompositeInsert %m2x2int %int_1 %2 1 1\n" +
7563 "OpReturn\n" +
7564 "OpFunctionEnd",
7565 3, false),
7566 // Test case 12: Don't fold when there is a partial insertion.
7567 InstructionFoldingCase<bool>(
7568 Header() +
7569 "%main = OpFunction %void None %void_func\n" +
7570 "%main_lab = OpLabel\n" +
7571 "%2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0\n" +
7572 "%3 = OpCompositeInsert %m2x2int %int_4 %2 0 0\n" +
7573 "%4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1\n" +
7574 "OpReturn\n" +
7575 "OpFunctionEnd",
7576 4, false),
7577 // Test case 13: Insert into a column of a matrix
7578 InstructionFoldingCase<bool>(
7579 Header() +
7580 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7581 "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7582 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7583 "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7584 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7585 // We keep this insert in the chain. DeadInsertElimPass should remove it.
7586 "; CHECK: [[insert:%\\w+]] = OpCompositeInsert [[m2x2]] %100 [[m2x2_undef]] 0 0\n" +
7587 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7588 "; CHECK: %3 = OpCompositeInsert [[m2x2]] [[construct]] [[insert]] 0\n" +
7589 "%main = OpFunction %void None %void_func\n" +
7590 "%main_lab = OpLabel\n" +
7591 "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7592 "%3 = OpCompositeInsert %m2x2int %int_1 %2 0 1\n" +
7593 "OpReturn\n" +
7594 "OpFunctionEnd",
7595 3, true),
7596 // Test case 14: Insert all elements of the matrix.
7597 InstructionFoldingCase<bool>(
7598 Header() +
7599 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7600 "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7601 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7602 "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7603 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7604 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7605 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7606 "; CHECK: [[c0:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7607 "; CHECK: [[c1:%\\w+]] = OpCompositeConstruct [[v2]] [[int2]] [[int3]]\n" +
7608 "; CHECK: [[matrix:%\\w+]] = OpCompositeConstruct [[m2x2]] [[c0]] [[c1]]\n" +
7609 "; CHECK: %5 = OpCopyObject [[m2x2]] [[matrix]]\n" +
7610 "%main = OpFunction %void None %void_func\n" +
7611 "%main_lab = OpLabel\n" +
7612 "%2 = OpCompositeConstruct %v2int %100 %int_1\n" +
7613 "%3 = OpCompositeInsert %m2x2int %2 %m2x2int_undef 0\n" +
7614 "%4 = OpCompositeInsert %m2x2int %int_2 %3 1 0\n" +
7615 "%5 = OpCompositeInsert %m2x2int %int_3 %4 1 1\n" +
7616 "OpReturn\n" +
7617 "OpFunctionEnd",
7618 5, true),
7619 // Test case 15: Replace construct with extract when reconstructing a member
7620 // of another object.
7621 InstructionFoldingCase<bool>(
7622 Header() +
7623 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7624 "; CHECK: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7625 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7626 "; CHECK: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7627 "; CHECK: %5 = OpCompositeExtract [[v2]] [[m2x2_undef]]\n" +
7628 "%main = OpFunction %void None %void_func\n" +
7629 "%main_lab = OpLabel\n" +
7630 "%3 = OpCompositeExtract %int %m2x2int_undef 1 0\n" +
7631 "%4 = OpCompositeExtract %int %m2x2int_undef 1 1\n" +
7632 "%5 = OpCompositeConstruct %v2int %3 %4\n" +
7633 "OpReturn\n" +
7634 "OpFunctionEnd",
7635 5, true),
7636 // Test case 16: Don't fold when type cannot be deduced to a constant.
7637 InstructionFoldingCase<bool>(
7638 Header() +
7639 "%main = OpFunction %void None %void_func\n" +
7640 "%main_lab = OpLabel\n" +
7641 "%4 = OpCompositeInsert %struct_v2int_int_int %int_1 %struct_v2int_int_int_null 2\n" +
7642 "OpReturn\n" +
7643 "OpFunctionEnd",
7644 4, false),
7645 // Test case 17: Don't fold when index into composite is out of bounds.
7646 InstructionFoldingCase<bool>(
7647 Header() +
7648 "%main = OpFunction %void None %void_func\n" +
7649 "%main_lab = OpLabel\n" +
7650 "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" +
7651 "OpReturn\n" +
7652 "OpFunctionEnd",
7653 4, false),
7654 // Test case 18: Fold when every element of an array is inserted.
7655 InstructionFoldingCase<bool>(
7656 Header() +
7657 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7658 "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7659 "; CHECK-DAG: [[arr_type:%\\w+]] = OpTypeArray [[int]] [[int2]]\n" +
7660 "; CHECK-DAG: [[int10:%\\w+]] = OpConstant [[int]] 10\n" +
7661 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7662 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[arr_type]] [[int10]] [[int1]]\n" +
7663 "; CHECK: %5 = OpCopyObject [[arr_type]] [[construct]]\n" +
7664 "%main = OpFunction %void None %void_func\n" +
7665 "%main_lab = OpLabel\n" +
7666 "%4 = OpCompositeInsert %int_arr_2 %int_10 %int_arr_2_undef 0\n" +
7667 "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" +
7668 "OpReturn\n" +
7669 "OpFunctionEnd",
7670 5, true)
7671 ));
7672
7673 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
7674 ::testing::Values(
7675 // Test case 0: Using OpDot to extract last element.
7676 InstructionFoldingCase<bool>(
7677 Header() +
7678 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7679 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7680 "%main = OpFunction %void None %void_func\n" +
7681 "%main_lab = OpLabel\n" +
7682 "%n = OpVariable %_ptr_v4float Function\n" +
7683 "%2 = OpLoad %v4float %n\n" +
7684 "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
7685 "OpReturn\n" +
7686 "OpFunctionEnd",
7687 3, true),
7688 // Test case 1: Using OpDot to extract last element.
7689 InstructionFoldingCase<bool>(
7690 Header() +
7691 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7692 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7693 "%main = OpFunction %void None %void_func\n" +
7694 "%main_lab = OpLabel\n" +
7695 "%n = OpVariable %_ptr_v4float Function\n" +
7696 "%2 = OpLoad %v4float %n\n" +
7697 "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
7698 "OpReturn\n" +
7699 "OpFunctionEnd",
7700 3, true),
7701 // Test case 2: Using OpDot to extract second element.
7702 InstructionFoldingCase<bool>(
7703 Header() +
7704 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7705 "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
7706 "%main = OpFunction %void None %void_func\n" +
7707 "%main_lab = OpLabel\n" +
7708 "%n = OpVariable %_ptr_v4float Function\n" +
7709 "%2 = OpLoad %v4float %n\n" +
7710 "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
7711 "OpReturn\n" +
7712 "OpFunctionEnd",
7713 3, true),
7714 // Test case 3: Using OpDot to extract last element.
7715 InstructionFoldingCase<bool>(
7716 Header() +
7717 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7718 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7719 "%main = OpFunction %void None %void_func\n" +
7720 "%main_lab = OpLabel\n" +
7721 "%n = OpVariable %_ptr_v4double Function\n" +
7722 "%2 = OpLoad %v4double %n\n" +
7723 "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
7724 "OpReturn\n" +
7725 "OpFunctionEnd",
7726 3, true),
7727 // Test case 4: Using OpDot to extract last element.
7728 InstructionFoldingCase<bool>(
7729 Header() +
7730 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7731 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7732 "%main = OpFunction %void None %void_func\n" +
7733 "%main_lab = OpLabel\n" +
7734 "%n = OpVariable %_ptr_v4double Function\n" +
7735 "%2 = OpLoad %v4double %n\n" +
7736 "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
7737 "OpReturn\n" +
7738 "OpFunctionEnd",
7739 3, true),
7740 // Test case 5: Using OpDot to extract second element.
7741 InstructionFoldingCase<bool>(
7742 Header() +
7743 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7744 "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
7745 "%main = OpFunction %void None %void_func\n" +
7746 "%main_lab = OpLabel\n" +
7747 "%n = OpVariable %_ptr_v4double Function\n" +
7748 "%2 = OpLoad %v4double %n\n" +
7749 "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
7750 "OpReturn\n" +
7751 "OpFunctionEnd",
7752 3, true)
7753 ));
7754
7755 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionFoldingTest,
7756 ::testing::Values(
7757 // Test case 0: Using OpDot to extract last element.
7758 InstructionFoldingCase<bool>(
7759 Header() +
7760 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7761 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
7762 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v2int]]\n" +
7763 "; CHECK: OpVectorShuffle\n" +
7764 "; CHECK: %3 = OpVectorShuffle [[v2int]] [[null]] {{%\\w+}} 4294967295 2\n" +
7765 "%main = OpFunction %void None %void_func\n" +
7766 "%main_lab = OpLabel\n" +
7767 "%n = OpVariable %_ptr_int Function\n" +
7768 "%load = OpLoad %int %n\n" +
7769 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 3 0xFFFFFFFF \n" +
7770 "%3 = OpVectorShuffle %v2int %2 %v2int_2_3 1 2 \n" +
7771 "OpReturn\n" +
7772 "OpFunctionEnd",
7773 3, true)
7774 ));
7775
7776 INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest,
7777 ::testing::Values(
7778 // Test case 0: (x * y) + a = Fma(x, y, a)
7779 InstructionFoldingCase<bool>(
7780 Header() +
7781 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7782 "; CHECK: OpFunction\n" +
7783 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7784 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7785 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7786 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7787 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7788 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7789 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7790 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7791 "%main = OpFunction %void None %void_func\n" +
7792 "%main_lab = OpLabel\n" +
7793 "%x = OpVariable %_ptr_float Function\n" +
7794 "%y = OpVariable %_ptr_float Function\n" +
7795 "%a = OpVariable %_ptr_float Function\n" +
7796 "%lx = OpLoad %float %x\n" +
7797 "%ly = OpLoad %float %y\n" +
7798 "%mul = OpFMul %float %lx %ly\n" +
7799 "%la = OpLoad %float %a\n" +
7800 "%3 = OpFAdd %float %mul %la\n" +
7801 "OpStore %a %3\n" +
7802 "OpReturn\n" +
7803 "OpFunctionEnd",
7804 3, true),
7805 // Test case 1: a + (x * y) = Fma(x, y, a)
7806 InstructionFoldingCase<bool>(
7807 Header() +
7808 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7809 "; CHECK: OpFunction\n" +
7810 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7811 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7812 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7813 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7814 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7815 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7816 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7817 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7818 "%main = OpFunction %void None %void_func\n" +
7819 "%main_lab = OpLabel\n" +
7820 "%x = OpVariable %_ptr_float Function\n" +
7821 "%y = OpVariable %_ptr_float Function\n" +
7822 "%a = OpVariable %_ptr_float Function\n" +
7823 "%lx = OpLoad %float %x\n" +
7824 "%ly = OpLoad %float %y\n" +
7825 "%mul = OpFMul %float %lx %ly\n" +
7826 "%la = OpLoad %float %a\n" +
7827 "%3 = OpFAdd %float %la %mul\n" +
7828 "OpStore %a %3\n" +
7829 "OpReturn\n" +
7830 "OpFunctionEnd",
7831 3, true),
7832 // Test case 2: (x * y) + a = Fma(x, y, a) with vectors
7833 InstructionFoldingCase<bool>(
7834 Header() +
7835 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7836 "; CHECK: OpFunction\n" +
7837 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7838 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7839 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7840 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7841 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7842 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7843 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7844 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7845 "%main = OpFunction %void None %void_func\n" +
7846 "%main_lab = OpLabel\n" +
7847 "%x = OpVariable %_ptr_v4float Function\n" +
7848 "%y = OpVariable %_ptr_v4float Function\n" +
7849 "%a = OpVariable %_ptr_v4float Function\n" +
7850 "%lx = OpLoad %v4float %x\n" +
7851 "%ly = OpLoad %v4float %y\n" +
7852 "%mul = OpFMul %v4float %lx %ly\n" +
7853 "%la = OpLoad %v4float %a\n" +
7854 "%3 = OpFAdd %v4float %mul %la\n" +
7855 "OpStore %a %3\n" +
7856 "OpReturn\n" +
7857 "OpFunctionEnd",
7858 3, true),
7859 // Test case 3: a + (x * y) = Fma(x, y, a) with vectors
7860 InstructionFoldingCase<bool>(
7861 Header() +
7862 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7863 "; CHECK: OpFunction\n" +
7864 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7865 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7866 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7867 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7868 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7869 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7870 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7871 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7872 "%main = OpFunction %void None %void_func\n" +
7873 "%main_lab = OpLabel\n" +
7874 "%x = OpVariable %_ptr_float Function\n" +
7875 "%y = OpVariable %_ptr_float Function\n" +
7876 "%a = OpVariable %_ptr_float Function\n" +
7877 "%lx = OpLoad %float %x\n" +
7878 "%ly = OpLoad %float %y\n" +
7879 "%mul = OpFMul %float %lx %ly\n" +
7880 "%la = OpLoad %float %a\n" +
7881 "%3 = OpFAdd %float %la %mul\n" +
7882 "OpStore %a %3\n" +
7883 "OpReturn\n" +
7884 "OpFunctionEnd",
7885 3, true),
7886 // Test 4: that the OpExtInstImport instruction is generated if it is missing.
7887 InstructionFoldingCase<bool>(
7888 std::string() +
7889 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7890 "; CHECK: OpFunction\n" +
7891 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7892 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7893 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7894 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7895 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7896 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7897 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7898 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7899 "OpCapability Shader\n" +
7900 "OpMemoryModel Logical GLSL450\n" +
7901 "OpEntryPoint Fragment %main \"main\"\n" +
7902 "OpExecutionMode %main OriginUpperLeft\n" +
7903 "OpSource GLSL 140\n" +
7904 "OpName %main \"main\"\n" +
7905 "%void = OpTypeVoid\n" +
7906 "%void_func = OpTypeFunction %void\n" +
7907 "%bool = OpTypeBool\n" +
7908 "%float = OpTypeFloat 32\n" +
7909 "%_ptr_float = OpTypePointer Function %float\n" +
7910 "%main = OpFunction %void None %void_func\n" +
7911 "%main_lab = OpLabel\n" +
7912 "%x = OpVariable %_ptr_float Function\n" +
7913 "%y = OpVariable %_ptr_float Function\n" +
7914 "%a = OpVariable %_ptr_float Function\n" +
7915 "%lx = OpLoad %float %x\n" +
7916 "%ly = OpLoad %float %y\n" +
7917 "%mul = OpFMul %float %lx %ly\n" +
7918 "%la = OpLoad %float %a\n" +
7919 "%3 = OpFAdd %float %mul %la\n" +
7920 "OpStore %a %3\n" +
7921 "OpReturn\n" +
7922 "OpFunctionEnd",
7923 3, true),
7924 // Test 5: Don't fold if the multiple is marked no contract.
7925 InstructionFoldingCase<bool>(
7926 std::string() +
7927 "OpCapability Shader\n" +
7928 "OpMemoryModel Logical GLSL450\n" +
7929 "OpEntryPoint Fragment %main \"main\"\n" +
7930 "OpExecutionMode %main OriginUpperLeft\n" +
7931 "OpSource GLSL 140\n" +
7932 "OpName %main \"main\"\n" +
7933 "OpDecorate %mul NoContraction\n" +
7934 "%void = OpTypeVoid\n" +
7935 "%void_func = OpTypeFunction %void\n" +
7936 "%bool = OpTypeBool\n" +
7937 "%float = OpTypeFloat 32\n" +
7938 "%_ptr_float = OpTypePointer Function %float\n" +
7939 "%main = OpFunction %void None %void_func\n" +
7940 "%main_lab = OpLabel\n" +
7941 "%x = OpVariable %_ptr_float Function\n" +
7942 "%y = OpVariable %_ptr_float Function\n" +
7943 "%a = OpVariable %_ptr_float Function\n" +
7944 "%lx = OpLoad %float %x\n" +
7945 "%ly = OpLoad %float %y\n" +
7946 "%mul = OpFMul %float %lx %ly\n" +
7947 "%la = OpLoad %float %a\n" +
7948 "%3 = OpFAdd %float %mul %la\n" +
7949 "OpStore %a %3\n" +
7950 "OpReturn\n" +
7951 "OpFunctionEnd",
7952 3, false),
7953 // Test 6: Don't fold if the add is marked no contract.
7954 InstructionFoldingCase<bool>(
7955 std::string() +
7956 "OpCapability Shader\n" +
7957 "OpMemoryModel Logical GLSL450\n" +
7958 "OpEntryPoint Fragment %main \"main\"\n" +
7959 "OpExecutionMode %main OriginUpperLeft\n" +
7960 "OpSource GLSL 140\n" +
7961 "OpName %main \"main\"\n" +
7962 "OpDecorate %3 NoContraction\n" +
7963 "%void = OpTypeVoid\n" +
7964 "%void_func = OpTypeFunction %void\n" +
7965 "%bool = OpTypeBool\n" +
7966 "%float = OpTypeFloat 32\n" +
7967 "%_ptr_float = OpTypePointer Function %float\n" +
7968 "%main = OpFunction %void None %void_func\n" +
7969 "%main_lab = OpLabel\n" +
7970 "%x = OpVariable %_ptr_float Function\n" +
7971 "%y = OpVariable %_ptr_float Function\n" +
7972 "%a = OpVariable %_ptr_float Function\n" +
7973 "%lx = OpLoad %float %x\n" +
7974 "%ly = OpLoad %float %y\n" +
7975 "%mul = OpFMul %float %lx %ly\n" +
7976 "%la = OpLoad %float %a\n" +
7977 "%3 = OpFAdd %float %mul %la\n" +
7978 "OpStore %a %3\n" +
7979 "OpReturn\n" +
7980 "OpFunctionEnd",
7981 3, false),
7982 // Test case 7: (x * y) - a = Fma(x, y, -a)
7983 InstructionFoldingCase<bool>(
7984 Header() +
7985 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7986 "; CHECK: OpFunction\n" +
7987 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7988 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7989 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7990 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7991 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7992 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7993 "; CHECK: [[na:%\\w+]] = OpFNegate {{%\\w+}} [[la]]\n" +
7994 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[na]]\n" +
7995 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7996 "%main = OpFunction %void None %void_func\n" +
7997 "%main_lab = OpLabel\n" +
7998 "%x = OpVariable %_ptr_float Function\n" +
7999 "%y = OpVariable %_ptr_float Function\n" +
8000 "%a = OpVariable %_ptr_float Function\n" +
8001 "%lx = OpLoad %float %x\n" +
8002 "%ly = OpLoad %float %y\n" +
8003 "%mul = OpFMul %float %lx %ly\n" +
8004 "%la = OpLoad %float %a\n" +
8005 "%3 = OpFSub %float %mul %la\n" +
8006 "OpStore %a %3\n" +
8007 "OpReturn\n" +
8008 "OpFunctionEnd",
8009 3, true),
8010 // Test case 8: a - (x * y) = Fma(-x, y, a)
8011 InstructionFoldingCase<bool>(
8012 Header() +
8013 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
8014 "; CHECK: OpFunction\n" +
8015 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8016 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8017 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
8018 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
8019 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
8020 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
8021 "; CHECK: [[nx:%\\w+]] = OpFNegate {{%\\w+}} [[lx]]\n" +
8022 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[nx]] [[ly]] [[la]]\n" +
8023 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
8024 "%main = OpFunction %void None %void_func\n" +
8025 "%main_lab = OpLabel\n" +
8026 "%x = OpVariable %_ptr_float Function\n" +
8027 "%y = OpVariable %_ptr_float Function\n" +
8028 "%a = OpVariable %_ptr_float Function\n" +
8029 "%lx = OpLoad %float %x\n" +
8030 "%ly = OpLoad %float %y\n" +
8031 "%mul = OpFMul %float %lx %ly\n" +
8032 "%la = OpLoad %float %a\n" +
8033 "%3 = OpFSub %float %la %mul\n" +
8034 "OpStore %a %3\n" +
8035 "OpReturn\n" +
8036 "OpFunctionEnd",
8037 3, true)
8038 ));
8039
8040 using MatchingInstructionWithNoResultFoldingTest =
8041 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8042
8043 // Test folding instructions that do not have a result. The instruction
8044 // that will be folded is the last instruction before the return. If there
8045 // are multiple returns, there is not guarantee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest, Case)8046 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
8047 const auto& tc = GetParam();
8048
8049 // Build module.
8050 std::unique_ptr<IRContext> context =
8051 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8052 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8053 ASSERT_NE(nullptr, context);
8054
8055 // Fold the instruction to test.
8056 Instruction* inst = nullptr;
8057 Function* func = &*context->module()->begin();
8058 for (auto& bb : *func) {
8059 Instruction* terminator = bb.terminator();
8060 if (terminator->IsReturnOrAbort()) {
8061 inst = terminator->PreviousNode();
8062 break;
8063 }
8064 }
8065 assert(inst && "Invalid test. Could not find instruction to fold.");
8066 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8067 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8068 EXPECT_EQ(succeeded, tc.expected_result);
8069 if (succeeded) {
8070 Match(tc.test_body, context.get());
8071 }
8072 }
8073
8074 INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8075 ::testing::Values(
8076 // Test case 0: Remove store of undef.
8077 InstructionFoldingCase<bool>(
8078 Header() +
8079 "; CHECK: OpLabel\n" +
8080 "; CHECK-NOT: OpStore\n" +
8081 "; CHECK: OpReturn\n" +
8082 "%main = OpFunction %void None %void_func\n" +
8083 "%main_lab = OpLabel\n" +
8084 "%n = OpVariable %_ptr_v4double Function\n" +
8085 "%undef = OpUndef %v4double\n" +
8086 "OpStore %n %undef\n" +
8087 "OpReturn\n" +
8088 "OpFunctionEnd",
8089 0 /* OpStore */, true),
8090 // Test case 1: Keep volatile store.
8091 InstructionFoldingCase<bool>(
8092 Header() +
8093 "%main = OpFunction %void None %void_func\n" +
8094 "%main_lab = OpLabel\n" +
8095 "%n = OpVariable %_ptr_v4double Function\n" +
8096 "%undef = OpUndef %v4double\n" +
8097 "OpStore %n %undef Volatile\n" +
8098 "OpReturn\n" +
8099 "OpFunctionEnd",
8100 0 /* OpStore */, false)
8101 ));
8102
8103 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
8104 ::testing::Values(
8105 // Test case 0: Basic test 1
8106 InstructionFoldingCase<bool>(
8107 Header() +
8108 "; CHECK: OpVectorShuffle\n" +
8109 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
8110 "; CHECK: OpReturn\n" +
8111 "%main = OpFunction %void None %void_func\n" +
8112 "%main_lab = OpLabel\n" +
8113 "%2 = OpVariable %_ptr_v4double Function\n" +
8114 "%3 = OpVariable %_ptr_v4double Function\n" +
8115 "%4 = OpVariable %_ptr_v4double Function\n" +
8116 "%5 = OpLoad %v4double %2\n" +
8117 "%6 = OpLoad %v4double %3\n" +
8118 "%7 = OpLoad %v4double %4\n" +
8119 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8120 "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
8121 "OpReturn\n" +
8122 "OpFunctionEnd",
8123 9, true),
8124 // Test case 1: Basic test 2
8125 InstructionFoldingCase<bool>(
8126 Header() +
8127 "; CHECK: OpVectorShuffle\n" +
8128 "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
8129 "; CHECK: OpReturn\n" +
8130 "%main = OpFunction %void None %void_func\n" +
8131 "%main_lab = OpLabel\n" +
8132 "%2 = OpVariable %_ptr_v4double Function\n" +
8133 "%3 = OpVariable %_ptr_v4double Function\n" +
8134 "%4 = OpVariable %_ptr_v4double Function\n" +
8135 "%5 = OpLoad %v4double %2\n" +
8136 "%6 = OpLoad %v4double %3\n" +
8137 "%7 = OpLoad %v4double %4\n" +
8138 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8139 "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
8140 "OpReturn\n" +
8141 "OpFunctionEnd",
8142 9, true),
8143 // Test case 2: Basic test 3
8144 InstructionFoldingCase<bool>(
8145 Header() +
8146 "; CHECK: OpVectorShuffle\n" +
8147 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
8148 "; CHECK: OpReturn\n" +
8149 "%main = OpFunction %void None %void_func\n" +
8150 "%main_lab = OpLabel\n" +
8151 "%2 = OpVariable %_ptr_v4double Function\n" +
8152 "%3 = OpVariable %_ptr_v4double Function\n" +
8153 "%4 = OpVariable %_ptr_v4double Function\n" +
8154 "%5 = OpLoad %v4double %2\n" +
8155 "%6 = OpLoad %v4double %3\n" +
8156 "%7 = OpLoad %v4double %4\n" +
8157 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8158 "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
8159 "OpReturn\n" +
8160 "OpFunctionEnd",
8161 9, true),
8162 // Test case 3: Basic test 4
8163 InstructionFoldingCase<bool>(
8164 Header() +
8165 "; CHECK: OpVectorShuffle\n" +
8166 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
8167 "; CHECK: OpReturn\n" +
8168 "%main = OpFunction %void None %void_func\n" +
8169 "%main_lab = OpLabel\n" +
8170 "%2 = OpVariable %_ptr_v4double Function\n" +
8171 "%3 = OpVariable %_ptr_v4double Function\n" +
8172 "%4 = OpVariable %_ptr_v4double Function\n" +
8173 "%5 = OpLoad %v4double %2\n" +
8174 "%6 = OpLoad %v4double %3\n" +
8175 "%7 = OpLoad %v4double %4\n" +
8176 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8177 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
8178 "OpReturn\n" +
8179 "OpFunctionEnd",
8180 9, true),
8181 // Test case 4: Don't fold, need both operands of the feeder.
8182 InstructionFoldingCase<bool>(
8183 Header() +
8184 "%main = OpFunction %void None %void_func\n" +
8185 "%main_lab = OpLabel\n" +
8186 "%2 = OpVariable %_ptr_v4double Function\n" +
8187 "%3 = OpVariable %_ptr_v4double Function\n" +
8188 "%4 = OpVariable %_ptr_v4double Function\n" +
8189 "%5 = OpLoad %v4double %2\n" +
8190 "%6 = OpLoad %v4double %3\n" +
8191 "%7 = OpLoad %v4double %4\n" +
8192 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8193 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
8194 "OpReturn\n" +
8195 "OpFunctionEnd",
8196 9, false),
8197 // Test case 5: Don't fold, need both operands of the feeder.
8198 InstructionFoldingCase<bool>(
8199 Header() +
8200 "%main = OpFunction %void None %void_func\n" +
8201 "%main_lab = OpLabel\n" +
8202 "%2 = OpVariable %_ptr_v4double Function\n" +
8203 "%3 = OpVariable %_ptr_v4double Function\n" +
8204 "%4 = OpVariable %_ptr_v4double Function\n" +
8205 "%5 = OpLoad %v4double %2\n" +
8206 "%6 = OpLoad %v4double %3\n" +
8207 "%7 = OpLoad %v4double %4\n" +
8208 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
8209 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8210 "OpReturn\n" +
8211 "OpFunctionEnd",
8212 9, false),
8213 // Test case 6: Fold, need both operands of the feeder, but they are the same.
8214 InstructionFoldingCase<bool>(
8215 Header() +
8216 "; CHECK: OpVectorShuffle\n" +
8217 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
8218 "; CHECK: OpReturn\n" +
8219 "%main = OpFunction %void None %void_func\n" +
8220 "%main_lab = OpLabel\n" +
8221 "%2 = OpVariable %_ptr_v4double Function\n" +
8222 "%3 = OpVariable %_ptr_v4double Function\n" +
8223 "%4 = OpVariable %_ptr_v4double Function\n" +
8224 "%5 = OpLoad %v4double %2\n" +
8225 "%6 = OpLoad %v4double %3\n" +
8226 "%7 = OpLoad %v4double %4\n" +
8227 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8228 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8229 "OpReturn\n" +
8230 "OpFunctionEnd",
8231 9, true),
8232 // Test case 7: Fold, need both operands of the feeder, but they are the same.
8233 InstructionFoldingCase<bool>(
8234 Header() +
8235 "; CHECK: OpVectorShuffle\n" +
8236 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
8237 "; CHECK: OpReturn\n" +
8238 "%main = OpFunction %void None %void_func\n" +
8239 "%main_lab = OpLabel\n" +
8240 "%2 = OpVariable %_ptr_v4double Function\n" +
8241 "%3 = OpVariable %_ptr_v4double Function\n" +
8242 "%4 = OpVariable %_ptr_v4double Function\n" +
8243 "%5 = OpLoad %v4double %2\n" +
8244 "%6 = OpLoad %v4double %3\n" +
8245 "%7 = OpLoad %v4double %4\n" +
8246 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
8247 "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
8248 "OpReturn\n" +
8249 "OpFunctionEnd",
8250 9, true),
8251 // Test case 8: Replace first operand with a smaller vector.
8252 InstructionFoldingCase<bool>(
8253 Header() +
8254 "; CHECK: OpVectorShuffle\n" +
8255 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
8256 "; CHECK: OpReturn\n" +
8257 "%main = OpFunction %void None %void_func\n" +
8258 "%main_lab = OpLabel\n" +
8259 "%2 = OpVariable %_ptr_v2double Function\n" +
8260 "%3 = OpVariable %_ptr_v4double Function\n" +
8261 "%4 = OpVariable %_ptr_v4double Function\n" +
8262 "%5 = OpLoad %v2double %2\n" +
8263 "%6 = OpLoad %v4double %3\n" +
8264 "%7 = OpLoad %v4double %4\n" +
8265 "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
8266 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
8267 "OpReturn\n" +
8268 "OpFunctionEnd",
8269 9, true),
8270 // Test case 9: Replace first operand with a larger vector.
8271 InstructionFoldingCase<bool>(
8272 Header() +
8273 "; CHECK: OpVectorShuffle\n" +
8274 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
8275 "; CHECK: OpReturn\n" +
8276 "%main = OpFunction %void None %void_func\n" +
8277 "%main_lab = OpLabel\n" +
8278 "%2 = OpVariable %_ptr_v4double Function\n" +
8279 "%3 = OpVariable %_ptr_v4double Function\n" +
8280 "%4 = OpVariable %_ptr_v4double Function\n" +
8281 "%5 = OpLoad %v4double %2\n" +
8282 "%6 = OpLoad %v4double %3\n" +
8283 "%7 = OpLoad %v4double %4\n" +
8284 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8285 "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
8286 "OpReturn\n" +
8287 "OpFunctionEnd",
8288 9, true),
8289 // Test case 10: Replace unused operand with null.
8290 InstructionFoldingCase<bool>(
8291 Header() +
8292 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8293 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8294 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8295 "; CHECK: OpVectorShuffle\n" +
8296 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
8297 "; CHECK: OpReturn\n" +
8298 "%main = OpFunction %void None %void_func\n" +
8299 "%main_lab = OpLabel\n" +
8300 "%2 = OpVariable %_ptr_v4double Function\n" +
8301 "%3 = OpVariable %_ptr_v4double Function\n" +
8302 "%4 = OpVariable %_ptr_v4double Function\n" +
8303 "%5 = OpLoad %v4double %2\n" +
8304 "%6 = OpLoad %v4double %3\n" +
8305 "%7 = OpLoad %v4double %4\n" +
8306 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8307 "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
8308 "OpReturn\n" +
8309 "OpFunctionEnd",
8310 9, true),
8311 // Test case 11: Replace unused operand with null.
8312 InstructionFoldingCase<bool>(
8313 Header() +
8314 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8315 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8316 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8317 "; CHECK: OpVectorShuffle\n" +
8318 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
8319 "; CHECK: OpReturn\n" +
8320 "%main = OpFunction %void None %void_func\n" +
8321 "%main_lab = OpLabel\n" +
8322 "%2 = OpVariable %_ptr_v4double Function\n" +
8323 "%3 = OpVariable %_ptr_v4double Function\n" +
8324 "%5 = OpLoad %v4double %2\n" +
8325 "%6 = OpLoad %v4double %3\n" +
8326 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8327 "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
8328 "OpReturn\n" +
8329 "OpFunctionEnd",
8330 9, true),
8331 // Test case 12: Replace unused operand with null.
8332 InstructionFoldingCase<bool>(
8333 Header() +
8334 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8335 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8336 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8337 "; CHECK: OpVectorShuffle\n" +
8338 "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
8339 "; CHECK: OpReturn\n" +
8340 "%main = OpFunction %void None %void_func\n" +
8341 "%main_lab = OpLabel\n" +
8342 "%2 = OpVariable %_ptr_v4double Function\n" +
8343 "%3 = OpVariable %_ptr_v4double Function\n" +
8344 "%4 = OpVariable %_ptr_v4double Function\n" +
8345 "%5 = OpLoad %v4double %2\n" +
8346 "%6 = OpLoad %v4double %3\n" +
8347 "%7 = OpLoad %v4double %4\n" +
8348 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8349 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
8350 "OpReturn\n" +
8351 "OpFunctionEnd",
8352 9, true),
8353 // Test case 13: Shuffle with undef literal.
8354 InstructionFoldingCase<bool>(
8355 Header() +
8356 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8357 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8358 "; CHECK: OpVectorShuffle\n" +
8359 "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
8360 "; CHECK: OpReturn\n" +
8361 "%main = OpFunction %void None %void_func\n" +
8362 "%main_lab = OpLabel\n" +
8363 "%2 = OpVariable %_ptr_v4double Function\n" +
8364 "%3 = OpVariable %_ptr_v4double Function\n" +
8365 "%4 = OpVariable %_ptr_v4double Function\n" +
8366 "%5 = OpLoad %v4double %2\n" +
8367 "%6 = OpLoad %v4double %3\n" +
8368 "%7 = OpLoad %v4double %4\n" +
8369 "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8370 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
8371 "OpReturn\n" +
8372 "OpFunctionEnd",
8373 9, true),
8374 // Test case 14: Shuffle with undef literal and change size of first input vector.
8375 InstructionFoldingCase<bool>(
8376 Header() +
8377 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8378 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8379 "; CHECK: OpVectorShuffle\n" +
8380 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 1 4 4294967295\n" +
8381 "; CHECK: OpReturn\n" +
8382 "%main = OpFunction %void None %void_func\n" +
8383 "%main_lab = OpLabel\n" +
8384 "%2 = OpVariable %_ptr_v4double Function\n" +
8385 "%3 = OpVariable %_ptr_v4double Function\n" +
8386 "%4 = OpVariable %_ptr_v4double Function\n" +
8387 "%5 = OpLoad %v4double %2\n" +
8388 "%6 = OpLoad %v4double %3\n" +
8389 "%7 = OpLoad %v4double %4\n" +
8390 "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8391 "%9 = OpVectorShuffle %v4double %8 %7 0 1 2 4294967295\n" +
8392 "OpReturn\n" +
8393 "OpFunctionEnd",
8394 9, true)
8395 ));
8396
8397 using EntryPointFoldingTest =
8398 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8399
TEST_P(EntryPointFoldingTest, Case)8400 TEST_P(EntryPointFoldingTest, Case) {
8401 const auto& tc = GetParam();
8402
8403 // Build module.
8404 std::unique_ptr<IRContext> context =
8405 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8406 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8407 ASSERT_NE(nullptr, context);
8408
8409 // Fold the instruction to test.
8410 Instruction* inst = nullptr;
8411 inst = &*context->module()->entry_points().begin();
8412 assert(inst && "Invalid test. Could not find entry point instruction to fold.");
8413 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8414 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8415 EXPECT_EQ(succeeded, tc.expected_result);
8416 if (succeeded) {
8417 Match(tc.test_body, context.get());
8418 }
8419 }
8420
8421 INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest,
8422 ::testing::Values(
8423 // Test case 0: Basic test 1
8424 InstructionFoldingCase<bool>(std::string() +
8425 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" +
8426 "OpCapability Shader\n" +
8427 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8428 "OpMemoryModel Logical GLSL450\n" +
8429 "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" +
8430 "OpExecutionMode %2 OriginUpperLeft\n" +
8431 "OpSource GLSL 430\n" +
8432 "OpDecorate %3 Location 0\n" +
8433 "%void = OpTypeVoid\n" +
8434 "%5 = OpTypeFunction %void\n" +
8435 "%float = OpTypeFloat 32\n" +
8436 "%v4float = OpTypeVector %float 4\n" +
8437 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8438 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8439 "%int = OpTypeInt 32 1\n" +
8440 "%int_0 = OpConstant %int 0\n" +
8441 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8442 "%2 = OpFunction %void None %5\n" +
8443 "%12 = OpLabel\n" +
8444 "OpReturn\n" +
8445 "OpFunctionEnd\n",
8446 9, true),
8447 InstructionFoldingCase<bool>(std::string() +
8448 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" +
8449 "OpCapability Shader\n" +
8450 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8451 "OpMemoryModel Logical GLSL450\n" +
8452 "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" +
8453 "OpExecutionMode %2 OriginUpperLeft\n" +
8454 "OpSource GLSL 430\n" +
8455 "OpDecorate %3 Location 0\n" +
8456 "%void = OpTypeVoid\n" +
8457 "%5 = OpTypeFunction %void\n" +
8458 "%float = OpTypeFloat 32\n" +
8459 "%v4float = OpTypeVector %float 4\n" +
8460 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8461 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8462 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8463 "%int = OpTypeInt 32 1\n" +
8464 "%int_0 = OpConstant %int 0\n" +
8465 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8466 "%2 = OpFunction %void None %5\n" +
8467 "%12 = OpLabel\n" +
8468 "OpReturn\n" +
8469 "OpFunctionEnd\n",
8470 9, true),
8471 InstructionFoldingCase<bool>(std::string() +
8472 "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" +
8473 "OpCapability Shader\n" +
8474 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8475 "OpMemoryModel Logical GLSL450\n" +
8476 "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" +
8477 "OpExecutionMode %2 OriginUpperLeft\n" +
8478 "OpSource GLSL 430\n" +
8479 "OpDecorate %3 Location 0\n" +
8480 "%void = OpTypeVoid\n" +
8481 "%5 = OpTypeFunction %void\n" +
8482 "%float = OpTypeFloat 32\n" +
8483 "%v4float = OpTypeVector %float 4\n" +
8484 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8485 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8486 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8487 "%int = OpTypeInt 32 1\n" +
8488 "%int_0 = OpConstant %int 0\n" +
8489 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8490 "%2 = OpFunction %void None %5\n" +
8491 "%12 = OpLabel\n" +
8492 "OpReturn\n" +
8493 "OpFunctionEnd\n",
8494 9, true)
8495 ));
8496
8497 using SPV14FoldingTest =
8498 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8499
TEST_P(SPV14FoldingTest, Case)8500 TEST_P(SPV14FoldingTest, Case) {
8501 const auto& tc = GetParam();
8502
8503 // Build module.
8504 std::unique_ptr<IRContext> context =
8505 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8506 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8507 ASSERT_NE(nullptr, context);
8508
8509 // Fold the instruction to test.
8510 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8511 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8512 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8513 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8514 EXPECT_EQ(succeeded, tc.expected_result);
8515 if (succeeded) {
8516 Match(tc.test_body, context.get());
8517 }
8518 }
8519
8520 INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest,
8521 ::testing::Values(
8522 // Test case 0: select vectors with scalar condition.
8523 InstructionFoldingCase<bool>(std::string() +
8524 "; CHECK-NOT: OpSelect\n" +
8525 "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" +
8526 "OpCapability Shader\n" +
8527 "OpCapability Linkage\n" +
8528 "%void = OpTypeVoid\n" +
8529 "%bool = OpTypeBool\n" +
8530 "%true = OpConstantTrue %bool\n" +
8531 "%int = OpTypeInt 32 0\n" +
8532 "%int4 = OpTypeVector %int 4\n" +
8533 "%int_0 = OpConstant %int 0\n" +
8534 "%int_1 = OpConstant %int 1\n" +
8535 "%1 = OpUndef %int4\n" +
8536 "%2 = OpUndef %int4\n" +
8537 "%void_fn = OpTypeFunction %void\n" +
8538 "%func = OpFunction %void None %void_fn\n" +
8539 "%entry = OpLabel\n" +
8540 "%3 = OpSelect %int4 %true %1 %2\n" +
8541 "OpReturn\n" +
8542 "OpFunctionEnd\n"
8543 ,
8544 3, true),
8545 // Test case 1: select struct with scalar condition.
8546 InstructionFoldingCase<bool>(std::string() +
8547 "; CHECK-NOT: OpSelect\n" +
8548 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8549 "OpCapability Shader\n" +
8550 "OpCapability Linkage\n" +
8551 "%void = OpTypeVoid\n" +
8552 "%bool = OpTypeBool\n" +
8553 "%true = OpConstantFalse %bool\n" +
8554 "%int = OpTypeInt 32 0\n" +
8555 "%struct = OpTypeStruct %int %int %int %int\n" +
8556 "%int_0 = OpConstant %int 0\n" +
8557 "%int_1 = OpConstant %int 1\n" +
8558 "%1 = OpUndef %struct\n" +
8559 "%2 = OpUndef %struct\n" +
8560 "%void_fn = OpTypeFunction %void\n" +
8561 "%func = OpFunction %void None %void_fn\n" +
8562 "%entry = OpLabel\n" +
8563 "%3 = OpSelect %struct %true %1 %2\n" +
8564 "OpReturn\n" +
8565 "OpFunctionEnd\n"
8566 ,
8567 3, true),
8568 // Test case 1: select array with scalar condition.
8569 InstructionFoldingCase<bool>(std::string() +
8570 "; CHECK-NOT: OpSelect\n" +
8571 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8572 "OpCapability Shader\n" +
8573 "OpCapability Linkage\n" +
8574 "%void = OpTypeVoid\n" +
8575 "%bool = OpTypeBool\n" +
8576 "%true = OpConstantFalse %bool\n" +
8577 "%int = OpTypeInt 32 0\n" +
8578 "%int_0 = OpConstant %int 0\n" +
8579 "%int_1 = OpConstant %int 1\n" +
8580 "%int_4 = OpConstant %int 4\n" +
8581 "%array = OpTypeStruct %int %int %int %int\n" +
8582 "%1 = OpUndef %array\n" +
8583 "%2 = OpUndef %array\n" +
8584 "%void_fn = OpTypeFunction %void\n" +
8585 "%func = OpFunction %void None %void_fn\n" +
8586 "%entry = OpLabel\n" +
8587 "%3 = OpSelect %array %true %1 %2\n" +
8588 "OpReturn\n" +
8589 "OpFunctionEnd\n"
8590 ,
8591 3, true)
8592 ));
8593
FloatControlsHeader(const std::string& capabilities)8594 std::string FloatControlsHeader(const std::string& capabilities) {
8595 std::string header = R"(
8596 OpCapability Shader
8597 )" + capabilities + R"(
8598 %void = OpTypeVoid
8599 %float = OpTypeFloat 32
8600 %float_0 = OpConstant %float 0
8601 %float_1 = OpConstant %float 1
8602 %void_fn = OpTypeFunction %void
8603 %func = OpFunction %void None %void_fn
8604 %entry = OpLabel
8605 )";
8606
8607 return header;
8608 }
8609
8610 using FloatControlsFoldingTest =
8611 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8612
TEST_P(FloatControlsFoldingTest, Case)8613 TEST_P(FloatControlsFoldingTest, Case) {
8614 const auto& tc = GetParam();
8615
8616 // Build module.
8617 std::unique_ptr<IRContext> context =
8618 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8619 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8620 ASSERT_NE(nullptr, context);
8621
8622 // Fold the instruction to test.
8623 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8624 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8625 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8626 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8627 EXPECT_EQ(succeeded, tc.expected_result);
8628 if (succeeded) {
8629 Match(tc.test_body, context.get());
8630 }
8631 }
8632
8633 INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
8634 ::testing::Values(
8635 // Test case 0: no folding with DenormPreserve
8636 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormPreserve") +
8637 "%1 = OpFAdd %float %float_0 %float_1\n" +
8638 "OpReturn\n" +
8639 "OpFunctionEnd\n"
8640 ,
8641 1, false),
8642 // Test case 1: no folding with DenormFlushToZero
8643 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormFlushToZero") +
8644 "%1 = OpFAdd %float %float_0 %float_1\n" +
8645 "OpReturn\n" +
8646 "OpFunctionEnd\n"
8647 ,
8648 1, false),
8649 // Test case 2: no folding with SignedZeroInfNanPreserve
8650 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") +
8651 "%1 = OpFAdd %float %float_0 %float_1\n" +
8652 "OpReturn\n" +
8653 "OpFunctionEnd\n"
8654 ,
8655 1, false),
8656 // Test case 3: no folding with RoundingModeRTE
8657 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTE") +
8658 "%1 = OpFAdd %float %float_0 %float_1\n" +
8659 "OpReturn\n" +
8660 "OpFunctionEnd\n"
8661 ,
8662 1, false),
8663 // Test case 4: no folding with RoundingModeRTZ
8664 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTZ") +
8665 "%1 = OpFAdd %float %float_0 %float_1\n" +
8666 "OpReturn\n" +
8667 "OpFunctionEnd\n"
8668 ,
8669 1, false)
8670 ));
8671
ImageOperandsTestBody(const std::string& image_instruction)8672 std::string ImageOperandsTestBody(const std::string& image_instruction) {
8673 std::string body = R"(
8674 OpCapability Shader
8675 OpCapability ImageGatherExtended
8676 OpMemoryModel Logical GLSL450
8677 OpEntryPoint Fragment %main "main"
8678 OpExecutionMode %main OriginUpperLeft
8679 OpDecorate %Texture DescriptorSet 0
8680 OpDecorate %Texture Binding 0
8681 %int = OpTypeInt 32 1
8682 %int_n1 = OpConstant %int -1
8683 %5 = OpConstant %int 0
8684 %float = OpTypeFloat 32
8685 %float_0 = OpConstant %float 0
8686 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
8687 %type_sampled_image = OpTypeSampledImage %type_2d_image
8688 %type_sampler = OpTypeSampler
8689 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
8690 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
8691 %_ptr_int = OpTypePointer Function %int
8692 %v2int = OpTypeVector %int 2
8693 %10 = OpTypeVector %float 4
8694 %void = OpTypeVoid
8695 %22 = OpTypeFunction %void
8696 %v2float = OpTypeVector %float 2
8697 %v3int = OpTypeVector %int 3
8698 %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
8699 %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
8700 %110 = OpConstantComposite %v2int %5 %5
8701 %101 = OpConstantComposite %v2int %int_n1 %int_n1
8702 %20 = OpConstantComposite %v2float %float_0 %float_0
8703 %main = OpFunction %void None %22
8704 %23 = OpLabel
8705 %var = OpVariable %_ptr_int Function
8706 %88 = OpLoad %type_2d_image %Texture
8707 %val = OpLoad %int %var
8708 %sampler = OpLoad %type_sampler %gSampler
8709 %26 = OpSampledImage %type_sampled_image %88 %sampler
8710 )" + image_instruction + R"(
8711 OpReturn
8712 OpFunctionEnd
8713 )";
8714
8715 return body;
8716 }
8717
8718 INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
8719 ::testing::Values(
8720 // Test case 0: OpImageFetch without Offset
8721 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8722 "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
8723 , 89, false),
8724 // Test case 1: OpImageFetch with non-const offset
8725 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8726 "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
8727 , 89, false),
8728 // Test case 2: OpImageFetch with Lod and Offset
8729 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8730 " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n"
8731 "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
8732 , 89, true),
8733 // Test case 3: OpImageFetch with Bias and Offset
8734 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8735 " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n"
8736 "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
8737 , 89, true),
8738 // Test case 4: OpImageFetch with Grad and Offset.
8739 // Grad adds 2 operands to the instruction.
8740 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8741 " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n"
8742 "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
8743 , 89, true),
8744 // Test case 5: OpImageFetch with Offset and MinLod.
8745 // This is an example of a case where the bitmask bit-offset is larger than
8746 // that of the Offset.
8747 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8748 " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n"
8749 "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
8750 , 89, true),
8751 // Test case 6: OpImageGather with constant Offset
8752 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8753 " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n"
8754 "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
8755 , 89, true),
8756 // Test case 7: OpImageWrite with constant Offset
8757 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8758 " OpImageWrite %88 %5 %101 Offset %101 \n"
8759 "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
8760 , 0 /* No result-id */, true),
8761 // Test case 8: OpImageFetch with zero constant Offset
8762 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8763 " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %110 \n"
8764 "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod %5 \n")
8765 , 89, true)
8766 ));
8767
8768 } // namespace
8769 } // namespace opt
8770 } // namespace spvtools
8771