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 #include "test/opt/pass_utils.h"
31
32 namespace spvtools {
33 namespace opt {
34 namespace {
35
36 using ::testing::Contains;
37
Disassemble(const std::string & original,IRContext * context,uint32_t disassemble_options=0)38 std::string Disassemble(const std::string& original, IRContext* context,
39 uint32_t disassemble_options = 0) {
40 std::vector<uint32_t> optimized_bin;
41 context->module()->ToBinary(&optimized_bin, true);
42 spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
43 SpirvTools tools(target_env);
44 std::string optimized_asm;
45 EXPECT_TRUE(
46 tools.Disassemble(optimized_bin, &optimized_asm, disassemble_options))
47 << "Disassembling failed for shader:\n"
48 << original << std::endl;
49 return optimized_asm;
50 }
51
Match(const std::string & original,IRContext * context,uint32_t disassemble_options=0)52 void Match(const std::string& original, IRContext* context,
53 uint32_t disassemble_options = 0) {
54 std::string disassembly = Disassemble(original, context, disassemble_options);
55 auto match_result = effcee::Match(disassembly, original);
56 EXPECT_EQ(effcee::Result::Status::Ok, match_result.status())
57 << match_result.message() << "\nChecking result:\n"
58 << disassembly;
59 }
60
61 template <class ResultType>
62 struct InstructionFoldingCase {
InstructionFoldingCasespvtools::opt::__anon56844f860111::InstructionFoldingCase63 InstructionFoldingCase(const std::string& tb, uint32_t id, ResultType result)
64 : test_body(tb), id_to_fold(id), expected_result(result) {}
65
66 std::string test_body;
67 uint32_t id_to_fold;
68 ResultType expected_result;
69 };
70
71 using IntegerInstructionFoldingTest =
72 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
73
TEST_P(IntegerInstructionFoldingTest,Case)74 TEST_P(IntegerInstructionFoldingTest, Case) {
75 const auto& tc = GetParam();
76
77 // Build module.
78 std::unique_ptr<IRContext> context =
79 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
80 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
81 ASSERT_NE(nullptr, context);
82
83 // Fold the instruction to test.
84 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
85 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
86 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
87
88 // Make sure the instruction folded as expected.
89 EXPECT_TRUE(succeeded);
90 if (inst != nullptr) {
91 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
92 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
93 EXPECT_EQ(inst->opcode(), SpvOpConstant);
94 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
95 const analysis::IntConstant* result =
96 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
97 EXPECT_NE(result, nullptr);
98 if (result != nullptr) {
99 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
100 }
101 }
102 }
103
104 // Returns a common SPIR-V header for all of the test that follow.
105 #define INT_0_ID 100
106 #define TRUE_ID 101
107 #define VEC2_0_ID 102
108 #define INT_7_ID 103
109 #define FLOAT_0_ID 104
110 #define DOUBLE_0_ID 105
111 #define VEC4_0_ID 106
112 #define DVEC4_0_ID 106
113 #define HALF_0_ID 108
Header()114 const std::string& Header() {
115 static const std::string header = R"(OpCapability Shader
116 OpCapability Float16
117 OpCapability Float64
118 OpCapability Int16
119 OpCapability Int64
120 %1 = OpExtInstImport "GLSL.std.450"
121 OpMemoryModel Logical GLSL450
122 OpEntryPoint Fragment %main "main"
123 OpExecutionMode %main OriginUpperLeft
124 OpSource GLSL 140
125 OpName %main "main"
126 %void = OpTypeVoid
127 %void_func = OpTypeFunction %void
128 %bool = OpTypeBool
129 %float = OpTypeFloat 32
130 %double = OpTypeFloat 64
131 %half = OpTypeFloat 16
132 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
133 %true = OpConstantTrue %bool
134 %false = OpConstantFalse %bool
135 %bool_null = OpConstantNull %bool
136 %short = OpTypeInt 16 1
137 %int = OpTypeInt 32 1
138 %long = OpTypeInt 64 1
139 %uint = OpTypeInt 32 0
140 %ulong = OpTypeInt 64 0
141 %v2int = OpTypeVector %int 2
142 %v4int = OpTypeVector %int 4
143 %v4float = OpTypeVector %float 4
144 %v4double = OpTypeVector %double 4
145 %v2uint = OpTypeVector %uint 2
146 %v2float = OpTypeVector %float 2
147 %v2double = OpTypeVector %double 2
148 %v2half = OpTypeVector %half 2
149 %v2bool = OpTypeVector %bool 2
150 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
151 %_ptr_int = OpTypePointer Function %int
152 %_ptr_uint = OpTypePointer Function %uint
153 %_ptr_bool = OpTypePointer Function %bool
154 %_ptr_float = OpTypePointer Function %float
155 %_ptr_double = OpTypePointer Function %double
156 %_ptr_half = OpTypePointer Function %half
157 %_ptr_long = OpTypePointer Function %long
158 %_ptr_ulong = OpTypePointer Function %ulong
159 %_ptr_v2int = OpTypePointer Function %v2int
160 %_ptr_v4int = OpTypePointer Function %v4int
161 %_ptr_v4float = OpTypePointer Function %v4float
162 %_ptr_v4double = OpTypePointer Function %v4double
163 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
164 %_ptr_v2float = OpTypePointer Function %v2float
165 %_ptr_v2double = OpTypePointer Function %v2double
166 %short_0 = OpConstant %short 0
167 %short_2 = OpConstant %short 2
168 %short_3 = OpConstant %short 3
169 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
170 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
171 %int_0 = OpConstant %int 0
172 %int_1 = OpConstant %int 1
173 %int_2 = OpConstant %int 2
174 %int_3 = OpConstant %int 3
175 %int_4 = OpConstant %int 4
176 %int_10 = OpConstant %int 10
177 %int_1073741824 = OpConstant %int 1073741824
178 %int_n1 = OpConstant %int -1
179 %int_n24 = OpConstant %int -24
180 %int_n858993459 = OpConstant %int -858993459
181 %int_min = OpConstant %int -2147483648
182 %int_max = OpConstant %int 2147483647
183 %long_0 = OpConstant %long 0
184 %long_1 = OpConstant %long 1
185 %long_2 = OpConstant %long 2
186 %long_3 = OpConstant %long 3
187 %long_10 = OpConstant %long 10
188 %long_4611686018427387904 = OpConstant %long 4611686018427387904
189 %long_n1 = OpConstant %long -1
190 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
191 %long_min = OpConstant %long -9223372036854775808
192 %long_max = OpConstant %long 9223372036854775807
193 %uint_0 = OpConstant %uint 0
194 %uint_1 = OpConstant %uint 1
195 %uint_2 = OpConstant %uint 2
196 %uint_3 = OpConstant %uint 3
197 %uint_4 = OpConstant %uint 4
198 %uint_32 = OpConstant %uint 32
199 %uint_42 = OpConstant %uint 42
200 %uint_2147483649 = OpConstant %uint 2147483649
201 %uint_max = OpConstant %uint 4294967295
202 %ulong_0 = OpConstant %ulong 0
203 %ulong_1 = OpConstant %ulong 1
204 %ulong_2 = OpConstant %ulong 2
205 %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809
206 %ulong_max = OpConstant %ulong 18446744073709551615
207 %v2int_undef = OpUndef %v2int
208 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
209 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
210 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
211 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
212 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
213 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
214 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
215 %v2bool_null = OpConstantNull %v2bool
216 %v2bool_true_false = OpConstantComposite %v2bool %true %false
217 %v2bool_false_true = OpConstantComposite %v2bool %false %true
218 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
219 %v2int_null = OpConstantNull %v2int
220 %102 = OpConstantComposite %v2int %103 %103
221 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
222 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
223 %float_n1 = OpConstant %float -1
224 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
225 %float_null = OpConstantNull %float
226 %float_0 = OpConstant %float 0
227 %float_1 = OpConstant %float 1
228 %float_2 = OpConstant %float 2
229 %float_3 = OpConstant %float 3
230 %float_4 = OpConstant %float 4
231 %float_2049 = OpConstant %float 2049
232 %float_n2049 = OpConstant %float -2049
233 %float_0p5 = OpConstant %float 0.5
234 %float_0p2 = OpConstant %float 0.2
235 %float_pi = OpConstant %float 1.5555
236 %float_1e16 = OpConstant %float 1e16
237 %float_n1e16 = OpConstant %float -1e16
238 %float_1en16 = OpConstant %float 1e-16
239 %float_n1en16 = OpConstant %float -1e-16
240 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
241 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
242 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
243 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
244 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
245 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
246 %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
247 %v2float_null = OpConstantNull %v2float
248 %double_n1 = OpConstant %double -1
249 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
250 %double_null = OpConstantNull %double
251 %double_0 = OpConstant %double 0
252 %double_1 = OpConstant %double 1
253 %double_2 = OpConstant %double 2
254 %double_3 = OpConstant %double 3
255 %double_4 = OpConstant %double 4
256 %double_5 = OpConstant %double 5
257 %double_0p5 = OpConstant %double 0.5
258 %double_0p2 = OpConstant %double 0.2
259 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
260 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
261 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
262 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
263 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
264 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
265 %v2double_null = OpConstantNull %v2double
266 %108 = OpConstant %half 0
267 %half_1 = OpConstant %half 1
268 %half_0_1 = OpConstantComposite %v2half %108 %half_1
269 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
270 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
271 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
272 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
273 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
274 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
275 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
276 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
277 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
278 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
279 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
280 %v4double_null = OpConstantNull %v4double
281 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
282 %uint_0x3f800000 = OpConstant %uint 0x3f800000
283 %uint_0xbf800000 = OpConstant %uint 0xbf800000
284 %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000
285 %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000
286 %int_0x3FF00000 = OpConstant %int 0x3FF00000
287 %int_0x00000000 = OpConstant %int 0x00000000
288 %int_0xC05FD666 = OpConstant %int 0xC05FD666
289 %int_0x66666666 = OpConstant %int 0x66666666
290 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
291 )";
292
293 return header;
294 }
295
296 // Returns the header with definitions of float NaN and double NaN. Since FC
297 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
298 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
299 // %double_n0 = OpConstant %double -0,
300 // we separates those definitions from Header().
HeaderWithNaN()301 const std::string& HeaderWithNaN() {
302 static const std::string headerWithNaN =
303 Header() +
304 R"(%float_nan = OpConstant %float -0x1.8p+128
305 %double_nan = OpConstant %double -0x1.8p+1024
306 )";
307
308 return headerWithNaN;
309 }
310
311 // clang-format off
312 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
313 ::testing::Values(
314 // Test case 0: fold 0*n
315 InstructionFoldingCase<uint32_t>(
316 Header() + "%main = OpFunction %void None %void_func\n" +
317 "%main_lab = OpLabel\n" +
318 "%n = OpVariable %_ptr_int Function\n" +
319 "%load = OpLoad %int %n\n" +
320 "%2 = OpIMul %int %int_0 %load\n" +
321 "OpReturn\n" +
322 "OpFunctionEnd",
323 2, 0),
324 // Test case 1: fold n*0
325 InstructionFoldingCase<uint32_t>(
326 Header() + "%main = OpFunction %void None %void_func\n" +
327 "%main_lab = OpLabel\n" +
328 "%n = OpVariable %_ptr_int Function\n" +
329 "%load = OpLoad %int %n\n" +
330 "%2 = OpIMul %int %load %int_0\n" +
331 "OpReturn\n" +
332 "OpFunctionEnd",
333 2, 0),
334 // Test case 2: fold 0/n (signed)
335 InstructionFoldingCase<uint32_t>(
336 Header() + "%main = OpFunction %void None %void_func\n" +
337 "%main_lab = OpLabel\n" +
338 "%n = OpVariable %_ptr_int Function\n" +
339 "%load = OpLoad %int %n\n" +
340 "%2 = OpSDiv %int %int_0 %load\n" +
341 "OpReturn\n" +
342 "OpFunctionEnd",
343 2, 0),
344 // Test case 3: fold n/0 (signed)
345 InstructionFoldingCase<uint32_t>(
346 Header() + "%main = OpFunction %void None %void_func\n" +
347 "%main_lab = OpLabel\n" +
348 "%n = OpVariable %_ptr_int Function\n" +
349 "%load = OpLoad %int %n\n" +
350 "%2 = OpSDiv %int %load %int_0\n" +
351 "OpReturn\n" +
352 "OpFunctionEnd",
353 2, 0),
354 // Test case 4: fold 0/n (unsigned)
355 InstructionFoldingCase<uint32_t>(
356 Header() + "%main = OpFunction %void None %void_func\n" +
357 "%main_lab = OpLabel\n" +
358 "%n = OpVariable %_ptr_uint Function\n" +
359 "%load = OpLoad %uint %n\n" +
360 "%2 = OpUDiv %uint %uint_0 %load\n" +
361 "OpReturn\n" +
362 "OpFunctionEnd",
363 2, 0),
364 // Test case 5: fold n/0 (unsigned)
365 InstructionFoldingCase<uint32_t>(
366 Header() + "%main = OpFunction %void None %void_func\n" +
367 "%main_lab = OpLabel\n" +
368 "%n = OpVariable %_ptr_int Function\n" +
369 "%load = OpLoad %int %n\n" +
370 "%2 = OpSDiv %int %load %int_0\n" +
371 "OpReturn\n" +
372 "OpFunctionEnd",
373 2, 0),
374 // Test case 6: fold 0 remainder n
375 InstructionFoldingCase<uint32_t>(
376 Header() + "%main = OpFunction %void None %void_func\n" +
377 "%main_lab = OpLabel\n" +
378 "%n = OpVariable %_ptr_int Function\n" +
379 "%load = OpLoad %int %n\n" +
380 "%2 = OpSRem %int %int_0 %load\n" +
381 "OpReturn\n" +
382 "OpFunctionEnd",
383 2, 0),
384 // Test case 7: fold n remainder 0
385 InstructionFoldingCase<uint32_t>(
386 Header() + "%main = OpFunction %void None %void_func\n" +
387 "%main_lab = OpLabel\n" +
388 "%n = OpVariable %_ptr_int Function\n" +
389 "%load = OpLoad %int %n\n" +
390 "%2 = OpSRem %int %load %int_0\n" +
391 "OpReturn\n" +
392 "OpFunctionEnd",
393 2, 0),
394 // Test case 8: fold 0%n (signed)
395 InstructionFoldingCase<uint32_t>(
396 Header() + "%main = OpFunction %void None %void_func\n" +
397 "%main_lab = OpLabel\n" +
398 "%n = OpVariable %_ptr_int Function\n" +
399 "%load = OpLoad %int %n\n" +
400 "%2 = OpSMod %int %int_0 %load\n" +
401 "OpReturn\n" +
402 "OpFunctionEnd",
403 2, 0),
404 // Test case 9: fold n%0 (signed)
405 InstructionFoldingCase<uint32_t>(
406 Header() + "%main = OpFunction %void None %void_func\n" +
407 "%main_lab = OpLabel\n" +
408 "%n = OpVariable %_ptr_int Function\n" +
409 "%load = OpLoad %int %n\n" +
410 "%2 = OpSMod %int %load %int_0\n" +
411 "OpReturn\n" +
412 "OpFunctionEnd",
413 2, 0),
414 // Test case 10: fold 0%n (unsigned)
415 InstructionFoldingCase<uint32_t>(
416 Header() + "%main = OpFunction %void None %void_func\n" +
417 "%main_lab = OpLabel\n" +
418 "%n = OpVariable %_ptr_uint Function\n" +
419 "%load = OpLoad %uint %n\n" +
420 "%2 = OpUMod %uint %uint_0 %load\n" +
421 "OpReturn\n" +
422 "OpFunctionEnd",
423 2, 0),
424 // Test case 11: fold n%0 (unsigned)
425 InstructionFoldingCase<uint32_t>(
426 Header() + "%main = OpFunction %void None %void_func\n" +
427 "%main_lab = OpLabel\n" +
428 "%n = OpVariable %_ptr_uint Function\n" +
429 "%load = OpLoad %uint %n\n" +
430 "%2 = OpUMod %uint %load %uint_0\n" +
431 "OpReturn\n" +
432 "OpFunctionEnd",
433 2, 0),
434 // Test case 12: fold n << 32
435 InstructionFoldingCase<uint32_t>(
436 Header() + "%main = OpFunction %void None %void_func\n" +
437 "%main_lab = OpLabel\n" +
438 "%n = OpVariable %_ptr_uint Function\n" +
439 "%load = OpLoad %uint %n\n" +
440 "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
441 "OpReturn\n" +
442 "OpFunctionEnd",
443 2, 0),
444 // Test case 13: fold n >> 32
445 InstructionFoldingCase<uint32_t>(
446 Header() + "%main = OpFunction %void None %void_func\n" +
447 "%main_lab = OpLabel\n" +
448 "%n = OpVariable %_ptr_uint Function\n" +
449 "%load = OpLoad %uint %n\n" +
450 "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
451 "OpReturn\n" +
452 "OpFunctionEnd",
453 2, 0),
454 // Test case 14: fold n | 0xFFFFFFFF
455 InstructionFoldingCase<uint32_t>(
456 Header() + "%main = OpFunction %void None %void_func\n" +
457 "%main_lab = OpLabel\n" +
458 "%n = OpVariable %_ptr_uint Function\n" +
459 "%load = OpLoad %uint %n\n" +
460 "%2 = OpBitwiseOr %uint %load %uint_max\n" +
461 "OpReturn\n" +
462 "OpFunctionEnd",
463 2, 0xFFFFFFFF),
464 // Test case 15: fold 0xFFFFFFFF | n
465 InstructionFoldingCase<uint32_t>(
466 Header() + "%main = OpFunction %void None %void_func\n" +
467 "%main_lab = OpLabel\n" +
468 "%n = OpVariable %_ptr_uint Function\n" +
469 "%load = OpLoad %uint %n\n" +
470 "%2 = OpBitwiseOr %uint %uint_max %load\n" +
471 "OpReturn\n" +
472 "OpFunctionEnd",
473 2, 0xFFFFFFFF),
474 // Test case 16: fold n & 0
475 InstructionFoldingCase<uint32_t>(
476 Header() + "%main = OpFunction %void None %void_func\n" +
477 "%main_lab = OpLabel\n" +
478 "%n = OpVariable %_ptr_uint Function\n" +
479 "%load = OpLoad %uint %n\n" +
480 "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
481 "OpReturn\n" +
482 "OpFunctionEnd",
483 2, 0),
484 // Test case 17: fold 1/0 (signed)
485 InstructionFoldingCase<uint32_t>(
486 Header() + "%main = OpFunction %void None %void_func\n" +
487 "%main_lab = OpLabel\n" +
488 "%2 = OpSDiv %int %int_1 %int_0\n" +
489 "OpReturn\n" +
490 "OpFunctionEnd",
491 2, 0),
492 // Test case 18: fold 1/0 (unsigned)
493 InstructionFoldingCase<uint32_t>(
494 Header() + "%main = OpFunction %void None %void_func\n" +
495 "%main_lab = OpLabel\n" +
496 "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
497 "OpReturn\n" +
498 "OpFunctionEnd",
499 2, 0),
500 // Test case 19: fold OpSRem 1 0 (signed)
501 InstructionFoldingCase<uint32_t>(
502 Header() + "%main = OpFunction %void None %void_func\n" +
503 "%main_lab = OpLabel\n" +
504 "%2 = OpSRem %int %int_1 %int_0\n" +
505 "OpReturn\n" +
506 "OpFunctionEnd",
507 2, 0),
508 // Test case 20: fold 1%0 (signed)
509 InstructionFoldingCase<uint32_t>(
510 Header() + "%main = OpFunction %void None %void_func\n" +
511 "%main_lab = OpLabel\n" +
512 "%2 = OpSMod %int %int_1 %int_0\n" +
513 "OpReturn\n" +
514 "OpFunctionEnd",
515 2, 0),
516 // Test case 21: fold 1%0 (unsigned)
517 InstructionFoldingCase<uint32_t>(
518 Header() + "%main = OpFunction %void None %void_func\n" +
519 "%main_lab = OpLabel\n" +
520 "%2 = OpUMod %uint %uint_1 %uint_0\n" +
521 "OpReturn\n" +
522 "OpFunctionEnd",
523 2, 0),
524 // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
525 InstructionFoldingCase<uint32_t>(
526 Header() + "%main = OpFunction %void None %void_func\n" +
527 "%main_lab = OpLabel\n" +
528 "%n = OpVariable %_ptr_uint Function\n" +
529 "%load = OpLoad %uint %n\n" +
530 "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
531 "OpReturn\n" +
532 "OpFunctionEnd",
533 2, 0),
534 // Test case 23: fold signed n >> 42 (undefined, so set to zero).
535 InstructionFoldingCase<uint32_t>(
536 Header() + "%main = OpFunction %void None %void_func\n" +
537 "%main_lab = OpLabel\n" +
538 "%n = OpVariable %_ptr_int Function\n" +
539 "%load = OpLoad %int %n\n" +
540 "%2 = OpShiftRightLogical %int %load %uint_42\n" +
541 "OpReturn\n" +
542 "OpFunctionEnd",
543 2, 0),
544 // Test case 24: fold n << 42 (undefined, so set to zero).
545 InstructionFoldingCase<uint32_t>(
546 Header() + "%main = OpFunction %void None %void_func\n" +
547 "%main_lab = OpLabel\n" +
548 "%n = OpVariable %_ptr_int Function\n" +
549 "%load = OpLoad %int %n\n" +
550 "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
551 "OpReturn\n" +
552 "OpFunctionEnd",
553 2, 0),
554 // Test case 25: fold -24 >> 32 (defined as -1)
555 InstructionFoldingCase<uint32_t>(
556 Header() + "%main = OpFunction %void None %void_func\n" +
557 "%main_lab = OpLabel\n" +
558 "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
559 "OpReturn\n" +
560 "OpFunctionEnd",
561 2, -1),
562 // Test case 26: fold 2 >> 32 (signed)
563 InstructionFoldingCase<uint32_t>(
564 Header() + "%main = OpFunction %void None %void_func\n" +
565 "%main_lab = OpLabel\n" +
566 "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
567 "OpReturn\n" +
568 "OpFunctionEnd",
569 2, 0),
570 // Test case 27: fold 2 >> 32 (unsigned)
571 InstructionFoldingCase<uint32_t>(
572 Header() + "%main = OpFunction %void None %void_func\n" +
573 "%main_lab = OpLabel\n" +
574 "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
575 "OpReturn\n" +
576 "OpFunctionEnd",
577 2, 0),
578 // Test case 28: fold 2 << 32
579 InstructionFoldingCase<uint32_t>(
580 Header() + "%main = OpFunction %void None %void_func\n" +
581 "%main_lab = OpLabel\n" +
582 "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
583 "OpReturn\n" +
584 "OpFunctionEnd",
585 2, 0),
586 // Test case 29: fold -INT_MIN
587 InstructionFoldingCase<uint32_t>(
588 Header() + "%main = OpFunction %void None %void_func\n" +
589 "%main_lab = OpLabel\n" +
590 "%2 = OpSNegate %int %int_min\n" +
591 "OpReturn\n" +
592 "OpFunctionEnd",
593 2, std::numeric_limits<int32_t>::min()),
594 // Test case 30: fold UMin 3 4
595 InstructionFoldingCase<uint32_t>(
596 Header() + "%main = OpFunction %void None %void_func\n" +
597 "%main_lab = OpLabel\n" +
598 "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
599 "OpReturn\n" +
600 "OpFunctionEnd",
601 2, 3),
602 // Test case 31: fold UMin 4 2
603 InstructionFoldingCase<uint32_t>(
604 Header() + "%main = OpFunction %void None %void_func\n" +
605 "%main_lab = OpLabel\n" +
606 "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
607 "OpReturn\n" +
608 "OpFunctionEnd",
609 2, 2),
610 // Test case 32: fold SMin 3 4
611 InstructionFoldingCase<uint32_t>(
612 Header() + "%main = OpFunction %void None %void_func\n" +
613 "%main_lab = OpLabel\n" +
614 "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
615 "OpReturn\n" +
616 "OpFunctionEnd",
617 2, 3),
618 // Test case 33: fold SMin 4 2
619 InstructionFoldingCase<uint32_t>(
620 Header() + "%main = OpFunction %void None %void_func\n" +
621 "%main_lab = OpLabel\n" +
622 "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
623 "OpReturn\n" +
624 "OpFunctionEnd",
625 2, 2),
626 // Test case 34: fold UMax 3 4
627 InstructionFoldingCase<uint32_t>(
628 Header() + "%main = OpFunction %void None %void_func\n" +
629 "%main_lab = OpLabel\n" +
630 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
631 "OpReturn\n" +
632 "OpFunctionEnd",
633 2, 4),
634 // Test case 35: fold UMax 3 2
635 InstructionFoldingCase<uint32_t>(
636 Header() + "%main = OpFunction %void None %void_func\n" +
637 "%main_lab = OpLabel\n" +
638 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
639 "OpReturn\n" +
640 "OpFunctionEnd",
641 2, 3),
642 // Test case 36: fold SMax 3 4
643 InstructionFoldingCase<uint32_t>(
644 Header() + "%main = OpFunction %void None %void_func\n" +
645 "%main_lab = OpLabel\n" +
646 "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
647 "OpReturn\n" +
648 "OpFunctionEnd",
649 2, 4),
650 // Test case 37: fold SMax 3 2
651 InstructionFoldingCase<uint32_t>(
652 Header() + "%main = OpFunction %void None %void_func\n" +
653 "%main_lab = OpLabel\n" +
654 "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
655 "OpReturn\n" +
656 "OpFunctionEnd",
657 2, 3),
658 // Test case 38: fold UClamp 2 3 4
659 InstructionFoldingCase<uint32_t>(
660 Header() + "%main = OpFunction %void None %void_func\n" +
661 "%main_lab = OpLabel\n" +
662 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
663 "OpReturn\n" +
664 "OpFunctionEnd",
665 2, 3),
666 // Test case 39: fold UClamp 2 0 4
667 InstructionFoldingCase<uint32_t>(
668 Header() + "%main = OpFunction %void None %void_func\n" +
669 "%main_lab = OpLabel\n" +
670 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
671 "OpReturn\n" +
672 "OpFunctionEnd",
673 2, 2),
674 // Test case 40: fold UClamp 2 0 1
675 InstructionFoldingCase<uint32_t>(
676 Header() + "%main = OpFunction %void None %void_func\n" +
677 "%main_lab = OpLabel\n" +
678 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
679 "OpReturn\n" +
680 "OpFunctionEnd",
681 2, 1),
682 // Test case 41: fold SClamp 2 3 4
683 InstructionFoldingCase<uint32_t>(
684 Header() + "%main = OpFunction %void None %void_func\n" +
685 "%main_lab = OpLabel\n" +
686 "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
687 "OpReturn\n" +
688 "OpFunctionEnd",
689 2, 3),
690 // Test case 42: fold SClamp 2 0 4
691 InstructionFoldingCase<uint32_t>(
692 Header() + "%main = OpFunction %void None %void_func\n" +
693 "%main_lab = OpLabel\n" +
694 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
695 "OpReturn\n" +
696 "OpFunctionEnd",
697 2, 2),
698 // Test case 43: fold SClamp 2 0 1
699 InstructionFoldingCase<uint32_t>(
700 Header() + "%main = OpFunction %void None %void_func\n" +
701 "%main_lab = OpLabel\n" +
702 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
703 "OpReturn\n" +
704 "OpFunctionEnd",
705 2, 1),
706 // Test case 44: SClamp 1 2 x
707 InstructionFoldingCase<uint32_t>(
708 Header() + "%main = OpFunction %void None %void_func\n" +
709 "%main_lab = OpLabel\n" +
710 "%undef = OpUndef %int\n" +
711 "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
712 "OpReturn\n" +
713 "OpFunctionEnd",
714 2, 2),
715 // Test case 45: SClamp 2 x 1
716 InstructionFoldingCase<uint32_t>(
717 Header() + "%main = OpFunction %void None %void_func\n" +
718 "%main_lab = OpLabel\n" +
719 "%undef = OpUndef %int\n" +
720 "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
721 "OpReturn\n" +
722 "OpFunctionEnd",
723 2, 1),
724 // Test case 44: UClamp 1 2 x
725 InstructionFoldingCase<uint32_t>(
726 Header() + "%main = OpFunction %void None %void_func\n" +
727 "%main_lab = OpLabel\n" +
728 "%undef = OpUndef %uint\n" +
729 "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
730 "OpReturn\n" +
731 "OpFunctionEnd",
732 2, 2),
733 // Test case 45: UClamp 2 x 1
734 InstructionFoldingCase<uint32_t>(
735 Header() + "%main = OpFunction %void None %void_func\n" +
736 "%main_lab = OpLabel\n" +
737 "%undef = OpUndef %uint\n" +
738 "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
739 "OpReturn\n" +
740 "OpFunctionEnd",
741 2, 1),
742 // Test case 46: Bit-cast int 0 to unsigned int
743 InstructionFoldingCase<uint32_t>(
744 Header() + "%main = OpFunction %void None %void_func\n" +
745 "%main_lab = OpLabel\n" +
746 "%2 = OpBitcast %uint %int_0\n" +
747 "OpReturn\n" +
748 "OpFunctionEnd",
749 2, 0),
750 // Test case 47: Bit-cast int -24 to unsigned int
751 InstructionFoldingCase<uint32_t>(
752 Header() + "%main = OpFunction %void None %void_func\n" +
753 "%main_lab = OpLabel\n" +
754 "%2 = OpBitcast %uint %int_n24\n" +
755 "OpReturn\n" +
756 "OpFunctionEnd",
757 2, static_cast<uint32_t>(-24)),
758 // Test case 48: Bit-cast float 1.0f to unsigned int
759 InstructionFoldingCase<uint32_t>(
760 Header() + "%main = OpFunction %void None %void_func\n" +
761 "%main_lab = OpLabel\n" +
762 "%2 = OpBitcast %uint %float_1\n" +
763 "OpReturn\n" +
764 "OpFunctionEnd",
765 2, static_cast<uint32_t>(0x3f800000))
766 ));
767 // clang-format on
768
769 using IntVectorInstructionFoldingTest =
770 ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
771
TEST_P(IntVectorInstructionFoldingTest,Case)772 TEST_P(IntVectorInstructionFoldingTest, Case) {
773 const auto& tc = GetParam();
774
775 // Build module.
776 std::unique_ptr<IRContext> context =
777 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
778 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
779 ASSERT_NE(nullptr, context);
780
781 // Fold the instruction to test.
782 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
783 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
784 SpvOp original_opcode = inst->opcode();
785 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
786
787 // Make sure the instruction folded as expected.
788 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
789 if (succeeded && inst != nullptr) {
790 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
791 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
792 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
793 EXPECT_THAT(opcodes, Contains(inst->opcode()));
794 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
795 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
796 EXPECT_NE(result, nullptr);
797 if (result != nullptr) {
798 const std::vector<const analysis::Constant*>& componenets =
799 result->AsVectorConstant()->GetComponents();
800 EXPECT_EQ(componenets.size(), tc.expected_result.size());
801 for (size_t i = 0; i < componenets.size(); i++) {
802 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
803 }
804 }
805 }
806 }
807
808 // clang-format off
809 INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
810 ::testing::Values(
811 // Test case 0: fold 0*n
812 InstructionFoldingCase<std::vector<uint32_t>>(
813 Header() + "%main = OpFunction %void None %void_func\n" +
814 "%main_lab = OpLabel\n" +
815 "%n = OpVariable %_ptr_int Function\n" +
816 "%load = OpLoad %int %n\n" +
817 "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
818 "OpReturn\n" +
819 "OpFunctionEnd",
820 2, {2,3}),
821 InstructionFoldingCase<std::vector<uint32_t>>(
822 Header() + "%main = OpFunction %void None %void_func\n" +
823 "%main_lab = OpLabel\n" +
824 "%n = OpVariable %_ptr_int Function\n" +
825 "%load = OpLoad %int %n\n" +
826 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
827 "OpReturn\n" +
828 "OpFunctionEnd",
829 2, {0,3}),
830 InstructionFoldingCase<std::vector<uint32_t>>(
831 Header() + "%main = OpFunction %void None %void_func\n" +
832 "%main_lab = OpLabel\n" +
833 "%n = OpVariable %_ptr_int Function\n" +
834 "%load = OpLoad %int %n\n" +
835 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
836 "OpReturn\n" +
837 "OpFunctionEnd",
838 2, {0,0}),
839 InstructionFoldingCase<std::vector<uint32_t>>(
840 Header() + "%main = OpFunction %void None %void_func\n" +
841 "%main_lab = OpLabel\n" +
842 "%n = OpVariable %_ptr_int Function\n" +
843 "%load = OpLoad %int %n\n" +
844 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
845 "OpReturn\n" +
846 "OpFunctionEnd",
847 2, {0,0}),
848 // Test case 4: fold bit-cast int -24 to unsigned int
849 InstructionFoldingCase<std::vector<uint32_t>>(
850 Header() + "%main = OpFunction %void None %void_func\n" +
851 "%main_lab = OpLabel\n" +
852 "%n = OpVariable %_ptr_int Function\n" +
853 "%load = OpLoad %int %n\n" +
854 "%2 = OpBitcast %v2uint %v2int_min_max\n" +
855 "OpReturn\n" +
856 "OpFunctionEnd",
857 2, {2147483648, 2147483647})
858 ));
859 // clang-format on
860
861 using DoubleVectorInstructionFoldingTest =
862 ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
863
TEST_P(DoubleVectorInstructionFoldingTest,Case)864 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
865 const auto& tc = GetParam();
866
867 // Build module.
868 std::unique_ptr<IRContext> context =
869 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
870 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
871 ASSERT_NE(nullptr, context);
872
873 // Fold the instruction to test.
874 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
875 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
876 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
877
878 // Make sure the instruction folded as expected.
879 EXPECT_TRUE(succeeded);
880 if (succeeded && inst != nullptr) {
881 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
882 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
883 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
884 EXPECT_THAT(opcodes, Contains(inst->opcode()));
885 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
886 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
887 EXPECT_NE(result, nullptr);
888 if (result != nullptr) {
889 const std::vector<const analysis::Constant*>& componenets =
890 result->AsVectorConstant()->GetComponents();
891 EXPECT_EQ(componenets.size(), tc.expected_result.size());
892 for (size_t i = 0; i < componenets.size(); i++) {
893 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble());
894 }
895 }
896 }
897 }
898
899 // clang-format off
900 INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
901 ::testing::Values(
902 // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
903 // to double vector
904 InstructionFoldingCase<std::vector<double>>(
905 Header() + "%main = OpFunction %void None %void_func\n" +
906 "%main_lab = OpLabel\n" +
907 "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
908 "OpReturn\n" +
909 "OpFunctionEnd",
910 2, {1.0,-127.35})
911 ));
912
913 using FloatVectorInstructionFoldingTest =
914 ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
915
TEST_P(FloatVectorInstructionFoldingTest,Case)916 TEST_P(FloatVectorInstructionFoldingTest, Case) {
917 const auto& tc = GetParam();
918
919 // Build module.
920 std::unique_ptr<IRContext> context =
921 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
922 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
923 ASSERT_NE(nullptr, context);
924
925 // Fold the instruction to test.
926 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
927 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
928 SpvOp original_opcode = inst->opcode();
929 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
930
931 // Make sure the instruction folded as expected.
932 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
933 if (succeeded && inst != nullptr) {
934 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
935 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
936 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
937 EXPECT_THAT(opcodes, Contains(inst->opcode()));
938 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
939 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
940 EXPECT_NE(result, nullptr);
941 if (result != nullptr) {
942 const std::vector<const analysis::Constant*>& componenets =
943 result->AsVectorConstant()->GetComponents();
944 EXPECT_EQ(componenets.size(), tc.expected_result.size());
945 for (size_t i = 0; i < componenets.size(); i++) {
946 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
947 }
948 }
949 }
950 }
951
952 // clang-format off
953 INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
954 ::testing::Values(
955 // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
956 InstructionFoldingCase<std::vector<float>>(
957 Header() + "%main = OpFunction %void None %void_func\n" +
958 "%main_lab = OpLabel\n" +
959 "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
960 "OpReturn\n" +
961 "OpFunctionEnd",
962 2, {1.6f,1.5f}),
963 // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
964 // float vector
965 InstructionFoldingCase<std::vector<float>>(
966 Header() + "%main = OpFunction %void None %void_func\n" +
967 "%main_lab = OpLabel\n" +
968 "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
969 "OpReturn\n" +
970 "OpFunctionEnd",
971 2, {1.0f,-1.0f}),
972 // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
973 InstructionFoldingCase<std::vector<float>>(
974 Header() + "%main = OpFunction %void None %void_func\n" +
975 "%main_lab = OpLabel\n" +
976 "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
977 "OpReturn\n" +
978 "OpFunctionEnd",
979 2, {1.0f,-1.0f})
980 ));
981 // clang-format on
982 using BooleanInstructionFoldingTest =
983 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
984
TEST_P(BooleanInstructionFoldingTest,Case)985 TEST_P(BooleanInstructionFoldingTest, Case) {
986 const auto& tc = GetParam();
987
988 // Build module.
989 std::unique_ptr<IRContext> context =
990 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
991 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
992 ASSERT_NE(nullptr, context);
993
994 // Fold the instruction to test.
995 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
996 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
997 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
998
999 // Make sure the instruction folded as expected.
1000 EXPECT_TRUE(succeeded);
1001 if (inst != nullptr) {
1002 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1003 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1004 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
1005 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
1006 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1007 const analysis::BoolConstant* result =
1008 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
1009 EXPECT_NE(result, nullptr);
1010 if (result != nullptr) {
1011 EXPECT_EQ(result->value(), tc.expected_result);
1012 }
1013 }
1014 }
1015
1016 // clang-format off
1017 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
1018 ::testing::Values(
1019 // Test case 0: fold true || n
1020 InstructionFoldingCase<bool>(
1021 Header() + "%main = OpFunction %void None %void_func\n" +
1022 "%main_lab = OpLabel\n" +
1023 "%n = OpVariable %_ptr_bool Function\n" +
1024 "%load = OpLoad %bool %n\n" +
1025 "%2 = OpLogicalOr %bool %true %load\n" +
1026 "OpReturn\n" +
1027 "OpFunctionEnd",
1028 2, true),
1029 // Test case 1: fold n || true
1030 InstructionFoldingCase<bool>(
1031 Header() + "%main = OpFunction %void None %void_func\n" +
1032 "%main_lab = OpLabel\n" +
1033 "%n = OpVariable %_ptr_bool Function\n" +
1034 "%load = OpLoad %bool %n\n" +
1035 "%2 = OpLogicalOr %bool %load %true\n" +
1036 "OpReturn\n" +
1037 "OpFunctionEnd",
1038 2, true),
1039 // Test case 2: fold false && n
1040 InstructionFoldingCase<bool>(
1041 Header() + "%main = OpFunction %void None %void_func\n" +
1042 "%main_lab = OpLabel\n" +
1043 "%n = OpVariable %_ptr_bool Function\n" +
1044 "%load = OpLoad %bool %n\n" +
1045 "%2 = OpLogicalAnd %bool %false %load\n" +
1046 "OpReturn\n" +
1047 "OpFunctionEnd",
1048 2, false),
1049 // Test case 3: fold n && false
1050 InstructionFoldingCase<bool>(
1051 Header() + "%main = OpFunction %void None %void_func\n" +
1052 "%main_lab = OpLabel\n" +
1053 "%n = OpVariable %_ptr_bool Function\n" +
1054 "%load = OpLoad %bool %n\n" +
1055 "%2 = OpLogicalAnd %bool %load %false\n" +
1056 "OpReturn\n" +
1057 "OpFunctionEnd",
1058 2, false),
1059 // Test case 4: fold n < 0 (unsigned)
1060 InstructionFoldingCase<bool>(
1061 Header() + "%main = OpFunction %void None %void_func\n" +
1062 "%main_lab = OpLabel\n" +
1063 "%n = OpVariable %_ptr_uint Function\n" +
1064 "%load = OpLoad %uint %n\n" +
1065 "%2 = OpULessThan %bool %load %uint_0\n" +
1066 "OpReturn\n" +
1067 "OpFunctionEnd",
1068 2, false),
1069 // Test case 5: fold UINT_MAX < n (unsigned)
1070 InstructionFoldingCase<bool>(
1071 Header() + "%main = OpFunction %void None %void_func\n" +
1072 "%main_lab = OpLabel\n" +
1073 "%n = OpVariable %_ptr_uint Function\n" +
1074 "%load = OpLoad %uint %n\n" +
1075 "%2 = OpULessThan %bool %uint_max %load\n" +
1076 "OpReturn\n" +
1077 "OpFunctionEnd",
1078 2, false),
1079 // Test case 6: fold INT_MAX < n (signed)
1080 InstructionFoldingCase<bool>(
1081 Header() + "%main = OpFunction %void None %void_func\n" +
1082 "%main_lab = OpLabel\n" +
1083 "%n = OpVariable %_ptr_int Function\n" +
1084 "%load = OpLoad %int %n\n" +
1085 "%2 = OpSLessThan %bool %int_max %load\n" +
1086 "OpReturn\n" +
1087 "OpFunctionEnd",
1088 2, false),
1089 // Test case 7: fold n < INT_MIN (signed)
1090 InstructionFoldingCase<bool>(
1091 Header() + "%main = OpFunction %void None %void_func\n" +
1092 "%main_lab = OpLabel\n" +
1093 "%n = OpVariable %_ptr_int Function\n" +
1094 "%load = OpLoad %int %n\n" +
1095 "%2 = OpSLessThan %bool %load %int_min\n" +
1096 "OpReturn\n" +
1097 "OpFunctionEnd",
1098 2, false),
1099 // Test case 8: fold 0 > n (unsigned)
1100 InstructionFoldingCase<bool>(
1101 Header() + "%main = OpFunction %void None %void_func\n" +
1102 "%main_lab = OpLabel\n" +
1103 "%n = OpVariable %_ptr_uint Function\n" +
1104 "%load = OpLoad %uint %n\n" +
1105 "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
1106 "OpReturn\n" +
1107 "OpFunctionEnd",
1108 2, false),
1109 // Test case 9: fold n > UINT_MAX (unsigned)
1110 InstructionFoldingCase<bool>(
1111 Header() + "%main = OpFunction %void None %void_func\n" +
1112 "%main_lab = OpLabel\n" +
1113 "%n = OpVariable %_ptr_uint Function\n" +
1114 "%load = OpLoad %uint %n\n" +
1115 "%2 = OpUGreaterThan %bool %load %uint_max\n" +
1116 "OpReturn\n" +
1117 "OpFunctionEnd",
1118 2, false),
1119 // Test case 10: fold n > INT_MAX (signed)
1120 InstructionFoldingCase<bool>(
1121 Header() + "%main = OpFunction %void None %void_func\n" +
1122 "%main_lab = OpLabel\n" +
1123 "%n = OpVariable %_ptr_int Function\n" +
1124 "%load = OpLoad %int %n\n" +
1125 "%2 = OpSGreaterThan %bool %load %int_max\n" +
1126 "OpReturn\n" +
1127 "OpFunctionEnd",
1128 2, false),
1129 // Test case 11: fold INT_MIN > n (signed)
1130 InstructionFoldingCase<bool>(
1131 Header() + "%main = OpFunction %void None %void_func\n" +
1132 "%main_lab = OpLabel\n" +
1133 "%n = OpVariable %_ptr_uint Function\n" +
1134 "%load = OpLoad %uint %n\n" +
1135 "%2 = OpSGreaterThan %bool %int_min %load\n" +
1136 "OpReturn\n" +
1137 "OpFunctionEnd",
1138 2, false),
1139 // Test case 12: fold 0 <= n (unsigned)
1140 InstructionFoldingCase<bool>(
1141 Header() + "%main = OpFunction %void None %void_func\n" +
1142 "%main_lab = OpLabel\n" +
1143 "%n = OpVariable %_ptr_uint Function\n" +
1144 "%load = OpLoad %uint %n\n" +
1145 "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
1146 "OpReturn\n" +
1147 "OpFunctionEnd",
1148 2, true),
1149 // Test case 13: fold n <= UINT_MAX (unsigned)
1150 InstructionFoldingCase<bool>(
1151 Header() + "%main = OpFunction %void None %void_func\n" +
1152 "%main_lab = OpLabel\n" +
1153 "%n = OpVariable %_ptr_uint Function\n" +
1154 "%load = OpLoad %uint %n\n" +
1155 "%2 = OpULessThanEqual %bool %load %uint_max\n" +
1156 "OpReturn\n" +
1157 "OpFunctionEnd",
1158 2, true),
1159 // Test case 14: fold INT_MIN <= n (signed)
1160 InstructionFoldingCase<bool>(
1161 Header() + "%main = OpFunction %void None %void_func\n" +
1162 "%main_lab = OpLabel\n" +
1163 "%n = OpVariable %_ptr_int Function\n" +
1164 "%load = OpLoad %int %n\n" +
1165 "%2 = OpSLessThanEqual %bool %int_min %load\n" +
1166 "OpReturn\n" +
1167 "OpFunctionEnd",
1168 2, true),
1169 // Test case 15: fold n <= INT_MAX (signed)
1170 InstructionFoldingCase<bool>(
1171 Header() + "%main = OpFunction %void None %void_func\n" +
1172 "%main_lab = OpLabel\n" +
1173 "%n = OpVariable %_ptr_int Function\n" +
1174 "%load = OpLoad %int %n\n" +
1175 "%2 = OpSLessThanEqual %bool %load %int_max\n" +
1176 "OpReturn\n" +
1177 "OpFunctionEnd",
1178 2, true),
1179 // Test case 16: fold n >= 0 (unsigned)
1180 InstructionFoldingCase<bool>(
1181 Header() + "%main = OpFunction %void None %void_func\n" +
1182 "%main_lab = OpLabel\n" +
1183 "%n = OpVariable %_ptr_uint Function\n" +
1184 "%load = OpLoad %uint %n\n" +
1185 "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
1186 "OpReturn\n" +
1187 "OpFunctionEnd",
1188 2, true),
1189 // Test case 17: fold UINT_MAX >= n (unsigned)
1190 InstructionFoldingCase<bool>(
1191 Header() + "%main = OpFunction %void None %void_func\n" +
1192 "%main_lab = OpLabel\n" +
1193 "%n = OpVariable %_ptr_uint Function\n" +
1194 "%load = OpLoad %uint %n\n" +
1195 "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
1196 "OpReturn\n" +
1197 "OpFunctionEnd",
1198 2, true),
1199 // Test case 18: fold n >= INT_MIN (signed)
1200 InstructionFoldingCase<bool>(
1201 Header() + "%main = OpFunction %void None %void_func\n" +
1202 "%main_lab = OpLabel\n" +
1203 "%n = OpVariable %_ptr_int Function\n" +
1204 "%load = OpLoad %int %n\n" +
1205 "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
1206 "OpReturn\n" +
1207 "OpFunctionEnd",
1208 2, true),
1209 // Test case 19: fold INT_MAX >= n (signed)
1210 InstructionFoldingCase<bool>(
1211 Header() + "%main = OpFunction %void None %void_func\n" +
1212 "%main_lab = OpLabel\n" +
1213 "%n = OpVariable %_ptr_int Function\n" +
1214 "%load = OpLoad %int %n\n" +
1215 "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
1216 "OpReturn\n" +
1217 "OpFunctionEnd",
1218 2, true)
1219 ));
1220
1221 INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
1222 ::testing::Values(
1223 // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
1224 InstructionFoldingCase<bool>(
1225 Header() + "%main = OpFunction %void None %void_func\n" +
1226 "%main_lab = OpLabel\n" +
1227 "%n = OpVariable %_ptr_float Function\n" +
1228 "%ld = OpLoad %float %n\n" +
1229 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1230 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1231 "OpReturn\n" +
1232 "OpFunctionEnd",
1233 2, false),
1234 // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
1235 InstructionFoldingCase<bool>(
1236 Header() + "%main = OpFunction %void None %void_func\n" +
1237 "%main_lab = OpLabel\n" +
1238 "%n = OpVariable %_ptr_float Function\n" +
1239 "%ld = OpLoad %float %n\n" +
1240 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1241 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1242 "OpReturn\n" +
1243 "OpFunctionEnd",
1244 2, true),
1245 // Test case 2: fold 0.0 >= clamp(n, 1, 2)
1246 InstructionFoldingCase<bool>(
1247 Header() + "%main = OpFunction %void None %void_func\n" +
1248 "%main_lab = OpLabel\n" +
1249 "%n = OpVariable %_ptr_float Function\n" +
1250 "%ld = OpLoad %float %n\n" +
1251 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1252 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1253 "OpReturn\n" +
1254 "OpFunctionEnd",
1255 2, false),
1256 // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
1257 InstructionFoldingCase<bool>(
1258 Header() + "%main = OpFunction %void None %void_func\n" +
1259 "%main_lab = OpLabel\n" +
1260 "%n = OpVariable %_ptr_float Function\n" +
1261 "%ld = OpLoad %float %n\n" +
1262 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1263 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1264 "OpReturn\n" +
1265 "OpFunctionEnd",
1266 2, true),
1267 // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
1268 InstructionFoldingCase<bool>(
1269 Header() + "%main = OpFunction %void None %void_func\n" +
1270 "%main_lab = OpLabel\n" +
1271 "%n = OpVariable %_ptr_float Function\n" +
1272 "%ld = OpLoad %float %n\n" +
1273 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1274 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1275 "OpReturn\n" +
1276 "OpFunctionEnd",
1277 2, true),
1278 // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
1279 InstructionFoldingCase<bool>(
1280 Header() + "%main = OpFunction %void None %void_func\n" +
1281 "%main_lab = OpLabel\n" +
1282 "%n = OpVariable %_ptr_float Function\n" +
1283 "%ld = OpLoad %float %n\n" +
1284 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1285 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1286 "OpReturn\n" +
1287 "OpFunctionEnd",
1288 2, false),
1289 // Test case 6: fold 0.0 < clamp(n, 1, 2)
1290 InstructionFoldingCase<bool>(
1291 Header() + "%main = OpFunction %void None %void_func\n" +
1292 "%main_lab = OpLabel\n" +
1293 "%n = OpVariable %_ptr_float Function\n" +
1294 "%ld = OpLoad %float %n\n" +
1295 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1296 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1297 "OpReturn\n" +
1298 "OpFunctionEnd",
1299 2, true),
1300 // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
1301 InstructionFoldingCase<bool>(
1302 Header() + "%main = OpFunction %void None %void_func\n" +
1303 "%main_lab = OpLabel\n" +
1304 "%n = OpVariable %_ptr_float Function\n" +
1305 "%ld = OpLoad %float %n\n" +
1306 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1307 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1308 "OpReturn\n" +
1309 "OpFunctionEnd",
1310 2, false),
1311 // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
1312 InstructionFoldingCase<bool>(
1313 Header() + "%main = OpFunction %void None %void_func\n" +
1314 "%main_lab = OpLabel\n" +
1315 "%n = OpVariable %_ptr_float Function\n" +
1316 "%ld = OpLoad %float %n\n" +
1317 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1318 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1319 "OpReturn\n" +
1320 "OpFunctionEnd",
1321 2, false),
1322 // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
1323 InstructionFoldingCase<bool>(
1324 Header() + "%main = OpFunction %void None %void_func\n" +
1325 "%main_lab = OpLabel\n" +
1326 "%n = OpVariable %_ptr_float Function\n" +
1327 "%ld = OpLoad %float %n\n" +
1328 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1329 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1330 "OpReturn\n" +
1331 "OpFunctionEnd",
1332 2, true),
1333 // Test case 10: fold 0.0 >= clamp(n, 1, 2)
1334 InstructionFoldingCase<bool>(
1335 Header() + "%main = OpFunction %void None %void_func\n" +
1336 "%main_lab = OpLabel\n" +
1337 "%n = OpVariable %_ptr_float Function\n" +
1338 "%ld = OpLoad %float %n\n" +
1339 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1340 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1341 "OpReturn\n" +
1342 "OpFunctionEnd",
1343 2, false),
1344 // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
1345 InstructionFoldingCase<bool>(
1346 Header() + "%main = OpFunction %void None %void_func\n" +
1347 "%main_lab = OpLabel\n" +
1348 "%n = OpVariable %_ptr_float Function\n" +
1349 "%ld = OpLoad %float %n\n" +
1350 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1351 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1352 "OpReturn\n" +
1353 "OpFunctionEnd",
1354 2, true),
1355 // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
1356 InstructionFoldingCase<bool>(
1357 Header() + "%main = OpFunction %void None %void_func\n" +
1358 "%main_lab = OpLabel\n" +
1359 "%n = OpVariable %_ptr_float Function\n" +
1360 "%ld = OpLoad %float %n\n" +
1361 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1362 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1363 "OpReturn\n" +
1364 "OpFunctionEnd",
1365 2, true),
1366 // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
1367 InstructionFoldingCase<bool>(
1368 Header() + "%main = OpFunction %void None %void_func\n" +
1369 "%main_lab = OpLabel\n" +
1370 "%n = OpVariable %_ptr_float Function\n" +
1371 "%ld = OpLoad %float %n\n" +
1372 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1373 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1374 "OpReturn\n" +
1375 "OpFunctionEnd",
1376 2, false),
1377 // Test case 14: fold 0.0 < clamp(n, 1, 2)
1378 InstructionFoldingCase<bool>(
1379 Header() + "%main = OpFunction %void None %void_func\n" +
1380 "%main_lab = OpLabel\n" +
1381 "%n = OpVariable %_ptr_float Function\n" +
1382 "%ld = OpLoad %float %n\n" +
1383 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1384 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1385 "OpReturn\n" +
1386 "OpFunctionEnd",
1387 2, true),
1388 // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
1389 InstructionFoldingCase<bool>(
1390 Header() + "%main = OpFunction %void None %void_func\n" +
1391 "%main_lab = OpLabel\n" +
1392 "%n = OpVariable %_ptr_float Function\n" +
1393 "%ld = OpLoad %float %n\n" +
1394 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1395 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1396 "OpReturn\n" +
1397 "OpFunctionEnd",
1398 2, false)
1399 ));
1400
1401 INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
1402 ::testing::Values(
1403 // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
1404 InstructionFoldingCase<bool>(
1405 Header() + "%main = OpFunction %void None %void_func\n" +
1406 "%main_lab = OpLabel\n" +
1407 "%n = OpVariable %_ptr_float Function\n" +
1408 "%ld = OpLoad %float %n\n" +
1409 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1410 "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
1411 "OpReturn\n" +
1412 "OpFunctionEnd",
1413 2, false),
1414 // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
1415 InstructionFoldingCase<bool>(
1416 Header() + "%main = OpFunction %void None %void_func\n" +
1417 "%main_lab = OpLabel\n" +
1418 "%n = OpVariable %_ptr_float Function\n" +
1419 "%ld = OpLoad %float %n\n" +
1420 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1421 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
1422 "OpReturn\n" +
1423 "OpFunctionEnd",
1424 2, true),
1425 // Test case 2: fold clamp(n, 1, 2) >= 0.0
1426 InstructionFoldingCase<bool>(
1427 Header() + "%main = OpFunction %void None %void_func\n" +
1428 "%main_lab = OpLabel\n" +
1429 "%n = OpVariable %_ptr_float Function\n" +
1430 "%ld = OpLoad %float %n\n" +
1431 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1432 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
1433 "OpReturn\n" +
1434 "OpFunctionEnd",
1435 2, true),
1436 // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
1437 InstructionFoldingCase<bool>(
1438 Header() + "%main = OpFunction %void None %void_func\n" +
1439 "%main_lab = OpLabel\n" +
1440 "%n = OpVariable %_ptr_float Function\n" +
1441 "%ld = OpLoad %float %n\n" +
1442 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1443 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
1444 "OpReturn\n" +
1445 "OpFunctionEnd",
1446 2, false),
1447 // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
1448 InstructionFoldingCase<bool>(
1449 Header() + "%main = OpFunction %void None %void_func\n" +
1450 "%main_lab = OpLabel\n" +
1451 "%n = OpVariable %_ptr_float Function\n" +
1452 "%ld = OpLoad %float %n\n" +
1453 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1454 "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
1455 "OpReturn\n" +
1456 "OpFunctionEnd",
1457 2, true),
1458 // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
1459 InstructionFoldingCase<bool>(
1460 Header() + "%main = OpFunction %void None %void_func\n" +
1461 "%main_lab = OpLabel\n" +
1462 "%n = OpVariable %_ptr_float Function\n" +
1463 "%ld = OpLoad %float %n\n" +
1464 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1465 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
1466 "OpReturn\n" +
1467 "OpFunctionEnd",
1468 2, false),
1469 // Test case 6: fold clamp(n, 1, 2) < 3
1470 InstructionFoldingCase<bool>(
1471 Header() + "%main = OpFunction %void None %void_func\n" +
1472 "%main_lab = OpLabel\n" +
1473 "%n = OpVariable %_ptr_float Function\n" +
1474 "%ld = OpLoad %float %n\n" +
1475 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1476 "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
1477 "OpReturn\n" +
1478 "OpFunctionEnd",
1479 2, true),
1480 // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
1481 InstructionFoldingCase<bool>(
1482 Header() + "%main = OpFunction %void None %void_func\n" +
1483 "%main_lab = OpLabel\n" +
1484 "%n = OpVariable %_ptr_float Function\n" +
1485 "%ld = OpLoad %float %n\n" +
1486 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1487 "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
1488 "OpReturn\n" +
1489 "OpFunctionEnd",
1490 2, false),
1491 // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
1492 InstructionFoldingCase<bool>(
1493 Header() + "%main = OpFunction %void None %void_func\n" +
1494 "%main_lab = OpLabel\n" +
1495 "%n = OpVariable %_ptr_float Function\n" +
1496 "%ld = OpLoad %float %n\n" +
1497 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1498 "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
1499 "OpReturn\n" +
1500 "OpFunctionEnd",
1501 2, false),
1502 // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
1503 InstructionFoldingCase<bool>(
1504 Header() + "%main = OpFunction %void None %void_func\n" +
1505 "%main_lab = OpLabel\n" +
1506 "%n = OpVariable %_ptr_float Function\n" +
1507 "%ld = OpLoad %float %n\n" +
1508 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1509 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
1510 "OpReturn\n" +
1511 "OpFunctionEnd",
1512 2, true),
1513 // Test case 10: fold clamp(n, 1, 2) >= 3.0
1514 InstructionFoldingCase<bool>(
1515 Header() + "%main = OpFunction %void None %void_func\n" +
1516 "%main_lab = OpLabel\n" +
1517 "%n = OpVariable %_ptr_float Function\n" +
1518 "%ld = OpLoad %float %n\n" +
1519 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1520 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
1521 "OpReturn\n" +
1522 "OpFunctionEnd",
1523 2, false),
1524 // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
1525 InstructionFoldingCase<bool>(
1526 Header() + "%main = OpFunction %void None %void_func\n" +
1527 "%main_lab = OpLabel\n" +
1528 "%n = OpVariable %_ptr_float Function\n" +
1529 "%ld = OpLoad %float %n\n" +
1530 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1531 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
1532 "OpReturn\n" +
1533 "OpFunctionEnd",
1534 2, true),
1535 // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
1536 InstructionFoldingCase<bool>(
1537 Header() + "%main = OpFunction %void None %void_func\n" +
1538 "%main_lab = OpLabel\n" +
1539 "%n = OpVariable %_ptr_float Function\n" +
1540 "%ld = OpLoad %float %n\n" +
1541 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1542 "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
1543 "OpReturn\n" +
1544 "OpFunctionEnd",
1545 2, true),
1546 // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
1547 InstructionFoldingCase<bool>(
1548 Header() + "%main = OpFunction %void None %void_func\n" +
1549 "%main_lab = OpLabel\n" +
1550 "%n = OpVariable %_ptr_float Function\n" +
1551 "%ld = OpLoad %float %n\n" +
1552 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1553 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
1554 "OpReturn\n" +
1555 "OpFunctionEnd",
1556 2, false),
1557 // Test case 14: fold clamp(n, 1, 2) < 3
1558 InstructionFoldingCase<bool>(
1559 Header() + "%main = OpFunction %void None %void_func\n" +
1560 "%main_lab = OpLabel\n" +
1561 "%n = OpVariable %_ptr_float Function\n" +
1562 "%ld = OpLoad %float %n\n" +
1563 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1564 "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
1565 "OpReturn\n" +
1566 "OpFunctionEnd",
1567 2, true),
1568 // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
1569 InstructionFoldingCase<bool>(
1570 Header() + "%main = OpFunction %void None %void_func\n" +
1571 "%main_lab = OpLabel\n" +
1572 "%n = OpVariable %_ptr_float Function\n" +
1573 "%ld = OpLoad %float %n\n" +
1574 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1575 "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
1576 "OpReturn\n" +
1577 "OpFunctionEnd",
1578 2, false),
1579 // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
1580 InstructionFoldingCase<bool>(
1581 Header() + "%main = OpFunction %void None %void_func\n" +
1582 "%main_lab = OpLabel\n" +
1583 "%n = OpVariable %_ptr_double Function\n" +
1584 "%ld = OpLoad %double %n\n" +
1585 "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
1586 "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
1587 "OpReturn\n" +
1588 "OpFunctionEnd",
1589 2, false)
1590 ));
1591 // clang-format on
1592
1593 using FloatInstructionFoldingTest =
1594 ::testing::TestWithParam<InstructionFoldingCase<float>>;
1595
TEST_P(FloatInstructionFoldingTest,Case)1596 TEST_P(FloatInstructionFoldingTest, Case) {
1597 const auto& tc = GetParam();
1598
1599 // Build module.
1600 std::unique_ptr<IRContext> context =
1601 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1602 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1603 ASSERT_NE(nullptr, context);
1604
1605 // Fold the instruction to test.
1606 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1607 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1608 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1609
1610 // Make sure the instruction folded as expected.
1611 EXPECT_TRUE(succeeded);
1612 if (inst != nullptr) {
1613 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1614 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1615 EXPECT_EQ(inst->opcode(), SpvOpConstant);
1616 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1617 const analysis::FloatConstant* result =
1618 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
1619 EXPECT_NE(result, nullptr);
1620 if (result != nullptr) {
1621 if (!std::isnan(tc.expected_result)) {
1622 EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
1623 } else {
1624 EXPECT_TRUE(std::isnan(result->GetFloatValue()));
1625 }
1626 }
1627 }
1628 }
1629
1630 // Not testing NaNs because there are no expectations concerning NaNs according
1631 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
1632 // specification.
1633
1634 // clang-format off
1635 INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
1636 ::testing::Values(
1637 // Test case 0: Fold 2.0 - 1.0
1638 InstructionFoldingCase<float>(
1639 Header() + "%main = OpFunction %void None %void_func\n" +
1640 "%main_lab = OpLabel\n" +
1641 "%2 = OpFSub %float %float_2 %float_1\n" +
1642 "OpReturn\n" +
1643 "OpFunctionEnd",
1644 2, 1.0),
1645 // Test case 1: Fold 2.0 + 1.0
1646 InstructionFoldingCase<float>(
1647 Header() + "%main = OpFunction %void None %void_func\n" +
1648 "%main_lab = OpLabel\n" +
1649 "%2 = OpFAdd %float %float_2 %float_1\n" +
1650 "OpReturn\n" +
1651 "OpFunctionEnd",
1652 2, 3.0),
1653 // Test case 2: Fold 3.0 * 2.0
1654 InstructionFoldingCase<float>(
1655 Header() + "%main = OpFunction %void None %void_func\n" +
1656 "%main_lab = OpLabel\n" +
1657 "%2 = OpFMul %float %float_3 %float_2\n" +
1658 "OpReturn\n" +
1659 "OpFunctionEnd",
1660 2, 6.0),
1661 // Test case 3: Fold 1.0 / 2.0
1662 InstructionFoldingCase<float>(
1663 Header() + "%main = OpFunction %void None %void_func\n" +
1664 "%main_lab = OpLabel\n" +
1665 "%2 = OpFDiv %float %float_1 %float_2\n" +
1666 "OpReturn\n" +
1667 "OpFunctionEnd",
1668 2, 0.5),
1669 // Test case 4: Fold 1.0 / 0.0
1670 InstructionFoldingCase<float>(
1671 Header() + "%main = OpFunction %void None %void_func\n" +
1672 "%main_lab = OpLabel\n" +
1673 "%2 = OpFDiv %float %float_1 %float_0\n" +
1674 "OpReturn\n" +
1675 "OpFunctionEnd",
1676 2, std::numeric_limits<float>::infinity()),
1677 // Test case 5: Fold -1.0 / 0.0
1678 InstructionFoldingCase<float>(
1679 Header() + "%main = OpFunction %void None %void_func\n" +
1680 "%main_lab = OpLabel\n" +
1681 "%2 = OpFDiv %float %float_n1 %float_0\n" +
1682 "OpReturn\n" +
1683 "OpFunctionEnd",
1684 2, -std::numeric_limits<float>::infinity()),
1685 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
1686 InstructionFoldingCase<float>(
1687 Header() + "%main = OpFunction %void None %void_func\n" +
1688 "%main_lab = OpLabel\n" +
1689 "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
1690 "OpReturn\n" +
1691 "OpFunctionEnd",
1692 2, 5.5f),
1693 // Test case 7: Fold (0.0, 0.0) dot v
1694 InstructionFoldingCase<float>(
1695 Header() + "%main = OpFunction %void None %void_func\n" +
1696 "%main_lab = OpLabel\n" +
1697 "%v = OpVariable %_ptr_v2float Function\n" +
1698 "%2 = OpLoad %v2float %v\n" +
1699 "%3 = OpDot %float %v2float_0_0 %2\n" +
1700 "OpReturn\n" +
1701 "OpFunctionEnd",
1702 3, 0.0f),
1703 // Test case 8: Fold v dot (0.0, 0.0)
1704 InstructionFoldingCase<float>(
1705 Header() + "%main = OpFunction %void None %void_func\n" +
1706 "%main_lab = OpLabel\n" +
1707 "%v = OpVariable %_ptr_v2float Function\n" +
1708 "%2 = OpLoad %v2float %v\n" +
1709 "%3 = OpDot %float %2 %v2float_0_0\n" +
1710 "OpReturn\n" +
1711 "OpFunctionEnd",
1712 3, 0.0f),
1713 // Test case 9: Fold Null dot v
1714 InstructionFoldingCase<float>(
1715 Header() + "%main = OpFunction %void None %void_func\n" +
1716 "%main_lab = OpLabel\n" +
1717 "%v = OpVariable %_ptr_v2float Function\n" +
1718 "%2 = OpLoad %v2float %v\n" +
1719 "%3 = OpDot %float %v2float_null %2\n" +
1720 "OpReturn\n" +
1721 "OpFunctionEnd",
1722 3, 0.0f),
1723 // Test case 10: Fold v dot Null
1724 InstructionFoldingCase<float>(
1725 Header() + "%main = OpFunction %void None %void_func\n" +
1726 "%main_lab = OpLabel\n" +
1727 "%v = OpVariable %_ptr_v2float Function\n" +
1728 "%2 = OpLoad %v2float %v\n" +
1729 "%3 = OpDot %float %2 %v2float_null\n" +
1730 "OpReturn\n" +
1731 "OpFunctionEnd",
1732 3, 0.0f),
1733 // Test case 11: Fold -2.0
1734 InstructionFoldingCase<float>(
1735 Header() + "%main = OpFunction %void None %void_func\n" +
1736 "%main_lab = OpLabel\n" +
1737 "%2 = OpFNegate %float %float_2\n" +
1738 "OpReturn\n" +
1739 "OpFunctionEnd",
1740 2, -2),
1741 // Test case 12: QuantizeToF16 1.0
1742 InstructionFoldingCase<float>(
1743 Header() + "%main = OpFunction %void None %void_func\n" +
1744 "%main_lab = OpLabel\n" +
1745 "%2 = OpQuantizeToF16 %float %float_1\n" +
1746 "OpReturn\n" +
1747 "OpFunctionEnd",
1748 2, 1.0),
1749 // Test case 13: QuantizeToF16 positive non exact
1750 InstructionFoldingCase<float>(
1751 Header() + "%main = OpFunction %void None %void_func\n" +
1752 "%main_lab = OpLabel\n" +
1753 "%2 = OpQuantizeToF16 %float %float_2049\n" +
1754 "OpReturn\n" +
1755 "OpFunctionEnd",
1756 2, 2048),
1757 // Test case 14: QuantizeToF16 negative non exact
1758 InstructionFoldingCase<float>(
1759 Header() + "%main = OpFunction %void None %void_func\n" +
1760 "%main_lab = OpLabel\n" +
1761 "%2 = OpQuantizeToF16 %float %float_n2049\n" +
1762 "OpReturn\n" +
1763 "OpFunctionEnd",
1764 2, -2048),
1765 // Test case 15: QuantizeToF16 large positive
1766 InstructionFoldingCase<float>(
1767 Header() + "%main = OpFunction %void None %void_func\n" +
1768 "%main_lab = OpLabel\n" +
1769 "%2 = OpQuantizeToF16 %float %float_1e16\n" +
1770 "OpReturn\n" +
1771 "OpFunctionEnd",
1772 2, std::numeric_limits<float>::infinity()),
1773 // Test case 16: QuantizeToF16 large negative
1774 InstructionFoldingCase<float>(
1775 Header() + "%main = OpFunction %void None %void_func\n" +
1776 "%main_lab = OpLabel\n" +
1777 "%2 = OpQuantizeToF16 %float %float_n1e16\n" +
1778 "OpReturn\n" +
1779 "OpFunctionEnd",
1780 2, -std::numeric_limits<float>::infinity()),
1781 // Test case 17: QuantizeToF16 small positive
1782 InstructionFoldingCase<float>(
1783 Header() + "%main = OpFunction %void None %void_func\n" +
1784 "%main_lab = OpLabel\n" +
1785 "%2 = OpQuantizeToF16 %float %float_1en16\n" +
1786 "OpReturn\n" +
1787 "OpFunctionEnd",
1788 2, 0.0),
1789 // Test case 18: QuantizeToF16 small negative
1790 InstructionFoldingCase<float>(
1791 Header() + "%main = OpFunction %void None %void_func\n" +
1792 "%main_lab = OpLabel\n" +
1793 "%2 = OpQuantizeToF16 %float %float_n1en16\n" +
1794 "OpReturn\n" +
1795 "OpFunctionEnd",
1796 2, 0.0),
1797 // Test case 19: QuantizeToF16 nan
1798 InstructionFoldingCase<float>(
1799 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
1800 "%main_lab = OpLabel\n" +
1801 "%2 = OpQuantizeToF16 %float %float_nan\n" +
1802 "OpReturn\n" +
1803 "OpFunctionEnd",
1804 2, std::numeric_limits<float>::quiet_NaN()),
1805 // Test case 20: FMix 1.0 4.0 0.2
1806 InstructionFoldingCase<float>(
1807 Header() + "%main = OpFunction %void None %void_func\n" +
1808 "%main_lab = OpLabel\n" +
1809 "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
1810 "OpReturn\n" +
1811 "OpFunctionEnd",
1812 2, 1.6f),
1813 // Test case 21: FMin 1.0 4.0
1814 InstructionFoldingCase<float>(
1815 Header() + "%main = OpFunction %void None %void_func\n" +
1816 "%main_lab = OpLabel\n" +
1817 "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
1818 "OpReturn\n" +
1819 "OpFunctionEnd",
1820 2, 1.0f),
1821 // Test case 22: FMin 4.0 0.2
1822 InstructionFoldingCase<float>(
1823 Header() + "%main = OpFunction %void None %void_func\n" +
1824 "%main_lab = OpLabel\n" +
1825 "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
1826 "OpReturn\n" +
1827 "OpFunctionEnd",
1828 2, 0.2f),
1829 // Test case 23: FMax 1.0 4.0
1830 InstructionFoldingCase<float>(
1831 Header() + "%main = OpFunction %void None %void_func\n" +
1832 "%main_lab = OpLabel\n" +
1833 "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
1834 "OpReturn\n" +
1835 "OpFunctionEnd",
1836 2, 4.0f),
1837 // Test case 24: FMax 1.0 0.2
1838 InstructionFoldingCase<float>(
1839 Header() + "%main = OpFunction %void None %void_func\n" +
1840 "%main_lab = OpLabel\n" +
1841 "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
1842 "OpReturn\n" +
1843 "OpFunctionEnd",
1844 2, 1.0f),
1845 // Test case 25: FClamp 1.0 0.2 4.0
1846 InstructionFoldingCase<float>(
1847 Header() + "%main = OpFunction %void None %void_func\n" +
1848 "%main_lab = OpLabel\n" +
1849 "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
1850 "OpReturn\n" +
1851 "OpFunctionEnd",
1852 2, 1.0f),
1853 // Test case 26: FClamp 0.2 2.0 4.0
1854 InstructionFoldingCase<float>(
1855 Header() + "%main = OpFunction %void None %void_func\n" +
1856 "%main_lab = OpLabel\n" +
1857 "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
1858 "OpReturn\n" +
1859 "OpFunctionEnd",
1860 2, 2.0f),
1861 // Test case 27: FClamp 2049.0 2.0 4.0
1862 InstructionFoldingCase<float>(
1863 Header() + "%main = OpFunction %void None %void_func\n" +
1864 "%main_lab = OpLabel\n" +
1865 "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
1866 "OpReturn\n" +
1867 "OpFunctionEnd",
1868 2, 4.0f),
1869 // Test case 28: FClamp 1.0 2.0 x
1870 InstructionFoldingCase<float>(
1871 Header() + "%main = OpFunction %void None %void_func\n" +
1872 "%main_lab = OpLabel\n" +
1873 "%undef = OpUndef %float\n" +
1874 "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
1875 "OpReturn\n" +
1876 "OpFunctionEnd",
1877 2, 2.0),
1878 // Test case 29: FClamp 1.0 x 0.5
1879 InstructionFoldingCase<float>(
1880 Header() + "%main = OpFunction %void None %void_func\n" +
1881 "%main_lab = OpLabel\n" +
1882 "%undef = OpUndef %float\n" +
1883 "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
1884 "OpReturn\n" +
1885 "OpFunctionEnd",
1886 2, 0.5),
1887 // Test case 30: Sin 0.0
1888 InstructionFoldingCase<float>(
1889 Header() + "%main = OpFunction %void None %void_func\n" +
1890 "%main_lab = OpLabel\n" +
1891 "%2 = OpExtInst %float %1 Sin %float_0\n" +
1892 "OpReturn\n" +
1893 "OpFunctionEnd",
1894 2, 0.0),
1895 // Test case 31: Cos 0.0
1896 InstructionFoldingCase<float>(
1897 Header() + "%main = OpFunction %void None %void_func\n" +
1898 "%main_lab = OpLabel\n" +
1899 "%2 = OpExtInst %float %1 Cos %float_0\n" +
1900 "OpReturn\n" +
1901 "OpFunctionEnd",
1902 2, 1.0),
1903 // Test case 32: Tan 0.0
1904 InstructionFoldingCase<float>(
1905 Header() + "%main = OpFunction %void None %void_func\n" +
1906 "%main_lab = OpLabel\n" +
1907 "%2 = OpExtInst %float %1 Tan %float_0\n" +
1908 "OpReturn\n" +
1909 "OpFunctionEnd",
1910 2, 0.0),
1911 // Test case 33: Asin 0.0
1912 InstructionFoldingCase<float>(
1913 Header() + "%main = OpFunction %void None %void_func\n" +
1914 "%main_lab = OpLabel\n" +
1915 "%2 = OpExtInst %float %1 Asin %float_0\n" +
1916 "OpReturn\n" +
1917 "OpFunctionEnd",
1918 2, 0.0),
1919 // Test case 34: Acos 1.0
1920 InstructionFoldingCase<float>(
1921 Header() + "%main = OpFunction %void None %void_func\n" +
1922 "%main_lab = OpLabel\n" +
1923 "%2 = OpExtInst %float %1 Acos %float_1\n" +
1924 "OpReturn\n" +
1925 "OpFunctionEnd",
1926 2, 0.0),
1927 // Test case 35: Atan 0.0
1928 InstructionFoldingCase<float>(
1929 Header() + "%main = OpFunction %void None %void_func\n" +
1930 "%main_lab = OpLabel\n" +
1931 "%2 = OpExtInst %float %1 Atan %float_0\n" +
1932 "OpReturn\n" +
1933 "OpFunctionEnd",
1934 2, 0.0),
1935 // Test case 36: Exp 0.0
1936 InstructionFoldingCase<float>(
1937 Header() + "%main = OpFunction %void None %void_func\n" +
1938 "%main_lab = OpLabel\n" +
1939 "%2 = OpExtInst %float %1 Exp %float_0\n" +
1940 "OpReturn\n" +
1941 "OpFunctionEnd",
1942 2, 1.0),
1943 // Test case 37: Log 1.0
1944 InstructionFoldingCase<float>(
1945 Header() + "%main = OpFunction %void None %void_func\n" +
1946 "%main_lab = OpLabel\n" +
1947 "%2 = OpExtInst %float %1 Log %float_1\n" +
1948 "OpReturn\n" +
1949 "OpFunctionEnd",
1950 2, 0.0),
1951 // Test case 38: Exp2 2.0
1952 InstructionFoldingCase<float>(
1953 Header() + "%main = OpFunction %void None %void_func\n" +
1954 "%main_lab = OpLabel\n" +
1955 "%2 = OpExtInst %float %1 Exp2 %float_2\n" +
1956 "OpReturn\n" +
1957 "OpFunctionEnd",
1958 2, 4.0),
1959 // Test case 39: Log2 4.0
1960 InstructionFoldingCase<float>(
1961 Header() + "%main = OpFunction %void None %void_func\n" +
1962 "%main_lab = OpLabel\n" +
1963 "%2 = OpExtInst %float %1 Log2 %float_4\n" +
1964 "OpReturn\n" +
1965 "OpFunctionEnd",
1966 2, 2.0),
1967 // Test case 40: Sqrt 4.0
1968 InstructionFoldingCase<float>(
1969 Header() + "%main = OpFunction %void None %void_func\n" +
1970 "%main_lab = OpLabel\n" +
1971 "%2 = OpExtInst %float %1 Sqrt %float_4\n" +
1972 "OpReturn\n" +
1973 "OpFunctionEnd",
1974 2, 2.0),
1975 // Test case 41: Atan2 0.0 1.0
1976 InstructionFoldingCase<float>(
1977 Header() + "%main = OpFunction %void None %void_func\n" +
1978 "%main_lab = OpLabel\n" +
1979 "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
1980 "OpReturn\n" +
1981 "OpFunctionEnd",
1982 2, 0.0),
1983 // Test case 42: Pow 2.0 3.0
1984 InstructionFoldingCase<float>(
1985 Header() + "%main = OpFunction %void None %void_func\n" +
1986 "%main_lab = OpLabel\n" +
1987 "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
1988 "OpReturn\n" +
1989 "OpFunctionEnd",
1990 2, 8.0)
1991 ));
1992 // clang-format on
1993
1994 using DoubleInstructionFoldingTest =
1995 ::testing::TestWithParam<InstructionFoldingCase<double>>;
1996
TEST_P(DoubleInstructionFoldingTest,Case)1997 TEST_P(DoubleInstructionFoldingTest, Case) {
1998 const auto& tc = GetParam();
1999
2000 // Build module.
2001 std::unique_ptr<IRContext> context =
2002 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2003 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2004 ASSERT_NE(nullptr, context);
2005
2006 // Fold the instruction to test.
2007 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2008 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2009 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2010
2011 // Make sure the instruction folded as expected.
2012 EXPECT_TRUE(succeeded);
2013 if (inst != nullptr) {
2014 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
2015 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2016 EXPECT_EQ(inst->opcode(), SpvOpConstant);
2017 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2018 const analysis::FloatConstant* result =
2019 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2020 EXPECT_NE(result, nullptr);
2021 if (result != nullptr) {
2022 EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
2023 }
2024 }
2025 }
2026
2027 // clang-format off
2028 INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
2029 ::testing::Values(
2030 // Test case 0: Fold 2.0 - 1.0
2031 InstructionFoldingCase<double>(
2032 Header() + "%main = OpFunction %void None %void_func\n" +
2033 "%main_lab = OpLabel\n" +
2034 "%2 = OpFSub %double %double_2 %double_1\n" +
2035 "OpReturn\n" +
2036 "OpFunctionEnd",
2037 2, 1.0),
2038 // Test case 1: Fold 2.0 + 1.0
2039 InstructionFoldingCase<double>(
2040 Header() + "%main = OpFunction %void None %void_func\n" +
2041 "%main_lab = OpLabel\n" +
2042 "%2 = OpFAdd %double %double_2 %double_1\n" +
2043 "OpReturn\n" +
2044 "OpFunctionEnd",
2045 2, 3.0),
2046 // Test case 2: Fold 3.0 * 2.0
2047 InstructionFoldingCase<double>(
2048 Header() + "%main = OpFunction %void None %void_func\n" +
2049 "%main_lab = OpLabel\n" +
2050 "%2 = OpFMul %double %double_3 %double_2\n" +
2051 "OpReturn\n" +
2052 "OpFunctionEnd",
2053 2, 6.0),
2054 // Test case 3: Fold 1.0 / 2.0
2055 InstructionFoldingCase<double>(
2056 Header() + "%main = OpFunction %void None %void_func\n" +
2057 "%main_lab = OpLabel\n" +
2058 "%2 = OpFDiv %double %double_1 %double_2\n" +
2059 "OpReturn\n" +
2060 "OpFunctionEnd",
2061 2, 0.5),
2062 // Test case 4: Fold 1.0 / 0.0
2063 InstructionFoldingCase<double>(
2064 Header() + "%main = OpFunction %void None %void_func\n" +
2065 "%main_lab = OpLabel\n" +
2066 "%2 = OpFDiv %double %double_1 %double_0\n" +
2067 "OpReturn\n" +
2068 "OpFunctionEnd",
2069 2, std::numeric_limits<double>::infinity()),
2070 // Test case 5: Fold -1.0 / 0.0
2071 InstructionFoldingCase<double>(
2072 Header() + "%main = OpFunction %void None %void_func\n" +
2073 "%main_lab = OpLabel\n" +
2074 "%2 = OpFDiv %double %double_n1 %double_0\n" +
2075 "OpReturn\n" +
2076 "OpFunctionEnd",
2077 2, -std::numeric_limits<double>::infinity()),
2078 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2079 InstructionFoldingCase<double>(
2080 Header() + "%main = OpFunction %void None %void_func\n" +
2081 "%main_lab = OpLabel\n" +
2082 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
2083 "OpReturn\n" +
2084 "OpFunctionEnd",
2085 2, 5.5f),
2086 // Test case 7: Fold (0.0, 0.0) dot v
2087 InstructionFoldingCase<double>(
2088 Header() + "%main = OpFunction %void None %void_func\n" +
2089 "%main_lab = OpLabel\n" +
2090 "%v = OpVariable %_ptr_v2double Function\n" +
2091 "%2 = OpLoad %v2double %v\n" +
2092 "%3 = OpDot %double %v2double_0_0 %2\n" +
2093 "OpReturn\n" +
2094 "OpFunctionEnd",
2095 3, 0.0f),
2096 // Test case 8: Fold v dot (0.0, 0.0)
2097 InstructionFoldingCase<double>(
2098 Header() + "%main = OpFunction %void None %void_func\n" +
2099 "%main_lab = OpLabel\n" +
2100 "%v = OpVariable %_ptr_v2double Function\n" +
2101 "%2 = OpLoad %v2double %v\n" +
2102 "%3 = OpDot %double %2 %v2double_0_0\n" +
2103 "OpReturn\n" +
2104 "OpFunctionEnd",
2105 3, 0.0f),
2106 // Test case 9: Fold Null dot v
2107 InstructionFoldingCase<double>(
2108 Header() + "%main = OpFunction %void None %void_func\n" +
2109 "%main_lab = OpLabel\n" +
2110 "%v = OpVariable %_ptr_v2double Function\n" +
2111 "%2 = OpLoad %v2double %v\n" +
2112 "%3 = OpDot %double %v2double_null %2\n" +
2113 "OpReturn\n" +
2114 "OpFunctionEnd",
2115 3, 0.0f),
2116 // Test case 10: Fold v dot Null
2117 InstructionFoldingCase<double>(
2118 Header() + "%main = OpFunction %void None %void_func\n" +
2119 "%main_lab = OpLabel\n" +
2120 "%v = OpVariable %_ptr_v2double Function\n" +
2121 "%2 = OpLoad %v2double %v\n" +
2122 "%3 = OpDot %double %2 %v2double_null\n" +
2123 "OpReturn\n" +
2124 "OpFunctionEnd",
2125 3, 0.0f),
2126 // Test case 11: Fold -2.0
2127 InstructionFoldingCase<double>(
2128 Header() + "%main = OpFunction %void None %void_func\n" +
2129 "%main_lab = OpLabel\n" +
2130 "%2 = OpFNegate %double %double_2\n" +
2131 "OpReturn\n" +
2132 "OpFunctionEnd",
2133 2, -2),
2134 // Test case 12: FMin 1.0 4.0
2135 InstructionFoldingCase<double>(
2136 Header() + "%main = OpFunction %void None %void_func\n" +
2137 "%main_lab = OpLabel\n" +
2138 "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
2139 "OpReturn\n" +
2140 "OpFunctionEnd",
2141 2, 1.0),
2142 // Test case 13: FMin 4.0 0.2
2143 InstructionFoldingCase<double>(
2144 Header() + "%main = OpFunction %void None %void_func\n" +
2145 "%main_lab = OpLabel\n" +
2146 "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
2147 "OpReturn\n" +
2148 "OpFunctionEnd",
2149 2, 0.2),
2150 // Test case 14: FMax 1.0 4.0
2151 InstructionFoldingCase<double>(
2152 Header() + "%main = OpFunction %void None %void_func\n" +
2153 "%main_lab = OpLabel\n" +
2154 "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
2155 "OpReturn\n" +
2156 "OpFunctionEnd",
2157 2, 4.0),
2158 // Test case 15: FMax 1.0 0.2
2159 InstructionFoldingCase<double>(
2160 Header() + "%main = OpFunction %void None %void_func\n" +
2161 "%main_lab = OpLabel\n" +
2162 "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
2163 "OpReturn\n" +
2164 "OpFunctionEnd",
2165 2, 1.0),
2166 // Test case 16: FClamp 1.0 0.2 4.0
2167 InstructionFoldingCase<double>(
2168 Header() + "%main = OpFunction %void None %void_func\n" +
2169 "%main_lab = OpLabel\n" +
2170 "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
2171 "OpReturn\n" +
2172 "OpFunctionEnd",
2173 2, 1.0),
2174 // Test case 17: FClamp 0.2 2.0 4.0
2175 InstructionFoldingCase<double>(
2176 Header() + "%main = OpFunction %void None %void_func\n" +
2177 "%main_lab = OpLabel\n" +
2178 "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
2179 "OpReturn\n" +
2180 "OpFunctionEnd",
2181 2, 2.0),
2182 // Test case 18: FClamp 5.0 2.0 4.0
2183 InstructionFoldingCase<double>(
2184 Header() + "%main = OpFunction %void None %void_func\n" +
2185 "%main_lab = OpLabel\n" +
2186 "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
2187 "OpReturn\n" +
2188 "OpFunctionEnd",
2189 2, 4.0),
2190 // Test case 19: FClamp 1.0 2.0 x
2191 InstructionFoldingCase<double>(
2192 Header() + "%main = OpFunction %void None %void_func\n" +
2193 "%main_lab = OpLabel\n" +
2194 "%undef = OpUndef %double\n" +
2195 "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
2196 "OpReturn\n" +
2197 "OpFunctionEnd",
2198 2, 2.0),
2199 // Test case 20: FClamp 1.0 x 0.5
2200 InstructionFoldingCase<double>(
2201 Header() + "%main = OpFunction %void None %void_func\n" +
2202 "%main_lab = OpLabel\n" +
2203 "%undef = OpUndef %double\n" +
2204 "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
2205 "OpReturn\n" +
2206 "OpFunctionEnd",
2207 2, 0.5),
2208 // Test case 21: Sqrt 4.0
2209 InstructionFoldingCase<double>(
2210 Header() + "%main = OpFunction %void None %void_func\n" +
2211 "%main_lab = OpLabel\n" +
2212 "%undef = OpUndef %double\n" +
2213 "%2 = OpExtInst %double %1 Sqrt %double_4\n" +
2214 "OpReturn\n" +
2215 "OpFunctionEnd",
2216 2, 2.0),
2217 // Test case 22: Pow 2.0 3.0
2218 InstructionFoldingCase<double>(
2219 Header() + "%main = OpFunction %void None %void_func\n" +
2220 "%main_lab = OpLabel\n" +
2221 "%undef = OpUndef %double\n" +
2222 "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" +
2223 "OpReturn\n" +
2224 "OpFunctionEnd",
2225 2, 8.0)
2226 ));
2227 // clang-format on
2228
2229 // clang-format off
2230 INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2231 ::testing::Values(
2232 // Test case 0: fold 1.0 == 2.0
2233 InstructionFoldingCase<bool>(
2234 Header() + "%main = OpFunction %void None %void_func\n" +
2235 "%main_lab = OpLabel\n" +
2236 "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
2237 "OpReturn\n" +
2238 "OpFunctionEnd",
2239 2, false),
2240 // Test case 1: fold 1.0 != 2.0
2241 InstructionFoldingCase<bool>(
2242 Header() + "%main = OpFunction %void None %void_func\n" +
2243 "%main_lab = OpLabel\n" +
2244 "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
2245 "OpReturn\n" +
2246 "OpFunctionEnd",
2247 2, true),
2248 // Test case 2: fold 1.0 < 2.0
2249 InstructionFoldingCase<bool>(
2250 Header() + "%main = OpFunction %void None %void_func\n" +
2251 "%main_lab = OpLabel\n" +
2252 "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
2253 "OpReturn\n" +
2254 "OpFunctionEnd",
2255 2, true),
2256 // Test case 3: fold 1.0 > 2.0
2257 InstructionFoldingCase<bool>(
2258 Header() + "%main = OpFunction %void None %void_func\n" +
2259 "%main_lab = OpLabel\n" +
2260 "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
2261 "OpReturn\n" +
2262 "OpFunctionEnd",
2263 2, false),
2264 // Test case 4: fold 1.0 <= 2.0
2265 InstructionFoldingCase<bool>(
2266 Header() + "%main = OpFunction %void None %void_func\n" +
2267 "%main_lab = OpLabel\n" +
2268 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
2269 "OpReturn\n" +
2270 "OpFunctionEnd",
2271 2, true),
2272 // Test case 5: fold 1.0 >= 2.0
2273 InstructionFoldingCase<bool>(
2274 Header() + "%main = OpFunction %void None %void_func\n" +
2275 "%main_lab = OpLabel\n" +
2276 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
2277 "OpReturn\n" +
2278 "OpFunctionEnd",
2279 2, false),
2280 // Test case 6: fold 1.0 == 1.0
2281 InstructionFoldingCase<bool>(
2282 Header() + "%main = OpFunction %void None %void_func\n" +
2283 "%main_lab = OpLabel\n" +
2284 "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
2285 "OpReturn\n" +
2286 "OpFunctionEnd",
2287 2, true),
2288 // Test case 7: fold 1.0 != 1.0
2289 InstructionFoldingCase<bool>(
2290 Header() + "%main = OpFunction %void None %void_func\n" +
2291 "%main_lab = OpLabel\n" +
2292 "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
2293 "OpReturn\n" +
2294 "OpFunctionEnd",
2295 2, false),
2296 // Test case 8: fold 1.0 < 1.0
2297 InstructionFoldingCase<bool>(
2298 Header() + "%main = OpFunction %void None %void_func\n" +
2299 "%main_lab = OpLabel\n" +
2300 "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
2301 "OpReturn\n" +
2302 "OpFunctionEnd",
2303 2, false),
2304 // Test case 9: fold 1.0 > 1.0
2305 InstructionFoldingCase<bool>(
2306 Header() + "%main = OpFunction %void None %void_func\n" +
2307 "%main_lab = OpLabel\n" +
2308 "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
2309 "OpReturn\n" +
2310 "OpFunctionEnd",
2311 2, false),
2312 // Test case 10: fold 1.0 <= 1.0
2313 InstructionFoldingCase<bool>(
2314 Header() + "%main = OpFunction %void None %void_func\n" +
2315 "%main_lab = OpLabel\n" +
2316 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
2317 "OpReturn\n" +
2318 "OpFunctionEnd",
2319 2, true),
2320 // Test case 11: fold 1.0 >= 1.0
2321 InstructionFoldingCase<bool>(
2322 Header() + "%main = OpFunction %void None %void_func\n" +
2323 "%main_lab = OpLabel\n" +
2324 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
2325 "OpReturn\n" +
2326 "OpFunctionEnd",
2327 2, true),
2328 // Test case 12: fold 2.0 < 1.0
2329 InstructionFoldingCase<bool>(
2330 Header() + "%main = OpFunction %void None %void_func\n" +
2331 "%main_lab = OpLabel\n" +
2332 "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
2333 "OpReturn\n" +
2334 "OpFunctionEnd",
2335 2, false),
2336 // Test case 13: fold 2.0 > 1.0
2337 InstructionFoldingCase<bool>(
2338 Header() + "%main = OpFunction %void None %void_func\n" +
2339 "%main_lab = OpLabel\n" +
2340 "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
2341 "OpReturn\n" +
2342 "OpFunctionEnd",
2343 2, true),
2344 // Test case 14: fold 2.0 <= 1.0
2345 InstructionFoldingCase<bool>(
2346 Header() + "%main = OpFunction %void None %void_func\n" +
2347 "%main_lab = OpLabel\n" +
2348 "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
2349 "OpReturn\n" +
2350 "OpFunctionEnd",
2351 2, false),
2352 // Test case 15: fold 2.0 >= 1.0
2353 InstructionFoldingCase<bool>(
2354 Header() + "%main = OpFunction %void None %void_func\n" +
2355 "%main_lab = OpLabel\n" +
2356 "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
2357 "OpReturn\n" +
2358 "OpFunctionEnd",
2359 2, true)
2360 ));
2361
2362 INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2363 ::testing::Values(
2364 // Test case 0: fold 1.0 == 2.0
2365 InstructionFoldingCase<bool>(
2366 Header() + "%main = OpFunction %void None %void_func\n" +
2367 "%main_lab = OpLabel\n" +
2368 "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
2369 "OpReturn\n" +
2370 "OpFunctionEnd",
2371 2, false),
2372 // Test case 1: fold 1.0 != 2.0
2373 InstructionFoldingCase<bool>(
2374 Header() + "%main = OpFunction %void None %void_func\n" +
2375 "%main_lab = OpLabel\n" +
2376 "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
2377 "OpReturn\n" +
2378 "OpFunctionEnd",
2379 2, true),
2380 // Test case 2: fold 1.0 < 2.0
2381 InstructionFoldingCase<bool>(
2382 Header() + "%main = OpFunction %void None %void_func\n" +
2383 "%main_lab = OpLabel\n" +
2384 "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
2385 "OpReturn\n" +
2386 "OpFunctionEnd",
2387 2, true),
2388 // Test case 3: fold 1.0 > 2.0
2389 InstructionFoldingCase<bool>(
2390 Header() + "%main = OpFunction %void None %void_func\n" +
2391 "%main_lab = OpLabel\n" +
2392 "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
2393 "OpReturn\n" +
2394 "OpFunctionEnd",
2395 2, false),
2396 // Test case 4: fold 1.0 <= 2.0
2397 InstructionFoldingCase<bool>(
2398 Header() + "%main = OpFunction %void None %void_func\n" +
2399 "%main_lab = OpLabel\n" +
2400 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
2401 "OpReturn\n" +
2402 "OpFunctionEnd",
2403 2, true),
2404 // Test case 5: fold 1.0 >= 2.0
2405 InstructionFoldingCase<bool>(
2406 Header() + "%main = OpFunction %void None %void_func\n" +
2407 "%main_lab = OpLabel\n" +
2408 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
2409 "OpReturn\n" +
2410 "OpFunctionEnd",
2411 2, false),
2412 // Test case 6: fold 1.0 == 1.0
2413 InstructionFoldingCase<bool>(
2414 Header() + "%main = OpFunction %void None %void_func\n" +
2415 "%main_lab = OpLabel\n" +
2416 "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
2417 "OpReturn\n" +
2418 "OpFunctionEnd",
2419 2, true),
2420 // Test case 7: fold 1.0 != 1.0
2421 InstructionFoldingCase<bool>(
2422 Header() + "%main = OpFunction %void None %void_func\n" +
2423 "%main_lab = OpLabel\n" +
2424 "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
2425 "OpReturn\n" +
2426 "OpFunctionEnd",
2427 2, false),
2428 // Test case 8: fold 1.0 < 1.0
2429 InstructionFoldingCase<bool>(
2430 Header() + "%main = OpFunction %void None %void_func\n" +
2431 "%main_lab = OpLabel\n" +
2432 "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
2433 "OpReturn\n" +
2434 "OpFunctionEnd",
2435 2, false),
2436 // Test case 9: fold 1.0 > 1.0
2437 InstructionFoldingCase<bool>(
2438 Header() + "%main = OpFunction %void None %void_func\n" +
2439 "%main_lab = OpLabel\n" +
2440 "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
2441 "OpReturn\n" +
2442 "OpFunctionEnd",
2443 2, false),
2444 // Test case 10: fold 1.0 <= 1.0
2445 InstructionFoldingCase<bool>(
2446 Header() + "%main = OpFunction %void None %void_func\n" +
2447 "%main_lab = OpLabel\n" +
2448 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
2449 "OpReturn\n" +
2450 "OpFunctionEnd",
2451 2, true),
2452 // Test case 11: fold 1.0 >= 1.0
2453 InstructionFoldingCase<bool>(
2454 Header() + "%main = OpFunction %void None %void_func\n" +
2455 "%main_lab = OpLabel\n" +
2456 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
2457 "OpReturn\n" +
2458 "OpFunctionEnd",
2459 2, true),
2460 // Test case 12: fold 2.0 < 1.0
2461 InstructionFoldingCase<bool>(
2462 Header() + "%main = OpFunction %void None %void_func\n" +
2463 "%main_lab = OpLabel\n" +
2464 "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
2465 "OpReturn\n" +
2466 "OpFunctionEnd",
2467 2, false),
2468 // Test case 13: fold 2.0 > 1.0
2469 InstructionFoldingCase<bool>(
2470 Header() + "%main = OpFunction %void None %void_func\n" +
2471 "%main_lab = OpLabel\n" +
2472 "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
2473 "OpReturn\n" +
2474 "OpFunctionEnd",
2475 2, true),
2476 // Test case 14: fold 2.0 <= 1.0
2477 InstructionFoldingCase<bool>(
2478 Header() + "%main = OpFunction %void None %void_func\n" +
2479 "%main_lab = OpLabel\n" +
2480 "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
2481 "OpReturn\n" +
2482 "OpFunctionEnd",
2483 2, false),
2484 // Test case 15: fold 2.0 >= 1.0
2485 InstructionFoldingCase<bool>(
2486 Header() + "%main = OpFunction %void None %void_func\n" +
2487 "%main_lab = OpLabel\n" +
2488 "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
2489 "OpReturn\n" +
2490 "OpFunctionEnd",
2491 2, true)
2492 ));
2493
2494 INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2495 ::testing::Values(
2496 // Test case 0: fold 1.0 == 2.0
2497 InstructionFoldingCase<bool>(
2498 Header() + "%main = OpFunction %void None %void_func\n" +
2499 "%main_lab = OpLabel\n" +
2500 "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
2501 "OpReturn\n" +
2502 "OpFunctionEnd",
2503 2, false),
2504 // Test case 1: fold 1.0 != 2.0
2505 InstructionFoldingCase<bool>(
2506 Header() + "%main = OpFunction %void None %void_func\n" +
2507 "%main_lab = OpLabel\n" +
2508 "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
2509 "OpReturn\n" +
2510 "OpFunctionEnd",
2511 2, true),
2512 // Test case 2: fold 1.0 < 2.0
2513 InstructionFoldingCase<bool>(
2514 Header() + "%main = OpFunction %void None %void_func\n" +
2515 "%main_lab = OpLabel\n" +
2516 "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
2517 "OpReturn\n" +
2518 "OpFunctionEnd",
2519 2, true),
2520 // Test case 3: fold 1.0 > 2.0
2521 InstructionFoldingCase<bool>(
2522 Header() + "%main = OpFunction %void None %void_func\n" +
2523 "%main_lab = OpLabel\n" +
2524 "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
2525 "OpReturn\n" +
2526 "OpFunctionEnd",
2527 2, false),
2528 // Test case 4: fold 1.0 <= 2.0
2529 InstructionFoldingCase<bool>(
2530 Header() + "%main = OpFunction %void None %void_func\n" +
2531 "%main_lab = OpLabel\n" +
2532 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
2533 "OpReturn\n" +
2534 "OpFunctionEnd",
2535 2, true),
2536 // Test case 5: fold 1.0 >= 2.0
2537 InstructionFoldingCase<bool>(
2538 Header() + "%main = OpFunction %void None %void_func\n" +
2539 "%main_lab = OpLabel\n" +
2540 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
2541 "OpReturn\n" +
2542 "OpFunctionEnd",
2543 2, false),
2544 // Test case 6: fold 1.0 == 1.0
2545 InstructionFoldingCase<bool>(
2546 Header() + "%main = OpFunction %void None %void_func\n" +
2547 "%main_lab = OpLabel\n" +
2548 "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
2549 "OpReturn\n" +
2550 "OpFunctionEnd",
2551 2, true),
2552 // Test case 7: fold 1.0 != 1.0
2553 InstructionFoldingCase<bool>(
2554 Header() + "%main = OpFunction %void None %void_func\n" +
2555 "%main_lab = OpLabel\n" +
2556 "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
2557 "OpReturn\n" +
2558 "OpFunctionEnd",
2559 2, false),
2560 // Test case 8: fold 1.0 < 1.0
2561 InstructionFoldingCase<bool>(
2562 Header() + "%main = OpFunction %void None %void_func\n" +
2563 "%main_lab = OpLabel\n" +
2564 "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
2565 "OpReturn\n" +
2566 "OpFunctionEnd",
2567 2, false),
2568 // Test case 9: fold 1.0 > 1.0
2569 InstructionFoldingCase<bool>(
2570 Header() + "%main = OpFunction %void None %void_func\n" +
2571 "%main_lab = OpLabel\n" +
2572 "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
2573 "OpReturn\n" +
2574 "OpFunctionEnd",
2575 2, false),
2576 // Test case 10: fold 1.0 <= 1.0
2577 InstructionFoldingCase<bool>(
2578 Header() + "%main = OpFunction %void None %void_func\n" +
2579 "%main_lab = OpLabel\n" +
2580 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
2581 "OpReturn\n" +
2582 "OpFunctionEnd",
2583 2, true),
2584 // Test case 11: fold 1.0 >= 1.0
2585 InstructionFoldingCase<bool>(
2586 Header() + "%main = OpFunction %void None %void_func\n" +
2587 "%main_lab = OpLabel\n" +
2588 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
2589 "OpReturn\n" +
2590 "OpFunctionEnd",
2591 2, true),
2592 // Test case 12: fold 2.0 < 1.0
2593 InstructionFoldingCase<bool>(
2594 Header() + "%main = OpFunction %void None %void_func\n" +
2595 "%main_lab = OpLabel\n" +
2596 "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
2597 "OpReturn\n" +
2598 "OpFunctionEnd",
2599 2, false),
2600 // Test case 13: fold 2.0 > 1.0
2601 InstructionFoldingCase<bool>(
2602 Header() + "%main = OpFunction %void None %void_func\n" +
2603 "%main_lab = OpLabel\n" +
2604 "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
2605 "OpReturn\n" +
2606 "OpFunctionEnd",
2607 2, true),
2608 // Test case 14: fold 2.0 <= 1.0
2609 InstructionFoldingCase<bool>(
2610 Header() + "%main = OpFunction %void None %void_func\n" +
2611 "%main_lab = OpLabel\n" +
2612 "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
2613 "OpReturn\n" +
2614 "OpFunctionEnd",
2615 2, false),
2616 // Test case 15: fold 2.0 >= 1.0
2617 InstructionFoldingCase<bool>(
2618 Header() + "%main = OpFunction %void None %void_func\n" +
2619 "%main_lab = OpLabel\n" +
2620 "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
2621 "OpReturn\n" +
2622 "OpFunctionEnd",
2623 2, true)
2624 ));
2625
2626 INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2627 ::testing::Values(
2628 // Test case 0: fold 1.0 == 2.0
2629 InstructionFoldingCase<bool>(
2630 Header() + "%main = OpFunction %void None %void_func\n" +
2631 "%main_lab = OpLabel\n" +
2632 "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
2633 "OpReturn\n" +
2634 "OpFunctionEnd",
2635 2, false),
2636 // Test case 1: fold 1.0 != 2.0
2637 InstructionFoldingCase<bool>(
2638 Header() + "%main = OpFunction %void None %void_func\n" +
2639 "%main_lab = OpLabel\n" +
2640 "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
2641 "OpReturn\n" +
2642 "OpFunctionEnd",
2643 2, true),
2644 // Test case 2: fold 1.0 < 2.0
2645 InstructionFoldingCase<bool>(
2646 Header() + "%main = OpFunction %void None %void_func\n" +
2647 "%main_lab = OpLabel\n" +
2648 "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
2649 "OpReturn\n" +
2650 "OpFunctionEnd",
2651 2, true),
2652 // Test case 3: fold 1.0 > 2.0
2653 InstructionFoldingCase<bool>(
2654 Header() + "%main = OpFunction %void None %void_func\n" +
2655 "%main_lab = OpLabel\n" +
2656 "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
2657 "OpReturn\n" +
2658 "OpFunctionEnd",
2659 2, false),
2660 // Test case 4: fold 1.0 <= 2.0
2661 InstructionFoldingCase<bool>(
2662 Header() + "%main = OpFunction %void None %void_func\n" +
2663 "%main_lab = OpLabel\n" +
2664 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
2665 "OpReturn\n" +
2666 "OpFunctionEnd",
2667 2, true),
2668 // Test case 5: fold 1.0 >= 2.0
2669 InstructionFoldingCase<bool>(
2670 Header() + "%main = OpFunction %void None %void_func\n" +
2671 "%main_lab = OpLabel\n" +
2672 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
2673 "OpReturn\n" +
2674 "OpFunctionEnd",
2675 2, false),
2676 // Test case 6: fold 1.0 == 1.0
2677 InstructionFoldingCase<bool>(
2678 Header() + "%main = OpFunction %void None %void_func\n" +
2679 "%main_lab = OpLabel\n" +
2680 "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
2681 "OpReturn\n" +
2682 "OpFunctionEnd",
2683 2, true),
2684 // Test case 7: fold 1.0 != 1.0
2685 InstructionFoldingCase<bool>(
2686 Header() + "%main = OpFunction %void None %void_func\n" +
2687 "%main_lab = OpLabel\n" +
2688 "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
2689 "OpReturn\n" +
2690 "OpFunctionEnd",
2691 2, false),
2692 // Test case 8: fold 1.0 < 1.0
2693 InstructionFoldingCase<bool>(
2694 Header() + "%main = OpFunction %void None %void_func\n" +
2695 "%main_lab = OpLabel\n" +
2696 "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
2697 "OpReturn\n" +
2698 "OpFunctionEnd",
2699 2, false),
2700 // Test case 9: fold 1.0 > 1.0
2701 InstructionFoldingCase<bool>(
2702 Header() + "%main = OpFunction %void None %void_func\n" +
2703 "%main_lab = OpLabel\n" +
2704 "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
2705 "OpReturn\n" +
2706 "OpFunctionEnd",
2707 2, false),
2708 // Test case 10: fold 1.0 <= 1.0
2709 InstructionFoldingCase<bool>(
2710 Header() + "%main = OpFunction %void None %void_func\n" +
2711 "%main_lab = OpLabel\n" +
2712 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
2713 "OpReturn\n" +
2714 "OpFunctionEnd",
2715 2, true),
2716 // Test case 11: fold 1.0 >= 1.0
2717 InstructionFoldingCase<bool>(
2718 Header() + "%main = OpFunction %void None %void_func\n" +
2719 "%main_lab = OpLabel\n" +
2720 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
2721 "OpReturn\n" +
2722 "OpFunctionEnd",
2723 2, true),
2724 // Test case 12: fold 2.0 < 1.0
2725 InstructionFoldingCase<bool>(
2726 Header() + "%main = OpFunction %void None %void_func\n" +
2727 "%main_lab = OpLabel\n" +
2728 "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
2729 "OpReturn\n" +
2730 "OpFunctionEnd",
2731 2, false),
2732 // Test case 13: fold 2.0 > 1.0
2733 InstructionFoldingCase<bool>(
2734 Header() + "%main = OpFunction %void None %void_func\n" +
2735 "%main_lab = OpLabel\n" +
2736 "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
2737 "OpReturn\n" +
2738 "OpFunctionEnd",
2739 2, true),
2740 // Test case 14: fold 2.0 <= 1.0
2741 InstructionFoldingCase<bool>(
2742 Header() + "%main = OpFunction %void None %void_func\n" +
2743 "%main_lab = OpLabel\n" +
2744 "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
2745 "OpReturn\n" +
2746 "OpFunctionEnd",
2747 2, false),
2748 // Test case 15: fold 2.0 >= 1.0
2749 InstructionFoldingCase<bool>(
2750 Header() + "%main = OpFunction %void None %void_func\n" +
2751 "%main_lab = OpLabel\n" +
2752 "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
2753 "OpReturn\n" +
2754 "OpFunctionEnd",
2755 2, true)
2756 ));
2757
2758 INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2759 ::testing::Values(
2760 // Test case 0: fold NaN == 0 (ord)
2761 InstructionFoldingCase<bool>(
2762 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2763 "%main_lab = OpLabel\n" +
2764 "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
2765 "OpReturn\n" +
2766 "OpFunctionEnd",
2767 2, false),
2768 // Test case 1: fold NaN == NaN (unord)
2769 InstructionFoldingCase<bool>(
2770 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2771 "%main_lab = OpLabel\n" +
2772 "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
2773 "OpReturn\n" +
2774 "OpFunctionEnd",
2775 2, true),
2776 // Test case 2: fold NaN != NaN (ord)
2777 InstructionFoldingCase<bool>(
2778 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2779 "%main_lab = OpLabel\n" +
2780 "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
2781 "OpReturn\n" +
2782 "OpFunctionEnd",
2783 2, false),
2784 // Test case 3: fold NaN != NaN (unord)
2785 InstructionFoldingCase<bool>(
2786 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2787 "%main_lab = OpLabel\n" +
2788 "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
2789 "OpReturn\n" +
2790 "OpFunctionEnd",
2791 2, true)
2792 ));
2793
2794 INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2795 ::testing::Values(
2796 // Test case 0: fold NaN == 0 (ord)
2797 InstructionFoldingCase<bool>(
2798 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2799 "%main_lab = OpLabel\n" +
2800 "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
2801 "OpReturn\n" +
2802 "OpFunctionEnd",
2803 2, false),
2804 // Test case 1: fold NaN == NaN (unord)
2805 InstructionFoldingCase<bool>(
2806 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2807 "%main_lab = OpLabel\n" +
2808 "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
2809 "OpReturn\n" +
2810 "OpFunctionEnd",
2811 2, true),
2812 // Test case 2: fold NaN != NaN (ord)
2813 InstructionFoldingCase<bool>(
2814 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2815 "%main_lab = OpLabel\n" +
2816 "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
2817 "OpReturn\n" +
2818 "OpFunctionEnd",
2819 2, false),
2820 // Test case 3: fold NaN != NaN (unord)
2821 InstructionFoldingCase<bool>(
2822 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2823 "%main_lab = OpLabel\n" +
2824 "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
2825 "OpReturn\n" +
2826 "OpFunctionEnd",
2827 2, true)
2828 ));
2829 // clang-format on
2830
2831 template <class ResultType>
2832 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anon56844f860111::InstructionFoldingCaseWithMap2833 InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
2834 ResultType result,
2835 std::function<uint32_t(uint32_t)> map)
2836 : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
2837
2838 std::string test_body;
2839 uint32_t id_to_fold;
2840 ResultType expected_result;
2841 std::function<uint32_t(uint32_t)> id_map;
2842 };
2843
2844 using IntegerInstructionFoldingTestWithMap =
2845 ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
2846
TEST_P(IntegerInstructionFoldingTestWithMap,Case)2847 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
2848 const auto& tc = GetParam();
2849
2850 // Build module.
2851 std::unique_ptr<IRContext> context =
2852 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2853 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2854 ASSERT_NE(nullptr, context);
2855
2856 // Fold the instruction to test.
2857 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2858 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2859 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
2860 tc.id_map);
2861
2862 // Make sure the instruction folded as expected.
2863 EXPECT_NE(inst, nullptr);
2864 if (inst != nullptr) {
2865 EXPECT_EQ(inst->opcode(), SpvOpConstant);
2866 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2867 const analysis::IntConstant* result =
2868 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
2869 EXPECT_NE(result, nullptr);
2870 if (result != nullptr) {
2871 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
2872 }
2873 }
2874 }
2875 // clang-format off
2876 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
2877 ::testing::Values(
2878 // Test case 0: fold %3 = 0; %3 * n
2879 InstructionFoldingCaseWithMap<uint32_t>(
2880 Header() + "%main = OpFunction %void None %void_func\n" +
2881 "%main_lab = OpLabel\n" +
2882 "%n = OpVariable %_ptr_int Function\n" +
2883 "%load = OpLoad %int %n\n" +
2884 "%3 = OpCopyObject %int %int_0\n"
2885 "%2 = OpIMul %int %3 %load\n" +
2886 "OpReturn\n" +
2887 "OpFunctionEnd",
__anon56844f860202(uint32_t id) 2888 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
2889 ));
2890 // clang-format on
2891
2892 using BooleanInstructionFoldingTestWithMap =
2893 ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
2894
TEST_P(BooleanInstructionFoldingTestWithMap,Case)2895 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
2896 const auto& tc = GetParam();
2897
2898 // Build module.
2899 std::unique_ptr<IRContext> context =
2900 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2901 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2902 ASSERT_NE(nullptr, context);
2903
2904 // Fold the instruction to test.
2905 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2906 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2907 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
2908 tc.id_map);
2909
2910 // Make sure the instruction folded as expected.
2911 EXPECT_NE(inst, nullptr);
2912 if (inst != nullptr) {
2913 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
2914 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
2915 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2916 const analysis::BoolConstant* result =
2917 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
2918 EXPECT_NE(result, nullptr);
2919 if (result != nullptr) {
2920 EXPECT_EQ(result->value(), tc.expected_result);
2921 }
2922 }
2923 }
2924
2925 // clang-format off
2926 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap,
2927 ::testing::Values(
2928 // Test case 0: fold %3 = true; %3 || n
2929 InstructionFoldingCaseWithMap<bool>(
2930 Header() + "%main = OpFunction %void None %void_func\n" +
2931 "%main_lab = OpLabel\n" +
2932 "%n = OpVariable %_ptr_bool Function\n" +
2933 "%load = OpLoad %bool %n\n" +
2934 "%3 = OpCopyObject %bool %true\n" +
2935 "%2 = OpLogicalOr %bool %3 %load\n" +
2936 "OpReturn\n" +
2937 "OpFunctionEnd",
__anon56844f860302(uint32_t id) 2938 2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
2939 ));
2940 // clang-format on
2941
2942 using GeneralInstructionFoldingTest =
2943 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
2944
TEST_P(GeneralInstructionFoldingTest,Case)2945 TEST_P(GeneralInstructionFoldingTest, Case) {
2946 const auto& tc = GetParam();
2947
2948 // Build module.
2949 std::unique_ptr<IRContext> context =
2950 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2951 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2952 ASSERT_NE(nullptr, context);
2953
2954 // Fold the instruction to test.
2955 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2956 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2957 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
2958 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2959
2960 // Make sure the instruction folded as expected.
2961 EXPECT_EQ(inst->result_id(), original_inst->result_id());
2962 EXPECT_EQ(inst->type_id(), original_inst->type_id());
2963 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
2964 if (succeeded) {
2965 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
2966 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
2967 } else {
2968 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
2969 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
2970 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
2971 }
2972 }
2973 }
2974
2975 // clang-format off
2976 INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
2977 ::testing::Values(
2978 // Test case 0: Don't fold n * m
2979 InstructionFoldingCase<uint32_t>(
2980 Header() + "%main = OpFunction %void None %void_func\n" +
2981 "%main_lab = OpLabel\n" +
2982 "%n = OpVariable %_ptr_int Function\n" +
2983 "%m = OpVariable %_ptr_int Function\n" +
2984 "%load_n = OpLoad %int %n\n" +
2985 "%load_m = OpLoad %int %m\n" +
2986 "%2 = OpIMul %int %load_n %load_m\n" +
2987 "OpReturn\n" +
2988 "OpFunctionEnd",
2989 2, 0),
2990 // Test case 1: Don't fold n / m (unsigned)
2991 InstructionFoldingCase<uint32_t>(
2992 Header() + "%main = OpFunction %void None %void_func\n" +
2993 "%main_lab = OpLabel\n" +
2994 "%n = OpVariable %_ptr_uint Function\n" +
2995 "%m = OpVariable %_ptr_uint Function\n" +
2996 "%load_n = OpLoad %uint %n\n" +
2997 "%load_m = OpLoad %uint %m\n" +
2998 "%2 = OpUDiv %uint %load_n %load_m\n" +
2999 "OpReturn\n" +
3000 "OpFunctionEnd",
3001 2, 0),
3002 // Test case 2: Don't fold n / m (signed)
3003 InstructionFoldingCase<uint32_t>(
3004 Header() + "%main = OpFunction %void None %void_func\n" +
3005 "%main_lab = OpLabel\n" +
3006 "%n = OpVariable %_ptr_int Function\n" +
3007 "%m = OpVariable %_ptr_int Function\n" +
3008 "%load_n = OpLoad %int %n\n" +
3009 "%load_m = OpLoad %int %m\n" +
3010 "%2 = OpSDiv %int %load_n %load_m\n" +
3011 "OpReturn\n" +
3012 "OpFunctionEnd",
3013 2, 0),
3014 // Test case 3: Don't fold n remainder m
3015 InstructionFoldingCase<uint32_t>(
3016 Header() + "%main = OpFunction %void None %void_func\n" +
3017 "%main_lab = OpLabel\n" +
3018 "%n = OpVariable %_ptr_int Function\n" +
3019 "%m = OpVariable %_ptr_int Function\n" +
3020 "%load_n = OpLoad %int %n\n" +
3021 "%load_m = OpLoad %int %m\n" +
3022 "%2 = OpSRem %int %load_n %load_m\n" +
3023 "OpReturn\n" +
3024 "OpFunctionEnd",
3025 2, 0),
3026 // Test case 4: Don't fold n % m (signed)
3027 InstructionFoldingCase<uint32_t>(
3028 Header() + "%main = OpFunction %void None %void_func\n" +
3029 "%main_lab = OpLabel\n" +
3030 "%n = OpVariable %_ptr_int Function\n" +
3031 "%m = OpVariable %_ptr_int Function\n" +
3032 "%load_n = OpLoad %int %n\n" +
3033 "%load_m = OpLoad %int %m\n" +
3034 "%2 = OpSMod %int %load_n %load_m\n" +
3035 "OpReturn\n" +
3036 "OpFunctionEnd",
3037 2, 0),
3038 // Test case 5: Don't fold n % m (unsigned)
3039 InstructionFoldingCase<uint32_t>(
3040 Header() + "%main = OpFunction %void None %void_func\n" +
3041 "%main_lab = OpLabel\n" +
3042 "%n = OpVariable %_ptr_uint Function\n" +
3043 "%m = OpVariable %_ptr_uint Function\n" +
3044 "%load_n = OpLoad %uint %n\n" +
3045 "%load_m = OpLoad %uint %m\n" +
3046 "%2 = OpUMod %int %load_n %load_m\n" +
3047 "OpReturn\n" +
3048 "OpFunctionEnd",
3049 2, 0),
3050 // Test case 6: Don't fold n << m
3051 InstructionFoldingCase<uint32_t>(
3052 Header() + "%main = OpFunction %void None %void_func\n" +
3053 "%main_lab = OpLabel\n" +
3054 "%n = OpVariable %_ptr_uint Function\n" +
3055 "%m = OpVariable %_ptr_uint Function\n" +
3056 "%load_n = OpLoad %uint %n\n" +
3057 "%load_m = OpLoad %uint %m\n" +
3058 "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
3059 "OpReturn\n" +
3060 "OpFunctionEnd",
3061 2, 0),
3062 // Test case 7: Don't fold n >> m
3063 InstructionFoldingCase<uint32_t>(
3064 Header() + "%main = OpFunction %void None %void_func\n" +
3065 "%main_lab = OpLabel\n" +
3066 "%n = OpVariable %_ptr_uint Function\n" +
3067 "%m = OpVariable %_ptr_uint Function\n" +
3068 "%load_n = OpLoad %uint %n\n" +
3069 "%load_m = OpLoad %uint %m\n" +
3070 "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
3071 "OpReturn\n" +
3072 "OpFunctionEnd",
3073 2, 0),
3074 // Test case 8: Don't fold n | m
3075 InstructionFoldingCase<uint32_t>(
3076 Header() + "%main = OpFunction %void None %void_func\n" +
3077 "%main_lab = OpLabel\n" +
3078 "%n = OpVariable %_ptr_uint Function\n" +
3079 "%m = OpVariable %_ptr_uint Function\n" +
3080 "%load_n = OpLoad %uint %n\n" +
3081 "%load_m = OpLoad %uint %m\n" +
3082 "%2 = OpBitwiseOr %int %load_n %load_m\n" +
3083 "OpReturn\n" +
3084 "OpFunctionEnd",
3085 2, 0),
3086 // Test case 9: Don't fold n & m
3087 InstructionFoldingCase<uint32_t>(
3088 Header() + "%main = OpFunction %void None %void_func\n" +
3089 "%main_lab = OpLabel\n" +
3090 "%n = OpVariable %_ptr_uint Function\n" +
3091 "%m = OpVariable %_ptr_uint Function\n" +
3092 "%load_n = OpLoad %uint %n\n" +
3093 "%load_m = OpLoad %uint %m\n" +
3094 "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
3095 "OpReturn\n" +
3096 "OpFunctionEnd",
3097 2, 0),
3098 // Test case 10: Don't fold n < m (unsigned)
3099 InstructionFoldingCase<uint32_t>(
3100 Header() + "%main = OpFunction %void None %void_func\n" +
3101 "%main_lab = OpLabel\n" +
3102 "%n = OpVariable %_ptr_uint Function\n" +
3103 "%m = OpVariable %_ptr_uint Function\n" +
3104 "%load_n = OpLoad %uint %n\n" +
3105 "%load_m = OpLoad %uint %m\n" +
3106 "%2 = OpULessThan %bool %load_n %load_m\n" +
3107 "OpReturn\n" +
3108 "OpFunctionEnd",
3109 2, 0),
3110 // Test case 11: Don't fold n > m (unsigned)
3111 InstructionFoldingCase<uint32_t>(
3112 Header() + "%main = OpFunction %void None %void_func\n" +
3113 "%main_lab = OpLabel\n" +
3114 "%n = OpVariable %_ptr_uint Function\n" +
3115 "%m = OpVariable %_ptr_uint Function\n" +
3116 "%load_n = OpLoad %uint %n\n" +
3117 "%load_m = OpLoad %uint %m\n" +
3118 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3119 "OpReturn\n" +
3120 "OpFunctionEnd",
3121 2, 0),
3122 // Test case 12: Don't fold n <= m (unsigned)
3123 InstructionFoldingCase<uint32_t>(
3124 Header() + "%main = OpFunction %void None %void_func\n" +
3125 "%main_lab = OpLabel\n" +
3126 "%n = OpVariable %_ptr_uint Function\n" +
3127 "%m = OpVariable %_ptr_uint Function\n" +
3128 "%load_n = OpLoad %uint %n\n" +
3129 "%load_m = OpLoad %uint %m\n" +
3130 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3131 "OpReturn\n" +
3132 "OpFunctionEnd",
3133 2, 0),
3134 // Test case 13: Don't fold n >= m (unsigned)
3135 InstructionFoldingCase<uint32_t>(
3136 Header() + "%main = OpFunction %void None %void_func\n" +
3137 "%main_lab = OpLabel\n" +
3138 "%n = OpVariable %_ptr_uint Function\n" +
3139 "%m = OpVariable %_ptr_uint Function\n" +
3140 "%load_n = OpLoad %uint %n\n" +
3141 "%load_m = OpLoad %uint %m\n" +
3142 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3143 "OpReturn\n" +
3144 "OpFunctionEnd",
3145 2, 0),
3146 // Test case 14: Don't fold n < m (signed)
3147 InstructionFoldingCase<uint32_t>(
3148 Header() + "%main = OpFunction %void None %void_func\n" +
3149 "%main_lab = OpLabel\n" +
3150 "%n = OpVariable %_ptr_int Function\n" +
3151 "%m = OpVariable %_ptr_int Function\n" +
3152 "%load_n = OpLoad %int %n\n" +
3153 "%load_m = OpLoad %int %m\n" +
3154 "%2 = OpULessThan %bool %load_n %load_m\n" +
3155 "OpReturn\n" +
3156 "OpFunctionEnd",
3157 2, 0),
3158 // Test case 15: Don't fold n > m (signed)
3159 InstructionFoldingCase<uint32_t>(
3160 Header() + "%main = OpFunction %void None %void_func\n" +
3161 "%main_lab = OpLabel\n" +
3162 "%n = OpVariable %_ptr_int Function\n" +
3163 "%m = OpVariable %_ptr_int Function\n" +
3164 "%load_n = OpLoad %int %n\n" +
3165 "%load_m = OpLoad %int %m\n" +
3166 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3167 "OpReturn\n" +
3168 "OpFunctionEnd",
3169 2, 0),
3170 // Test case 16: Don't fold n <= m (signed)
3171 InstructionFoldingCase<uint32_t>(
3172 Header() + "%main = OpFunction %void None %void_func\n" +
3173 "%main_lab = OpLabel\n" +
3174 "%n = OpVariable %_ptr_int Function\n" +
3175 "%m = OpVariable %_ptr_int Function\n" +
3176 "%load_n = OpLoad %int %n\n" +
3177 "%load_m = OpLoad %int %m\n" +
3178 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3179 "OpReturn\n" +
3180 "OpFunctionEnd",
3181 2, 0),
3182 // Test case 17: Don't fold n >= m (signed)
3183 InstructionFoldingCase<uint32_t>(
3184 Header() + "%main = OpFunction %void None %void_func\n" +
3185 "%main_lab = OpLabel\n" +
3186 "%n = OpVariable %_ptr_int Function\n" +
3187 "%m = OpVariable %_ptr_int Function\n" +
3188 "%load_n = OpLoad %int %n\n" +
3189 "%load_m = OpLoad %int %m\n" +
3190 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3191 "OpReturn\n" +
3192 "OpFunctionEnd",
3193 2, 0),
3194 // Test case 18: Don't fold n || m
3195 InstructionFoldingCase<uint32_t>(
3196 Header() + "%main = OpFunction %void None %void_func\n" +
3197 "%main_lab = OpLabel\n" +
3198 "%n = OpVariable %_ptr_bool Function\n" +
3199 "%m = OpVariable %_ptr_bool Function\n" +
3200 "%load_n = OpLoad %bool %n\n" +
3201 "%load_m = OpLoad %bool %m\n" +
3202 "%2 = OpLogicalOr %bool %load_n %load_m\n" +
3203 "OpReturn\n" +
3204 "OpFunctionEnd",
3205 2, 0),
3206 // Test case 19: Don't fold n && m
3207 InstructionFoldingCase<uint32_t>(
3208 Header() + "%main = OpFunction %void None %void_func\n" +
3209 "%main_lab = OpLabel\n" +
3210 "%n = OpVariable %_ptr_bool Function\n" +
3211 "%m = OpVariable %_ptr_bool Function\n" +
3212 "%load_n = OpLoad %bool %n\n" +
3213 "%load_m = OpLoad %bool %m\n" +
3214 "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
3215 "OpReturn\n" +
3216 "OpFunctionEnd",
3217 2, 0),
3218 // Test case 20: Don't fold n * 3
3219 InstructionFoldingCase<uint32_t>(
3220 Header() + "%main = OpFunction %void None %void_func\n" +
3221 "%main_lab = OpLabel\n" +
3222 "%n = OpVariable %_ptr_int Function\n" +
3223 "%load_n = OpLoad %int %n\n" +
3224 "%2 = OpIMul %int %load_n %int_3\n" +
3225 "OpReturn\n" +
3226 "OpFunctionEnd",
3227 2, 0),
3228 // Test case 21: Don't fold n / 3 (unsigned)
3229 InstructionFoldingCase<uint32_t>(
3230 Header() + "%main = OpFunction %void None %void_func\n" +
3231 "%main_lab = OpLabel\n" +
3232 "%n = OpVariable %_ptr_uint Function\n" +
3233 "%load_n = OpLoad %uint %n\n" +
3234 "%2 = OpUDiv %uint %load_n %uint_3\n" +
3235 "OpReturn\n" +
3236 "OpFunctionEnd",
3237 2, 0),
3238 // Test case 22: Don't fold n / 3 (signed)
3239 InstructionFoldingCase<uint32_t>(
3240 Header() + "%main = OpFunction %void None %void_func\n" +
3241 "%main_lab = OpLabel\n" +
3242 "%n = OpVariable %_ptr_int Function\n" +
3243 "%load_n = OpLoad %int %n\n" +
3244 "%2 = OpSDiv %int %load_n %int_3\n" +
3245 "OpReturn\n" +
3246 "OpFunctionEnd",
3247 2, 0),
3248 // Test case 23: Don't fold n remainder 3
3249 InstructionFoldingCase<uint32_t>(
3250 Header() + "%main = OpFunction %void None %void_func\n" +
3251 "%main_lab = OpLabel\n" +
3252 "%n = OpVariable %_ptr_int Function\n" +
3253 "%load_n = OpLoad %int %n\n" +
3254 "%2 = OpSRem %int %load_n %int_3\n" +
3255 "OpReturn\n" +
3256 "OpFunctionEnd",
3257 2, 0),
3258 // Test case 24: Don't fold n % 3 (signed)
3259 InstructionFoldingCase<uint32_t>(
3260 Header() + "%main = OpFunction %void None %void_func\n" +
3261 "%main_lab = OpLabel\n" +
3262 "%n = OpVariable %_ptr_int Function\n" +
3263 "%load_n = OpLoad %int %n\n" +
3264 "%2 = OpSMod %int %load_n %int_3\n" +
3265 "OpReturn\n" +
3266 "OpFunctionEnd",
3267 2, 0),
3268 // Test case 25: Don't fold n % 3 (unsigned)
3269 InstructionFoldingCase<uint32_t>(
3270 Header() + "%main = OpFunction %void None %void_func\n" +
3271 "%main_lab = OpLabel\n" +
3272 "%n = OpVariable %_ptr_uint Function\n" +
3273 "%load_n = OpLoad %uint %n\n" +
3274 "%2 = OpUMod %int %load_n %int_3\n" +
3275 "OpReturn\n" +
3276 "OpFunctionEnd",
3277 2, 0),
3278 // Test case 26: Don't fold n << 3
3279 InstructionFoldingCase<uint32_t>(
3280 Header() + "%main = OpFunction %void None %void_func\n" +
3281 "%main_lab = OpLabel\n" +
3282 "%n = OpVariable %_ptr_uint Function\n" +
3283 "%load_n = OpLoad %uint %n\n" +
3284 "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
3285 "OpReturn\n" +
3286 "OpFunctionEnd",
3287 2, 0),
3288 // Test case 27: Don't fold n >> 3
3289 InstructionFoldingCase<uint32_t>(
3290 Header() + "%main = OpFunction %void None %void_func\n" +
3291 "%main_lab = OpLabel\n" +
3292 "%n = OpVariable %_ptr_uint Function\n" +
3293 "%load_n = OpLoad %uint %n\n" +
3294 "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
3295 "OpReturn\n" +
3296 "OpFunctionEnd",
3297 2, 0),
3298 // Test case 28: Don't fold n | 3
3299 InstructionFoldingCase<uint32_t>(
3300 Header() + "%main = OpFunction %void None %void_func\n" +
3301 "%main_lab = OpLabel\n" +
3302 "%n = OpVariable %_ptr_uint Function\n" +
3303 "%load_n = OpLoad %uint %n\n" +
3304 "%2 = OpBitwiseOr %int %load_n %int_3\n" +
3305 "OpReturn\n" +
3306 "OpFunctionEnd",
3307 2, 0),
3308 // Test case 29: Don't fold n & 3
3309 InstructionFoldingCase<uint32_t>(
3310 Header() + "%main = OpFunction %void None %void_func\n" +
3311 "%main_lab = OpLabel\n" +
3312 "%n = OpVariable %_ptr_uint Function\n" +
3313 "%load_n = OpLoad %uint %n\n" +
3314 "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
3315 "OpReturn\n" +
3316 "OpFunctionEnd",
3317 2, 0),
3318 // Test case 30: Don't fold n < 3 (unsigned)
3319 InstructionFoldingCase<uint32_t>(
3320 Header() + "%main = OpFunction %void None %void_func\n" +
3321 "%main_lab = OpLabel\n" +
3322 "%n = OpVariable %_ptr_uint Function\n" +
3323 "%load_n = OpLoad %uint %n\n" +
3324 "%2 = OpULessThan %bool %load_n %uint_3\n" +
3325 "OpReturn\n" +
3326 "OpFunctionEnd",
3327 2, 0),
3328 // Test case 31: Don't fold n > 3 (unsigned)
3329 InstructionFoldingCase<uint32_t>(
3330 Header() + "%main = OpFunction %void None %void_func\n" +
3331 "%main_lab = OpLabel\n" +
3332 "%n = OpVariable %_ptr_uint Function\n" +
3333 "%load_n = OpLoad %uint %n\n" +
3334 "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
3335 "OpReturn\n" +
3336 "OpFunctionEnd",
3337 2, 0),
3338 // Test case 32: Don't fold n <= 3 (unsigned)
3339 InstructionFoldingCase<uint32_t>(
3340 Header() + "%main = OpFunction %void None %void_func\n" +
3341 "%main_lab = OpLabel\n" +
3342 "%n = OpVariable %_ptr_uint Function\n" +
3343 "%load_n = OpLoad %uint %n\n" +
3344 "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
3345 "OpReturn\n" +
3346 "OpFunctionEnd",
3347 2, 0),
3348 // Test case 33: Don't fold n >= 3 (unsigned)
3349 InstructionFoldingCase<uint32_t>(
3350 Header() + "%main = OpFunction %void None %void_func\n" +
3351 "%main_lab = OpLabel\n" +
3352 "%n = OpVariable %_ptr_uint Function\n" +
3353 "%load_n = OpLoad %uint %n\n" +
3354 "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
3355 "OpReturn\n" +
3356 "OpFunctionEnd",
3357 2, 0),
3358 // Test case 34: Don't fold n < 3 (signed)
3359 InstructionFoldingCase<uint32_t>(
3360 Header() + "%main = OpFunction %void None %void_func\n" +
3361 "%main_lab = OpLabel\n" +
3362 "%n = OpVariable %_ptr_int Function\n" +
3363 "%load_n = OpLoad %int %n\n" +
3364 "%2 = OpULessThan %bool %load_n %int_3\n" +
3365 "OpReturn\n" +
3366 "OpFunctionEnd",
3367 2, 0),
3368 // Test case 35: Don't fold n > 3 (signed)
3369 InstructionFoldingCase<uint32_t>(
3370 Header() + "%main = OpFunction %void None %void_func\n" +
3371 "%main_lab = OpLabel\n" +
3372 "%n = OpVariable %_ptr_int Function\n" +
3373 "%load_n = OpLoad %int %n\n" +
3374 "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
3375 "OpReturn\n" +
3376 "OpFunctionEnd",
3377 2, 0),
3378 // Test case 36: Don't fold n <= 3 (signed)
3379 InstructionFoldingCase<uint32_t>(
3380 Header() + "%main = OpFunction %void None %void_func\n" +
3381 "%main_lab = OpLabel\n" +
3382 "%n = OpVariable %_ptr_int Function\n" +
3383 "%load_n = OpLoad %int %n\n" +
3384 "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
3385 "OpReturn\n" +
3386 "OpFunctionEnd",
3387 2, 0),
3388 // Test case 37: Don't fold n >= 3 (signed)
3389 InstructionFoldingCase<uint32_t>(
3390 Header() + "%main = OpFunction %void None %void_func\n" +
3391 "%main_lab = OpLabel\n" +
3392 "%n = OpVariable %_ptr_int Function\n" +
3393 "%load_n = OpLoad %int %n\n" +
3394 "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
3395 "OpReturn\n" +
3396 "OpFunctionEnd",
3397 2, 0),
3398 // Test case 38: Don't fold 2 + 3 (long), bad length
3399 InstructionFoldingCase<uint32_t>(
3400 Header() + "%main = OpFunction %void None %void_func\n" +
3401 "%main_lab = OpLabel\n" +
3402 "%2 = OpIAdd %long %long_2 %long_3\n" +
3403 "OpReturn\n" +
3404 "OpFunctionEnd",
3405 2, 0),
3406 // Test case 39: Don't fold 2 + 3 (short), bad length
3407 InstructionFoldingCase<uint32_t>(
3408 Header() + "%main = OpFunction %void None %void_func\n" +
3409 "%main_lab = OpLabel\n" +
3410 "%2 = OpIAdd %short %short_2 %short_3\n" +
3411 "OpReturn\n" +
3412 "OpFunctionEnd",
3413 2, 0),
3414 // Test case 40: fold 1*n
3415 InstructionFoldingCase<uint32_t>(
3416 Header() + "%main = OpFunction %void None %void_func\n" +
3417 "%main_lab = OpLabel\n" +
3418 "%n = OpVariable %_ptr_int Function\n" +
3419 "%3 = OpLoad %int %n\n" +
3420 "%2 = OpIMul %int %int_1 %3\n" +
3421 "OpReturn\n" +
3422 "OpFunctionEnd",
3423 2, 3),
3424 // Test case 41: fold n*1
3425 InstructionFoldingCase<uint32_t>(
3426 Header() + "%main = OpFunction %void None %void_func\n" +
3427 "%main_lab = OpLabel\n" +
3428 "%n = OpVariable %_ptr_int Function\n" +
3429 "%3 = OpLoad %int %n\n" +
3430 "%2 = OpIMul %int %3 %int_1\n" +
3431 "OpReturn\n" +
3432 "OpFunctionEnd",
3433 2, 3),
3434 // Test case 42: Don't fold comparisons of 64-bit types
3435 // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
3436 InstructionFoldingCase<uint32_t>(
3437 Header() + "%main = OpFunction %void None %void_func\n" +
3438 "%main_lab = OpLabel\n" +
3439 "%2 = OpSLessThan %bool %long_0 %long_2\n" +
3440 "OpReturn\n" +
3441 "OpFunctionEnd",
3442 2, 0)
3443 ));
3444
3445 INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
3446 ::testing::Values(
3447 // Test case 0: fold Insert feeding extract
3448 InstructionFoldingCase<uint32_t>(
3449 Header() + "%main = OpFunction %void None %void_func\n" +
3450 "%main_lab = OpLabel\n" +
3451 "%n = OpVariable %_ptr_int Function\n" +
3452 "%2 = OpLoad %int %n\n" +
3453 "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
3454 "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
3455 "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
3456 "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
3457 "%7 = OpCompositeExtract %int %6 0\n" +
3458 "OpReturn\n" +
3459 "OpFunctionEnd",
3460 7, 2),
3461 // Test case 1: fold Composite construct feeding extract (position 0)
3462 InstructionFoldingCase<uint32_t>(
3463 Header() + "%main = OpFunction %void None %void_func\n" +
3464 "%main_lab = OpLabel\n" +
3465 "%n = OpVariable %_ptr_int Function\n" +
3466 "%2 = OpLoad %int %n\n" +
3467 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
3468 "%4 = OpCompositeExtract %int %3 0\n" +
3469 "OpReturn\n" +
3470 "OpFunctionEnd",
3471 4, 2),
3472 // Test case 2: fold Composite construct feeding extract (position 3)
3473 InstructionFoldingCase<uint32_t>(
3474 Header() + "%main = OpFunction %void None %void_func\n" +
3475 "%main_lab = OpLabel\n" +
3476 "%n = OpVariable %_ptr_int Function\n" +
3477 "%2 = OpLoad %int %n\n" +
3478 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
3479 "%4 = OpCompositeExtract %int %3 3\n" +
3480 "OpReturn\n" +
3481 "OpFunctionEnd",
3482 4, INT_0_ID),
3483 // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
3484 InstructionFoldingCase<uint32_t>(
3485 Header() + "%main = OpFunction %void None %void_func\n" +
3486 "%main_lab = OpLabel\n" +
3487 "%n = OpVariable %_ptr_int Function\n" +
3488 "%2 = OpLoad %int %n\n" +
3489 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
3490 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3491 "%5 = OpCompositeExtract %int %4 3\n" +
3492 "OpReturn\n" +
3493 "OpFunctionEnd",
3494 5, INT_0_ID),
3495 // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
3496 InstructionFoldingCase<uint32_t>(
3497 Header() + "%main = OpFunction %void None %void_func\n" +
3498 "%main_lab = OpLabel\n" +
3499 "%n = OpVariable %_ptr_int Function\n" +
3500 "%2 = OpLoad %int %n\n" +
3501 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
3502 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3503 "%5 = OpCompositeExtract %int %4 0\n" +
3504 "OpReturn\n" +
3505 "OpFunctionEnd",
3506 5, 2),
3507 // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
3508 InstructionFoldingCase<uint32_t>(
3509 Header() + "%main = OpFunction %void None %void_func\n" +
3510 "%main_lab = OpLabel\n" +
3511 "%n = OpVariable %_ptr_int Function\n" +
3512 "%2 = OpLoad %int %n\n" +
3513 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
3514 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3515 "%5 = OpCompositeExtract %int %4 1\n" +
3516 "OpReturn\n" +
3517 "OpFunctionEnd",
3518 5, 2),
3519 // Test case 6: fold Composite construct with multiple indices.
3520 InstructionFoldingCase<uint32_t>(
3521 Header() + "%main = OpFunction %void None %void_func\n" +
3522 "%main_lab = OpLabel\n" +
3523 "%n = OpVariable %_ptr_int Function\n" +
3524 "%2 = OpLoad %int %n\n" +
3525 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
3526 "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
3527 "%5 = OpCompositeExtract %int %4 0 1\n" +
3528 "OpReturn\n" +
3529 "OpFunctionEnd",
3530 5, 2),
3531 // Test case 7: fold constant extract.
3532 InstructionFoldingCase<uint32_t>(
3533 Header() + "%main = OpFunction %void None %void_func\n" +
3534 "%main_lab = OpLabel\n" +
3535 "%2 = OpCompositeExtract %int %102 1\n" +
3536 "OpReturn\n" +
3537 "OpFunctionEnd",
3538 2, INT_7_ID),
3539 // Test case 8: constant struct has OpUndef
3540 InstructionFoldingCase<uint32_t>(
3541 Header() + "%main = OpFunction %void None %void_func\n" +
3542 "%main_lab = OpLabel\n" +
3543 "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
3544 "OpReturn\n" +
3545 "OpFunctionEnd",
3546 2, 0),
3547 // Test case 9: Extracting a member of element inserted via Insert
3548 InstructionFoldingCase<uint32_t>(
3549 Header() + "%main = OpFunction %void None %void_func\n" +
3550 "%main_lab = OpLabel\n" +
3551 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
3552 "%2 = OpLoad %struct_v2int_int_int %n\n" +
3553 "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
3554 "%4 = OpCompositeExtract %int %3 0 1\n" +
3555 "OpReturn\n" +
3556 "OpFunctionEnd",
3557 4, 103),
3558 // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
3559 InstructionFoldingCase<uint32_t>(
3560 Header() + "%main = OpFunction %void None %void_func\n" +
3561 "%main_lab = OpLabel\n" +
3562 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
3563 "%2 = OpLoad %struct_v2int_int_int %n\n" +
3564 "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
3565 "%4 = OpCompositeExtract %v2int %3 0\n" +
3566 "OpReturn\n" +
3567 "OpFunctionEnd",
3568 4, 0),
3569 // Test case 11: Extracting from result of vector shuffle (first input)
3570 InstructionFoldingCase<uint32_t>(
3571 Header() + "%main = OpFunction %void None %void_func\n" +
3572 "%main_lab = OpLabel\n" +
3573 "%n = OpVariable %_ptr_v2int Function\n" +
3574 "%2 = OpLoad %v2int %n\n" +
3575 "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
3576 "%4 = OpCompositeExtract %int %3 1\n" +
3577 "OpReturn\n" +
3578 "OpFunctionEnd",
3579 4, INT_7_ID),
3580 // Test case 12: Extracting from result of vector shuffle (second input)
3581 InstructionFoldingCase<uint32_t>(
3582 Header() + "%main = OpFunction %void None %void_func\n" +
3583 "%main_lab = OpLabel\n" +
3584 "%n = OpVariable %_ptr_v2int Function\n" +
3585 "%2 = OpLoad %v2int %n\n" +
3586 "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
3587 "%4 = OpCompositeExtract %int %3 0\n" +
3588 "OpReturn\n" +
3589 "OpFunctionEnd",
3590 4, INT_7_ID),
3591 // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608
3592 // Out of bounds access. Do not fold.
3593 InstructionFoldingCase<uint32_t>(
3594 Header() + "%main = OpFunction %void None %void_func\n" +
3595 "%main_lab = OpLabel\n" +
3596 "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" +
3597 "%3 = OpCompositeExtract %float %2 4\n" +
3598 "OpReturn\n" +
3599 "OpFunctionEnd",
3600 3, 0),
3601 // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631
3602 // Extract the component right after the vector constituent.
3603 InstructionFoldingCase<uint32_t>(
3604 Header() + "%main = OpFunction %void None %void_func\n" +
3605 "%main_lab = OpLabel\n" +
3606 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
3607 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
3608 "%4 = OpCompositeExtract %int %3 2\n" +
3609 "OpReturn\n" +
3610 "OpFunctionEnd",
3611 4, INT_0_ID),
3612 // Test case 15:
3613 // Don't fold extract fed by construct with vector result if the index is
3614 // past the last element.
3615 InstructionFoldingCase<uint32_t>(
3616 Header() + "%main = OpFunction %void None %void_func\n" +
3617 "%main_lab = OpLabel\n" +
3618 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
3619 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
3620 "%4 = OpCompositeExtract %int %3 4\n" +
3621 "OpReturn\n" +
3622 "OpFunctionEnd",
3623 4, 0)
3624 ));
3625
3626 INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
3627 ::testing::Values(
3628 // Test case 0: fold Extracts feeding construct
3629 InstructionFoldingCase<uint32_t>(
3630 Header() + "%main = OpFunction %void None %void_func\n" +
3631 "%main_lab = OpLabel\n" +
3632 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3633 "%3 = OpCompositeExtract %int %2 0\n" +
3634 "%4 = OpCompositeExtract %int %2 1\n" +
3635 "%5 = OpCompositeExtract %int %2 2\n" +
3636 "%6 = OpCompositeExtract %int %2 3\n" +
3637 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3638 "OpReturn\n" +
3639 "OpFunctionEnd",
3640 7, 2),
3641 // Test case 1: Don't fold Extracts feeding construct (Different source)
3642 InstructionFoldingCase<uint32_t>(
3643 Header() + "%main = OpFunction %void None %void_func\n" +
3644 "%main_lab = OpLabel\n" +
3645 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3646 "%3 = OpCompositeExtract %int %2 0\n" +
3647 "%4 = OpCompositeExtract %int %2 1\n" +
3648 "%5 = OpCompositeExtract %int %2 2\n" +
3649 "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
3650 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3651 "OpReturn\n" +
3652 "OpFunctionEnd",
3653 7, 0),
3654 // Test case 2: Don't fold Extracts feeding construct (bad indices)
3655 InstructionFoldingCase<uint32_t>(
3656 Header() + "%main = OpFunction %void None %void_func\n" +
3657 "%main_lab = OpLabel\n" +
3658 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3659 "%3 = OpCompositeExtract %int %2 0\n" +
3660 "%4 = OpCompositeExtract %int %2 0\n" +
3661 "%5 = OpCompositeExtract %int %2 2\n" +
3662 "%6 = OpCompositeExtract %int %2 3\n" +
3663 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3664 "OpReturn\n" +
3665 "OpFunctionEnd",
3666 7, 0),
3667 // Test case 3: Don't fold Extracts feeding construct (different type)
3668 InstructionFoldingCase<uint32_t>(
3669 Header() + "%main = OpFunction %void None %void_func\n" +
3670 "%main_lab = OpLabel\n" +
3671 "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
3672 "%3 = OpCompositeExtract %v2int %2 0\n" +
3673 "%4 = OpCompositeExtract %int %2 1\n" +
3674 "%5 = OpCompositeExtract %int %2 2\n" +
3675 "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
3676 "OpReturn\n" +
3677 "OpFunctionEnd",
3678 7, 0),
3679 // Test case 4: Fold construct with constants to constant.
3680 InstructionFoldingCase<uint32_t>(
3681 Header() + "%main = OpFunction %void None %void_func\n" +
3682 "%main_lab = OpLabel\n" +
3683 "%2 = OpCompositeConstruct %v2int %103 %103\n" +
3684 "OpReturn\n" +
3685 "OpFunctionEnd",
3686 2, VEC2_0_ID),
3687 // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct
3688 // for an empty struct, and we reached the id limit.
3689 InstructionFoldingCase<uint32_t>(
3690 Header() + "%empty_struct = OpTypeStruct\n" +
3691 "%main = OpFunction %void None %void_func\n" +
3692 "%main_lab = OpLabel\n" +
3693 "%4194303 = OpCompositeConstruct %empty_struct\n" +
3694 "OpReturn\n" +
3695 "OpFunctionEnd",
3696 4194303, 0)
3697 ));
3698
3699 INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
3700 ::testing::Values(
3701 // Test case 0: Fold phi with the same values for all edges.
3702 InstructionFoldingCase<uint32_t>(
3703 Header() + "%main = OpFunction %void None %void_func\n" +
3704 "%main_lab = OpLabel\n" +
3705 " OpBranchConditional %true %l1 %l2\n" +
3706 "%l1 = OpLabel\n" +
3707 " OpBranch %merge_lab\n" +
3708 "%l2 = OpLabel\n" +
3709 " OpBranch %merge_lab\n" +
3710 "%merge_lab = OpLabel\n" +
3711 "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
3712 "OpReturn\n" +
3713 "OpFunctionEnd",
3714 2, INT_0_ID),
3715 // Test case 1: Fold phi in pass through loop.
3716 InstructionFoldingCase<uint32_t>(
3717 Header() + "%main = OpFunction %void None %void_func\n" +
3718 "%main_lab = OpLabel\n" +
3719 " OpBranch %l1\n" +
3720 "%l1 = OpLabel\n" +
3721 "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
3722 " OpBranchConditional %true %l1 %merge_lab\n" +
3723 "%merge_lab = OpLabel\n" +
3724 "OpReturn\n" +
3725 "OpFunctionEnd",
3726 2, INT_0_ID),
3727 // Test case 2: Don't Fold phi because of different values.
3728 InstructionFoldingCase<uint32_t>(
3729 Header() + "%main = OpFunction %void None %void_func\n" +
3730 "%main_lab = OpLabel\n" +
3731 " OpBranch %l1\n" +
3732 "%l1 = OpLabel\n" +
3733 "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
3734 " OpBranchConditional %true %l1 %merge_lab\n" +
3735 "%merge_lab = OpLabel\n" +
3736 "OpReturn\n" +
3737 "OpFunctionEnd",
3738 2, 0)
3739 ));
3740
3741 INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
3742 ::testing::Values(
3743 // Test case 0: Don't fold n + 1.0
3744 InstructionFoldingCase<uint32_t>(
3745 Header() + "%main = OpFunction %void None %void_func\n" +
3746 "%main_lab = OpLabel\n" +
3747 "%n = OpVariable %_ptr_float Function\n" +
3748 "%3 = OpLoad %float %n\n" +
3749 "%2 = OpFAdd %float %3 %float_2\n" +
3750 "OpReturn\n" +
3751 "OpFunctionEnd",
3752 2, 0),
3753 // Test case 1: Don't fold n - 1.0
3754 InstructionFoldingCase<uint32_t>(
3755 Header() + "%main = OpFunction %void None %void_func\n" +
3756 "%main_lab = OpLabel\n" +
3757 "%n = OpVariable %_ptr_float Function\n" +
3758 "%3 = OpLoad %float %n\n" +
3759 "%2 = OpFSub %float %3 %float_2\n" +
3760 "OpReturn\n" +
3761 "OpFunctionEnd",
3762 2, 0),
3763 // Test case 2: Don't fold n * 2.0
3764 InstructionFoldingCase<uint32_t>(
3765 Header() + "%main = OpFunction %void None %void_func\n" +
3766 "%main_lab = OpLabel\n" +
3767 "%n = OpVariable %_ptr_float Function\n" +
3768 "%3 = OpLoad %float %n\n" +
3769 "%2 = OpFMul %float %3 %float_2\n" +
3770 "OpReturn\n" +
3771 "OpFunctionEnd",
3772 2, 0),
3773 // Test case 3: Fold n + 0.0
3774 InstructionFoldingCase<uint32_t>(
3775 Header() + "%main = OpFunction %void None %void_func\n" +
3776 "%main_lab = OpLabel\n" +
3777 "%n = OpVariable %_ptr_float Function\n" +
3778 "%3 = OpLoad %float %n\n" +
3779 "%2 = OpFAdd %float %3 %float_0\n" +
3780 "OpReturn\n" +
3781 "OpFunctionEnd",
3782 2, 3),
3783 // Test case 4: Fold 0.0 + n
3784 InstructionFoldingCase<uint32_t>(
3785 Header() + "%main = OpFunction %void None %void_func\n" +
3786 "%main_lab = OpLabel\n" +
3787 "%n = OpVariable %_ptr_float Function\n" +
3788 "%3 = OpLoad %float %n\n" +
3789 "%2 = OpFAdd %float %float_0 %3\n" +
3790 "OpReturn\n" +
3791 "OpFunctionEnd",
3792 2, 3),
3793 // Test case 5: Fold n - 0.0
3794 InstructionFoldingCase<uint32_t>(
3795 Header() + "%main = OpFunction %void None %void_func\n" +
3796 "%main_lab = OpLabel\n" +
3797 "%n = OpVariable %_ptr_float Function\n" +
3798 "%3 = OpLoad %float %n\n" +
3799 "%2 = OpFSub %float %3 %float_0\n" +
3800 "OpReturn\n" +
3801 "OpFunctionEnd",
3802 2, 3),
3803 // Test case 6: Fold n * 1.0
3804 InstructionFoldingCase<uint32_t>(
3805 Header() + "%main = OpFunction %void None %void_func\n" +
3806 "%main_lab = OpLabel\n" +
3807 "%n = OpVariable %_ptr_float Function\n" +
3808 "%3 = OpLoad %float %n\n" +
3809 "%2 = OpFMul %float %3 %float_1\n" +
3810 "OpReturn\n" +
3811 "OpFunctionEnd",
3812 2, 3),
3813 // Test case 7: Fold 1.0 * n
3814 InstructionFoldingCase<uint32_t>(
3815 Header() + "%main = OpFunction %void None %void_func\n" +
3816 "%main_lab = OpLabel\n" +
3817 "%n = OpVariable %_ptr_float Function\n" +
3818 "%3 = OpLoad %float %n\n" +
3819 "%2 = OpFMul %float %float_1 %3\n" +
3820 "OpReturn\n" +
3821 "OpFunctionEnd",
3822 2, 3),
3823 // Test case 8: Fold n / 1.0
3824 InstructionFoldingCase<uint32_t>(
3825 Header() + "%main = OpFunction %void None %void_func\n" +
3826 "%main_lab = OpLabel\n" +
3827 "%n = OpVariable %_ptr_float Function\n" +
3828 "%3 = OpLoad %float %n\n" +
3829 "%2 = OpFDiv %float %3 %float_1\n" +
3830 "OpReturn\n" +
3831 "OpFunctionEnd",
3832 2, 3),
3833 // Test case 9: Fold n * 0.0
3834 InstructionFoldingCase<uint32_t>(
3835 Header() + "%main = OpFunction %void None %void_func\n" +
3836 "%main_lab = OpLabel\n" +
3837 "%n = OpVariable %_ptr_float Function\n" +
3838 "%3 = OpLoad %float %n\n" +
3839 "%2 = OpFMul %float %3 %104\n" +
3840 "OpReturn\n" +
3841 "OpFunctionEnd",
3842 2, FLOAT_0_ID),
3843 // Test case 10: Fold 0.0 * n
3844 InstructionFoldingCase<uint32_t>(
3845 Header() + "%main = OpFunction %void None %void_func\n" +
3846 "%main_lab = OpLabel\n" +
3847 "%n = OpVariable %_ptr_float Function\n" +
3848 "%3 = OpLoad %float %n\n" +
3849 "%2 = OpFMul %float %104 %3\n" +
3850 "OpReturn\n" +
3851 "OpFunctionEnd",
3852 2, FLOAT_0_ID),
3853 // Test case 11: Fold 0.0 / n
3854 InstructionFoldingCase<uint32_t>(
3855 Header() + "%main = OpFunction %void None %void_func\n" +
3856 "%main_lab = OpLabel\n" +
3857 "%n = OpVariable %_ptr_float Function\n" +
3858 "%3 = OpLoad %float %n\n" +
3859 "%2 = OpFDiv %float %104 %3\n" +
3860 "OpReturn\n" +
3861 "OpFunctionEnd",
3862 2, FLOAT_0_ID),
3863 // Test case 12: Don't fold mix(a, b, 2.0)
3864 InstructionFoldingCase<uint32_t>(
3865 Header() + "%main = OpFunction %void None %void_func\n" +
3866 "%main_lab = OpLabel\n" +
3867 "%a = OpVariable %_ptr_float Function\n" +
3868 "%b = OpVariable %_ptr_float Function\n" +
3869 "%3 = OpLoad %float %a\n" +
3870 "%4 = OpLoad %float %b\n" +
3871 "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
3872 "OpReturn\n" +
3873 "OpFunctionEnd",
3874 2, 0),
3875 // Test case 13: Fold mix(a, b, 0.0)
3876 InstructionFoldingCase<uint32_t>(
3877 Header() + "%main = OpFunction %void None %void_func\n" +
3878 "%main_lab = OpLabel\n" +
3879 "%a = OpVariable %_ptr_float Function\n" +
3880 "%b = OpVariable %_ptr_float Function\n" +
3881 "%3 = OpLoad %float %a\n" +
3882 "%4 = OpLoad %float %b\n" +
3883 "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
3884 "OpReturn\n" +
3885 "OpFunctionEnd",
3886 2, 3),
3887 // Test case 14: Fold mix(a, b, 1.0)
3888 InstructionFoldingCase<uint32_t>(
3889 Header() + "%main = OpFunction %void None %void_func\n" +
3890 "%main_lab = OpLabel\n" +
3891 "%a = OpVariable %_ptr_float Function\n" +
3892 "%b = OpVariable %_ptr_float Function\n" +
3893 "%3 = OpLoad %float %a\n" +
3894 "%4 = OpLoad %float %b\n" +
3895 "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
3896 "OpReturn\n" +
3897 "OpFunctionEnd",
3898 2, 4),
3899 // Test case 15: Fold vector fadd with null
3900 InstructionFoldingCase<uint32_t>(
3901 Header() + "%main = OpFunction %void None %void_func\n" +
3902 "%main_lab = OpLabel\n" +
3903 "%a = OpVariable %_ptr_v2float Function\n" +
3904 "%2 = OpLoad %v2float %a\n" +
3905 "%3 = OpFAdd %v2float %2 %v2float_null\n" +
3906 "OpReturn\n" +
3907 "OpFunctionEnd",
3908 3, 2),
3909 // Test case 16: Fold vector fadd with null
3910 InstructionFoldingCase<uint32_t>(
3911 Header() + "%main = OpFunction %void None %void_func\n" +
3912 "%main_lab = OpLabel\n" +
3913 "%a = OpVariable %_ptr_v2float Function\n" +
3914 "%2 = OpLoad %v2float %a\n" +
3915 "%3 = OpFAdd %v2float %v2float_null %2\n" +
3916 "OpReturn\n" +
3917 "OpFunctionEnd",
3918 3, 2),
3919 // Test case 17: Fold vector fsub with null
3920 InstructionFoldingCase<uint32_t>(
3921 Header() + "%main = OpFunction %void None %void_func\n" +
3922 "%main_lab = OpLabel\n" +
3923 "%a = OpVariable %_ptr_v2float Function\n" +
3924 "%2 = OpLoad %v2float %a\n" +
3925 "%3 = OpFSub %v2float %2 %v2float_null\n" +
3926 "OpReturn\n" +
3927 "OpFunctionEnd",
3928 3, 2),
3929 // Test case 18: Fold 0.0(half) * n
3930 InstructionFoldingCase<uint32_t>(
3931 Header() + "%main = OpFunction %void None %void_func\n" +
3932 "%main_lab = OpLabel\n" +
3933 "%n = OpVariable %_ptr_half Function\n" +
3934 "%3 = OpLoad %half %n\n" +
3935 "%2 = OpFMul %half %108 %3\n" +
3936 "OpReturn\n" +
3937 "OpFunctionEnd",
3938 2, HALF_0_ID),
3939 // Test case 19: Don't fold 1.0(half) * n
3940 InstructionFoldingCase<uint32_t>(
3941 Header() + "%main = OpFunction %void None %void_func\n" +
3942 "%main_lab = OpLabel\n" +
3943 "%n = OpVariable %_ptr_half Function\n" +
3944 "%3 = OpLoad %half %n\n" +
3945 "%2 = OpFMul %half %half_1 %3\n" +
3946 "OpReturn\n" +
3947 "OpFunctionEnd",
3948 2, 0),
3949 // Test case 20: Don't fold 1.0 * 1.0 (half)
3950 InstructionFoldingCase<uint32_t>(
3951 Header() + "%main = OpFunction %void None %void_func\n" +
3952 "%main_lab = OpLabel\n" +
3953 "%2 = OpFMul %half %half_1 %half_1\n" +
3954 "OpReturn\n" +
3955 "OpFunctionEnd",
3956 2, 0),
3957 // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half)
3958 InstructionFoldingCase<uint32_t>(
3959 Header() + "%main = OpFunction %void None %void_func\n" +
3960 "%main_lab = OpLabel\n" +
3961 "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" +
3962 "OpReturn\n" +
3963 "OpFunctionEnd",
3964 2, 0),
3965 // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half)
3966 InstructionFoldingCase<uint32_t>(
3967 Header() + "%main = OpFunction %void None %void_func\n" +
3968 "%main_lab = OpLabel\n" +
3969 "%2 = OpDot %half %half_0_1 %half_0_1\n" +
3970 "OpReturn\n" +
3971 "OpFunctionEnd",
3972 2, 0)
3973 ));
3974
3975 INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
3976 ::testing::Values(
3977 // Test case 0: Don't fold n + 1.0
3978 InstructionFoldingCase<uint32_t>(
3979 Header() + "%main = OpFunction %void None %void_func\n" +
3980 "%main_lab = OpLabel\n" +
3981 "%n = OpVariable %_ptr_double Function\n" +
3982 "%3 = OpLoad %double %n\n" +
3983 "%2 = OpFAdd %double %3 %double_2\n" +
3984 "OpReturn\n" +
3985 "OpFunctionEnd",
3986 2, 0),
3987 // Test case 1: Don't fold n - 1.0
3988 InstructionFoldingCase<uint32_t>(
3989 Header() + "%main = OpFunction %void None %void_func\n" +
3990 "%main_lab = OpLabel\n" +
3991 "%n = OpVariable %_ptr_double Function\n" +
3992 "%3 = OpLoad %double %n\n" +
3993 "%2 = OpFSub %double %3 %double_2\n" +
3994 "OpReturn\n" +
3995 "OpFunctionEnd",
3996 2, 0),
3997 // Test case 2: Don't fold n * 2.0
3998 InstructionFoldingCase<uint32_t>(
3999 Header() + "%main = OpFunction %void None %void_func\n" +
4000 "%main_lab = OpLabel\n" +
4001 "%n = OpVariable %_ptr_double Function\n" +
4002 "%3 = OpLoad %double %n\n" +
4003 "%2 = OpFMul %double %3 %double_2\n" +
4004 "OpReturn\n" +
4005 "OpFunctionEnd",
4006 2, 0),
4007 // Test case 3: Fold n + 0.0
4008 InstructionFoldingCase<uint32_t>(
4009 Header() + "%main = OpFunction %void None %void_func\n" +
4010 "%main_lab = OpLabel\n" +
4011 "%n = OpVariable %_ptr_double Function\n" +
4012 "%3 = OpLoad %double %n\n" +
4013 "%2 = OpFAdd %double %3 %double_0\n" +
4014 "OpReturn\n" +
4015 "OpFunctionEnd",
4016 2, 3),
4017 // Test case 4: Fold 0.0 + n
4018 InstructionFoldingCase<uint32_t>(
4019 Header() + "%main = OpFunction %void None %void_func\n" +
4020 "%main_lab = OpLabel\n" +
4021 "%n = OpVariable %_ptr_double Function\n" +
4022 "%3 = OpLoad %double %n\n" +
4023 "%2 = OpFAdd %double %double_0 %3\n" +
4024 "OpReturn\n" +
4025 "OpFunctionEnd",
4026 2, 3),
4027 // Test case 5: Fold n - 0.0
4028 InstructionFoldingCase<uint32_t>(
4029 Header() + "%main = OpFunction %void None %void_func\n" +
4030 "%main_lab = OpLabel\n" +
4031 "%n = OpVariable %_ptr_double Function\n" +
4032 "%3 = OpLoad %double %n\n" +
4033 "%2 = OpFSub %double %3 %double_0\n" +
4034 "OpReturn\n" +
4035 "OpFunctionEnd",
4036 2, 3),
4037 // Test case 6: Fold n * 1.0
4038 InstructionFoldingCase<uint32_t>(
4039 Header() + "%main = OpFunction %void None %void_func\n" +
4040 "%main_lab = OpLabel\n" +
4041 "%n = OpVariable %_ptr_double Function\n" +
4042 "%3 = OpLoad %double %n\n" +
4043 "%2 = OpFMul %double %3 %double_1\n" +
4044 "OpReturn\n" +
4045 "OpFunctionEnd",
4046 2, 3),
4047 // Test case 7: Fold 1.0 * n
4048 InstructionFoldingCase<uint32_t>(
4049 Header() + "%main = OpFunction %void None %void_func\n" +
4050 "%main_lab = OpLabel\n" +
4051 "%n = OpVariable %_ptr_double Function\n" +
4052 "%3 = OpLoad %double %n\n" +
4053 "%2 = OpFMul %double %double_1 %3\n" +
4054 "OpReturn\n" +
4055 "OpFunctionEnd",
4056 2, 3),
4057 // Test case 8: Fold n / 1.0
4058 InstructionFoldingCase<uint32_t>(
4059 Header() + "%main = OpFunction %void None %void_func\n" +
4060 "%main_lab = OpLabel\n" +
4061 "%n = OpVariable %_ptr_double Function\n" +
4062 "%3 = OpLoad %double %n\n" +
4063 "%2 = OpFDiv %double %3 %double_1\n" +
4064 "OpReturn\n" +
4065 "OpFunctionEnd",
4066 2, 3),
4067 // Test case 9: Fold n * 0.0
4068 InstructionFoldingCase<uint32_t>(
4069 Header() + "%main = OpFunction %void None %void_func\n" +
4070 "%main_lab = OpLabel\n" +
4071 "%n = OpVariable %_ptr_double Function\n" +
4072 "%3 = OpLoad %double %n\n" +
4073 "%2 = OpFMul %double %3 %105\n" +
4074 "OpReturn\n" +
4075 "OpFunctionEnd",
4076 2, DOUBLE_0_ID),
4077 // Test case 10: Fold 0.0 * n
4078 InstructionFoldingCase<uint32_t>(
4079 Header() + "%main = OpFunction %void None %void_func\n" +
4080 "%main_lab = OpLabel\n" +
4081 "%n = OpVariable %_ptr_double Function\n" +
4082 "%3 = OpLoad %double %n\n" +
4083 "%2 = OpFMul %double %105 %3\n" +
4084 "OpReturn\n" +
4085 "OpFunctionEnd",
4086 2, DOUBLE_0_ID),
4087 // Test case 11: Fold 0.0 / n
4088 InstructionFoldingCase<uint32_t>(
4089 Header() + "%main = OpFunction %void None %void_func\n" +
4090 "%main_lab = OpLabel\n" +
4091 "%n = OpVariable %_ptr_double Function\n" +
4092 "%3 = OpLoad %double %n\n" +
4093 "%2 = OpFDiv %double %105 %3\n" +
4094 "OpReturn\n" +
4095 "OpFunctionEnd",
4096 2, DOUBLE_0_ID),
4097 // Test case 12: Don't fold mix(a, b, 2.0)
4098 InstructionFoldingCase<uint32_t>(
4099 Header() + "%main = OpFunction %void None %void_func\n" +
4100 "%main_lab = OpLabel\n" +
4101 "%a = OpVariable %_ptr_double Function\n" +
4102 "%b = OpVariable %_ptr_double Function\n" +
4103 "%3 = OpLoad %double %a\n" +
4104 "%4 = OpLoad %double %b\n" +
4105 "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
4106 "OpReturn\n" +
4107 "OpFunctionEnd",
4108 2, 0),
4109 // Test case 13: Fold mix(a, b, 0.0)
4110 InstructionFoldingCase<uint32_t>(
4111 Header() + "%main = OpFunction %void None %void_func\n" +
4112 "%main_lab = OpLabel\n" +
4113 "%a = OpVariable %_ptr_double Function\n" +
4114 "%b = OpVariable %_ptr_double Function\n" +
4115 "%3 = OpLoad %double %a\n" +
4116 "%4 = OpLoad %double %b\n" +
4117 "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
4118 "OpReturn\n" +
4119 "OpFunctionEnd",
4120 2, 3),
4121 // Test case 14: Fold mix(a, b, 1.0)
4122 InstructionFoldingCase<uint32_t>(
4123 Header() + "%main = OpFunction %void None %void_func\n" +
4124 "%main_lab = OpLabel\n" +
4125 "%a = OpVariable %_ptr_double Function\n" +
4126 "%b = OpVariable %_ptr_double Function\n" +
4127 "%3 = OpLoad %double %a\n" +
4128 "%4 = OpLoad %double %b\n" +
4129 "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
4130 "OpReturn\n" +
4131 "OpFunctionEnd",
4132 2, 4)
4133 ));
4134
4135 INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4136 ::testing::Values(
4137 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4138 InstructionFoldingCase<uint32_t>(
4139 Header() + "%main = OpFunction %void None %void_func\n" +
4140 "%main_lab = OpLabel\n" +
4141 "%n = OpVariable %_ptr_v4float Function\n" +
4142 "%3 = OpLoad %v4float %n\n" +
4143 "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
4144 "OpReturn\n" +
4145 "OpFunctionEnd",
4146 2, 0),
4147 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4148 InstructionFoldingCase<uint32_t>(
4149 Header() + "%main = OpFunction %void None %void_func\n" +
4150 "%main_lab = OpLabel\n" +
4151 "%n = OpVariable %_ptr_v4float Function\n" +
4152 "%3 = OpLoad %v4float %n\n" +
4153 "%2 = OpFMul %v4float %3 %106\n" +
4154 "OpReturn\n" +
4155 "OpFunctionEnd",
4156 2, VEC4_0_ID),
4157 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4158 InstructionFoldingCase<uint32_t>(
4159 Header() + "%main = OpFunction %void None %void_func\n" +
4160 "%main_lab = OpLabel\n" +
4161 "%n = OpVariable %_ptr_v4float Function\n" +
4162 "%3 = OpLoad %v4float %n\n" +
4163 "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
4164 "OpReturn\n" +
4165 "OpFunctionEnd",
4166 2, 3)
4167 ));
4168
4169 INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4170 ::testing::Values(
4171 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4172 InstructionFoldingCase<uint32_t>(
4173 Header() + "%main = OpFunction %void None %void_func\n" +
4174 "%main_lab = OpLabel\n" +
4175 "%n = OpVariable %_ptr_v4double Function\n" +
4176 "%3 = OpLoad %v4double %n\n" +
4177 "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
4178 "OpReturn\n" +
4179 "OpFunctionEnd",
4180 2, 0),
4181 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4182 InstructionFoldingCase<uint32_t>(
4183 Header() + "%main = OpFunction %void None %void_func\n" +
4184 "%main_lab = OpLabel\n" +
4185 "%n = OpVariable %_ptr_v4double Function\n" +
4186 "%3 = OpLoad %v4double %n\n" +
4187 "%2 = OpFMul %v4double %3 %106\n" +
4188 "OpReturn\n" +
4189 "OpFunctionEnd",
4190 2, DVEC4_0_ID),
4191 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4192 InstructionFoldingCase<uint32_t>(
4193 Header() + "%main = OpFunction %void None %void_func\n" +
4194 "%main_lab = OpLabel\n" +
4195 "%n = OpVariable %_ptr_v4double Function\n" +
4196 "%3 = OpLoad %v4double %n\n" +
4197 "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
4198 "OpReturn\n" +
4199 "OpFunctionEnd",
4200 2, 3)
4201 ));
4202
4203 INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
4204 ::testing::Values(
4205 // Test case 0: Don't fold n + 1
4206 InstructionFoldingCase<uint32_t>(
4207 Header() + "%main = OpFunction %void None %void_func\n" +
4208 "%main_lab = OpLabel\n" +
4209 "%n = OpVariable %_ptr_uint Function\n" +
4210 "%3 = OpLoad %uint %n\n" +
4211 "%2 = OpIAdd %uint %3 %uint_1\n" +
4212 "OpReturn\n" +
4213 "OpFunctionEnd",
4214 2, 0),
4215 // Test case 1: Don't fold 1 + n
4216 InstructionFoldingCase<uint32_t>(
4217 Header() + "%main = OpFunction %void None %void_func\n" +
4218 "%main_lab = OpLabel\n" +
4219 "%n = OpVariable %_ptr_uint Function\n" +
4220 "%3 = OpLoad %uint %n\n" +
4221 "%2 = OpIAdd %uint %uint_1 %3\n" +
4222 "OpReturn\n" +
4223 "OpFunctionEnd",
4224 2, 0),
4225 // Test case 2: Fold n + 0
4226 InstructionFoldingCase<uint32_t>(
4227 Header() + "%main = OpFunction %void None %void_func\n" +
4228 "%main_lab = OpLabel\n" +
4229 "%n = OpVariable %_ptr_uint Function\n" +
4230 "%3 = OpLoad %uint %n\n" +
4231 "%2 = OpIAdd %uint %3 %uint_0\n" +
4232 "OpReturn\n" +
4233 "OpFunctionEnd",
4234 2, 3),
4235 // Test case 3: Fold 0 + n
4236 InstructionFoldingCase<uint32_t>(
4237 Header() + "%main = OpFunction %void None %void_func\n" +
4238 "%main_lab = OpLabel\n" +
4239 "%n = OpVariable %_ptr_uint Function\n" +
4240 "%3 = OpLoad %uint %n\n" +
4241 "%2 = OpIAdd %uint %uint_0 %3\n" +
4242 "OpReturn\n" +
4243 "OpFunctionEnd",
4244 2, 3),
4245 // Test case 4: Don't fold n + (1,0)
4246 InstructionFoldingCase<uint32_t>(
4247 Header() + "%main = OpFunction %void None %void_func\n" +
4248 "%main_lab = OpLabel\n" +
4249 "%n = OpVariable %_ptr_v2int Function\n" +
4250 "%3 = OpLoad %v2int %n\n" +
4251 "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
4252 "OpReturn\n" +
4253 "OpFunctionEnd",
4254 2, 0),
4255 // Test case 5: Don't fold (1,0) + n
4256 InstructionFoldingCase<uint32_t>(
4257 Header() + "%main = OpFunction %void None %void_func\n" +
4258 "%main_lab = OpLabel\n" +
4259 "%n = OpVariable %_ptr_v2int Function\n" +
4260 "%3 = OpLoad %v2int %n\n" +
4261 "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
4262 "OpReturn\n" +
4263 "OpFunctionEnd",
4264 2, 0),
4265 // Test case 6: Fold n + (0,0)
4266 InstructionFoldingCase<uint32_t>(
4267 Header() + "%main = OpFunction %void None %void_func\n" +
4268 "%main_lab = OpLabel\n" +
4269 "%n = OpVariable %_ptr_v2int Function\n" +
4270 "%3 = OpLoad %v2int %n\n" +
4271 "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
4272 "OpReturn\n" +
4273 "OpFunctionEnd",
4274 2, 3),
4275 // Test case 7: Fold (0,0) + n
4276 InstructionFoldingCase<uint32_t>(
4277 Header() + "%main = OpFunction %void None %void_func\n" +
4278 "%main_lab = OpLabel\n" +
4279 "%n = OpVariable %_ptr_v2int Function\n" +
4280 "%3 = OpLoad %v2int %n\n" +
4281 "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
4282 "OpReturn\n" +
4283 "OpFunctionEnd",
4284 2, 3)
4285 ));
4286
4287 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
4288 ::testing::Values(
4289 // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
4290 InstructionFoldingCase<uint32_t>(
4291 Header() + "%main = OpFunction %void None %void_func\n" +
4292 "%main_lab = OpLabel\n" +
4293 "%n = OpVariable %_ptr_float Function\n" +
4294 "%ld = OpLoad %float %n\n" +
4295 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4296 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4297 "OpReturn\n" +
4298 "OpFunctionEnd",
4299 2, 0),
4300 // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
4301 InstructionFoldingCase<uint32_t>(
4302 Header() + "%main = OpFunction %void None %void_func\n" +
4303 "%main_lab = OpLabel\n" +
4304 "%n = OpVariable %_ptr_float Function\n" +
4305 "%ld = OpLoad %float %n\n" +
4306 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4307 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4308 "OpReturn\n" +
4309 "OpFunctionEnd",
4310 2, 0),
4311 // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
4312 InstructionFoldingCase<uint32_t>(
4313 Header() + "%main = OpFunction %void None %void_func\n" +
4314 "%main_lab = OpLabel\n" +
4315 "%n = OpVariable %_ptr_float Function\n" +
4316 "%ld = OpLoad %float %n\n" +
4317 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4318 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
4319 "OpReturn\n" +
4320 "OpFunctionEnd",
4321 2, 0),
4322 // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
4323 InstructionFoldingCase<uint32_t>(
4324 Header() + "%main = OpFunction %void None %void_func\n" +
4325 "%main_lab = OpLabel\n" +
4326 "%n = OpVariable %_ptr_float Function\n" +
4327 "%ld = OpLoad %float %n\n" +
4328 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4329 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
4330 "OpReturn\n" +
4331 "OpFunctionEnd",
4332 2, 0),
4333 // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
4334 InstructionFoldingCase<uint32_t>(
4335 Header() + "%main = OpFunction %void None %void_func\n" +
4336 "%main_lab = OpLabel\n" +
4337 "%n = OpVariable %_ptr_float Function\n" +
4338 "%ld = OpLoad %float %n\n" +
4339 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4340 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4341 "OpReturn\n" +
4342 "OpFunctionEnd",
4343 2, 0),
4344 // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
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 "%ld = OpLoad %float %n\n" +
4350 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4351 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4352 "OpReturn\n" +
4353 "OpFunctionEnd",
4354 2, 0),
4355 // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
4356 InstructionFoldingCase<uint32_t>(
4357 Header() + "%main = OpFunction %void None %void_func\n" +
4358 "%main_lab = OpLabel\n" +
4359 "%n = OpVariable %_ptr_float Function\n" +
4360 "%ld = OpLoad %float %n\n" +
4361 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4362 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
4363 "OpReturn\n" +
4364 "OpFunctionEnd",
4365 2, 0),
4366 // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
4367 InstructionFoldingCase<uint32_t>(
4368 Header() + "%main = OpFunction %void None %void_func\n" +
4369 "%main_lab = OpLabel\n" +
4370 "%n = OpVariable %_ptr_float Function\n" +
4371 "%ld = OpLoad %float %n\n" +
4372 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4373 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
4374 "OpReturn\n" +
4375 "OpFunctionEnd",
4376 2, 0),
4377 // Test case 8: Don't Fold 0.0 < clamp(0, 1)
4378 InstructionFoldingCase<uint32_t>(
4379 Header() + "%main = OpFunction %void None %void_func\n" +
4380 "%main_lab = OpLabel\n" +
4381 "%n = OpVariable %_ptr_float Function\n" +
4382 "%ld = OpLoad %float %n\n" +
4383 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4384 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4385 "OpReturn\n" +
4386 "OpFunctionEnd",
4387 2, 0),
4388 // Test case 9: Don't Fold 0.0 < clamp(0, 1)
4389 InstructionFoldingCase<uint32_t>(
4390 Header() + "%main = OpFunction %void None %void_func\n" +
4391 "%main_lab = OpLabel\n" +
4392 "%n = OpVariable %_ptr_float Function\n" +
4393 "%ld = OpLoad %float %n\n" +
4394 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4395 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4396 "OpReturn\n" +
4397 "OpFunctionEnd",
4398 2, 0),
4399 // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
4400 InstructionFoldingCase<uint32_t>(
4401 Header() + "%main = OpFunction %void None %void_func\n" +
4402 "%main_lab = OpLabel\n" +
4403 "%n = OpVariable %_ptr_float Function\n" +
4404 "%ld = OpLoad %float %n\n" +
4405 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4406 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4407 "OpReturn\n" +
4408 "OpFunctionEnd",
4409 2, 0),
4410 // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
4411 InstructionFoldingCase<uint32_t>(
4412 Header() + "%main = OpFunction %void None %void_func\n" +
4413 "%main_lab = OpLabel\n" +
4414 "%n = OpVariable %_ptr_float Function\n" +
4415 "%ld = OpLoad %float %n\n" +
4416 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4417 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4418 "OpReturn\n" +
4419 "OpFunctionEnd",
4420 2, 0)
4421 ));
4422
4423 INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
4424 ::testing::Values(
4425 // Test case 0: Don't Fold clamp(-1, 1) < 0.0
4426 InstructionFoldingCase<uint32_t>(
4427 Header() + "%main = OpFunction %void None %void_func\n" +
4428 "%main_lab = OpLabel\n" +
4429 "%n = OpVariable %_ptr_float Function\n" +
4430 "%ld = OpLoad %float %n\n" +
4431 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4432 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4433 "OpReturn\n" +
4434 "OpFunctionEnd",
4435 2, 0),
4436 // Test case 1: Don't Fold clamp(-1, 1) < 0.0
4437 InstructionFoldingCase<uint32_t>(
4438 Header() + "%main = OpFunction %void None %void_func\n" +
4439 "%main_lab = OpLabel\n" +
4440 "%n = OpVariable %_ptr_float Function\n" +
4441 "%ld = OpLoad %float %n\n" +
4442 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4443 "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
4444 "OpReturn\n" +
4445 "OpFunctionEnd",
4446 2, 0),
4447 // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
4448 InstructionFoldingCase<uint32_t>(
4449 Header() + "%main = OpFunction %void None %void_func\n" +
4450 "%main_lab = OpLabel\n" +
4451 "%n = OpVariable %_ptr_float Function\n" +
4452 "%ld = OpLoad %float %n\n" +
4453 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4454 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
4455 "OpReturn\n" +
4456 "OpFunctionEnd",
4457 2, 0),
4458 // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
4459 InstructionFoldingCase<uint32_t>(
4460 Header() + "%main = OpFunction %void None %void_func\n" +
4461 "%main_lab = OpLabel\n" +
4462 "%n = OpVariable %_ptr_float Function\n" +
4463 "%ld = OpLoad %float %n\n" +
4464 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4465 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
4466 "OpReturn\n" +
4467 "OpFunctionEnd",
4468 2, 0),
4469 // Test case 4: Don't Fold clamp(-1, 1) > 0.0
4470 InstructionFoldingCase<uint32_t>(
4471 Header() + "%main = OpFunction %void None %void_func\n" +
4472 "%main_lab = OpLabel\n" +
4473 "%n = OpVariable %_ptr_float Function\n" +
4474 "%ld = OpLoad %float %n\n" +
4475 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4476 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
4477 "OpReturn\n" +
4478 "OpFunctionEnd",
4479 2, 0),
4480 // Test case 5: Don't Fold clamp(-1, 1) > 0.0
4481 InstructionFoldingCase<uint32_t>(
4482 Header() + "%main = OpFunction %void None %void_func\n" +
4483 "%main_lab = OpLabel\n" +
4484 "%n = OpVariable %_ptr_float Function\n" +
4485 "%ld = OpLoad %float %n\n" +
4486 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4487 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
4488 "OpReturn\n" +
4489 "OpFunctionEnd",
4490 2, 0),
4491 // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
4492 InstructionFoldingCase<uint32_t>(
4493 Header() + "%main = OpFunction %void None %void_func\n" +
4494 "%main_lab = OpLabel\n" +
4495 "%n = OpVariable %_ptr_float Function\n" +
4496 "%ld = OpLoad %float %n\n" +
4497 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4498 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
4499 "OpReturn\n" +
4500 "OpFunctionEnd",
4501 2, 0),
4502 // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
4503 InstructionFoldingCase<uint32_t>(
4504 Header() + "%main = OpFunction %void None %void_func\n" +
4505 "%main_lab = OpLabel\n" +
4506 "%n = OpVariable %_ptr_float Function\n" +
4507 "%ld = OpLoad %float %n\n" +
4508 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4509 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
4510 "OpReturn\n" +
4511 "OpFunctionEnd",
4512 2, 0),
4513 // Test case 8: Don't Fold clamp(-1, 0) < 0.0
4514 InstructionFoldingCase<uint32_t>(
4515 Header() + "%main = OpFunction %void None %void_func\n" +
4516 "%main_lab = OpLabel\n" +
4517 "%n = OpVariable %_ptr_float Function\n" +
4518 "%ld = OpLoad %float %n\n" +
4519 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4520 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4521 "OpReturn\n" +
4522 "OpFunctionEnd",
4523 2, 0),
4524 // Test case 9: Don't Fold clamp(0, 1) < 1
4525 InstructionFoldingCase<uint32_t>(
4526 Header() + "%main = OpFunction %void None %void_func\n" +
4527 "%main_lab = OpLabel\n" +
4528 "%n = OpVariable %_ptr_float Function\n" +
4529 "%ld = OpLoad %float %n\n" +
4530 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4531 "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
4532 "OpReturn\n" +
4533 "OpFunctionEnd",
4534 2, 0),
4535 // Test case 10: Don't Fold clamp(-1, 0) > -1
4536 InstructionFoldingCase<uint32_t>(
4537 Header() + "%main = OpFunction %void None %void_func\n" +
4538 "%main_lab = OpLabel\n" +
4539 "%n = OpVariable %_ptr_float Function\n" +
4540 "%ld = OpLoad %float %n\n" +
4541 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4542 "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
4543 "OpReturn\n" +
4544 "OpFunctionEnd",
4545 2, 0),
4546 // Test case 11: Don't Fold clamp(-1, 0) > -1
4547 InstructionFoldingCase<uint32_t>(
4548 Header() + "%main = OpFunction %void None %void_func\n" +
4549 "%main_lab = OpLabel\n" +
4550 "%n = OpVariable %_ptr_float Function\n" +
4551 "%ld = OpLoad %float %n\n" +
4552 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4553 "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
4554 "OpReturn\n" +
4555 "OpFunctionEnd",
4556 2, 0)
4557 ));
4558
4559 INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
4560 ::testing::Values(
4561 // Test case 0: Fold int(3.0)
4562 InstructionFoldingCase<uint32_t>(
4563 Header() + "%main = OpFunction %void None %void_func\n" +
4564 "%main_lab = OpLabel\n" +
4565 "%2 = OpConvertFToS %int %float_3\n" +
4566 "OpReturn\n" +
4567 "OpFunctionEnd",
4568 2, 3),
4569 // Test case 1: Fold uint(3.0)
4570 InstructionFoldingCase<uint32_t>(
4571 Header() + "%main = OpFunction %void None %void_func\n" +
4572 "%main_lab = OpLabel\n" +
4573 "%2 = OpConvertFToU %int %float_3\n" +
4574 "OpReturn\n" +
4575 "OpFunctionEnd",
4576 2, 3)
4577 ));
4578
4579 INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
4580 ::testing::Values(
4581 // Test case 0: Fold float(3)
4582 InstructionFoldingCase<float>(
4583 Header() + "%main = OpFunction %void None %void_func\n" +
4584 "%main_lab = OpLabel\n" +
4585 "%2 = OpConvertSToF %float %int_3\n" +
4586 "OpReturn\n" +
4587 "OpFunctionEnd",
4588 2, 3.0),
4589 // Test case 1: Fold float(3u)
4590 InstructionFoldingCase<float>(
4591 Header() + "%main = OpFunction %void None %void_func\n" +
4592 "%main_lab = OpLabel\n" +
4593 "%2 = OpConvertUToF %float %uint_3\n" +
4594 "OpReturn\n" +
4595 "OpFunctionEnd",
4596 2, 3.0)
4597 ));
4598 // clang-format on
4599
4600 using ToNegateFoldingTest =
4601 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
4602
TEST_P(ToNegateFoldingTest,Case)4603 TEST_P(ToNegateFoldingTest, Case) {
4604 const auto& tc = GetParam();
4605
4606 // Build module.
4607 std::unique_ptr<IRContext> context =
4608 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
4609 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4610 ASSERT_NE(nullptr, context);
4611
4612 // Fold the instruction to test.
4613 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
4614 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
4615 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
4616 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
4617
4618 // Make sure the instruction folded as expected.
4619 EXPECT_EQ(inst->result_id(), original_inst->result_id());
4620 EXPECT_EQ(inst->type_id(), original_inst->type_id());
4621 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
4622 if (succeeded) {
4623 EXPECT_EQ(inst->opcode(), SpvOpFNegate);
4624 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
4625 } else {
4626 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
4627 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
4628 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
4629 }
4630 }
4631 }
4632
4633 // clang-format off
4634 INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
4635 ::testing::Values(
4636 // Test case 0: Don't fold 1.0 - n
4637 InstructionFoldingCase<uint32_t>(
4638 Header() + "%main = OpFunction %void None %void_func\n" +
4639 "%main_lab = OpLabel\n" +
4640 "%n = OpVariable %_ptr_float Function\n" +
4641 "%3 = OpLoad %float %n\n" +
4642 "%2 = OpFSub %float %float_1 %3\n" +
4643 "OpReturn\n" +
4644 "OpFunctionEnd",
4645 2, 0),
4646 // Test case 1: Fold 0.0 - n
4647 InstructionFoldingCase<uint32_t>(
4648 Header() + "%main = OpFunction %void None %void_func\n" +
4649 "%main_lab = OpLabel\n" +
4650 "%n = OpVariable %_ptr_float Function\n" +
4651 "%3 = OpLoad %float %n\n" +
4652 "%2 = OpFSub %float %float_0 %3\n" +
4653 "OpReturn\n" +
4654 "OpFunctionEnd",
4655 2, 3),
4656 // Test case 2: Don't fold (0,0,0,1) - n
4657 InstructionFoldingCase<uint32_t>(
4658 Header() + "%main = OpFunction %void None %void_func\n" +
4659 "%main_lab = OpLabel\n" +
4660 "%n = OpVariable %_ptr_v4float Function\n" +
4661 "%3 = OpLoad %v4float %n\n" +
4662 "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
4663 "OpReturn\n" +
4664 "OpFunctionEnd",
4665 2, 0),
4666 // Test case 3: Fold (0,0,0,0) - n
4667 InstructionFoldingCase<uint32_t>(
4668 Header() + "%main = OpFunction %void None %void_func\n" +
4669 "%main_lab = OpLabel\n" +
4670 "%n = OpVariable %_ptr_v4float Function\n" +
4671 "%3 = OpLoad %v4float %n\n" +
4672 "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
4673 "OpReturn\n" +
4674 "OpFunctionEnd",
4675 2, 3)
4676 ));
4677
4678 INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
4679 ::testing::Values(
4680 // Test case 0: Don't fold 1.0 - n
4681 InstructionFoldingCase<uint32_t>(
4682 Header() + "%main = OpFunction %void None %void_func\n" +
4683 "%main_lab = OpLabel\n" +
4684 "%n = OpVariable %_ptr_double Function\n" +
4685 "%3 = OpLoad %double %n\n" +
4686 "%2 = OpFSub %double %double_1 %3\n" +
4687 "OpReturn\n" +
4688 "OpFunctionEnd",
4689 2, 0),
4690 // Test case 1: Fold 0.0 - n
4691 InstructionFoldingCase<uint32_t>(
4692 Header() + "%main = OpFunction %void None %void_func\n" +
4693 "%main_lab = OpLabel\n" +
4694 "%n = OpVariable %_ptr_double Function\n" +
4695 "%3 = OpLoad %double %n\n" +
4696 "%2 = OpFSub %double %double_0 %3\n" +
4697 "OpReturn\n" +
4698 "OpFunctionEnd",
4699 2, 3),
4700 // Test case 2: Don't fold (0,0,0,1) - n
4701 InstructionFoldingCase<uint32_t>(
4702 Header() + "%main = OpFunction %void None %void_func\n" +
4703 "%main_lab = OpLabel\n" +
4704 "%n = OpVariable %_ptr_v4double Function\n" +
4705 "%3 = OpLoad %v4double %n\n" +
4706 "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
4707 "OpReturn\n" +
4708 "OpFunctionEnd",
4709 2, 0),
4710 // Test case 3: Fold (0,0,0,0) - n
4711 InstructionFoldingCase<uint32_t>(
4712 Header() + "%main = OpFunction %void None %void_func\n" +
4713 "%main_lab = OpLabel\n" +
4714 "%n = OpVariable %_ptr_v4double Function\n" +
4715 "%3 = OpLoad %v4double %n\n" +
4716 "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
4717 "OpReturn\n" +
4718 "OpFunctionEnd",
4719 2, 3)
4720 ));
4721
4722 using MatchingInstructionFoldingTest =
4723 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
4724
TEST_P(MatchingInstructionFoldingTest,Case)4725 TEST_P(MatchingInstructionFoldingTest, Case) {
4726 const auto& tc = GetParam();
4727
4728 // Build module.
4729 std::unique_ptr<IRContext> context =
4730 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
4731 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4732 ASSERT_NE(nullptr, context);
4733
4734 // Fold the instruction to test.
4735 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
4736 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
4737 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
4738 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
4739 EXPECT_EQ(succeeded, tc.expected_result);
4740 if (succeeded) {
4741 Match(tc.test_body, context.get());
4742 }
4743 }
4744
4745 INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
4746 ::testing::Values(
4747 // Test case 0: Fold 0 + n (change sign)
4748 InstructionFoldingCase<bool>(
4749 Header() +
4750 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
4751 "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
4752 "%main = OpFunction %void None %void_func\n" +
4753 "%main_lab = OpLabel\n" +
4754 "%n = OpVariable %_ptr_int Function\n" +
4755 "%3 = OpLoad %uint %n\n" +
4756 "%2 = OpIAdd %uint %int_0 %3\n" +
4757 "OpReturn\n" +
4758 "OpFunctionEnd\n",
4759 2, true),
4760 // Test case 0: Fold 0 + n (change sign)
4761 InstructionFoldingCase<bool>(
4762 Header() +
4763 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4764 "; CHECK: %2 = OpBitcast [[int]] %3\n" +
4765 "%main = OpFunction %void None %void_func\n" +
4766 "%main_lab = OpLabel\n" +
4767 "%n = OpVariable %_ptr_int Function\n" +
4768 "%3 = OpLoad %int %n\n" +
4769 "%2 = OpIAdd %int %uint_0 %3\n" +
4770 "OpReturn\n" +
4771 "OpFunctionEnd\n",
4772 2, true)
4773 ));
4774
4775 INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest,
4776 ::testing::Values(
4777 // Test case 0: fold consecutive fnegate
4778 // -(-x) = x
4779 InstructionFoldingCase<bool>(
4780 Header() +
4781 "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
4782 "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
4783 "%main = OpFunction %void None %void_func\n" +
4784 "%main_lab = OpLabel\n" +
4785 "%var = OpVariable %_ptr_float Function\n" +
4786 "%2 = OpLoad %float %var\n" +
4787 "%3 = OpFNegate %float %2\n" +
4788 "%4 = OpFNegate %float %3\n" +
4789 "OpReturn\n" +
4790 "OpFunctionEnd",
4791 4, true),
4792 // Test case 1: fold fnegate(fmul with const).
4793 // -(x * 2.0) = x * -2.0
4794 InstructionFoldingCase<bool>(
4795 Header() +
4796 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4797 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
4798 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4799 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
4800 "%main = OpFunction %void None %void_func\n" +
4801 "%main_lab = OpLabel\n" +
4802 "%var = OpVariable %_ptr_float Function\n" +
4803 "%2 = OpLoad %float %var\n" +
4804 "%3 = OpFMul %float %2 %float_2\n" +
4805 "%4 = OpFNegate %float %3\n" +
4806 "OpReturn\n" +
4807 "OpFunctionEnd",
4808 4, true),
4809 // Test case 2: fold fnegate(fmul with const).
4810 // -(2.0 * x) = x * 2.0
4811 InstructionFoldingCase<bool>(
4812 Header() +
4813 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4814 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
4815 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4816 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
4817 "%main = OpFunction %void None %void_func\n" +
4818 "%main_lab = OpLabel\n" +
4819 "%var = OpVariable %_ptr_float Function\n" +
4820 "%2 = OpLoad %float %var\n" +
4821 "%3 = OpFMul %float %float_2 %2\n" +
4822 "%4 = OpFNegate %float %3\n" +
4823 "OpReturn\n" +
4824 "OpFunctionEnd",
4825 4, true),
4826 // Test case 3: fold fnegate(fdiv with const).
4827 // -(x / 2.0) = x * -0.5
4828 InstructionFoldingCase<bool>(
4829 Header() +
4830 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4831 "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
4832 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4833 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
4834 "%main = OpFunction %void None %void_func\n" +
4835 "%main_lab = OpLabel\n" +
4836 "%var = OpVariable %_ptr_float Function\n" +
4837 "%2 = OpLoad %float %var\n" +
4838 "%3 = OpFDiv %float %2 %float_2\n" +
4839 "%4 = OpFNegate %float %3\n" +
4840 "OpReturn\n" +
4841 "OpFunctionEnd",
4842 4, true),
4843 // Test case 4: fold fnegate(fdiv with const).
4844 // -(2.0 / x) = -2.0 / x
4845 InstructionFoldingCase<bool>(
4846 Header() +
4847 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4848 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
4849 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4850 "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
4851 "%main = OpFunction %void None %void_func\n" +
4852 "%main_lab = OpLabel\n" +
4853 "%var = OpVariable %_ptr_float Function\n" +
4854 "%2 = OpLoad %float %var\n" +
4855 "%3 = OpFDiv %float %float_2 %2\n" +
4856 "%4 = OpFNegate %float %3\n" +
4857 "OpReturn\n" +
4858 "OpFunctionEnd",
4859 4, true),
4860 // Test case 5: fold fnegate(fadd with const).
4861 // -(2.0 + x) = -2.0 - x
4862 InstructionFoldingCase<bool>(
4863 Header() +
4864 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4865 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
4866 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4867 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
4868 "%main = OpFunction %void None %void_func\n" +
4869 "%main_lab = OpLabel\n" +
4870 "%var = OpVariable %_ptr_float Function\n" +
4871 "%2 = OpLoad %float %var\n" +
4872 "%3 = OpFAdd %float %float_2 %2\n" +
4873 "%4 = OpFNegate %float %3\n" +
4874 "OpReturn\n" +
4875 "OpFunctionEnd",
4876 4, true),
4877 // Test case 6: fold fnegate(fadd with const).
4878 // -(x + 2.0) = -2.0 - x
4879 InstructionFoldingCase<bool>(
4880 Header() +
4881 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4882 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
4883 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4884 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
4885 "%main = OpFunction %void None %void_func\n" +
4886 "%main_lab = OpLabel\n" +
4887 "%var = OpVariable %_ptr_float Function\n" +
4888 "%2 = OpLoad %float %var\n" +
4889 "%3 = OpFAdd %float %2 %float_2\n" +
4890 "%4 = OpFNegate %float %3\n" +
4891 "OpReturn\n" +
4892 "OpFunctionEnd",
4893 4, true),
4894 // Test case 7: fold fnegate(fsub with const).
4895 // -(2.0 - x) = x - 2.0
4896 InstructionFoldingCase<bool>(
4897 Header() +
4898 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4899 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4900 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4901 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
4902 "%main = OpFunction %void None %void_func\n" +
4903 "%main_lab = OpLabel\n" +
4904 "%var = OpVariable %_ptr_float Function\n" +
4905 "%2 = OpLoad %float %var\n" +
4906 "%3 = OpFSub %float %float_2 %2\n" +
4907 "%4 = OpFNegate %float %3\n" +
4908 "OpReturn\n" +
4909 "OpFunctionEnd",
4910 4, true),
4911 // Test case 8: fold fnegate(fsub with const).
4912 // -(x - 2.0) = 2.0 - x
4913 InstructionFoldingCase<bool>(
4914 Header() +
4915 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
4916 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
4917 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
4918 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
4919 "%main = OpFunction %void None %void_func\n" +
4920 "%main_lab = OpLabel\n" +
4921 "%var = OpVariable %_ptr_float Function\n" +
4922 "%2 = OpLoad %float %var\n" +
4923 "%3 = OpFSub %float %2 %float_2\n" +
4924 "%4 = OpFNegate %float %3\n" +
4925 "OpReturn\n" +
4926 "OpFunctionEnd",
4927 4, true),
4928 // Test case 9: fold consecutive snegate
4929 // -(-x) = x
4930 InstructionFoldingCase<bool>(
4931 Header() +
4932 "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
4933 "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
4934 "%main = OpFunction %void None %void_func\n" +
4935 "%main_lab = OpLabel\n" +
4936 "%var = OpVariable %_ptr_int Function\n" +
4937 "%2 = OpLoad %int %var\n" +
4938 "%3 = OpSNegate %int %2\n" +
4939 "%4 = OpSNegate %int %3\n" +
4940 "OpReturn\n" +
4941 "OpFunctionEnd",
4942 4, true),
4943 // Test case 10: fold consecutive vector negate
4944 // -(-x) = x
4945 InstructionFoldingCase<bool>(
4946 Header() +
4947 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
4948 "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
4949 "%main = OpFunction %void None %void_func\n" +
4950 "%main_lab = OpLabel\n" +
4951 "%var = OpVariable %_ptr_v2float Function\n" +
4952 "%2 = OpLoad %v2float %var\n" +
4953 "%3 = OpFNegate %v2float %2\n" +
4954 "%4 = OpFNegate %v2float %3\n" +
4955 "OpReturn\n" +
4956 "OpFunctionEnd",
4957 4, true),
4958 // Test case 11: fold snegate(iadd with const).
4959 // -(2 + x) = -2 - x
4960 InstructionFoldingCase<bool>(
4961 Header() +
4962 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4963 "; CHECK: OpConstant [[int]] -2147483648\n" +
4964 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
4965 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4966 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
4967 "%main = OpFunction %void None %void_func\n" +
4968 "%main_lab = OpLabel\n" +
4969 "%var = OpVariable %_ptr_int Function\n" +
4970 "%2 = OpLoad %int %var\n" +
4971 "%3 = OpIAdd %int %int_2 %2\n" +
4972 "%4 = OpSNegate %int %3\n" +
4973 "OpReturn\n" +
4974 "OpFunctionEnd",
4975 4, true),
4976 // Test case 12: fold snegate(iadd with const).
4977 // -(x + 2) = -2 - x
4978 InstructionFoldingCase<bool>(
4979 Header() +
4980 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4981 "; CHECK: OpConstant [[int]] -2147483648\n" +
4982 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
4983 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
4984 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
4985 "%main = OpFunction %void None %void_func\n" +
4986 "%main_lab = OpLabel\n" +
4987 "%var = OpVariable %_ptr_int Function\n" +
4988 "%2 = OpLoad %int %var\n" +
4989 "%3 = OpIAdd %int %2 %int_2\n" +
4990 "%4 = OpSNegate %int %3\n" +
4991 "OpReturn\n" +
4992 "OpFunctionEnd",
4993 4, true),
4994 // Test case 13: fold snegate(isub with const).
4995 // -(2 - x) = x - 2
4996 InstructionFoldingCase<bool>(
4997 Header() +
4998 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
4999 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5000 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5001 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
5002 "%main = OpFunction %void None %void_func\n" +
5003 "%main_lab = OpLabel\n" +
5004 "%var = OpVariable %_ptr_int Function\n" +
5005 "%2 = OpLoad %int %var\n" +
5006 "%3 = OpISub %int %int_2 %2\n" +
5007 "%4 = OpSNegate %int %3\n" +
5008 "OpReturn\n" +
5009 "OpFunctionEnd",
5010 4, true),
5011 // Test case 14: fold snegate(isub with const).
5012 // -(x - 2) = 2 - x
5013 InstructionFoldingCase<bool>(
5014 Header() +
5015 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5016 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5017 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5018 "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
5019 "%main = OpFunction %void None %void_func\n" +
5020 "%main_lab = OpLabel\n" +
5021 "%var = OpVariable %_ptr_int Function\n" +
5022 "%2 = OpLoad %int %var\n" +
5023 "%3 = OpISub %int %2 %int_2\n" +
5024 "%4 = OpSNegate %int %3\n" +
5025 "OpReturn\n" +
5026 "OpFunctionEnd",
5027 4, true),
5028 // Test case 15: fold snegate(iadd with const).
5029 // -(x + 2) = -2 - x
5030 InstructionFoldingCase<bool>(
5031 Header() +
5032 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5033 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
5034 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5035 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5036 "%main = OpFunction %void None %void_func\n" +
5037 "%main_lab = OpLabel\n" +
5038 "%var = OpVariable %_ptr_long Function\n" +
5039 "%2 = OpLoad %long %var\n" +
5040 "%3 = OpIAdd %long %2 %long_2\n" +
5041 "%4 = OpSNegate %long %3\n" +
5042 "OpReturn\n" +
5043 "OpFunctionEnd",
5044 4, true),
5045 // Test case 16: fold snegate(isub with const).
5046 // -(2 - x) = x - 2
5047 InstructionFoldingCase<bool>(
5048 Header() +
5049 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5050 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5051 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5052 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
5053 "%main = OpFunction %void None %void_func\n" +
5054 "%main_lab = OpLabel\n" +
5055 "%var = OpVariable %_ptr_long Function\n" +
5056 "%2 = OpLoad %long %var\n" +
5057 "%3 = OpISub %long %long_2 %2\n" +
5058 "%4 = OpSNegate %long %3\n" +
5059 "OpReturn\n" +
5060 "OpFunctionEnd",
5061 4, true),
5062 // Test case 17: fold snegate(isub with const).
5063 // -(x - 2) = 2 - x
5064 InstructionFoldingCase<bool>(
5065 Header() +
5066 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5067 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5068 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5069 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5070 "%main = OpFunction %void None %void_func\n" +
5071 "%main_lab = OpLabel\n" +
5072 "%var = OpVariable %_ptr_long Function\n" +
5073 "%2 = OpLoad %long %var\n" +
5074 "%3 = OpISub %long %2 %long_2\n" +
5075 "%4 = OpSNegate %long %3\n" +
5076 "OpReturn\n" +
5077 "OpFunctionEnd",
5078 4, true),
5079 // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
5080 InstructionFoldingCase<bool>(
5081 Header() +
5082 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5083 "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" +
5084 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" +
5085 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" +
5086 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5087 "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" +
5088 "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
5089 "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
5090 "%main = OpFunction %void None %void_func\n" +
5091 "%main_lab = OpLabel\n" +
5092 "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
5093 "OpReturn\n" +
5094 "OpFunctionEnd",
5095 2, true),
5096 // Test case 19: fold vector fnegate with null
5097 InstructionFoldingCase<bool>(
5098 Header() +
5099 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5100 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5101 "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
5102 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
5103 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5104 "%main = OpFunction %void None %void_func\n" +
5105 "%main_lab = OpLabel\n" +
5106 "%2 = OpFNegate %v2double %v2double_null\n" +
5107 "OpReturn\n" +
5108 "OpFunctionEnd",
5109 2, true)
5110 ));
5111
5112 INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
5113 ::testing::Values(
5114 // Test case 0: scalar reicprocal
5115 // x / 0.5 = x * 2.0
5116 InstructionFoldingCase<bool>(
5117 Header() +
5118 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5119 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5120 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5121 "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
5122 "%main = OpFunction %void None %void_func\n" +
5123 "%main_lab = OpLabel\n" +
5124 "%var = OpVariable %_ptr_float Function\n" +
5125 "%2 = OpLoad %float %var\n" +
5126 "%3 = OpFDiv %float %2 %float_0p5\n" +
5127 "OpReturn\n" +
5128 "OpFunctionEnd\n",
5129 3, true),
5130 // Test case 1: Unfoldable
5131 InstructionFoldingCase<bool>(
5132 Header() +
5133 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5134 "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
5135 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5136 "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
5137 "%main = OpFunction %void None %void_func\n" +
5138 "%main_lab = OpLabel\n" +
5139 "%var = OpVariable %_ptr_float Function\n" +
5140 "%2 = OpLoad %float %var\n" +
5141 "%3 = OpFDiv %float %2 %104\n" +
5142 "OpReturn\n" +
5143 "OpFunctionEnd\n",
5144 3, false),
5145 // Test case 2: Vector reciprocal
5146 // x / {2.0, 0.5} = x * {0.5, 2.0}
5147 InstructionFoldingCase<bool>(
5148 Header() +
5149 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5150 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5151 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5152 "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
5153 "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
5154 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5155 "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
5156 "%main = OpFunction %void None %void_func\n" +
5157 "%main_lab = OpLabel\n" +
5158 "%var = OpVariable %_ptr_v2float Function\n" +
5159 "%2 = OpLoad %v2float %var\n" +
5160 "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
5161 "OpReturn\n" +
5162 "OpFunctionEnd\n",
5163 3, true),
5164 // Test case 3: double reciprocal
5165 // x / 2.0 = x * 0.5
5166 InstructionFoldingCase<bool>(
5167 Header() +
5168 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5169 "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
5170 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5171 "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
5172 "%main = OpFunction %void None %void_func\n" +
5173 "%main_lab = OpLabel\n" +
5174 "%var = OpVariable %_ptr_double Function\n" +
5175 "%2 = OpLoad %double %var\n" +
5176 "%3 = OpFDiv %double %2 %double_2\n" +
5177 "OpReturn\n" +
5178 "OpFunctionEnd\n",
5179 3, true),
5180 // Test case 4: don't fold x / 0.
5181 InstructionFoldingCase<bool>(
5182 Header() +
5183 "%main = OpFunction %void None %void_func\n" +
5184 "%main_lab = OpLabel\n" +
5185 "%var = OpVariable %_ptr_v2float Function\n" +
5186 "%2 = OpLoad %v2float %var\n" +
5187 "%3 = OpFDiv %v2float %2 %v2float_null\n" +
5188 "OpReturn\n" +
5189 "OpFunctionEnd\n",
5190 3, false)
5191 ));
5192
5193 INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest,
5194 ::testing::Values(
5195 // Test case 0: fold consecutive fmuls
5196 // (x * 3.0) * 2.0 = x * 6.0
5197 InstructionFoldingCase<bool>(
5198 Header() +
5199 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5200 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5201 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5202 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5203 "%main = OpFunction %void None %void_func\n" +
5204 "%main_lab = OpLabel\n" +
5205 "%var = OpVariable %_ptr_float Function\n" +
5206 "%2 = OpLoad %float %var\n" +
5207 "%3 = OpFMul %float %2 %float_3\n" +
5208 "%4 = OpFMul %float %3 %float_2\n" +
5209 "OpReturn\n" +
5210 "OpFunctionEnd\n",
5211 4, true),
5212 // Test case 1: fold consecutive fmuls
5213 // 2.0 * (x * 3.0) = x * 6.0
5214 InstructionFoldingCase<bool>(
5215 Header() +
5216 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5217 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5218 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5219 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5220 "%main = OpFunction %void None %void_func\n" +
5221 "%main_lab = OpLabel\n" +
5222 "%var = OpVariable %_ptr_float Function\n" +
5223 "%2 = OpLoad %float %var\n" +
5224 "%3 = OpFMul %float %2 %float_3\n" +
5225 "%4 = OpFMul %float %float_2 %3\n" +
5226 "OpReturn\n" +
5227 "OpFunctionEnd\n",
5228 4, true),
5229 // Test case 2: fold consecutive fmuls
5230 // (3.0 * x) * 2.0 = x * 6.0
5231 InstructionFoldingCase<bool>(
5232 Header() +
5233 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5234 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5235 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5236 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5237 "%main = OpFunction %void None %void_func\n" +
5238 "%main_lab = OpLabel\n" +
5239 "%var = OpVariable %_ptr_float Function\n" +
5240 "%2 = OpLoad %float %var\n" +
5241 "%3 = OpFMul %float %float_3 %2\n" +
5242 "%4 = OpFMul %float %float_2 %3\n" +
5243 "OpReturn\n" +
5244 "OpFunctionEnd\n",
5245 4, true),
5246 // Test case 3: fold vector fmul
5247 InstructionFoldingCase<bool>(
5248 Header() +
5249 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5250 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5251 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5252 "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
5253 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5254 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
5255 "%main = OpFunction %void None %void_func\n" +
5256 "%main_lab = OpLabel\n" +
5257 "%var = OpVariable %_ptr_v2float Function\n" +
5258 "%2 = OpLoad %v2float %var\n" +
5259 "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
5260 "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
5261 "OpReturn\n" +
5262 "OpFunctionEnd\n",
5263 4, true),
5264 // Test case 4: fold double fmuls
5265 // (x * 3.0) * 2.0 = x * 6.0
5266 InstructionFoldingCase<bool>(
5267 Header() +
5268 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5269 "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
5270 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5271 "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
5272 "%main = OpFunction %void None %void_func\n" +
5273 "%main_lab = OpLabel\n" +
5274 "%var = OpVariable %_ptr_double Function\n" +
5275 "%2 = OpLoad %double %var\n" +
5276 "%3 = OpFMul %double %2 %double_3\n" +
5277 "%4 = OpFMul %double %3 %double_2\n" +
5278 "OpReturn\n" +
5279 "OpFunctionEnd\n",
5280 4, true),
5281 // Test case 5: fold 32 bit imuls
5282 // (x * 3) * 2 = x * 6
5283 InstructionFoldingCase<bool>(
5284 Header() +
5285 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5286 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5287 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5288 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
5289 "%main = OpFunction %void None %void_func\n" +
5290 "%main_lab = OpLabel\n" +
5291 "%var = OpVariable %_ptr_int Function\n" +
5292 "%2 = OpLoad %int %var\n" +
5293 "%3 = OpIMul %int %2 %int_3\n" +
5294 "%4 = OpIMul %int %3 %int_2\n" +
5295 "OpReturn\n" +
5296 "OpFunctionEnd\n",
5297 4, true),
5298 // Test case 6: fold 64 bit imuls
5299 // (x * 3) * 2 = x * 6
5300 InstructionFoldingCase<bool>(
5301 Header() +
5302 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5303 "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
5304 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5305 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
5306 "%main = OpFunction %void None %void_func\n" +
5307 "%main_lab = OpLabel\n" +
5308 "%var = OpVariable %_ptr_long Function\n" +
5309 "%2 = OpLoad %long %var\n" +
5310 "%3 = OpIMul %long %2 %long_3\n" +
5311 "%4 = OpIMul %long %3 %long_2\n" +
5312 "OpReturn\n" +
5313 "OpFunctionEnd\n",
5314 4, true),
5315 // Test case 7: merge vector integer mults
5316 InstructionFoldingCase<bool>(
5317 Header() +
5318 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5319 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5320 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5321 "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
5322 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5323 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
5324 "%main = OpFunction %void None %void_func\n" +
5325 "%main_lab = OpLabel\n" +
5326 "%var = OpVariable %_ptr_v2int Function\n" +
5327 "%2 = OpLoad %v2int %var\n" +
5328 "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
5329 "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
5330 "OpReturn\n" +
5331 "OpFunctionEnd\n",
5332 4, true),
5333 // Test case 8: merge fmul of fdiv
5334 // 2.0 * (2.0 / x) = 4.0 / x
5335 InstructionFoldingCase<bool>(
5336 Header() +
5337 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5338 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5339 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5340 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5341 "%main = OpFunction %void None %void_func\n" +
5342 "%main_lab = OpLabel\n" +
5343 "%var = OpVariable %_ptr_float Function\n" +
5344 "%2 = OpLoad %float %var\n" +
5345 "%3 = OpFDiv %float %float_2 %2\n" +
5346 "%4 = OpFMul %float %float_2 %3\n" +
5347 "OpReturn\n" +
5348 "OpFunctionEnd\n",
5349 4, true),
5350 // Test case 9: merge fmul of fdiv
5351 // (2.0 / x) * 2.0 = 4.0 / x
5352 InstructionFoldingCase<bool>(
5353 Header() +
5354 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5355 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5356 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5357 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5358 "%main = OpFunction %void None %void_func\n" +
5359 "%main_lab = OpLabel\n" +
5360 "%var = OpVariable %_ptr_float Function\n" +
5361 "%2 = OpLoad %float %var\n" +
5362 "%3 = OpFDiv %float %float_2 %2\n" +
5363 "%4 = OpFMul %float %3 %float_2\n" +
5364 "OpReturn\n" +
5365 "OpFunctionEnd\n",
5366 4, true),
5367 // Test case 10: Do not merge imul of sdiv
5368 // 4 * (x / 2)
5369 InstructionFoldingCase<bool>(
5370 Header() +
5371 "%main = OpFunction %void None %void_func\n" +
5372 "%main_lab = OpLabel\n" +
5373 "%var = OpVariable %_ptr_int Function\n" +
5374 "%2 = OpLoad %int %var\n" +
5375 "%3 = OpSDiv %int %2 %int_2\n" +
5376 "%4 = OpIMul %int %int_4 %3\n" +
5377 "OpReturn\n" +
5378 "OpFunctionEnd\n",
5379 4, false),
5380 // Test case 11: Do not merge imul of sdiv
5381 // (x / 2) * 4
5382 InstructionFoldingCase<bool>(
5383 Header() +
5384 "%main = OpFunction %void None %void_func\n" +
5385 "%main_lab = OpLabel\n" +
5386 "%var = OpVariable %_ptr_int Function\n" +
5387 "%2 = OpLoad %int %var\n" +
5388 "%3 = OpSDiv %int %2 %int_2\n" +
5389 "%4 = OpIMul %int %3 %int_4\n" +
5390 "OpReturn\n" +
5391 "OpFunctionEnd\n",
5392 4, false),
5393 // Test case 12: Do not merge imul of udiv
5394 // 4 * (x / 2)
5395 InstructionFoldingCase<bool>(
5396 Header() +
5397 "%main = OpFunction %void None %void_func\n" +
5398 "%main_lab = OpLabel\n" +
5399 "%var = OpVariable %_ptr_uint Function\n" +
5400 "%2 = OpLoad %uint %var\n" +
5401 "%3 = OpUDiv %uint %2 %uint_2\n" +
5402 "%4 = OpIMul %uint %uint_4 %3\n" +
5403 "OpReturn\n" +
5404 "OpFunctionEnd\n",
5405 4, false),
5406 // Test case 13: Do not merge imul of udiv
5407 // (x / 2) * 4
5408 InstructionFoldingCase<bool>(
5409 Header() +
5410 "%main = OpFunction %void None %void_func\n" +
5411 "%main_lab = OpLabel\n" +
5412 "%var = OpVariable %_ptr_uint Function\n" +
5413 "%2 = OpLoad %uint %var\n" +
5414 "%3 = OpUDiv %uint %2 %uint_2\n" +
5415 "%4 = OpIMul %uint %3 %uint_4\n" +
5416 "OpReturn\n" +
5417 "OpFunctionEnd\n",
5418 4, false),
5419 // Test case 14: Don't fold
5420 // (x / 3) * 4
5421 InstructionFoldingCase<bool>(
5422 Header() +
5423 "%main = OpFunction %void None %void_func\n" +
5424 "%main_lab = OpLabel\n" +
5425 "%var = OpVariable %_ptr_uint Function\n" +
5426 "%2 = OpLoad %uint %var\n" +
5427 "%3 = OpUDiv %uint %2 %uint_3\n" +
5428 "%4 = OpIMul %uint %3 %uint_4\n" +
5429 "OpReturn\n" +
5430 "OpFunctionEnd\n",
5431 4, false),
5432 // Test case 15: merge vector fmul of fdiv
5433 // (x / {2,2}) * {4,4} = x * {2,2}
5434 InstructionFoldingCase<bool>(
5435 Header() +
5436 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5437 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5438 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5439 "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
5440 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5441 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
5442 "%main = OpFunction %void None %void_func\n" +
5443 "%main_lab = OpLabel\n" +
5444 "%var = OpVariable %_ptr_v2float Function\n" +
5445 "%2 = OpLoad %v2float %var\n" +
5446 "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
5447 "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
5448 "OpReturn\n" +
5449 "OpFunctionEnd\n",
5450 4, true),
5451 // Test case 16: merge vector imul of snegate
5452 // (-x) * {2,2} = x * {-2,-2}
5453 InstructionFoldingCase<bool>(
5454 Header() +
5455 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5456 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
5457 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
5458 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5459 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
5460 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5461 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
5462 "%main = OpFunction %void None %void_func\n" +
5463 "%main_lab = OpLabel\n" +
5464 "%var = OpVariable %_ptr_v2int Function\n" +
5465 "%2 = OpLoad %v2int %var\n" +
5466 "%3 = OpSNegate %v2int %2\n" +
5467 "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
5468 "OpReturn\n" +
5469 "OpFunctionEnd\n",
5470 4, true),
5471 // Test case 17: merge vector imul of snegate
5472 // {2,2} * (-x) = x * {-2,-2}
5473 InstructionFoldingCase<bool>(
5474 Header() +
5475 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5476 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
5477 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
5478 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5479 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
5480 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5481 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
5482 "%main = OpFunction %void None %void_func\n" +
5483 "%main_lab = OpLabel\n" +
5484 "%var = OpVariable %_ptr_v2int Function\n" +
5485 "%2 = OpLoad %v2int %var\n" +
5486 "%3 = OpSNegate %v2int %2\n" +
5487 "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
5488 "OpReturn\n" +
5489 "OpFunctionEnd\n",
5490 4, true),
5491 // Test case 18: Fold OpVectorTimesScalar
5492 // {4,4} = OpVectorTimesScalar v2float {2,2} 2
5493 InstructionFoldingCase<bool>(
5494 Header() +
5495 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5496 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5497 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5498 "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
5499 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
5500 "%main = OpFunction %void None %void_func\n" +
5501 "%main_lab = OpLabel\n" +
5502 "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
5503 "OpReturn\n" +
5504 "OpFunctionEnd",
5505 2, true),
5506 // Test case 19: Fold OpVectorTimesScalar
5507 // {0,0} = OpVectorTimesScalar v2float v2float_null -1
5508 InstructionFoldingCase<bool>(
5509 Header() +
5510 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5511 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5512 "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
5513 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
5514 "%main = OpFunction %void None %void_func\n" +
5515 "%main_lab = OpLabel\n" +
5516 "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
5517 "OpReturn\n" +
5518 "OpFunctionEnd",
5519 2, true),
5520 // Test case 20: Fold OpVectorTimesScalar
5521 // {4,4} = OpVectorTimesScalar v2double {2,2} 2
5522 InstructionFoldingCase<bool>(
5523 Header() +
5524 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5525 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5526 "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
5527 "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
5528 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
5529 "%main = OpFunction %void None %void_func\n" +
5530 "%main_lab = OpLabel\n" +
5531 "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
5532 "OpReturn\n" +
5533 "OpFunctionEnd",
5534 2, true),
5535 // Test case 21: Fold OpVectorTimesScalar
5536 // {0,0} = OpVectorTimesScalar v2double {0,0} n
5537 InstructionFoldingCase<bool>(
5538 Header() +
5539 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5540 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5541 "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
5542 "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
5543 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
5544 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5545 "%main = OpFunction %void None %void_func\n" +
5546 "%main_lab = OpLabel\n" +
5547 "%n = OpVariable %_ptr_double Function\n" +
5548 "%load = OpLoad %double %n\n" +
5549 "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
5550 "OpReturn\n" +
5551 "OpFunctionEnd",
5552 2, true),
5553 // Test case 22: Fold OpVectorTimesScalar
5554 // {0,0} = OpVectorTimesScalar v2double n 0
5555 InstructionFoldingCase<bool>(
5556 Header() +
5557 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5558 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5559 "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
5560 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
5561 "%main = OpFunction %void None %void_func\n" +
5562 "%main_lab = OpLabel\n" +
5563 "%n = OpVariable %_ptr_v2double Function\n" +
5564 "%load = OpLoad %v2double %n\n" +
5565 "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
5566 "OpReturn\n" +
5567 "OpFunctionEnd",
5568 2, true),
5569 // Test case 23: merge fmul of fdiv
5570 // x * (y / x) = y
5571 InstructionFoldingCase<bool>(
5572 Header() +
5573 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5574 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5575 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5576 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5577 "%main = OpFunction %void None %void_func\n" +
5578 "%main_lab = OpLabel\n" +
5579 "%x = OpVariable %_ptr_float Function\n" +
5580 "%y = OpVariable %_ptr_float Function\n" +
5581 "%2 = OpLoad %float %x\n" +
5582 "%3 = OpLoad %float %y\n" +
5583 "%4 = OpFDiv %float %3 %2\n" +
5584 "%5 = OpFMul %float %2 %4\n" +
5585 "OpReturn\n" +
5586 "OpFunctionEnd\n",
5587 5, true),
5588 // Test case 24: merge fmul of fdiv
5589 // (y / x) * x = y
5590 InstructionFoldingCase<bool>(
5591 Header() +
5592 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5593 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5594 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5595 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5596 "%main = OpFunction %void None %void_func\n" +
5597 "%main_lab = OpLabel\n" +
5598 "%x = OpVariable %_ptr_float Function\n" +
5599 "%y = OpVariable %_ptr_float Function\n" +
5600 "%2 = OpLoad %float %x\n" +
5601 "%3 = OpLoad %float %y\n" +
5602 "%4 = OpFDiv %float %3 %2\n" +
5603 "%5 = OpFMul %float %4 %2\n" +
5604 "OpReturn\n" +
5605 "OpFunctionEnd\n",
5606 5, true),
5607 // Test case 25: fold overflowing signed 32 bit imuls
5608 // (x * 1073741824) * 2 = x * int_min
5609 InstructionFoldingCase<bool>(
5610 Header() +
5611 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
5612 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
5613 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5614 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" +
5615 "%main = OpFunction %void None %void_func\n" +
5616 "%main_lab = OpLabel\n" +
5617 "%var = OpVariable %_ptr_int Function\n" +
5618 "%2 = OpLoad %int %var\n" +
5619 "%3 = OpIMul %int %2 %int_1073741824\n" +
5620 "%4 = OpIMul %int %3 %int_2\n" +
5621 "OpReturn\n" +
5622 "OpFunctionEnd\n",
5623 4, true),
5624 // Test case 26: fold overflowing signed 64 bit imuls
5625 // (x * 4611686018427387904) * 2 = x * long_min
5626 InstructionFoldingCase<bool>(
5627 Header() +
5628 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5629 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
5630 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5631 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\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 = OpIMul %long %2 %long_4611686018427387904\n" +
5637 "%4 = OpIMul %long %3 %long_2\n" +
5638 "OpReturn\n" +
5639 "OpFunctionEnd\n",
5640 4, true),
5641 // Test case 27: fold overflowing 32 bit unsigned imuls
5642 // (x * 2147483649) * 2 = x * 2
5643 InstructionFoldingCase<bool>(
5644 Header() +
5645 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5646 "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" +
5647 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
5648 "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" +
5649 "%main = OpFunction %void None %void_func\n" +
5650 "%main_lab = OpLabel\n" +
5651 "%var = OpVariable %_ptr_uint Function\n" +
5652 "%2 = OpLoad %uint %var\n" +
5653 "%3 = OpIMul %uint %2 %uint_2147483649\n" +
5654 "%4 = OpIMul %uint %3 %uint_2\n" +
5655 "OpReturn\n" +
5656 "OpFunctionEnd\n",
5657 4, true),
5658 // Test case 28: fold overflowing 64 bit unsigned imuls
5659 // (x * 9223372036854775809) * 2 = x * 2
5660 InstructionFoldingCase<bool>(
5661 Header() +
5662 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
5663 "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" +
5664 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
5665 "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" +
5666 "%main = OpFunction %void None %void_func\n" +
5667 "%main_lab = OpLabel\n" +
5668 "%var = OpVariable %_ptr_ulong Function\n" +
5669 "%2 = OpLoad %ulong %var\n" +
5670 "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" +
5671 "%4 = OpIMul %ulong %3 %ulong_2\n" +
5672 "OpReturn\n" +
5673 "OpFunctionEnd\n",
5674 4, true),
5675 // Test case 29: fold underflowing signed 32 bit imuls
5676 // (x * (-858993459)) * 10 = x * 2
5677 InstructionFoldingCase<bool>(
5678 Header() +
5679 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
5680 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5681 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5682 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" +
5683 "%main = OpFunction %void None %void_func\n" +
5684 "%main_lab = OpLabel\n" +
5685 "%var = OpVariable %_ptr_int Function\n" +
5686 "%2 = OpLoad %int %var\n" +
5687 "%3 = OpIMul %int %2 %int_n858993459\n" +
5688 "%4 = OpIMul %int %3 %int_10\n" +
5689 "OpReturn\n" +
5690 "OpFunctionEnd\n",
5691 4, true),
5692 // Test case 30: fold underflowing signed 64 bit imuls
5693 // (x * (-3689348814741910323)) * 10 = x * 2
5694 InstructionFoldingCase<bool>(
5695 Header() +
5696 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5697 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5698 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5699 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" +
5700 "%main = OpFunction %void None %void_func\n" +
5701 "%main_lab = OpLabel\n" +
5702 "%var = OpVariable %_ptr_long Function\n" +
5703 "%2 = OpLoad %long %var\n" +
5704 "%3 = OpIMul %long %2 %long_n3689348814741910323\n" +
5705 "%4 = OpIMul %long %3 %long_10\n" +
5706 "OpReturn\n" +
5707 "OpFunctionEnd\n",
5708 4, true)
5709 ));
5710
5711 INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest,
5712 ::testing::Values(
5713 // Test case 0: merge consecutive fdiv
5714 // 4.0 / (2.0 / x) = 2.0 * x
5715 InstructionFoldingCase<bool>(
5716 Header() +
5717 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5718 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5719 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5720 "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
5721 "%main = OpFunction %void None %void_func\n" +
5722 "%main_lab = OpLabel\n" +
5723 "%var = OpVariable %_ptr_float Function\n" +
5724 "%2 = OpLoad %float %var\n" +
5725 "%3 = OpFDiv %float %float_2 %2\n" +
5726 "%4 = OpFDiv %float %float_4 %3\n" +
5727 "OpReturn\n" +
5728 "OpFunctionEnd\n",
5729 4, true),
5730 // Test case 1: merge consecutive fdiv
5731 // 4.0 / (x / 2.0) = 8.0 / x
5732 InstructionFoldingCase<bool>(
5733 Header() +
5734 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5735 "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
5736 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5737 "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
5738 "%main = OpFunction %void None %void_func\n" +
5739 "%main_lab = OpLabel\n" +
5740 "%var = OpVariable %_ptr_float Function\n" +
5741 "%2 = OpLoad %float %var\n" +
5742 "%3 = OpFDiv %float %2 %float_2\n" +
5743 "%4 = OpFDiv %float %float_4 %3\n" +
5744 "OpReturn\n" +
5745 "OpFunctionEnd\n",
5746 4, true),
5747 // Test case 2: merge consecutive fdiv
5748 // (4.0 / x) / 2.0 = 2.0 / x
5749 InstructionFoldingCase<bool>(
5750 Header() +
5751 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5752 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5753 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5754 "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
5755 "%main = OpFunction %void None %void_func\n" +
5756 "%main_lab = OpLabel\n" +
5757 "%var = OpVariable %_ptr_float Function\n" +
5758 "%2 = OpLoad %float %var\n" +
5759 "%3 = OpFDiv %float %float_4 %2\n" +
5760 "%4 = OpFDiv %float %3 %float_2\n" +
5761 "OpReturn\n" +
5762 "OpFunctionEnd\n",
5763 4, true),
5764 // Test case 3: Do not merge consecutive sdiv
5765 // 4 / (2 / x)
5766 InstructionFoldingCase<bool>(
5767 Header() +
5768 "%main = OpFunction %void None %void_func\n" +
5769 "%main_lab = OpLabel\n" +
5770 "%var = OpVariable %_ptr_int Function\n" +
5771 "%2 = OpLoad %int %var\n" +
5772 "%3 = OpSDiv %int %int_2 %2\n" +
5773 "%4 = OpSDiv %int %int_4 %3\n" +
5774 "OpReturn\n" +
5775 "OpFunctionEnd\n",
5776 4, false),
5777 // Test case 4: Do not merge consecutive sdiv
5778 // 4 / (x / 2)
5779 InstructionFoldingCase<bool>(
5780 Header() +
5781 "%main = OpFunction %void None %void_func\n" +
5782 "%main_lab = OpLabel\n" +
5783 "%var = OpVariable %_ptr_int Function\n" +
5784 "%2 = OpLoad %int %var\n" +
5785 "%3 = OpSDiv %int %2 %int_2\n" +
5786 "%4 = OpSDiv %int %int_4 %3\n" +
5787 "OpReturn\n" +
5788 "OpFunctionEnd\n",
5789 4, false),
5790 // Test case 5: Do not merge consecutive sdiv
5791 // (4 / x) / 2
5792 InstructionFoldingCase<bool>(
5793 Header() +
5794 "%main = OpFunction %void None %void_func\n" +
5795 "%main_lab = OpLabel\n" +
5796 "%var = OpVariable %_ptr_int Function\n" +
5797 "%2 = OpLoad %int %var\n" +
5798 "%3 = OpSDiv %int %int_4 %2\n" +
5799 "%4 = OpSDiv %int %3 %int_2\n" +
5800 "OpReturn\n" +
5801 "OpFunctionEnd\n",
5802 4, false),
5803 // Test case 6: Do not merge consecutive sdiv
5804 // (x / 4) / 2
5805 InstructionFoldingCase<bool>(
5806 Header() +
5807 "%main = OpFunction %void None %void_func\n" +
5808 "%main_lab = OpLabel\n" +
5809 "%var = OpVariable %_ptr_int Function\n" +
5810 "%2 = OpLoad %int %var\n" +
5811 "%3 = OpSDiv %int %2 %int_4\n" +
5812 "%4 = OpSDiv %int %3 %int_2\n" +
5813 "OpReturn\n" +
5814 "OpFunctionEnd\n",
5815 4, false),
5816 // Test case 7: Do not merge sdiv of imul
5817 // 4 / (2 * x)
5818 InstructionFoldingCase<bool>(
5819 Header() +
5820 "%main = OpFunction %void None %void_func\n" +
5821 "%main_lab = OpLabel\n" +
5822 "%var = OpVariable %_ptr_int Function\n" +
5823 "%2 = OpLoad %int %var\n" +
5824 "%3 = OpIMul %int %int_2 %2\n" +
5825 "%4 = OpSDiv %int %int_4 %3\n" +
5826 "OpReturn\n" +
5827 "OpFunctionEnd\n",
5828 4, false),
5829 // Test case 8: Do not merge sdiv of imul
5830 // 4 / (x * 2)
5831 InstructionFoldingCase<bool>(
5832 Header() +
5833 "%main = OpFunction %void None %void_func\n" +
5834 "%main_lab = OpLabel\n" +
5835 "%var = OpVariable %_ptr_int Function\n" +
5836 "%2 = OpLoad %int %var\n" +
5837 "%3 = OpIMul %int %2 %int_2\n" +
5838 "%4 = OpSDiv %int %int_4 %3\n" +
5839 "OpReturn\n" +
5840 "OpFunctionEnd\n",
5841 4, false),
5842 // Test case 9: Do not merge sdiv of imul
5843 // (4 * x) / 2
5844 InstructionFoldingCase<bool>(
5845 Header() +
5846 "%main = OpFunction %void None %void_func\n" +
5847 "%main_lab = OpLabel\n" +
5848 "%var = OpVariable %_ptr_int Function\n" +
5849 "%2 = OpLoad %int %var\n" +
5850 "%3 = OpIMul %int %int_4 %2\n" +
5851 "%4 = OpSDiv %int %3 %int_2\n" +
5852 "OpReturn\n" +
5853 "OpFunctionEnd\n",
5854 4, false),
5855 // Test case 10: Do not merge sdiv of imul
5856 // (x * 4) / 2
5857 InstructionFoldingCase<bool>(
5858 Header() +
5859 "%main = OpFunction %void None %void_func\n" +
5860 "%main_lab = OpLabel\n" +
5861 "%var = OpVariable %_ptr_int Function\n" +
5862 "%2 = OpLoad %int %var\n" +
5863 "%3 = OpIMul %int %2 %int_4\n" +
5864 "%4 = OpSDiv %int %3 %int_2\n" +
5865 "OpReturn\n" +
5866 "OpFunctionEnd\n",
5867 4, false),
5868 // Test case 11: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
5869 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
5870 // Specifically, (-INT_MIN) / 2 != INT_MIN / -2.
5871 InstructionFoldingCase<bool>(
5872 Header() +
5873 "%main = OpFunction %void None %void_func\n" +
5874 "%main_lab = OpLabel\n" +
5875 "%var = OpVariable %_ptr_int Function\n" +
5876 "%2 = OpLoad %int %var\n" +
5877 "%3 = OpSNegate %int %2\n" +
5878 "%4 = OpSDiv %int %3 %int_2\n" +
5879 "OpReturn\n" +
5880 "OpFunctionEnd\n",
5881 4, false),
5882 // Test case 12: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
5883 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
5884 // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN.
5885 InstructionFoldingCase<bool>(
5886 Header() +
5887 "%main = OpFunction %void None %void_func\n" +
5888 "%main_lab = OpLabel\n" +
5889 "%var = OpVariable %_ptr_int Function\n" +
5890 "%2 = OpLoad %int %var\n" +
5891 "%3 = OpSNegate %int %2\n" +
5892 "%4 = OpSDiv %int %int_2 %3\n" +
5893 "OpReturn\n" +
5894 "OpFunctionEnd\n",
5895 4, false),
5896 // Test case 13: Don't merge
5897 // (x / {null}) / {null}
5898 InstructionFoldingCase<bool>(
5899 Header() +
5900 "%main = OpFunction %void None %void_func\n" +
5901 "%main_lab = OpLabel\n" +
5902 "%var = OpVariable %_ptr_v2float Function\n" +
5903 "%2 = OpLoad %float %var\n" +
5904 "%3 = OpFDiv %float %2 %v2float_null\n" +
5905 "%4 = OpFDiv %float %3 %v2float_null\n" +
5906 "OpReturn\n" +
5907 "OpFunctionEnd\n",
5908 4, false),
5909 // Test case 14: merge fmul of fdiv
5910 // (y * x) / x = y
5911 InstructionFoldingCase<bool>(
5912 Header() +
5913 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5914 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5915 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5916 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5917 "%main = OpFunction %void None %void_func\n" +
5918 "%main_lab = OpLabel\n" +
5919 "%x = OpVariable %_ptr_float Function\n" +
5920 "%y = OpVariable %_ptr_float Function\n" +
5921 "%2 = OpLoad %float %x\n" +
5922 "%3 = OpLoad %float %y\n" +
5923 "%4 = OpFMul %float %3 %2\n" +
5924 "%5 = OpFDiv %float %4 %2\n" +
5925 "OpReturn\n" +
5926 "OpFunctionEnd\n",
5927 5, true),
5928 // Test case 15: merge fmul of fdiv
5929 // (x * y) / x = y
5930 InstructionFoldingCase<bool>(
5931 Header() +
5932 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5933 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5934 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5935 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5936 "%main = OpFunction %void None %void_func\n" +
5937 "%main_lab = OpLabel\n" +
5938 "%x = OpVariable %_ptr_float Function\n" +
5939 "%y = OpVariable %_ptr_float Function\n" +
5940 "%2 = OpLoad %float %x\n" +
5941 "%3 = OpLoad %float %y\n" +
5942 "%4 = OpFMul %float %2 %3\n" +
5943 "%5 = OpFDiv %float %4 %2\n" +
5944 "OpReturn\n" +
5945 "OpFunctionEnd\n",
5946 5, true),
5947 // Test case 16: Do not merge udiv of snegate
5948 // (-x) / 2u
5949 InstructionFoldingCase<bool>(
5950 Header() +
5951 "%main = OpFunction %void None %void_func\n" +
5952 "%main_lab = OpLabel\n" +
5953 "%var = OpVariable %_ptr_uint Function\n" +
5954 "%2 = OpLoad %uint %var\n" +
5955 "%3 = OpSNegate %uint %2\n" +
5956 "%4 = OpUDiv %uint %3 %uint_2\n" +
5957 "OpReturn\n" +
5958 "OpFunctionEnd\n",
5959 4, false),
5960 // Test case 17: Do not merge udiv of snegate
5961 // 2u / (-x)
5962 InstructionFoldingCase<bool>(
5963 Header() +
5964 "%main = OpFunction %void None %void_func\n" +
5965 "%main_lab = OpLabel\n" +
5966 "%var = OpVariable %_ptr_uint Function\n" +
5967 "%2 = OpLoad %uint %var\n" +
5968 "%3 = OpSNegate %uint %2\n" +
5969 "%4 = OpUDiv %uint %uint_2 %3\n" +
5970 "OpReturn\n" +
5971 "OpFunctionEnd\n",
5972 4, false)
5973 ));
5974
5975 INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest,
5976 ::testing::Values(
5977 // Test case 0: merge add of negate
5978 // (-x) + 2 = 2 - x
5979 InstructionFoldingCase<bool>(
5980 Header() +
5981 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5982 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5983 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5984 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5985 "%main = OpFunction %void None %void_func\n" +
5986 "%main_lab = OpLabel\n" +
5987 "%var = OpVariable %_ptr_float Function\n" +
5988 "%2 = OpLoad %float %var\n" +
5989 "%3 = OpFNegate %float %2\n" +
5990 "%4 = OpFAdd %float %3 %float_2\n" +
5991 "OpReturn\n" +
5992 "OpFunctionEnd\n",
5993 4, true),
5994 // Test case 1: merge add of negate
5995 // 2 + (-x) = 2 - x
5996 InstructionFoldingCase<bool>(
5997 Header() +
5998 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5999 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6000 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6001 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6002 "%main = OpFunction %void None %void_func\n" +
6003 "%main_lab = OpLabel\n" +
6004 "%var = OpVariable %_ptr_float Function\n" +
6005 "%2 = OpLoad %float %var\n" +
6006 "%3 = OpSNegate %float %2\n" +
6007 "%4 = OpIAdd %float %float_2 %3\n" +
6008 "OpReturn\n" +
6009 "OpFunctionEnd\n",
6010 4, true),
6011 // Test case 2: merge add of negate
6012 // (-x) + 2 = 2 - x
6013 InstructionFoldingCase<bool>(
6014 Header() +
6015 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6016 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6017 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6018 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6019 "%main = OpFunction %void None %void_func\n" +
6020 "%main_lab = OpLabel\n" +
6021 "%var = OpVariable %_ptr_long Function\n" +
6022 "%2 = OpLoad %long %var\n" +
6023 "%3 = OpSNegate %long %2\n" +
6024 "%4 = OpIAdd %long %3 %long_2\n" +
6025 "OpReturn\n" +
6026 "OpFunctionEnd\n",
6027 4, true),
6028 // Test case 3: merge add of negate
6029 // 2 + (-x) = 2 - x
6030 InstructionFoldingCase<bool>(
6031 Header() +
6032 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6033 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6034 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6035 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6036 "%main = OpFunction %void None %void_func\n" +
6037 "%main_lab = OpLabel\n" +
6038 "%var = OpVariable %_ptr_long Function\n" +
6039 "%2 = OpLoad %long %var\n" +
6040 "%3 = OpSNegate %long %2\n" +
6041 "%4 = OpIAdd %long %long_2 %3\n" +
6042 "OpReturn\n" +
6043 "OpFunctionEnd\n",
6044 4, true),
6045 // Test case 4: merge add of subtract
6046 // (x - 1) + 2 = x + 1
6047 InstructionFoldingCase<bool>(
6048 Header() +
6049 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6050 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6051 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6052 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6053 "%main = OpFunction %void None %void_func\n" +
6054 "%main_lab = OpLabel\n" +
6055 "%var = OpVariable %_ptr_float Function\n" +
6056 "%2 = OpLoad %float %var\n" +
6057 "%3 = OpFSub %float %2 %float_1\n" +
6058 "%4 = OpFAdd %float %3 %float_2\n" +
6059 "OpReturn\n" +
6060 "OpFunctionEnd\n",
6061 4, true),
6062 // Test case 5: merge add of subtract
6063 // (1 - x) + 2 = 3 - x
6064 InstructionFoldingCase<bool>(
6065 Header() +
6066 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6067 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6068 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6069 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6070 "%main = OpFunction %void None %void_func\n" +
6071 "%main_lab = OpLabel\n" +
6072 "%var = OpVariable %_ptr_float Function\n" +
6073 "%2 = OpLoad %float %var\n" +
6074 "%3 = OpFSub %float %float_1 %2\n" +
6075 "%4 = OpFAdd %float %3 %float_2\n" +
6076 "OpReturn\n" +
6077 "OpFunctionEnd\n",
6078 4, true),
6079 // Test case 6: merge add of subtract
6080 // 2 + (x - 1) = x + 1
6081 InstructionFoldingCase<bool>(
6082 Header() +
6083 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6084 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6085 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6086 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6087 "%main = OpFunction %void None %void_func\n" +
6088 "%main_lab = OpLabel\n" +
6089 "%var = OpVariable %_ptr_float Function\n" +
6090 "%2 = OpLoad %float %var\n" +
6091 "%3 = OpFSub %float %2 %float_1\n" +
6092 "%4 = OpFAdd %float %float_2 %3\n" +
6093 "OpReturn\n" +
6094 "OpFunctionEnd\n",
6095 4, true),
6096 // Test case 7: merge add of subtract
6097 // 2 + (1 - x) = 3 - x
6098 InstructionFoldingCase<bool>(
6099 Header() +
6100 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6101 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6102 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6103 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6104 "%main = OpFunction %void None %void_func\n" +
6105 "%main_lab = OpLabel\n" +
6106 "%var = OpVariable %_ptr_float Function\n" +
6107 "%2 = OpLoad %float %var\n" +
6108 "%3 = OpFSub %float %float_1 %2\n" +
6109 "%4 = OpFAdd %float %float_2 %3\n" +
6110 "OpReturn\n" +
6111 "OpFunctionEnd\n",
6112 4, true),
6113 // Test case 8: merge add of add
6114 // (x + 1) + 2 = x + 3
6115 InstructionFoldingCase<bool>(
6116 Header() +
6117 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6118 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6119 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6120 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6121 "%main = OpFunction %void None %void_func\n" +
6122 "%main_lab = OpLabel\n" +
6123 "%var = OpVariable %_ptr_float Function\n" +
6124 "%2 = OpLoad %float %var\n" +
6125 "%3 = OpFAdd %float %2 %float_1\n" +
6126 "%4 = OpFAdd %float %3 %float_2\n" +
6127 "OpReturn\n" +
6128 "OpFunctionEnd\n",
6129 4, true),
6130 // Test case 9: merge add of add
6131 // (1 + x) + 2 = 3 + x
6132 InstructionFoldingCase<bool>(
6133 Header() +
6134 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6135 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6136 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6137 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6138 "%main = OpFunction %void None %void_func\n" +
6139 "%main_lab = OpLabel\n" +
6140 "%var = OpVariable %_ptr_float Function\n" +
6141 "%2 = OpLoad %float %var\n" +
6142 "%3 = OpFAdd %float %float_1 %2\n" +
6143 "%4 = OpFAdd %float %3 %float_2\n" +
6144 "OpReturn\n" +
6145 "OpFunctionEnd\n",
6146 4, true),
6147 // Test case 10: merge add of add
6148 // 2 + (x + 1) = x + 1
6149 InstructionFoldingCase<bool>(
6150 Header() +
6151 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6152 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6153 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6154 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6155 "%main = OpFunction %void None %void_func\n" +
6156 "%main_lab = OpLabel\n" +
6157 "%var = OpVariable %_ptr_float Function\n" +
6158 "%2 = OpLoad %float %var\n" +
6159 "%3 = OpFAdd %float %2 %float_1\n" +
6160 "%4 = OpFAdd %float %float_2 %3\n" +
6161 "OpReturn\n" +
6162 "OpFunctionEnd\n",
6163 4, true),
6164 // Test case 11: merge add of add
6165 // 2 + (1 + x) = 3 - x
6166 InstructionFoldingCase<bool>(
6167 Header() +
6168 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6169 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6170 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6171 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6172 "%main = OpFunction %void None %void_func\n" +
6173 "%main_lab = OpLabel\n" +
6174 "%var = OpVariable %_ptr_float Function\n" +
6175 "%2 = OpLoad %float %var\n" +
6176 "%3 = OpFAdd %float %float_1 %2\n" +
6177 "%4 = OpFAdd %float %float_2 %3\n" +
6178 "OpReturn\n" +
6179 "OpFunctionEnd\n",
6180 4, true),
6181 // Test case 12: fold overflowing signed 32 bit iadds
6182 // (x + int_max) + 1 = x + int_min
6183 InstructionFoldingCase<bool>(
6184 Header() +
6185 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6186 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6187 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6188 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" +
6189 "%main = OpFunction %void None %void_func\n" +
6190 "%main_lab = OpLabel\n" +
6191 "%var = OpVariable %_ptr_int Function\n" +
6192 "%2 = OpLoad %int %var\n" +
6193 "%3 = OpIAdd %int %2 %int_max\n" +
6194 "%4 = OpIAdd %int %3 %int_1\n" +
6195 "OpReturn\n" +
6196 "OpFunctionEnd\n",
6197 4, true),
6198 // Test case 13: fold overflowing signed 64 bit iadds
6199 // (x + long_max) + 1 = x + long_min
6200 InstructionFoldingCase<bool>(
6201 Header() +
6202 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6203 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6204 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6205 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" +
6206 "%main = OpFunction %void None %void_func\n" +
6207 "%main_lab = OpLabel\n" +
6208 "%var = OpVariable %_ptr_long Function\n" +
6209 "%2 = OpLoad %long %var\n" +
6210 "%3 = OpIAdd %long %2 %long_max\n" +
6211 "%4 = OpIAdd %long %3 %long_1\n" +
6212 "OpReturn\n" +
6213 "OpFunctionEnd\n",
6214 4, true),
6215 // Test case 14: fold overflowing 32 bit unsigned iadds
6216 // (x + uint_max) + 2 = x + 1
6217 InstructionFoldingCase<bool>(
6218 Header() +
6219 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6220 "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
6221 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6222 "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" +
6223 "%main = OpFunction %void None %void_func\n" +
6224 "%main_lab = OpLabel\n" +
6225 "%var = OpVariable %_ptr_uint Function\n" +
6226 "%2 = OpLoad %uint %var\n" +
6227 "%3 = OpIAdd %uint %2 %uint_max\n" +
6228 "%4 = OpIAdd %uint %3 %uint_2\n" +
6229 "OpReturn\n" +
6230 "OpFunctionEnd\n",
6231 4, true),
6232 // Test case 15: fold overflowing 64 bit unsigned iadds
6233 // (x + ulong_max) + 2 = x + 1
6234 InstructionFoldingCase<bool>(
6235 Header() +
6236 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6237 "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" +
6238 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6239 "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" +
6240 "%main = OpFunction %void None %void_func\n" +
6241 "%main_lab = OpLabel\n" +
6242 "%var = OpVariable %_ptr_ulong Function\n" +
6243 "%2 = OpLoad %ulong %var\n" +
6244 "%3 = OpIAdd %ulong %2 %ulong_max\n" +
6245 "%4 = OpIAdd %ulong %3 %ulong_2\n" +
6246 "OpReturn\n" +
6247 "OpFunctionEnd\n",
6248 4, true),
6249 // Test case 16: fold underflowing signed 32 bit iadds
6250 // (x + int_min) + (-1) = x + int_max
6251 InstructionFoldingCase<bool>(
6252 Header() +
6253 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6254 "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" +
6255 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6256 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" +
6257 "%main = OpFunction %void None %void_func\n" +
6258 "%main_lab = OpLabel\n" +
6259 "%var = OpVariable %_ptr_int Function\n" +
6260 "%2 = OpLoad %int %var\n" +
6261 "%3 = OpIAdd %int %2 %int_min\n" +
6262 "%4 = OpIAdd %int %3 %int_n1\n" +
6263 "OpReturn\n" +
6264 "OpFunctionEnd\n",
6265 4, true),
6266 // Test case 17: fold underflowing signed 64 bit iadds
6267 // (x + long_min) + (-1) = x + long_max
6268 InstructionFoldingCase<bool>(
6269 Header() +
6270 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6271 "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" +
6272 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6273 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" +
6274 "%main = OpFunction %void None %void_func\n" +
6275 "%main_lab = OpLabel\n" +
6276 "%var = OpVariable %_ptr_long Function\n" +
6277 "%2 = OpLoad %long %var\n" +
6278 "%3 = OpIAdd %long %2 %long_min\n" +
6279 "%4 = OpIAdd %long %3 %long_n1\n" +
6280 "OpReturn\n" +
6281 "OpFunctionEnd\n",
6282 4, true)
6283 ));
6284
6285 INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
6286 ::testing::Values(
6287 // Test case 0: merge of add of sub
6288 // (a - b) + b => a
6289 InstructionFoldingCase<bool>(
6290 Header() +
6291 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6292 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6293 "%main = OpFunction %void None %void_func\n" +
6294 "%main_lab = OpLabel\n" +
6295 "%var0 = OpVariable %_ptr_float Function\n" +
6296 "%var1 = OpVariable %_ptr_float Function\n" +
6297 "%3 = OpLoad %float %var0\n" +
6298 "%4 = OpLoad %float %var1\n" +
6299 "%5 = OpFSub %float %3 %4\n" +
6300 "%6 = OpFAdd %float %5 %4\n" +
6301 "OpReturn\n" +
6302 "OpFunctionEnd\n",
6303 6, true),
6304 // Test case 1: merge of add of sub
6305 // b + (a - b) => a
6306 InstructionFoldingCase<bool>(
6307 Header() +
6308 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6309 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6310 "%main = OpFunction %void None %void_func\n" +
6311 "%main_lab = OpLabel\n" +
6312 "%var0 = OpVariable %_ptr_float Function\n" +
6313 "%var1 = OpVariable %_ptr_float Function\n" +
6314 "%3 = OpLoad %float %var0\n" +
6315 "%4 = OpLoad %float %var1\n" +
6316 "%5 = OpFSub %float %3 %4\n" +
6317 "%6 = OpFAdd %float %4 %5\n" +
6318 "OpReturn\n" +
6319 "OpFunctionEnd\n",
6320 6, true)
6321 ));
6322
6323 INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
6324 ::testing::Values(
6325 // Test case 0: factor of add of muls
6326 // (a * b) + (a * c) => a * (b + c)
6327 InstructionFoldingCase<bool>(
6328 Header() +
6329 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6330 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6331 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6332 "%main = OpFunction %void None %void_func\n" +
6333 "%main_lab = OpLabel\n" +
6334 "%var0 = OpVariable %_ptr_float Function\n" +
6335 "%var1 = OpVariable %_ptr_float Function\n" +
6336 "%var2 = OpVariable %_ptr_float Function\n" +
6337 "%4 = OpLoad %float %var0\n" +
6338 "%5 = OpLoad %float %var1\n" +
6339 "%6 = OpLoad %float %var2\n" +
6340 "%7 = OpFMul %float %6 %4\n" +
6341 "%8 = OpFMul %float %6 %5\n" +
6342 "%9 = OpFAdd %float %7 %8\n" +
6343 "OpReturn\n" +
6344 "OpFunctionEnd\n",
6345 9, true),
6346 // Test case 1: factor of add of muls
6347 // (b * a) + (a * c) => a * (b + c)
6348 InstructionFoldingCase<bool>(
6349 Header() +
6350 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6351 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6352 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6353 "%main = OpFunction %void None %void_func\n" +
6354 "%main_lab = OpLabel\n" +
6355 "%var0 = OpVariable %_ptr_float Function\n" +
6356 "%var1 = OpVariable %_ptr_float Function\n" +
6357 "%var2 = OpVariable %_ptr_float Function\n" +
6358 "%4 = OpLoad %float %var0\n" +
6359 "%5 = OpLoad %float %var1\n" +
6360 "%6 = OpLoad %float %var2\n" +
6361 "%7 = OpFMul %float %4 %6\n" +
6362 "%8 = OpFMul %float %6 %5\n" +
6363 "%9 = OpFAdd %float %7 %8\n" +
6364 "OpReturn\n" +
6365 "OpFunctionEnd\n",
6366 9, true),
6367 // Test case 2: factor of add of muls
6368 // (a * b) + (c * a) => a * (b + c)
6369 InstructionFoldingCase<bool>(
6370 Header() +
6371 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6372 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6373 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6374 "%main = OpFunction %void None %void_func\n" +
6375 "%main_lab = OpLabel\n" +
6376 "%var0 = OpVariable %_ptr_float Function\n" +
6377 "%var1 = OpVariable %_ptr_float Function\n" +
6378 "%var2 = OpVariable %_ptr_float Function\n" +
6379 "%4 = OpLoad %float %var0\n" +
6380 "%5 = OpLoad %float %var1\n" +
6381 "%6 = OpLoad %float %var2\n" +
6382 "%7 = OpFMul %float %6 %4\n" +
6383 "%8 = OpFMul %float %5 %6\n" +
6384 "%9 = OpFAdd %float %7 %8\n" +
6385 "OpReturn\n" +
6386 "OpFunctionEnd\n",
6387 9, true),
6388 // Test case 3: factor of add of muls
6389 // (b * a) + (c * a) => a * (b + c)
6390 InstructionFoldingCase<bool>(
6391 Header() +
6392 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6393 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6394 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6395 "%main = OpFunction %void None %void_func\n" +
6396 "%main_lab = OpLabel\n" +
6397 "%var0 = OpVariable %_ptr_float Function\n" +
6398 "%var1 = OpVariable %_ptr_float Function\n" +
6399 "%var2 = OpVariable %_ptr_float Function\n" +
6400 "%4 = OpLoad %float %var0\n" +
6401 "%5 = OpLoad %float %var1\n" +
6402 "%6 = OpLoad %float %var2\n" +
6403 "%7 = OpFMul %float %4 %6\n" +
6404 "%8 = OpFMul %float %5 %6\n" +
6405 "%9 = OpFAdd %float %7 %8\n" +
6406 "OpReturn\n" +
6407 "OpFunctionEnd\n",
6408 9, true)
6409 ));
6410
6411 INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
6412 ::testing::Values(
6413 // Test case 0: merge sub of negate
6414 // (-x) - 2 = -2 - x
6415 InstructionFoldingCase<bool>(
6416 Header() +
6417 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6418 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
6419 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6420 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
6421 "%main = OpFunction %void None %void_func\n" +
6422 "%main_lab = OpLabel\n" +
6423 "%var = OpVariable %_ptr_float Function\n" +
6424 "%2 = OpLoad %float %var\n" +
6425 "%3 = OpFNegate %float %2\n" +
6426 "%4 = OpFSub %float %3 %float_2\n" +
6427 "OpReturn\n" +
6428 "OpFunctionEnd\n",
6429 4, true),
6430 // Test case 1: merge sub of negate
6431 // 2 - (-x) = x + 2
6432 InstructionFoldingCase<bool>(
6433 Header() +
6434 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6435 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6436 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6437 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
6438 "%main = OpFunction %void None %void_func\n" +
6439 "%main_lab = OpLabel\n" +
6440 "%var = OpVariable %_ptr_float Function\n" +
6441 "%2 = OpLoad %float %var\n" +
6442 "%3 = OpFNegate %float %2\n" +
6443 "%4 = OpFSub %float %float_2 %3\n" +
6444 "OpReturn\n" +
6445 "OpFunctionEnd\n",
6446 4, true),
6447 // Test case 2: merge sub of negate
6448 // (-x) - 2 = -2 - x
6449 InstructionFoldingCase<bool>(
6450 Header() +
6451 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6452 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
6453 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6454 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
6455 "%main = OpFunction %void None %void_func\n" +
6456 "%main_lab = OpLabel\n" +
6457 "%var = OpVariable %_ptr_long Function\n" +
6458 "%2 = OpLoad %long %var\n" +
6459 "%3 = OpSNegate %long %2\n" +
6460 "%4 = OpISub %long %3 %long_2\n" +
6461 "OpReturn\n" +
6462 "OpFunctionEnd\n",
6463 4, true),
6464 // Test case 3: merge sub of negate
6465 // 2 - (-x) = x + 2
6466 InstructionFoldingCase<bool>(
6467 Header() +
6468 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6469 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6470 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6471 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
6472 "%main = OpFunction %void None %void_func\n" +
6473 "%main_lab = OpLabel\n" +
6474 "%var = OpVariable %_ptr_long Function\n" +
6475 "%2 = OpLoad %long %var\n" +
6476 "%3 = OpSNegate %long %2\n" +
6477 "%4 = OpISub %long %long_2 %3\n" +
6478 "OpReturn\n" +
6479 "OpFunctionEnd\n",
6480 4, true),
6481 // Test case 4: merge add of subtract
6482 // (x + 2) - 1 = x + 1
6483 InstructionFoldingCase<bool>(
6484 Header() +
6485 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6486 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6487 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6488 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6489 "%main = OpFunction %void None %void_func\n" +
6490 "%main_lab = OpLabel\n" +
6491 "%var = OpVariable %_ptr_float Function\n" +
6492 "%2 = OpLoad %float %var\n" +
6493 "%3 = OpFAdd %float %2 %float_2\n" +
6494 "%4 = OpFSub %float %3 %float_1\n" +
6495 "OpReturn\n" +
6496 "OpFunctionEnd\n",
6497 4, true),
6498 // Test case 5: merge add of subtract
6499 // (2 + x) - 1 = x + 1
6500 InstructionFoldingCase<bool>(
6501 Header() +
6502 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6503 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6504 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6505 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6506 "%main = OpFunction %void None %void_func\n" +
6507 "%main_lab = OpLabel\n" +
6508 "%var = OpVariable %_ptr_float Function\n" +
6509 "%2 = OpLoad %float %var\n" +
6510 "%3 = OpFAdd %float %float_2 %2\n" +
6511 "%4 = OpFSub %float %3 %float_1\n" +
6512 "OpReturn\n" +
6513 "OpFunctionEnd\n",
6514 4, true),
6515 // Test case 6: merge add of subtract
6516 // 2 - (x + 1) = 1 - x
6517 InstructionFoldingCase<bool>(
6518 Header() +
6519 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6520 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6521 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6522 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6523 "%main = OpFunction %void None %void_func\n" +
6524 "%main_lab = OpLabel\n" +
6525 "%var = OpVariable %_ptr_float Function\n" +
6526 "%2 = OpLoad %float %var\n" +
6527 "%3 = OpFAdd %float %2 %float_1\n" +
6528 "%4 = OpFSub %float %float_2 %3\n" +
6529 "OpReturn\n" +
6530 "OpFunctionEnd\n",
6531 4, true),
6532 // Test case 7: merge add of subtract
6533 // 2 - (1 + x) = 1 - x
6534 InstructionFoldingCase<bool>(
6535 Header() +
6536 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6537 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6538 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6539 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6540 "%main = OpFunction %void None %void_func\n" +
6541 "%main_lab = OpLabel\n" +
6542 "%var = OpVariable %_ptr_float Function\n" +
6543 "%2 = OpLoad %float %var\n" +
6544 "%3 = OpFAdd %float %float_1 %2\n" +
6545 "%4 = OpFSub %float %float_2 %3\n" +
6546 "OpReturn\n" +
6547 "OpFunctionEnd\n",
6548 4, true),
6549 // Test case 8: merge subtract of subtract
6550 // (x - 2) - 1 = x - 3
6551 InstructionFoldingCase<bool>(
6552 Header() +
6553 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6554 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6555 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6556 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
6557 "%main = OpFunction %void None %void_func\n" +
6558 "%main_lab = OpLabel\n" +
6559 "%var = OpVariable %_ptr_float Function\n" +
6560 "%2 = OpLoad %float %var\n" +
6561 "%3 = OpFSub %float %2 %float_2\n" +
6562 "%4 = OpFSub %float %3 %float_1\n" +
6563 "OpReturn\n" +
6564 "OpFunctionEnd\n",
6565 4, true),
6566 // Test case 9: merge subtract of subtract
6567 // (2 - x) - 1 = 1 - x
6568 InstructionFoldingCase<bool>(
6569 Header() +
6570 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6571 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6572 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6573 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6574 "%main = OpFunction %void None %void_func\n" +
6575 "%main_lab = OpLabel\n" +
6576 "%var = OpVariable %_ptr_float Function\n" +
6577 "%2 = OpLoad %float %var\n" +
6578 "%3 = OpFSub %float %float_2 %2\n" +
6579 "%4 = OpFSub %float %3 %float_1\n" +
6580 "OpReturn\n" +
6581 "OpFunctionEnd\n",
6582 4, true),
6583 // Test case 10: merge subtract of subtract
6584 // 2 - (x - 1) = 3 - x
6585 InstructionFoldingCase<bool>(
6586 Header() +
6587 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6588 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6589 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6590 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6591 "%main = OpFunction %void None %void_func\n" +
6592 "%main_lab = OpLabel\n" +
6593 "%var = OpVariable %_ptr_float Function\n" +
6594 "%2 = OpLoad %float %var\n" +
6595 "%3 = OpFSub %float %2 %float_1\n" +
6596 "%4 = OpFSub %float %float_2 %3\n" +
6597 "OpReturn\n" +
6598 "OpFunctionEnd\n",
6599 4, true),
6600 // Test case 11: merge subtract of subtract
6601 // 1 - (2 - x) = x + (-1)
6602 InstructionFoldingCase<bool>(
6603 Header() +
6604 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6605 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
6606 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6607 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
6608 "%main = OpFunction %void None %void_func\n" +
6609 "%main_lab = OpLabel\n" +
6610 "%var = OpVariable %_ptr_float Function\n" +
6611 "%2 = OpLoad %float %var\n" +
6612 "%3 = OpFSub %float %float_2 %2\n" +
6613 "%4 = OpFSub %float %float_1 %3\n" +
6614 "OpReturn\n" +
6615 "OpFunctionEnd\n",
6616 4, true),
6617 // Test case 12: merge subtract of subtract
6618 // 2 - (1 - x) = x + 1
6619 InstructionFoldingCase<bool>(
6620 Header() +
6621 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6622 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6623 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6624 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6625 "%main = OpFunction %void None %void_func\n" +
6626 "%main_lab = OpLabel\n" +
6627 "%var = OpVariable %_ptr_float Function\n" +
6628 "%2 = OpLoad %float %var\n" +
6629 "%3 = OpFSub %float %float_1 %2\n" +
6630 "%4 = OpFSub %float %float_2 %3\n" +
6631 "OpReturn\n" +
6632 "OpFunctionEnd\n",
6633 4, true),
6634 // Test case 13: merge subtract of subtract with mixed types.
6635 // 2 - (1 - x) = x + 1
6636 InstructionFoldingCase<bool>(
6637 Header() +
6638 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6639 "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" +
6640 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6641 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" +
6642 "%main = OpFunction %void None %void_func\n" +
6643 "%main_lab = OpLabel\n" +
6644 "%var = OpVariable %_ptr_int Function\n" +
6645 "%2 = OpLoad %int %var\n" +
6646 "%3 = OpISub %int %uint_1 %2\n" +
6647 "%4 = OpISub %int %int_2 %3\n" +
6648 "OpReturn\n" +
6649 "OpFunctionEnd\n",
6650 4, true),
6651 // Test case 14: fold overflowing signed 32 bit isubs
6652 // (x - int_max) - 1 = x - int_min
6653 InstructionFoldingCase<bool>(
6654 Header() +
6655 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6656 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6657 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6658 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" +
6659 "%main = OpFunction %void None %void_func\n" +
6660 "%main_lab = OpLabel\n" +
6661 "%var = OpVariable %_ptr_int Function\n" +
6662 "%2 = OpLoad %int %var\n" +
6663 "%3 = OpISub %int %2 %int_max\n" +
6664 "%4 = OpISub %int %3 %int_1\n" +
6665 "OpReturn\n" +
6666 "OpFunctionEnd\n",
6667 4, true),
6668 // Test case 15: fold overflowing signed 64 bit isubs
6669 // (x - long_max) - 1 = x - long_min
6670 InstructionFoldingCase<bool>(
6671 Header() +
6672 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6673 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6674 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6675 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" +
6676 "%main = OpFunction %void None %void_func\n" +
6677 "%main_lab = OpLabel\n" +
6678 "%var = OpVariable %_ptr_long Function\n" +
6679 "%2 = OpLoad %long %var\n" +
6680 "%3 = OpISub %long %2 %long_max\n" +
6681 "%4 = OpISub %long %3 %long_1\n" +
6682 "OpReturn\n" +
6683 "OpFunctionEnd\n",
6684 4, true)
6685 ));
6686
6687 INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
6688 ::testing::Values(
6689 // Test case 0: Fold select with the same values for both sides
6690 InstructionFoldingCase<bool>(
6691 Header() +
6692 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6693 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6694 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
6695 "%main = OpFunction %void None %void_func\n" +
6696 "%main_lab = OpLabel\n" +
6697 "%n = OpVariable %_ptr_bool Function\n" +
6698 "%load = OpLoad %bool %n\n" +
6699 "%2 = OpSelect %int %load %100 %100\n" +
6700 "OpReturn\n" +
6701 "OpFunctionEnd",
6702 2, true),
6703 // Test case 1: Fold select true to left side
6704 InstructionFoldingCase<bool>(
6705 Header() +
6706 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6707 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6708 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
6709 "%main = OpFunction %void None %void_func\n" +
6710 "%main_lab = OpLabel\n" +
6711 "%n = OpVariable %_ptr_int Function\n" +
6712 "%load = OpLoad %bool %n\n" +
6713 "%2 = OpSelect %int %true %100 %n\n" +
6714 "OpReturn\n" +
6715 "OpFunctionEnd",
6716 2, true),
6717 // Test case 2: Fold select false to right side
6718 InstructionFoldingCase<bool>(
6719 Header() +
6720 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6721 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6722 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
6723 "%main = OpFunction %void None %void_func\n" +
6724 "%main_lab = OpLabel\n" +
6725 "%n = OpVariable %_ptr_int Function\n" +
6726 "%load = OpLoad %bool %n\n" +
6727 "%2 = OpSelect %int %false %n %100\n" +
6728 "OpReturn\n" +
6729 "OpFunctionEnd",
6730 2, true),
6731 // Test case 3: Fold select null to right side
6732 InstructionFoldingCase<bool>(
6733 Header() +
6734 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6735 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6736 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
6737 "%main = OpFunction %void None %void_func\n" +
6738 "%main_lab = OpLabel\n" +
6739 "%n = OpVariable %_ptr_int Function\n" +
6740 "%load = OpLoad %int %n\n" +
6741 "%2 = OpSelect %int %bool_null %load %100\n" +
6742 "OpReturn\n" +
6743 "OpFunctionEnd",
6744 2, true),
6745 // Test case 4: vector null
6746 InstructionFoldingCase<bool>(
6747 Header() +
6748 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6749 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
6750 "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
6751 "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
6752 "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
6753 "%main = OpFunction %void None %void_func\n" +
6754 "%main_lab = OpLabel\n" +
6755 "%n = OpVariable %_ptr_v2int Function\n" +
6756 "%load = OpLoad %v2int %n\n" +
6757 "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
6758 "OpReturn\n" +
6759 "OpFunctionEnd",
6760 2, true),
6761 // Test case 5: vector select
6762 InstructionFoldingCase<bool>(
6763 Header() +
6764 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6765 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
6766 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
6767 "%main = OpFunction %void None %void_func\n" +
6768 "%main_lab = OpLabel\n" +
6769 "%m = OpVariable %_ptr_v2int Function\n" +
6770 "%n = OpVariable %_ptr_v2int Function\n" +
6771 "%2 = OpLoad %v2int %n\n" +
6772 "%3 = OpLoad %v2int %n\n" +
6773 "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
6774 "OpReturn\n" +
6775 "OpFunctionEnd",
6776 4, true),
6777 // Test case 6: vector select
6778 InstructionFoldingCase<bool>(
6779 Header() +
6780 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6781 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
6782 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
6783 "%main = OpFunction %void None %void_func\n" +
6784 "%main_lab = OpLabel\n" +
6785 "%m = OpVariable %_ptr_v2int Function\n" +
6786 "%n = OpVariable %_ptr_v2int Function\n" +
6787 "%2 = OpLoad %v2int %n\n" +
6788 "%3 = OpLoad %v2int %n\n" +
6789 "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
6790 "OpReturn\n" +
6791 "OpFunctionEnd",
6792 4, true)
6793 ));
6794
6795 INSTANTIATE_TEST_SUITE_P(CompositeExtractMatchingTest, MatchingInstructionFoldingTest,
6796 ::testing::Values(
6797 // Test case 0: Extracting from result of consecutive shuffles of differing
6798 // size.
6799 InstructionFoldingCase<bool>(
6800 Header() +
6801 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6802 "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
6803 "%main = OpFunction %void None %void_func\n" +
6804 "%main_lab = OpLabel\n" +
6805 "%n = OpVariable %_ptr_v4int Function\n" +
6806 "%2 = OpLoad %v4int %n\n" +
6807 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
6808 "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
6809 "%5 = OpCompositeExtract %int %4 1\n" +
6810 "OpReturn\n" +
6811 "OpFunctionEnd",
6812 5, true),
6813 // Test case 1: Extracting from result of vector shuffle of differing
6814 // input and result sizes.
6815 InstructionFoldingCase<bool>(
6816 Header() +
6817 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6818 "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
6819 "%main = OpFunction %void None %void_func\n" +
6820 "%main_lab = OpLabel\n" +
6821 "%n = OpVariable %_ptr_v4int Function\n" +
6822 "%2 = OpLoad %v4int %n\n" +
6823 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
6824 "%4 = OpCompositeExtract %int %3 0\n" +
6825 "OpReturn\n" +
6826 "OpFunctionEnd",
6827 4, true),
6828 // Test case 2: Extracting from result of vector shuffle of differing
6829 // input and result sizes.
6830 InstructionFoldingCase<bool>(
6831 Header() +
6832 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6833 "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
6834 "%main = OpFunction %void None %void_func\n" +
6835 "%main_lab = OpLabel\n" +
6836 "%n = OpVariable %_ptr_v4int Function\n" +
6837 "%2 = OpLoad %v4int %n\n" +
6838 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
6839 "%4 = OpCompositeExtract %int %3 1\n" +
6840 "OpReturn\n" +
6841 "OpFunctionEnd",
6842 4, true),
6843 // Test case 3: Using fmix feeding extract with a 1 in the a position.
6844 InstructionFoldingCase<bool>(
6845 Header() +
6846 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6847 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
6848 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
6849 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6850 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6851 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
6852 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
6853 "%main = OpFunction %void None %void_func\n" +
6854 "%main_lab = OpLabel\n" +
6855 "%m = OpVariable %_ptr_v4double Function\n" +
6856 "%n = OpVariable %_ptr_v4double Function\n" +
6857 "%2 = OpLoad %v4double %m\n" +
6858 "%3 = OpLoad %v4double %n\n" +
6859 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
6860 "%5 = OpCompositeExtract %double %4 1\n" +
6861 "OpReturn\n" +
6862 "OpFunctionEnd",
6863 5, true),
6864 // Test case 4: Using fmix feeding extract with a 0 in the a position.
6865 InstructionFoldingCase<bool>(
6866 Header() +
6867 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6868 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
6869 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
6870 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6871 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6872 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
6873 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
6874 "%main = OpFunction %void None %void_func\n" +
6875 "%main_lab = OpLabel\n" +
6876 "%m = OpVariable %_ptr_v4double Function\n" +
6877 "%n = OpVariable %_ptr_v4double Function\n" +
6878 "%2 = OpLoad %v4double %m\n" +
6879 "%3 = OpLoad %v4double %n\n" +
6880 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
6881 "%5 = OpCompositeExtract %double %4 2\n" +
6882 "OpReturn\n" +
6883 "OpFunctionEnd",
6884 5, true),
6885 // Test case 5: Using fmix feeding extract with a null for the alpha
6886 InstructionFoldingCase<bool>(
6887 Header() +
6888 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6889 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
6890 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
6891 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6892 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
6893 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
6894 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
6895 "%main = OpFunction %void None %void_func\n" +
6896 "%main_lab = OpLabel\n" +
6897 "%m = OpVariable %_ptr_v4double Function\n" +
6898 "%n = OpVariable %_ptr_v4double Function\n" +
6899 "%2 = OpLoad %v4double %m\n" +
6900 "%3 = OpLoad %v4double %n\n" +
6901 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
6902 "%5 = OpCompositeExtract %double %4 0\n" +
6903 "OpReturn\n" +
6904 "OpFunctionEnd",
6905 5, true),
6906 // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
6907 // position.
6908 InstructionFoldingCase<bool>(
6909 Header() +
6910 "%main = OpFunction %void None %void_func\n" +
6911 "%main_lab = OpLabel\n" +
6912 "%m = OpVariable %_ptr_v4double Function\n" +
6913 "%n = OpVariable %_ptr_v4double Function\n" +
6914 "%2 = OpLoad %v4double %m\n" +
6915 "%3 = OpLoad %v4double %n\n" +
6916 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
6917 "%5 = OpCompositeExtract %double %4 3\n" +
6918 "OpReturn\n" +
6919 "OpFunctionEnd",
6920 5, false),
6921 // Test case 7: Extracting the undefined literal value from a vector
6922 // shuffle.
6923 InstructionFoldingCase<bool>(
6924 Header() +
6925 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6926 "; CHECK: %4 = OpUndef [[int]]\n" +
6927 "%main = OpFunction %void None %void_func\n" +
6928 "%main_lab = OpLabel\n" +
6929 "%n = OpVariable %_ptr_v4int Function\n" +
6930 "%2 = OpLoad %v4int %n\n" +
6931 "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
6932 "%4 = OpCompositeExtract %int %3 1\n" +
6933 "OpReturn\n" +
6934 "OpFunctionEnd",
6935 4, true)
6936 ));
6937
6938 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
6939 ::testing::Values(
6940 // Test case 0: Using OpDot to extract last element.
6941 InstructionFoldingCase<bool>(
6942 Header() +
6943 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6944 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
6945 "%main = OpFunction %void None %void_func\n" +
6946 "%main_lab = OpLabel\n" +
6947 "%n = OpVariable %_ptr_v4float Function\n" +
6948 "%2 = OpLoad %v4float %n\n" +
6949 "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
6950 "OpReturn\n" +
6951 "OpFunctionEnd",
6952 3, true),
6953 // Test case 1: Using OpDot to extract last element.
6954 InstructionFoldingCase<bool>(
6955 Header() +
6956 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6957 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
6958 "%main = OpFunction %void None %void_func\n" +
6959 "%main_lab = OpLabel\n" +
6960 "%n = OpVariable %_ptr_v4float Function\n" +
6961 "%2 = OpLoad %v4float %n\n" +
6962 "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
6963 "OpReturn\n" +
6964 "OpFunctionEnd",
6965 3, true),
6966 // Test case 2: Using OpDot to extract second element.
6967 InstructionFoldingCase<bool>(
6968 Header() +
6969 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6970 "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
6971 "%main = OpFunction %void None %void_func\n" +
6972 "%main_lab = OpLabel\n" +
6973 "%n = OpVariable %_ptr_v4float Function\n" +
6974 "%2 = OpLoad %v4float %n\n" +
6975 "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
6976 "OpReturn\n" +
6977 "OpFunctionEnd",
6978 3, true),
6979 // Test case 3: Using OpDot to extract last element.
6980 InstructionFoldingCase<bool>(
6981 Header() +
6982 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6983 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
6984 "%main = OpFunction %void None %void_func\n" +
6985 "%main_lab = OpLabel\n" +
6986 "%n = OpVariable %_ptr_v4double Function\n" +
6987 "%2 = OpLoad %v4double %n\n" +
6988 "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
6989 "OpReturn\n" +
6990 "OpFunctionEnd",
6991 3, true),
6992 // Test case 4: Using OpDot to extract last element.
6993 InstructionFoldingCase<bool>(
6994 Header() +
6995 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
6996 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
6997 "%main = OpFunction %void None %void_func\n" +
6998 "%main_lab = OpLabel\n" +
6999 "%n = OpVariable %_ptr_v4double Function\n" +
7000 "%2 = OpLoad %v4double %n\n" +
7001 "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
7002 "OpReturn\n" +
7003 "OpFunctionEnd",
7004 3, true),
7005 // Test case 5: Using OpDot to extract second element.
7006 InstructionFoldingCase<bool>(
7007 Header() +
7008 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7009 "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
7010 "%main = OpFunction %void None %void_func\n" +
7011 "%main_lab = OpLabel\n" +
7012 "%n = OpVariable %_ptr_v4double Function\n" +
7013 "%2 = OpLoad %v4double %n\n" +
7014 "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
7015 "OpReturn\n" +
7016 "OpFunctionEnd",
7017 3, true)
7018 ));
7019
7020 using MatchingInstructionWithNoResultFoldingTest =
7021 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
7022
7023 // Test folding instructions that do not have a result. The instruction
7024 // that will be folded is the last instruction before the return. If there
7025 // are multiple returns, there is not guarentee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest,Case)7026 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
7027 const auto& tc = GetParam();
7028
7029 // Build module.
7030 std::unique_ptr<IRContext> context =
7031 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
7032 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
7033 ASSERT_NE(nullptr, context);
7034
7035 // Fold the instruction to test.
7036 Instruction* inst = nullptr;
7037 Function* func = &*context->module()->begin();
7038 for (auto& bb : *func) {
7039 Instruction* terminator = bb.terminator();
7040 if (terminator->IsReturnOrAbort()) {
7041 inst = terminator->PreviousNode();
7042 break;
7043 }
7044 }
7045 assert(inst && "Invalid test. Could not find instruction to fold.");
7046 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
7047 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
7048 EXPECT_EQ(succeeded, tc.expected_result);
7049 if (succeeded) {
7050 Match(tc.test_body, context.get());
7051 }
7052 }
7053
7054 INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
7055 ::testing::Values(
7056 // Test case 0: Remove store of undef.
7057 InstructionFoldingCase<bool>(
7058 Header() +
7059 "; CHECK: OpLabel\n" +
7060 "; CHECK-NOT: OpStore\n" +
7061 "; CHECK: OpReturn\n" +
7062 "%main = OpFunction %void None %void_func\n" +
7063 "%main_lab = OpLabel\n" +
7064 "%n = OpVariable %_ptr_v4double Function\n" +
7065 "%undef = OpUndef %v4double\n" +
7066 "OpStore %n %undef\n" +
7067 "OpReturn\n" +
7068 "OpFunctionEnd",
7069 0 /* OpStore */, true),
7070 // Test case 1: Keep volatile store.
7071 InstructionFoldingCase<bool>(
7072 Header() +
7073 "%main = OpFunction %void None %void_func\n" +
7074 "%main_lab = OpLabel\n" +
7075 "%n = OpVariable %_ptr_v4double Function\n" +
7076 "%undef = OpUndef %v4double\n" +
7077 "OpStore %n %undef Volatile\n" +
7078 "OpReturn\n" +
7079 "OpFunctionEnd",
7080 0 /* OpStore */, false)
7081 ));
7082
7083 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
7084 ::testing::Values(
7085 // Test case 0: Basic test 1
7086 InstructionFoldingCase<bool>(
7087 Header() +
7088 "; CHECK: OpVectorShuffle\n" +
7089 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
7090 "; CHECK: OpReturn\n" +
7091 "%main = OpFunction %void None %void_func\n" +
7092 "%main_lab = OpLabel\n" +
7093 "%2 = OpVariable %_ptr_v4double Function\n" +
7094 "%3 = OpVariable %_ptr_v4double Function\n" +
7095 "%4 = OpVariable %_ptr_v4double Function\n" +
7096 "%5 = OpLoad %v4double %2\n" +
7097 "%6 = OpLoad %v4double %3\n" +
7098 "%7 = OpLoad %v4double %4\n" +
7099 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7100 "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
7101 "OpReturn\n" +
7102 "OpFunctionEnd",
7103 9, true),
7104 // Test case 1: Basic test 2
7105 InstructionFoldingCase<bool>(
7106 Header() +
7107 "; CHECK: OpVectorShuffle\n" +
7108 "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
7109 "; CHECK: OpReturn\n" +
7110 "%main = OpFunction %void None %void_func\n" +
7111 "%main_lab = OpLabel\n" +
7112 "%2 = OpVariable %_ptr_v4double Function\n" +
7113 "%3 = OpVariable %_ptr_v4double Function\n" +
7114 "%4 = OpVariable %_ptr_v4double Function\n" +
7115 "%5 = OpLoad %v4double %2\n" +
7116 "%6 = OpLoad %v4double %3\n" +
7117 "%7 = OpLoad %v4double %4\n" +
7118 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7119 "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
7120 "OpReturn\n" +
7121 "OpFunctionEnd",
7122 9, true),
7123 // Test case 2: Basic test 3
7124 InstructionFoldingCase<bool>(
7125 Header() +
7126 "; CHECK: OpVectorShuffle\n" +
7127 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
7128 "; CHECK: OpReturn\n" +
7129 "%main = OpFunction %void None %void_func\n" +
7130 "%main_lab = OpLabel\n" +
7131 "%2 = OpVariable %_ptr_v4double Function\n" +
7132 "%3 = OpVariable %_ptr_v4double Function\n" +
7133 "%4 = OpVariable %_ptr_v4double Function\n" +
7134 "%5 = OpLoad %v4double %2\n" +
7135 "%6 = OpLoad %v4double %3\n" +
7136 "%7 = OpLoad %v4double %4\n" +
7137 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7138 "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
7139 "OpReturn\n" +
7140 "OpFunctionEnd",
7141 9, true),
7142 // Test case 3: Basic test 4
7143 InstructionFoldingCase<bool>(
7144 Header() +
7145 "; CHECK: OpVectorShuffle\n" +
7146 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
7147 "; CHECK: OpReturn\n" +
7148 "%main = OpFunction %void None %void_func\n" +
7149 "%main_lab = OpLabel\n" +
7150 "%2 = OpVariable %_ptr_v4double Function\n" +
7151 "%3 = OpVariable %_ptr_v4double Function\n" +
7152 "%4 = OpVariable %_ptr_v4double Function\n" +
7153 "%5 = OpLoad %v4double %2\n" +
7154 "%6 = OpLoad %v4double %3\n" +
7155 "%7 = OpLoad %v4double %4\n" +
7156 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7157 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
7158 "OpReturn\n" +
7159 "OpFunctionEnd",
7160 9, true),
7161 // Test case 4: Don't fold, need both operands of the feeder.
7162 InstructionFoldingCase<bool>(
7163 Header() +
7164 "%main = OpFunction %void None %void_func\n" +
7165 "%main_lab = OpLabel\n" +
7166 "%2 = OpVariable %_ptr_v4double Function\n" +
7167 "%3 = OpVariable %_ptr_v4double Function\n" +
7168 "%4 = OpVariable %_ptr_v4double Function\n" +
7169 "%5 = OpLoad %v4double %2\n" +
7170 "%6 = OpLoad %v4double %3\n" +
7171 "%7 = OpLoad %v4double %4\n" +
7172 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7173 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
7174 "OpReturn\n" +
7175 "OpFunctionEnd",
7176 9, false),
7177 // Test case 5: Don't fold, need both operands of the feeder.
7178 InstructionFoldingCase<bool>(
7179 Header() +
7180 "%main = OpFunction %void None %void_func\n" +
7181 "%main_lab = OpLabel\n" +
7182 "%2 = OpVariable %_ptr_v4double Function\n" +
7183 "%3 = OpVariable %_ptr_v4double Function\n" +
7184 "%4 = OpVariable %_ptr_v4double Function\n" +
7185 "%5 = OpLoad %v4double %2\n" +
7186 "%6 = OpLoad %v4double %3\n" +
7187 "%7 = OpLoad %v4double %4\n" +
7188 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7189 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7190 "OpReturn\n" +
7191 "OpFunctionEnd",
7192 9, false),
7193 // Test case 6: Fold, need both operands of the feeder, but they are the same.
7194 InstructionFoldingCase<bool>(
7195 Header() +
7196 "; CHECK: OpVectorShuffle\n" +
7197 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
7198 "; CHECK: OpReturn\n" +
7199 "%main = OpFunction %void None %void_func\n" +
7200 "%main_lab = OpLabel\n" +
7201 "%2 = OpVariable %_ptr_v4double Function\n" +
7202 "%3 = OpVariable %_ptr_v4double Function\n" +
7203 "%4 = OpVariable %_ptr_v4double Function\n" +
7204 "%5 = OpLoad %v4double %2\n" +
7205 "%6 = OpLoad %v4double %3\n" +
7206 "%7 = OpLoad %v4double %4\n" +
7207 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
7208 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7209 "OpReturn\n" +
7210 "OpFunctionEnd",
7211 9, true),
7212 // Test case 7: Fold, need both operands of the feeder, but they are the same.
7213 InstructionFoldingCase<bool>(
7214 Header() +
7215 "; CHECK: OpVectorShuffle\n" +
7216 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
7217 "; CHECK: OpReturn\n" +
7218 "%main = OpFunction %void None %void_func\n" +
7219 "%main_lab = OpLabel\n" +
7220 "%2 = OpVariable %_ptr_v4double Function\n" +
7221 "%3 = OpVariable %_ptr_v4double Function\n" +
7222 "%4 = OpVariable %_ptr_v4double Function\n" +
7223 "%5 = OpLoad %v4double %2\n" +
7224 "%6 = OpLoad %v4double %3\n" +
7225 "%7 = OpLoad %v4double %4\n" +
7226 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
7227 "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
7228 "OpReturn\n" +
7229 "OpFunctionEnd",
7230 9, true),
7231 // Test case 8: Replace first operand with a smaller vector.
7232 InstructionFoldingCase<bool>(
7233 Header() +
7234 "; CHECK: OpVectorShuffle\n" +
7235 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
7236 "; CHECK: OpReturn\n" +
7237 "%main = OpFunction %void None %void_func\n" +
7238 "%main_lab = OpLabel\n" +
7239 "%2 = OpVariable %_ptr_v2double Function\n" +
7240 "%3 = OpVariable %_ptr_v4double Function\n" +
7241 "%4 = OpVariable %_ptr_v4double Function\n" +
7242 "%5 = OpLoad %v2double %2\n" +
7243 "%6 = OpLoad %v4double %3\n" +
7244 "%7 = OpLoad %v4double %4\n" +
7245 "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
7246 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7247 "OpReturn\n" +
7248 "OpFunctionEnd",
7249 9, true),
7250 // Test case 9: Replace first operand with a larger vector.
7251 InstructionFoldingCase<bool>(
7252 Header() +
7253 "; CHECK: OpVectorShuffle\n" +
7254 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
7255 "; CHECK: OpReturn\n" +
7256 "%main = OpFunction %void None %void_func\n" +
7257 "%main_lab = OpLabel\n" +
7258 "%2 = OpVariable %_ptr_v4double Function\n" +
7259 "%3 = OpVariable %_ptr_v4double Function\n" +
7260 "%4 = OpVariable %_ptr_v4double Function\n" +
7261 "%5 = OpLoad %v4double %2\n" +
7262 "%6 = OpLoad %v4double %3\n" +
7263 "%7 = OpLoad %v4double %4\n" +
7264 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
7265 "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
7266 "OpReturn\n" +
7267 "OpFunctionEnd",
7268 9, true),
7269 // Test case 10: Replace unused operand with null.
7270 InstructionFoldingCase<bool>(
7271 Header() +
7272 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7273 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
7274 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
7275 "; CHECK: OpVectorShuffle\n" +
7276 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
7277 "; CHECK: OpReturn\n" +
7278 "%main = OpFunction %void None %void_func\n" +
7279 "%main_lab = OpLabel\n" +
7280 "%2 = OpVariable %_ptr_v4double Function\n" +
7281 "%3 = OpVariable %_ptr_v4double Function\n" +
7282 "%4 = OpVariable %_ptr_v4double Function\n" +
7283 "%5 = OpLoad %v4double %2\n" +
7284 "%6 = OpLoad %v4double %3\n" +
7285 "%7 = OpLoad %v4double %4\n" +
7286 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
7287 "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
7288 "OpReturn\n" +
7289 "OpFunctionEnd",
7290 9, true),
7291 // Test case 11: Replace unused operand with null.
7292 InstructionFoldingCase<bool>(
7293 Header() +
7294 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7295 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
7296 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
7297 "; CHECK: OpVectorShuffle\n" +
7298 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
7299 "; CHECK: OpReturn\n" +
7300 "%main = OpFunction %void None %void_func\n" +
7301 "%main_lab = OpLabel\n" +
7302 "%2 = OpVariable %_ptr_v4double Function\n" +
7303 "%3 = OpVariable %_ptr_v4double Function\n" +
7304 "%5 = OpLoad %v4double %2\n" +
7305 "%6 = OpLoad %v4double %3\n" +
7306 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
7307 "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
7308 "OpReturn\n" +
7309 "OpFunctionEnd",
7310 9, true),
7311 // Test case 12: Replace unused operand with null.
7312 InstructionFoldingCase<bool>(
7313 Header() +
7314 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7315 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
7316 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
7317 "; CHECK: OpVectorShuffle\n" +
7318 "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
7319 "; CHECK: OpReturn\n" +
7320 "%main = OpFunction %void None %void_func\n" +
7321 "%main_lab = OpLabel\n" +
7322 "%2 = OpVariable %_ptr_v4double Function\n" +
7323 "%3 = OpVariable %_ptr_v4double Function\n" +
7324 "%4 = OpVariable %_ptr_v4double Function\n" +
7325 "%5 = OpLoad %v4double %2\n" +
7326 "%6 = OpLoad %v4double %3\n" +
7327 "%7 = OpLoad %v4double %4\n" +
7328 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
7329 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
7330 "OpReturn\n" +
7331 "OpFunctionEnd",
7332 9, true),
7333 // Test case 13: Shuffle with undef literal.
7334 InstructionFoldingCase<bool>(
7335 Header() +
7336 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7337 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
7338 "; CHECK: OpVectorShuffle\n" +
7339 "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
7340 "; CHECK: OpReturn\n" +
7341 "%main = OpFunction %void None %void_func\n" +
7342 "%main_lab = OpLabel\n" +
7343 "%2 = OpVariable %_ptr_v4double Function\n" +
7344 "%3 = OpVariable %_ptr_v4double Function\n" +
7345 "%4 = OpVariable %_ptr_v4double Function\n" +
7346 "%5 = OpLoad %v4double %2\n" +
7347 "%6 = OpLoad %v4double %3\n" +
7348 "%7 = OpLoad %v4double %4\n" +
7349 "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
7350 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
7351 "OpReturn\n" +
7352 "OpFunctionEnd",
7353 9, true)
7354 ));
7355
7356 using EntryPointFoldingTest =
7357 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
7358
TEST_P(EntryPointFoldingTest,Case)7359 TEST_P(EntryPointFoldingTest, Case) {
7360 const auto& tc = GetParam();
7361
7362 // Build module.
7363 std::unique_ptr<IRContext> context =
7364 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
7365 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
7366 ASSERT_NE(nullptr, context);
7367
7368 // Fold the instruction to test.
7369 Instruction* inst = nullptr;
7370 inst = &*context->module()->entry_points().begin();
7371 assert(inst && "Invalid test. Could not find entry point instruction to fold.");
7372 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
7373 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
7374 EXPECT_EQ(succeeded, tc.expected_result);
7375 if (succeeded) {
7376 Match(tc.test_body, context.get());
7377 }
7378 }
7379
7380 INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest,
7381 ::testing::Values(
7382 // Test case 0: Basic test 1
7383 InstructionFoldingCase<bool>(std::string() +
7384 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" +
7385 "OpCapability Shader\n" +
7386 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
7387 "OpMemoryModel Logical GLSL450\n" +
7388 "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" +
7389 "OpExecutionMode %2 OriginUpperLeft\n" +
7390 "OpSource GLSL 430\n" +
7391 "OpDecorate %3 Location 0\n" +
7392 "%void = OpTypeVoid\n" +
7393 "%5 = OpTypeFunction %void\n" +
7394 "%float = OpTypeFloat 32\n" +
7395 "%v4float = OpTypeVector %float 4\n" +
7396 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
7397 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
7398 "%int = OpTypeInt 32 1\n" +
7399 "%int_0 = OpConstant %int 0\n" +
7400 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
7401 "%2 = OpFunction %void None %5\n" +
7402 "%12 = OpLabel\n" +
7403 "OpReturn\n" +
7404 "OpFunctionEnd\n",
7405 9, true),
7406 InstructionFoldingCase<bool>(std::string() +
7407 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" +
7408 "OpCapability Shader\n" +
7409 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
7410 "OpMemoryModel Logical GLSL450\n" +
7411 "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" +
7412 "OpExecutionMode %2 OriginUpperLeft\n" +
7413 "OpSource GLSL 430\n" +
7414 "OpDecorate %3 Location 0\n" +
7415 "%void = OpTypeVoid\n" +
7416 "%5 = OpTypeFunction %void\n" +
7417 "%float = OpTypeFloat 32\n" +
7418 "%v4float = OpTypeVector %float 4\n" +
7419 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
7420 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
7421 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
7422 "%int = OpTypeInt 32 1\n" +
7423 "%int_0 = OpConstant %int 0\n" +
7424 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
7425 "%2 = OpFunction %void None %5\n" +
7426 "%12 = OpLabel\n" +
7427 "OpReturn\n" +
7428 "OpFunctionEnd\n",
7429 9, true),
7430 InstructionFoldingCase<bool>(std::string() +
7431 "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" +
7432 "OpCapability Shader\n" +
7433 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
7434 "OpMemoryModel Logical GLSL450\n" +
7435 "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" +
7436 "OpExecutionMode %2 OriginUpperLeft\n" +
7437 "OpSource GLSL 430\n" +
7438 "OpDecorate %3 Location 0\n" +
7439 "%void = OpTypeVoid\n" +
7440 "%5 = OpTypeFunction %void\n" +
7441 "%float = OpTypeFloat 32\n" +
7442 "%v4float = OpTypeVector %float 4\n" +
7443 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
7444 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
7445 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
7446 "%int = OpTypeInt 32 1\n" +
7447 "%int_0 = OpConstant %int 0\n" +
7448 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
7449 "%2 = OpFunction %void None %5\n" +
7450 "%12 = OpLabel\n" +
7451 "OpReturn\n" +
7452 "OpFunctionEnd\n",
7453 9, true)
7454 ));
7455
7456 using SPV14FoldingTest =
7457 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
7458
TEST_P(SPV14FoldingTest,Case)7459 TEST_P(SPV14FoldingTest, Case) {
7460 const auto& tc = GetParam();
7461
7462 // Build module.
7463 std::unique_ptr<IRContext> context =
7464 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
7465 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
7466 ASSERT_NE(nullptr, context);
7467
7468 // Fold the instruction to test.
7469 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
7470 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
7471 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
7472 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
7473 EXPECT_EQ(succeeded, tc.expected_result);
7474 if (succeeded) {
7475 Match(tc.test_body, context.get());
7476 }
7477 }
7478
7479 INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest,
7480 ::testing::Values(
7481 // Test case 0: select vectors with scalar condition.
7482 InstructionFoldingCase<bool>(std::string() +
7483 "; CHECK-NOT: OpSelect\n" +
7484 "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" +
7485 "OpCapability Shader\n" +
7486 "OpCapability Linkage\n" +
7487 "%void = OpTypeVoid\n" +
7488 "%bool = OpTypeBool\n" +
7489 "%true = OpConstantTrue %bool\n" +
7490 "%int = OpTypeInt 32 0\n" +
7491 "%int4 = OpTypeVector %int 4\n" +
7492 "%int_0 = OpConstant %int 0\n" +
7493 "%int_1 = OpConstant %int 1\n" +
7494 "%1 = OpUndef %int4\n" +
7495 "%2 = OpUndef %int4\n" +
7496 "%void_fn = OpTypeFunction %void\n" +
7497 "%func = OpFunction %void None %void_fn\n" +
7498 "%entry = OpLabel\n" +
7499 "%3 = OpSelect %int4 %true %1 %2\n" +
7500 "OpReturn\n" +
7501 "OpFunctionEnd\n"
7502 ,
7503 3, true),
7504 // Test case 1: select struct with scalar condition.
7505 InstructionFoldingCase<bool>(std::string() +
7506 "; CHECK-NOT: OpSelect\n" +
7507 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
7508 "OpCapability Shader\n" +
7509 "OpCapability Linkage\n" +
7510 "%void = OpTypeVoid\n" +
7511 "%bool = OpTypeBool\n" +
7512 "%true = OpConstantFalse %bool\n" +
7513 "%int = OpTypeInt 32 0\n" +
7514 "%struct = OpTypeStruct %int %int %int %int\n" +
7515 "%int_0 = OpConstant %int 0\n" +
7516 "%int_1 = OpConstant %int 1\n" +
7517 "%1 = OpUndef %struct\n" +
7518 "%2 = OpUndef %struct\n" +
7519 "%void_fn = OpTypeFunction %void\n" +
7520 "%func = OpFunction %void None %void_fn\n" +
7521 "%entry = OpLabel\n" +
7522 "%3 = OpSelect %struct %true %1 %2\n" +
7523 "OpReturn\n" +
7524 "OpFunctionEnd\n"
7525 ,
7526 3, true),
7527 // Test case 1: select array with scalar condition.
7528 InstructionFoldingCase<bool>(std::string() +
7529 "; CHECK-NOT: OpSelect\n" +
7530 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
7531 "OpCapability Shader\n" +
7532 "OpCapability Linkage\n" +
7533 "%void = OpTypeVoid\n" +
7534 "%bool = OpTypeBool\n" +
7535 "%true = OpConstantFalse %bool\n" +
7536 "%int = OpTypeInt 32 0\n" +
7537 "%int_0 = OpConstant %int 0\n" +
7538 "%int_1 = OpConstant %int 1\n" +
7539 "%int_4 = OpConstant %int 4\n" +
7540 "%array = OpTypeStruct %int %int %int %int\n" +
7541 "%1 = OpUndef %array\n" +
7542 "%2 = OpUndef %array\n" +
7543 "%void_fn = OpTypeFunction %void\n" +
7544 "%func = OpFunction %void None %void_fn\n" +
7545 "%entry = OpLabel\n" +
7546 "%3 = OpSelect %array %true %1 %2\n" +
7547 "OpReturn\n" +
7548 "OpFunctionEnd\n"
7549 ,
7550 3, true)
7551 ));
7552
FloatControlsHeader(const std::string & capabilities)7553 std::string FloatControlsHeader(const std::string& capabilities) {
7554 std::string header = R"(
7555 OpCapability Shader
7556 )" + capabilities + R"(
7557 %void = OpTypeVoid
7558 %float = OpTypeFloat 32
7559 %float_0 = OpConstant %float 0
7560 %float_1 = OpConstant %float 1
7561 %void_fn = OpTypeFunction %void
7562 %func = OpFunction %void None %void_fn
7563 %entry = OpLabel
7564 )";
7565
7566 return header;
7567 }
7568
7569 using FloatControlsFoldingTest =
7570 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
7571
TEST_P(FloatControlsFoldingTest,Case)7572 TEST_P(FloatControlsFoldingTest, Case) {
7573 const auto& tc = GetParam();
7574
7575 // Build module.
7576 std::unique_ptr<IRContext> context =
7577 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
7578 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
7579 ASSERT_NE(nullptr, context);
7580
7581 // Fold the instruction to test.
7582 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
7583 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
7584 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
7585 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
7586 EXPECT_EQ(succeeded, tc.expected_result);
7587 if (succeeded) {
7588 Match(tc.test_body, context.get());
7589 }
7590 }
7591
7592 INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
7593 ::testing::Values(
7594 // Test case 0: no folding with DenormPreserve
7595 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormPreserve") +
7596 "%1 = OpFAdd %float %float_0 %float_1\n" +
7597 "OpReturn\n" +
7598 "OpFunctionEnd\n"
7599 ,
7600 1, false),
7601 // Test case 1: no folding with DenormFlushToZero
7602 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormFlushToZero") +
7603 "%1 = OpFAdd %float %float_0 %float_1\n" +
7604 "OpReturn\n" +
7605 "OpFunctionEnd\n"
7606 ,
7607 1, false),
7608 // Test case 2: no folding with SignedZeroInfNanPreserve
7609 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") +
7610 "%1 = OpFAdd %float %float_0 %float_1\n" +
7611 "OpReturn\n" +
7612 "OpFunctionEnd\n"
7613 ,
7614 1, false),
7615 // Test case 3: no folding with RoundingModeRTE
7616 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTE") +
7617 "%1 = OpFAdd %float %float_0 %float_1\n" +
7618 "OpReturn\n" +
7619 "OpFunctionEnd\n"
7620 ,
7621 1, false),
7622 // Test case 4: no folding with RoundingModeRTZ
7623 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTZ") +
7624 "%1 = OpFAdd %float %float_0 %float_1\n" +
7625 "OpReturn\n" +
7626 "OpFunctionEnd\n"
7627 ,
7628 1, false)
7629 ));
7630
ImageOperandsTestBody(const std::string & image_instruction)7631 std::string ImageOperandsTestBody(const std::string& image_instruction) {
7632 std::string body = R"(
7633 OpCapability Shader
7634 OpCapability ImageGatherExtended
7635 OpMemoryModel Logical GLSL450
7636 OpEntryPoint Fragment %main "main"
7637 OpExecutionMode %main OriginUpperLeft
7638 OpDecorate %Texture DescriptorSet 0
7639 OpDecorate %Texture Binding 0
7640 %int = OpTypeInt 32 1
7641 %int_n1 = OpConstant %int -1
7642 %5 = OpConstant %int 0
7643 %float = OpTypeFloat 32
7644 %float_0 = OpConstant %float 0
7645 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
7646 %type_sampled_image = OpTypeSampledImage %type_2d_image
7647 %type_sampler = OpTypeSampler
7648 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
7649 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
7650 %_ptr_int = OpTypePointer Function %int
7651 %v2int = OpTypeVector %int 2
7652 %10 = OpTypeVector %float 4
7653 %void = OpTypeVoid
7654 %22 = OpTypeFunction %void
7655 %v2float = OpTypeVector %float 2
7656 %v3int = OpTypeVector %int 3
7657 %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
7658 %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
7659 %101 = OpConstantComposite %v2int %int_n1 %int_n1
7660 %20 = OpConstantComposite %v2float %float_0 %float_0
7661 %main = OpFunction %void None %22
7662 %23 = OpLabel
7663 %var = OpVariable %_ptr_int Function
7664 %88 = OpLoad %type_2d_image %Texture
7665 %val = OpLoad %int %var
7666 %sampler = OpLoad %type_sampler %gSampler
7667 %26 = OpSampledImage %type_sampled_image %88 %sampler
7668 )" + image_instruction + R"(
7669 OpReturn
7670 OpFunctionEnd
7671 )";
7672
7673 return body;
7674 }
7675
7676 INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
7677 ::testing::Values(
7678 // Test case 0: OpImageFetch without Offset
7679 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7680 "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
7681 , 89, false),
7682 // Test case 1: OpImageFetch with non-const offset
7683 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7684 "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
7685 , 89, false),
7686 // Test case 2: OpImageFetch with Lod and Offset
7687 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7688 " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n"
7689 "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
7690 , 89, true),
7691 // Test case 3: OpImageFetch with Bias and Offset
7692 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7693 " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n"
7694 "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
7695 , 89, true),
7696 // Test case 4: OpImageFetch with Grad and Offset.
7697 // Grad adds 2 operands to the instruction.
7698 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7699 " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n"
7700 "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
7701 , 89, true),
7702 // Test case 5: OpImageFetch with Offset and MinLod.
7703 // This is an example of a case where the bitmask bit-offset is larger than
7704 // that of the Offset.
7705 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7706 " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n"
7707 "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
7708 , 89, true),
7709 // Test case 6: OpImageGather with constant Offset
7710 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7711 " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n"
7712 "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
7713 , 89, true),
7714 // Test case 7: OpImageWrite with constant Offset
7715 InstructionFoldingCase<bool>(ImageOperandsTestBody(
7716 " OpImageWrite %88 %5 %101 Offset %101 \n"
7717 "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
7718 , 0 /* No result-id */, true)
7719 ));
7720
7721 } // namespace
7722 } // namespace opt
7723 } // namespace spvtools
7724