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::__anon28d0f2160111::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::Constant* constant = const_mrg->GetConstantFromInst(inst);
96 // We expect to see either integer types or 16-bit float types here.
97 EXPECT_TRUE((constant->AsIntConstant() != nullptr) ||
98 ((constant->AsFloatConstant() != nullptr) &&
99 (constant->type()->AsFloat()->width() == 16)));
100 const analysis::ScalarConstant* result =
101 const_mrg->GetConstantFromInst(inst)->AsScalarConstant();
102 EXPECT_NE(result, nullptr);
103 if (result != nullptr) {
104 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
105 }
106 }
107 }
108
109 // Returns a common SPIR-V header for all of the test that follow.
110 #define INT_0_ID 100
111 #define TRUE_ID 101
112 #define VEC2_0_ID 102
113 #define INT_7_ID 103
114 #define FLOAT_0_ID 104
115 #define DOUBLE_0_ID 105
116 #define VEC4_0_ID 106
117 #define DVEC4_0_ID 106
118 #define HALF_0_ID 108
Header()119 const std::string& Header() {
120 static const std::string header = R"(OpCapability Shader
121 OpCapability Float16
122 OpCapability Float64
123 OpCapability Int8
124 OpCapability Int16
125 OpCapability Int64
126 %1 = OpExtInstImport "GLSL.std.450"
127 OpMemoryModel Logical GLSL450
128 OpEntryPoint Fragment %main "main"
129 OpExecutionMode %main OriginUpperLeft
130 OpSource GLSL 140
131 OpName %main "main"
132 %void = OpTypeVoid
133 %void_func = OpTypeFunction %void
134 %bool = OpTypeBool
135 %float = OpTypeFloat 32
136 %double = OpTypeFloat 64
137 %half = OpTypeFloat 16
138 %101 = OpConstantTrue %bool ; Need a def with an numerical id to define id maps.
139 %true = OpConstantTrue %bool
140 %false = OpConstantFalse %bool
141 %bool_null = OpConstantNull %bool
142 %short = OpTypeInt 16 1
143 %ushort = OpTypeInt 16 0
144 %byte = OpTypeInt 8 1
145 %ubyte = OpTypeInt 8 0
146 %int = OpTypeInt 32 1
147 %long = OpTypeInt 64 1
148 %uint = OpTypeInt 32 0
149 %ulong = OpTypeInt 64 0
150 %v2int = OpTypeVector %int 2
151 %v4int = OpTypeVector %int 4
152 %v4float = OpTypeVector %float 4
153 %v4double = OpTypeVector %double 4
154 %v2uint = OpTypeVector %uint 2
155 %v2float = OpTypeVector %float 2
156 %v2double = OpTypeVector %double 2
157 %v2half = OpTypeVector %half 2
158 %v2bool = OpTypeVector %bool 2
159 %m2x2int = OpTypeMatrix %v2int 2
160 %mat4v4float = OpTypeMatrix %v4float 4
161 %mat4v4double = OpTypeMatrix %v4double 4
162 %struct_v2int_int_int = OpTypeStruct %v2int %int %int
163 %_ptr_int = OpTypePointer Function %int
164 %_ptr_uint = OpTypePointer Function %uint
165 %_ptr_bool = OpTypePointer Function %bool
166 %_ptr_float = OpTypePointer Function %float
167 %_ptr_double = OpTypePointer Function %double
168 %_ptr_half = OpTypePointer Function %half
169 %_ptr_long = OpTypePointer Function %long
170 %_ptr_ulong = OpTypePointer Function %ulong
171 %_ptr_v2int = OpTypePointer Function %v2int
172 %_ptr_v4int = OpTypePointer Function %v4int
173 %_ptr_v4float = OpTypePointer Function %v4float
174 %_ptr_v4double = OpTypePointer Function %v4double
175 %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int
176 %_ptr_v2float = OpTypePointer Function %v2float
177 %_ptr_v2double = OpTypePointer Function %v2double
178 %short_0 = OpConstant %short 0
179 %short_2 = OpConstant %short 2
180 %short_3 = OpConstant %short 3
181 %ubyte_1 = OpConstant %ubyte 1
182 %byte_n1 = OpConstant %byte -1
183 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps.
184 %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps.
185 %int_0 = OpConstant %int 0
186 %int_1 = OpConstant %int 1
187 %int_2 = OpConstant %int 2
188 %int_3 = OpConstant %int 3
189 %int_4 = OpConstant %int 4
190 %int_10 = OpConstant %int 10
191 %int_1073741824 = OpConstant %int 1073741824
192 %int_n1 = OpConstant %int -1
193 %int_n24 = OpConstant %int -24
194 %int_n858993459 = OpConstant %int -858993459
195 %int_min = OpConstant %int -2147483648
196 %int_max = OpConstant %int 2147483647
197 %long_0 = OpConstant %long 0
198 %long_1 = OpConstant %long 1
199 %long_2 = OpConstant %long 2
200 %long_3 = OpConstant %long 3
201 %long_10 = OpConstant %long 10
202 %long_4611686018427387904 = OpConstant %long 4611686018427387904
203 %long_n1 = OpConstant %long -1
204 %long_n3689348814741910323 = OpConstant %long -3689348814741910323
205 %long_min = OpConstant %long -9223372036854775808
206 %long_max = OpConstant %long 9223372036854775807
207 %uint_0 = OpConstant %uint 0
208 %uint_1 = OpConstant %uint 1
209 %uint_2 = OpConstant %uint 2
210 %uint_3 = OpConstant %uint 3
211 %uint_4 = OpConstant %uint 4
212 %uint_32 = OpConstant %uint 32
213 %uint_42 = OpConstant %uint 42
214 %uint_2147483649 = OpConstant %uint 2147483649
215 %uint_max = OpConstant %uint 4294967295
216 %ulong_0 = OpConstant %ulong 0
217 %ulong_1 = OpConstant %ulong 1
218 %ulong_2 = OpConstant %ulong 2
219 %ulong_9223372036854775809 = OpConstant %ulong 9223372036854775809
220 %ulong_max = OpConstant %ulong 18446744073709551615
221 %v2int_undef = OpUndef %v2int
222 %v2int_0_0 = OpConstantComposite %v2int %int_0 %int_0
223 %v2int_1_0 = OpConstantComposite %v2int %int_1 %int_0
224 %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2
225 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3
226 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2
227 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4
228 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max
229 %v2bool_null = OpConstantNull %v2bool
230 %v2bool_true_false = OpConstantComposite %v2bool %true %false
231 %v2bool_false_true = OpConstantComposite %v2bool %false %true
232 %struct_v2int_int_int_null = OpConstantNull %struct_v2int_int_int
233 %v2int_null = OpConstantNull %v2int
234 %102 = OpConstantComposite %v2int %103 %103
235 %v4int_undef = OpUndef %v4int
236 %v4int_0_0_0_0 = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0
237 %m2x2int_undef = OpUndef %m2x2int
238 %struct_undef_0_0 = OpConstantComposite %struct_v2int_int_int %v2int_undef %int_0 %int_0
239 %float_n1 = OpConstant %float -1
240 %104 = OpConstant %float 0 ; Need a def with an numerical id to define id maps.
241 %float_null = OpConstantNull %float
242 %float_0 = OpConstant %float 0
243 %float_n0 = OpConstant %float -0.0
244 %float_1 = OpConstant %float 1
245 %float_2 = OpConstant %float 2
246 %float_3 = OpConstant %float 3
247 %float_4 = OpConstant %float 4
248 %float_2049 = OpConstant %float 2049
249 %float_n2049 = OpConstant %float -2049
250 %float_0p5 = OpConstant %float 0.5
251 %float_0p2 = OpConstant %float 0.2
252 %float_pi = OpConstant %float 1.5555
253 %float_1e16 = OpConstant %float 1e16
254 %float_n1e16 = OpConstant %float -1e16
255 %float_1en16 = OpConstant %float 1e-16
256 %float_n1en16 = OpConstant %float -1e-16
257 %v2float_0_0 = OpConstantComposite %v2float %float_0 %float_0
258 %v2float_2_2 = OpConstantComposite %v2float %float_2 %float_2
259 %v2float_2_3 = OpConstantComposite %v2float %float_2 %float_3
260 %v2float_3_2 = OpConstantComposite %v2float %float_3 %float_2
261 %v2float_4_4 = OpConstantComposite %v2float %float_4 %float_4
262 %v2float_2_0p5 = OpConstantComposite %v2float %float_2 %float_0p5
263 %v2float_0p2_0p5 = OpConstantComposite %v2float %float_0p2 %float_0p5
264 %v2float_null = OpConstantNull %v2float
265 %double_n1 = OpConstant %double -1
266 %105 = OpConstant %double 0 ; Need a def with an numerical id to define id maps.
267 %double_null = OpConstantNull %double
268 %double_0 = OpConstant %double 0
269 %double_n0 = OpConstant %double -0.0
270 %double_1 = OpConstant %double 1
271 %double_2 = OpConstant %double 2
272 %double_3 = OpConstant %double 3
273 %double_4 = OpConstant %double 4
274 %double_5 = OpConstant %double 5
275 %double_0p5 = OpConstant %double 0.5
276 %double_0p2 = OpConstant %double 0.2
277 %v2double_0_0 = OpConstantComposite %v2double %double_0 %double_0
278 %v2double_2_2 = OpConstantComposite %v2double %double_2 %double_2
279 %v2double_2_3 = OpConstantComposite %v2double %double_2 %double_3
280 %v2double_3_2 = OpConstantComposite %v2double %double_3 %double_2
281 %v2double_4_4 = OpConstantComposite %v2double %double_4 %double_4
282 %v2double_2_0p5 = OpConstantComposite %v2double %double_2 %double_0p5
283 %v2double_null = OpConstantNull %v2double
284 %108 = OpConstant %half 0
285 %half_1 = OpConstant %half 1
286 %half_0_1 = OpConstantComposite %v2half %108 %half_1
287 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
288 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
289 %v4float_0_0_0_1 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_1
290 %v4float_0_1_0_0 = OpConstantComposite %v4float %float_0 %float_1 %float_null %float_0
291 %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
292 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
293 %v4float_null = OpConstantNull %v4float
294 %mat4v4float_null = OpConstantComposite %mat4v4float %v4float_null %v4float_null %v4float_null %v4float_null
295 %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4
296 %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
297 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0
298 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1
299 %v4double_0_1_0_0 = OpConstantComposite %v4double %double_0 %double_1 %double_null %double_0
300 %v4double_1_1_1_1 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_1
301 %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4
302 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5
303 %v4double_null = OpConstantNull %v4double
304 %mat4v4double_null = OpConstantComposite %mat4v4double %v4double_null %v4double_null %v4double_null %v4double_null
305 %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4
306 %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3
307 %uint_0x3f800000 = OpConstant %uint 0x3f800000
308 %uint_0xbf800000 = OpConstant %uint 0xbf800000
309 %v2uint_0x3f800000_0xbf800000 = OpConstantComposite %v2uint %uint_0x3f800000 %uint_0xbf800000
310 %long_0xbf8000003f800000 = OpConstant %long 0xbf8000003f800000
311 %int_0x3FF00000 = OpConstant %int 0x3FF00000
312 %int_0x00000000 = OpConstant %int 0x00000000
313 %int_0xC05FD666 = OpConstant %int 0xC05FD666
314 %int_0x66666666 = OpConstant %int 0x66666666
315 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666
316 %ushort_0xBC00 = OpConstant %ushort 0xBC00
317 %short_0xBC00 = OpConstant %short 0xBC00
318 )";
319
320 return header;
321 }
322
323 // Returns the header with definitions of float NaN and double NaN. Since FC
324 // "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" finds
325 // %double_nan = OpConstant %double -0x1.8p+1024 instead of
326 // %double_n0 = OpConstant %double -0,
327 // we separates those definitions from Header().
HeaderWithNaN()328 const std::string& HeaderWithNaN() {
329 static const std::string headerWithNaN =
330 Header() +
331 R"(%float_nan = OpConstant %float -0x1.8p+128
332 %double_nan = OpConstant %double -0x1.8p+1024
333 )";
334
335 return headerWithNaN;
336 }
337
338 // clang-format off
339 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest,
340 ::testing::Values(
341 // Test case 0: fold 0*n
342 InstructionFoldingCase<uint32_t>(
343 Header() + "%main = OpFunction %void None %void_func\n" +
344 "%main_lab = OpLabel\n" +
345 "%n = OpVariable %_ptr_int Function\n" +
346 "%load = OpLoad %int %n\n" +
347 "%2 = OpIMul %int %int_0 %load\n" +
348 "OpReturn\n" +
349 "OpFunctionEnd",
350 2, 0),
351 // Test case 1: fold n*0
352 InstructionFoldingCase<uint32_t>(
353 Header() + "%main = OpFunction %void None %void_func\n" +
354 "%main_lab = OpLabel\n" +
355 "%n = OpVariable %_ptr_int Function\n" +
356 "%load = OpLoad %int %n\n" +
357 "%2 = OpIMul %int %load %int_0\n" +
358 "OpReturn\n" +
359 "OpFunctionEnd",
360 2, 0),
361 // Test case 2: fold 0/n (signed)
362 InstructionFoldingCase<uint32_t>(
363 Header() + "%main = OpFunction %void None %void_func\n" +
364 "%main_lab = OpLabel\n" +
365 "%n = OpVariable %_ptr_int Function\n" +
366 "%load = OpLoad %int %n\n" +
367 "%2 = OpSDiv %int %int_0 %load\n" +
368 "OpReturn\n" +
369 "OpFunctionEnd",
370 2, 0),
371 // Test case 3: fold n/0 (signed)
372 InstructionFoldingCase<uint32_t>(
373 Header() + "%main = OpFunction %void None %void_func\n" +
374 "%main_lab = OpLabel\n" +
375 "%n = OpVariable %_ptr_int Function\n" +
376 "%load = OpLoad %int %n\n" +
377 "%2 = OpSDiv %int %load %int_0\n" +
378 "OpReturn\n" +
379 "OpFunctionEnd",
380 2, 0),
381 // Test case 4: fold 0/n (unsigned)
382 InstructionFoldingCase<uint32_t>(
383 Header() + "%main = OpFunction %void None %void_func\n" +
384 "%main_lab = OpLabel\n" +
385 "%n = OpVariable %_ptr_uint Function\n" +
386 "%load = OpLoad %uint %n\n" +
387 "%2 = OpUDiv %uint %uint_0 %load\n" +
388 "OpReturn\n" +
389 "OpFunctionEnd",
390 2, 0),
391 // Test case 5: fold n/0 (unsigned)
392 InstructionFoldingCase<uint32_t>(
393 Header() + "%main = OpFunction %void None %void_func\n" +
394 "%main_lab = OpLabel\n" +
395 "%n = OpVariable %_ptr_int Function\n" +
396 "%load = OpLoad %int %n\n" +
397 "%2 = OpSDiv %int %load %int_0\n" +
398 "OpReturn\n" +
399 "OpFunctionEnd",
400 2, 0),
401 // Test case 6: fold 0 remainder n
402 InstructionFoldingCase<uint32_t>(
403 Header() + "%main = OpFunction %void None %void_func\n" +
404 "%main_lab = OpLabel\n" +
405 "%n = OpVariable %_ptr_int Function\n" +
406 "%load = OpLoad %int %n\n" +
407 "%2 = OpSRem %int %int_0 %load\n" +
408 "OpReturn\n" +
409 "OpFunctionEnd",
410 2, 0),
411 // Test case 7: fold n remainder 0
412 InstructionFoldingCase<uint32_t>(
413 Header() + "%main = OpFunction %void None %void_func\n" +
414 "%main_lab = OpLabel\n" +
415 "%n = OpVariable %_ptr_int Function\n" +
416 "%load = OpLoad %int %n\n" +
417 "%2 = OpSRem %int %load %int_0\n" +
418 "OpReturn\n" +
419 "OpFunctionEnd",
420 2, 0),
421 // Test case 8: fold 0%n (signed)
422 InstructionFoldingCase<uint32_t>(
423 Header() + "%main = OpFunction %void None %void_func\n" +
424 "%main_lab = OpLabel\n" +
425 "%n = OpVariable %_ptr_int Function\n" +
426 "%load = OpLoad %int %n\n" +
427 "%2 = OpSMod %int %int_0 %load\n" +
428 "OpReturn\n" +
429 "OpFunctionEnd",
430 2, 0),
431 // Test case 9: fold n%0 (signed)
432 InstructionFoldingCase<uint32_t>(
433 Header() + "%main = OpFunction %void None %void_func\n" +
434 "%main_lab = OpLabel\n" +
435 "%n = OpVariable %_ptr_int Function\n" +
436 "%load = OpLoad %int %n\n" +
437 "%2 = OpSMod %int %load %int_0\n" +
438 "OpReturn\n" +
439 "OpFunctionEnd",
440 2, 0),
441 // Test case 10: fold 0%n (unsigned)
442 InstructionFoldingCase<uint32_t>(
443 Header() + "%main = OpFunction %void None %void_func\n" +
444 "%main_lab = OpLabel\n" +
445 "%n = OpVariable %_ptr_uint Function\n" +
446 "%load = OpLoad %uint %n\n" +
447 "%2 = OpUMod %uint %uint_0 %load\n" +
448 "OpReturn\n" +
449 "OpFunctionEnd",
450 2, 0),
451 // Test case 11: fold n%0 (unsigned)
452 InstructionFoldingCase<uint32_t>(
453 Header() + "%main = OpFunction %void None %void_func\n" +
454 "%main_lab = OpLabel\n" +
455 "%n = OpVariable %_ptr_uint Function\n" +
456 "%load = OpLoad %uint %n\n" +
457 "%2 = OpUMod %uint %load %uint_0\n" +
458 "OpReturn\n" +
459 "OpFunctionEnd",
460 2, 0),
461 // Test case 12: fold n << 32
462 InstructionFoldingCase<uint32_t>(
463 Header() + "%main = OpFunction %void None %void_func\n" +
464 "%main_lab = OpLabel\n" +
465 "%n = OpVariable %_ptr_uint Function\n" +
466 "%load = OpLoad %uint %n\n" +
467 "%2 = OpShiftLeftLogical %uint %load %uint_32\n" +
468 "OpReturn\n" +
469 "OpFunctionEnd",
470 2, 0),
471 // Test case 13: fold n >> 32
472 InstructionFoldingCase<uint32_t>(
473 Header() + "%main = OpFunction %void None %void_func\n" +
474 "%main_lab = OpLabel\n" +
475 "%n = OpVariable %_ptr_uint Function\n" +
476 "%load = OpLoad %uint %n\n" +
477 "%2 = OpShiftRightLogical %uint %load %uint_32\n" +
478 "OpReturn\n" +
479 "OpFunctionEnd",
480 2, 0),
481 // Test case 14: fold n | 0xFFFFFFFF
482 InstructionFoldingCase<uint32_t>(
483 Header() + "%main = OpFunction %void None %void_func\n" +
484 "%main_lab = OpLabel\n" +
485 "%n = OpVariable %_ptr_uint Function\n" +
486 "%load = OpLoad %uint %n\n" +
487 "%2 = OpBitwiseOr %uint %load %uint_max\n" +
488 "OpReturn\n" +
489 "OpFunctionEnd",
490 2, 0xFFFFFFFF),
491 // Test case 15: fold 0xFFFFFFFF | n
492 InstructionFoldingCase<uint32_t>(
493 Header() + "%main = OpFunction %void None %void_func\n" +
494 "%main_lab = OpLabel\n" +
495 "%n = OpVariable %_ptr_uint Function\n" +
496 "%load = OpLoad %uint %n\n" +
497 "%2 = OpBitwiseOr %uint %uint_max %load\n" +
498 "OpReturn\n" +
499 "OpFunctionEnd",
500 2, 0xFFFFFFFF),
501 // Test case 16: fold n & 0
502 InstructionFoldingCase<uint32_t>(
503 Header() + "%main = OpFunction %void None %void_func\n" +
504 "%main_lab = OpLabel\n" +
505 "%n = OpVariable %_ptr_uint Function\n" +
506 "%load = OpLoad %uint %n\n" +
507 "%2 = OpBitwiseAnd %uint %load %uint_0\n" +
508 "OpReturn\n" +
509 "OpFunctionEnd",
510 2, 0),
511 // Test case 17: fold 1/0 (signed)
512 InstructionFoldingCase<uint32_t>(
513 Header() + "%main = OpFunction %void None %void_func\n" +
514 "%main_lab = OpLabel\n" +
515 "%2 = OpSDiv %int %int_1 %int_0\n" +
516 "OpReturn\n" +
517 "OpFunctionEnd",
518 2, 0),
519 // Test case 18: fold 1/0 (unsigned)
520 InstructionFoldingCase<uint32_t>(
521 Header() + "%main = OpFunction %void None %void_func\n" +
522 "%main_lab = OpLabel\n" +
523 "%2 = OpUDiv %uint %uint_1 %uint_0\n" +
524 "OpReturn\n" +
525 "OpFunctionEnd",
526 2, 0),
527 // Test case 19: fold OpSRem 1 0 (signed)
528 InstructionFoldingCase<uint32_t>(
529 Header() + "%main = OpFunction %void None %void_func\n" +
530 "%main_lab = OpLabel\n" +
531 "%2 = OpSRem %int %int_1 %int_0\n" +
532 "OpReturn\n" +
533 "OpFunctionEnd",
534 2, 0),
535 // Test case 20: fold 1%0 (signed)
536 InstructionFoldingCase<uint32_t>(
537 Header() + "%main = OpFunction %void None %void_func\n" +
538 "%main_lab = OpLabel\n" +
539 "%2 = OpSMod %int %int_1 %int_0\n" +
540 "OpReturn\n" +
541 "OpFunctionEnd",
542 2, 0),
543 // Test case 21: fold 1%0 (unsigned)
544 InstructionFoldingCase<uint32_t>(
545 Header() + "%main = OpFunction %void None %void_func\n" +
546 "%main_lab = OpLabel\n" +
547 "%2 = OpUMod %uint %uint_1 %uint_0\n" +
548 "OpReturn\n" +
549 "OpFunctionEnd",
550 2, 0),
551 // Test case 22: fold unsigned n >> 42 (undefined, so set to zero).
552 InstructionFoldingCase<uint32_t>(
553 Header() + "%main = OpFunction %void None %void_func\n" +
554 "%main_lab = OpLabel\n" +
555 "%n = OpVariable %_ptr_uint Function\n" +
556 "%load = OpLoad %uint %n\n" +
557 "%2 = OpShiftRightLogical %uint %load %uint_42\n" +
558 "OpReturn\n" +
559 "OpFunctionEnd",
560 2, 0),
561 // Test case 23: fold signed n >> 42 (undefined, so set to zero).
562 InstructionFoldingCase<uint32_t>(
563 Header() + "%main = OpFunction %void None %void_func\n" +
564 "%main_lab = OpLabel\n" +
565 "%n = OpVariable %_ptr_int Function\n" +
566 "%load = OpLoad %int %n\n" +
567 "%2 = OpShiftRightLogical %int %load %uint_42\n" +
568 "OpReturn\n" +
569 "OpFunctionEnd",
570 2, 0),
571 // Test case 24: fold n << 42 (undefined, so set to zero).
572 InstructionFoldingCase<uint32_t>(
573 Header() + "%main = OpFunction %void None %void_func\n" +
574 "%main_lab = OpLabel\n" +
575 "%n = OpVariable %_ptr_int Function\n" +
576 "%load = OpLoad %int %n\n" +
577 "%2 = OpShiftLeftLogical %int %load %uint_42\n" +
578 "OpReturn\n" +
579 "OpFunctionEnd",
580 2, 0),
581 // Test case 25: fold -24 >> 32 (defined as -1)
582 InstructionFoldingCase<uint32_t>(
583 Header() + "%main = OpFunction %void None %void_func\n" +
584 "%main_lab = OpLabel\n" +
585 "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" +
586 "OpReturn\n" +
587 "OpFunctionEnd",
588 2, -1),
589 // Test case 26: fold 2 >> 32 (signed)
590 InstructionFoldingCase<uint32_t>(
591 Header() + "%main = OpFunction %void None %void_func\n" +
592 "%main_lab = OpLabel\n" +
593 "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" +
594 "OpReturn\n" +
595 "OpFunctionEnd",
596 2, 0),
597 // Test case 27: fold 2 >> 32 (unsigned)
598 InstructionFoldingCase<uint32_t>(
599 Header() + "%main = OpFunction %void None %void_func\n" +
600 "%main_lab = OpLabel\n" +
601 "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" +
602 "OpReturn\n" +
603 "OpFunctionEnd",
604 2, 0),
605 // Test case 28: fold 2 << 32
606 InstructionFoldingCase<uint32_t>(
607 Header() + "%main = OpFunction %void None %void_func\n" +
608 "%main_lab = OpLabel\n" +
609 "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" +
610 "OpReturn\n" +
611 "OpFunctionEnd",
612 2, 0),
613 // Test case 29: fold -INT_MIN
614 InstructionFoldingCase<uint32_t>(
615 Header() + "%main = OpFunction %void None %void_func\n" +
616 "%main_lab = OpLabel\n" +
617 "%2 = OpSNegate %int %int_min\n" +
618 "OpReturn\n" +
619 "OpFunctionEnd",
620 2, std::numeric_limits<int32_t>::min()),
621 // Test case 30: fold UMin 3 4
622 InstructionFoldingCase<uint32_t>(
623 Header() + "%main = OpFunction %void None %void_func\n" +
624 "%main_lab = OpLabel\n" +
625 "%2 = OpExtInst %uint %1 UMin %uint_3 %uint_4\n" +
626 "OpReturn\n" +
627 "OpFunctionEnd",
628 2, 3),
629 // Test case 31: fold UMin 4 2
630 InstructionFoldingCase<uint32_t>(
631 Header() + "%main = OpFunction %void None %void_func\n" +
632 "%main_lab = OpLabel\n" +
633 "%2 = OpExtInst %uint %1 UMin %uint_4 %uint_2\n" +
634 "OpReturn\n" +
635 "OpFunctionEnd",
636 2, 2),
637 // Test case 32: fold SMin 3 4
638 InstructionFoldingCase<uint32_t>(
639 Header() + "%main = OpFunction %void None %void_func\n" +
640 "%main_lab = OpLabel\n" +
641 "%2 = OpExtInst %int %1 UMin %int_3 %int_4\n" +
642 "OpReturn\n" +
643 "OpFunctionEnd",
644 2, 3),
645 // Test case 33: fold SMin 4 2
646 InstructionFoldingCase<uint32_t>(
647 Header() + "%main = OpFunction %void None %void_func\n" +
648 "%main_lab = OpLabel\n" +
649 "%2 = OpExtInst %int %1 SMin %int_4 %int_2\n" +
650 "OpReturn\n" +
651 "OpFunctionEnd",
652 2, 2),
653 // Test case 34: fold UMax 3 4
654 InstructionFoldingCase<uint32_t>(
655 Header() + "%main = OpFunction %void None %void_func\n" +
656 "%main_lab = OpLabel\n" +
657 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_4\n" +
658 "OpReturn\n" +
659 "OpFunctionEnd",
660 2, 4),
661 // Test case 35: fold UMax 3 2
662 InstructionFoldingCase<uint32_t>(
663 Header() + "%main = OpFunction %void None %void_func\n" +
664 "%main_lab = OpLabel\n" +
665 "%2 = OpExtInst %uint %1 UMax %uint_3 %uint_2\n" +
666 "OpReturn\n" +
667 "OpFunctionEnd",
668 2, 3),
669 // Test case 36: fold SMax 3 4
670 InstructionFoldingCase<uint32_t>(
671 Header() + "%main = OpFunction %void None %void_func\n" +
672 "%main_lab = OpLabel\n" +
673 "%2 = OpExtInst %int %1 UMax %int_3 %int_4\n" +
674 "OpReturn\n" +
675 "OpFunctionEnd",
676 2, 4),
677 // Test case 37: fold SMax 3 2
678 InstructionFoldingCase<uint32_t>(
679 Header() + "%main = OpFunction %void None %void_func\n" +
680 "%main_lab = OpLabel\n" +
681 "%2 = OpExtInst %int %1 SMax %int_3 %int_2\n" +
682 "OpReturn\n" +
683 "OpFunctionEnd",
684 2, 3),
685 // Test case 38: fold UClamp 2 3 4
686 InstructionFoldingCase<uint32_t>(
687 Header() + "%main = OpFunction %void None %void_func\n" +
688 "%main_lab = OpLabel\n" +
689 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_3 %uint_4\n" +
690 "OpReturn\n" +
691 "OpFunctionEnd",
692 2, 3),
693 // Test case 39: fold UClamp 2 0 4
694 InstructionFoldingCase<uint32_t>(
695 Header() + "%main = OpFunction %void None %void_func\n" +
696 "%main_lab = OpLabel\n" +
697 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_4\n" +
698 "OpReturn\n" +
699 "OpFunctionEnd",
700 2, 2),
701 // Test case 40: fold UClamp 2 0 1
702 InstructionFoldingCase<uint32_t>(
703 Header() + "%main = OpFunction %void None %void_func\n" +
704 "%main_lab = OpLabel\n" +
705 "%2 = OpExtInst %uint %1 UClamp %uint_2 %uint_0 %uint_1\n" +
706 "OpReturn\n" +
707 "OpFunctionEnd",
708 2, 1),
709 // Test case 41: fold SClamp 2 3 4
710 InstructionFoldingCase<uint32_t>(
711 Header() + "%main = OpFunction %void None %void_func\n" +
712 "%main_lab = OpLabel\n" +
713 "%2 = OpExtInst %int %1 SClamp %int_2 %int_3 %int_4\n" +
714 "OpReturn\n" +
715 "OpFunctionEnd",
716 2, 3),
717 // Test case 42: fold SClamp 2 0 4
718 InstructionFoldingCase<uint32_t>(
719 Header() + "%main = OpFunction %void None %void_func\n" +
720 "%main_lab = OpLabel\n" +
721 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_4\n" +
722 "OpReturn\n" +
723 "OpFunctionEnd",
724 2, 2),
725 // Test case 43: fold SClamp 2 0 1
726 InstructionFoldingCase<uint32_t>(
727 Header() + "%main = OpFunction %void None %void_func\n" +
728 "%main_lab = OpLabel\n" +
729 "%2 = OpExtInst %int %1 SClamp %int_2 %int_0 %int_1\n" +
730 "OpReturn\n" +
731 "OpFunctionEnd",
732 2, 1),
733 // Test case 44: SClamp 1 2 x
734 InstructionFoldingCase<uint32_t>(
735 Header() + "%main = OpFunction %void None %void_func\n" +
736 "%main_lab = OpLabel\n" +
737 "%undef = OpUndef %int\n" +
738 "%2 = OpExtInst %int %1 SClamp %int_1 %int_2 %undef\n" +
739 "OpReturn\n" +
740 "OpFunctionEnd",
741 2, 2),
742 // Test case 45: SClamp 2 x 1
743 InstructionFoldingCase<uint32_t>(
744 Header() + "%main = OpFunction %void None %void_func\n" +
745 "%main_lab = OpLabel\n" +
746 "%undef = OpUndef %int\n" +
747 "%2 = OpExtInst %int %1 SClamp %int_2 %undef %int_1\n" +
748 "OpReturn\n" +
749 "OpFunctionEnd",
750 2, 1),
751 // Test case 44: UClamp 1 2 x
752 InstructionFoldingCase<uint32_t>(
753 Header() + "%main = OpFunction %void None %void_func\n" +
754 "%main_lab = OpLabel\n" +
755 "%undef = OpUndef %uint\n" +
756 "%2 = OpExtInst %uint %1 UClamp %uint_1 %uint_2 %undef\n" +
757 "OpReturn\n" +
758 "OpFunctionEnd",
759 2, 2),
760 // Test case 45: UClamp 2 x 1
761 InstructionFoldingCase<uint32_t>(
762 Header() + "%main = OpFunction %void None %void_func\n" +
763 "%main_lab = OpLabel\n" +
764 "%undef = OpUndef %uint\n" +
765 "%2 = OpExtInst %uint %1 UClamp %uint_2 %undef %uint_1\n" +
766 "OpReturn\n" +
767 "OpFunctionEnd",
768 2, 1),
769 // Test case 46: Bit-cast int 0 to unsigned int
770 InstructionFoldingCase<uint32_t>(
771 Header() + "%main = OpFunction %void None %void_func\n" +
772 "%main_lab = OpLabel\n" +
773 "%2 = OpBitcast %uint %int_0\n" +
774 "OpReturn\n" +
775 "OpFunctionEnd",
776 2, 0),
777 // Test case 47: Bit-cast int -24 to unsigned int
778 InstructionFoldingCase<uint32_t>(
779 Header() + "%main = OpFunction %void None %void_func\n" +
780 "%main_lab = OpLabel\n" +
781 "%2 = OpBitcast %uint %int_n24\n" +
782 "OpReturn\n" +
783 "OpFunctionEnd",
784 2, static_cast<uint32_t>(-24)),
785 // Test case 48: Bit-cast float 1.0f to unsigned int
786 InstructionFoldingCase<uint32_t>(
787 Header() + "%main = OpFunction %void None %void_func\n" +
788 "%main_lab = OpLabel\n" +
789 "%2 = OpBitcast %uint %float_1\n" +
790 "OpReturn\n" +
791 "OpFunctionEnd",
792 2, static_cast<uint32_t>(0x3f800000)),
793 // Test case 49: Bit-cast ushort 0xBC00 to ushort
794 InstructionFoldingCase<uint32_t>(
795 Header() + "%main = OpFunction %void None %void_func\n" +
796 "%main_lab = OpLabel\n" +
797 "%2 = OpBitcast %ushort %ushort_0xBC00\n" +
798 "OpReturn\n" +
799 "OpFunctionEnd",
800 2, 0xBC00),
801 // Test case 50: Bit-cast short 0xBC00 to ushort
802 InstructionFoldingCase<uint32_t>(
803 Header() + "%main = OpFunction %void None %void_func\n" +
804 "%main_lab = OpLabel\n" +
805 "%2 = OpBitcast %ushort %short_0xBC00\n" +
806 "OpReturn\n" +
807 "OpFunctionEnd",
808 2, 0xFFFFBC00),
809 // Test case 51: Bit-cast half 1 to ushort
810 InstructionFoldingCase<uint32_t>(
811 Header() + "%main = OpFunction %void None %void_func\n" +
812 "%main_lab = OpLabel\n" +
813 "%2 = OpBitcast %ushort %half_1\n" +
814 "OpReturn\n" +
815 "OpFunctionEnd",
816 2, 0x3C00),
817 // Test case 52: Bit-cast ushort 0xBC00 to short
818 InstructionFoldingCase<uint32_t>(
819 Header() + "%main = OpFunction %void None %void_func\n" +
820 "%main_lab = OpLabel\n" +
821 "%2 = OpBitcast %short %ushort_0xBC00\n" +
822 "OpReturn\n" +
823 "OpFunctionEnd",
824 2, 0xBC00),
825 // Test case 53: Bit-cast short 0xBC00 to short
826 InstructionFoldingCase<uint32_t>(
827 Header() + "%main = OpFunction %void None %void_func\n" +
828 "%main_lab = OpLabel\n" +
829 "%2 = OpBitcast %short %short_0xBC00\n" +
830 "OpReturn\n" +
831 "OpFunctionEnd",
832 2, 0xFFFFBC00),
833 // Test case 54: Bit-cast half 1 to short
834 InstructionFoldingCase<uint32_t>(
835 Header() + "%main = OpFunction %void None %void_func\n" +
836 "%main_lab = OpLabel\n" +
837 "%2 = OpBitcast %short %half_1\n" +
838 "OpReturn\n" +
839 "OpFunctionEnd",
840 2, 0x3C00),
841 // Test case 55: Bit-cast ushort 0xBC00 to half
842 InstructionFoldingCase<uint32_t>(
843 Header() + "%main = OpFunction %void None %void_func\n" +
844 "%main_lab = OpLabel\n" +
845 "%2 = OpBitcast %half %ushort_0xBC00\n" +
846 "OpReturn\n" +
847 "OpFunctionEnd",
848 2, 0xBC00),
849 // Test case 56: Bit-cast short 0xBC00 to half
850 InstructionFoldingCase<uint32_t>(
851 Header() + "%main = OpFunction %void None %void_func\n" +
852 "%main_lab = OpLabel\n" +
853 "%2 = OpBitcast %half %short_0xBC00\n" +
854 "OpReturn\n" +
855 "OpFunctionEnd",
856 2, 0xFFFFBC00),
857 // Test case 57: Bit-cast half 1 to half
858 InstructionFoldingCase<uint32_t>(
859 Header() + "%main = OpFunction %void None %void_func\n" +
860 "%main_lab = OpLabel\n" +
861 "%2 = OpBitcast %half %half_1\n" +
862 "OpReturn\n" +
863 "OpFunctionEnd",
864 2, 0x3C00),
865 // Test case 58: Bit-cast ubyte 1 to byte
866 InstructionFoldingCase<uint32_t>(
867 Header() + "%main = OpFunction %void None %void_func\n" +
868 "%main_lab = OpLabel\n" +
869 "%2 = OpBitcast %byte %ubyte_1\n" +
870 "OpReturn\n" +
871 "OpFunctionEnd",
872 2, 1),
873 // Test case 59: Bit-cast byte -1 to ubyte
874 InstructionFoldingCase<uint32_t>(
875 Header() + "%main = OpFunction %void None %void_func\n" +
876 "%main_lab = OpLabel\n" +
877 "%2 = OpBitcast %ubyte %byte_n1\n" +
878 "OpReturn\n" +
879 "OpFunctionEnd",
880 2, 0xFFFFFFFF)
881 ));
882 // clang-format on
883
884 using IntVectorInstructionFoldingTest =
885 ::testing::TestWithParam<InstructionFoldingCase<std::vector<uint32_t>>>;
886
TEST_P(IntVectorInstructionFoldingTest,Case)887 TEST_P(IntVectorInstructionFoldingTest, Case) {
888 const auto& tc = GetParam();
889
890 // Build module.
891 std::unique_ptr<IRContext> context =
892 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
893 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
894 ASSERT_NE(nullptr, context);
895
896 // Fold the instruction to test.
897 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
898 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
899 SpvOp original_opcode = inst->opcode();
900 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
901
902 // Make sure the instruction folded as expected.
903 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
904 if (succeeded && inst != nullptr) {
905 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
906 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
907 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
908 EXPECT_THAT(opcodes, Contains(inst->opcode()));
909 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
910 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
911 EXPECT_NE(result, nullptr);
912 if (result != nullptr) {
913 const std::vector<const analysis::Constant*>& componenets =
914 result->AsVectorConstant()->GetComponents();
915 EXPECT_EQ(componenets.size(), tc.expected_result.size());
916 for (size_t i = 0; i < componenets.size(); i++) {
917 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32());
918 }
919 }
920 }
921 }
922
923 // clang-format off
924 INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest,
925 ::testing::Values(
926 // Test case 0: fold 0*n
927 InstructionFoldingCase<std::vector<uint32_t>>(
928 Header() + "%main = OpFunction %void None %void_func\n" +
929 "%main_lab = OpLabel\n" +
930 "%n = OpVariable %_ptr_int Function\n" +
931 "%load = OpLoad %int %n\n" +
932 "%2 = OpVectorShuffle %v2int %v2int_2_2 %v2int_2_3 0 3\n" +
933 "OpReturn\n" +
934 "OpFunctionEnd",
935 2, {2,3}),
936 InstructionFoldingCase<std::vector<uint32_t>>(
937 Header() + "%main = OpFunction %void None %void_func\n" +
938 "%main_lab = OpLabel\n" +
939 "%n = OpVariable %_ptr_int Function\n" +
940 "%load = OpLoad %int %n\n" +
941 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 3\n" +
942 "OpReturn\n" +
943 "OpFunctionEnd",
944 2, {0,3}),
945 InstructionFoldingCase<std::vector<uint32_t>>(
946 Header() + "%main = OpFunction %void None %void_func\n" +
947 "%main_lab = OpLabel\n" +
948 "%n = OpVariable %_ptr_int Function\n" +
949 "%load = OpLoad %int %n\n" +
950 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" +
951 "OpReturn\n" +
952 "OpFunctionEnd",
953 2, {0,0}),
954 InstructionFoldingCase<std::vector<uint32_t>>(
955 Header() + "%main = OpFunction %void None %void_func\n" +
956 "%main_lab = OpLabel\n" +
957 "%n = OpVariable %_ptr_int Function\n" +
958 "%load = OpLoad %int %n\n" +
959 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" +
960 "OpReturn\n" +
961 "OpFunctionEnd",
962 2, {0,0}),
963 // Test case 4: fold bit-cast int -24 to unsigned int
964 InstructionFoldingCase<std::vector<uint32_t>>(
965 Header() + "%main = OpFunction %void None %void_func\n" +
966 "%main_lab = OpLabel\n" +
967 "%n = OpVariable %_ptr_int Function\n" +
968 "%load = OpLoad %int %n\n" +
969 "%2 = OpBitcast %v2uint %v2int_min_max\n" +
970 "OpReturn\n" +
971 "OpFunctionEnd",
972 2, {2147483648, 2147483647})
973 ));
974 // clang-format on
975
976 using DoubleVectorInstructionFoldingTest =
977 ::testing::TestWithParam<InstructionFoldingCase<std::vector<double>>>;
978
TEST_P(DoubleVectorInstructionFoldingTest,Case)979 TEST_P(DoubleVectorInstructionFoldingTest, Case) {
980 const auto& tc = GetParam();
981
982 // Build module.
983 std::unique_ptr<IRContext> context =
984 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
985 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
986 ASSERT_NE(nullptr, context);
987
988 // Fold the instruction to test.
989 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
990 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
991 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
992
993 // Make sure the instruction folded as expected.
994 EXPECT_TRUE(succeeded);
995 if (succeeded && inst != nullptr) {
996 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
997 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
998 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
999 EXPECT_THAT(opcodes, Contains(inst->opcode()));
1000 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1001 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1002 EXPECT_NE(result, nullptr);
1003 if (result != nullptr) {
1004 const std::vector<const analysis::Constant*>& componenets =
1005 result->AsVectorConstant()->GetComponents();
1006 EXPECT_EQ(componenets.size(), tc.expected_result.size());
1007 for (size_t i = 0; i < componenets.size(); i++) {
1008 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble());
1009 }
1010 }
1011 }
1012 }
1013
1014 // clang-format off
1015 INSTANTIATE_TEST_SUITE_P(TestCase, DoubleVectorInstructionFoldingTest,
1016 ::testing::Values(
1017 // Test case 0: bit-cast int {0x3FF00000,0x00000000,0xC05FD666,0x66666666}
1018 // to double vector
1019 InstructionFoldingCase<std::vector<double>>(
1020 Header() + "%main = OpFunction %void None %void_func\n" +
1021 "%main_lab = OpLabel\n" +
1022 "%2 = OpBitcast %v2double %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666\n" +
1023 "OpReturn\n" +
1024 "OpFunctionEnd",
1025 2, {1.0,-127.35}),
1026 // Test case 1: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1027 InstructionFoldingCase<std::vector<double>>(
1028 Header() +
1029 "%main = OpFunction %void None %void_func\n" +
1030 "%main_lab = OpLabel\n" +
1031 "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_null\n" +
1032 "OpReturn\n" +
1033 "OpFunctionEnd",
1034 2, {0.0,0.0,0.0,0.0}),
1035 // Test case 2: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1036 InstructionFoldingCase<std::vector<double>>(
1037 Header() +
1038 "%main = OpFunction %void None %void_func\n" +
1039 "%main_lab = OpLabel\n" +
1040 "%2 = OpVectorTimesMatrix %v4double %v4double_null %mat4v4double_1_2_3_4\n" +
1041 "OpReturn\n" +
1042 "OpFunctionEnd",
1043 2, {0.0,0.0,0.0,0.0}),
1044 // Test case 3: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1045 InstructionFoldingCase<std::vector<double>>(
1046 Header() +
1047 "%main = OpFunction %void None %void_func\n" +
1048 "%main_lab = OpLabel\n" +
1049 "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4\n" +
1050 "OpReturn\n" +
1051 "OpFunctionEnd",
1052 2, {30.0,30.0,30.0,30.0}),
1053 // Test case 4: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1054 InstructionFoldingCase<std::vector<double>>(
1055 Header() +
1056 "%main = OpFunction %void None %void_func\n" +
1057 "%main_lab = OpLabel\n" +
1058 "%2 = OpMatrixTimesVector %v4double %mat4v4double_null %v4double_1_2_3_4\n" +
1059 "OpReturn\n" +
1060 "OpFunctionEnd",
1061 2, {0.0,0.0,0.0,0.0}),
1062 // Test case 5: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1063 InstructionFoldingCase<std::vector<double>>(
1064 Header() +
1065 "%main = OpFunction %void None %void_func\n" +
1066 "%main_lab = OpLabel\n" +
1067 "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_null\n" +
1068 "OpReturn\n" +
1069 "OpFunctionEnd",
1070 2, {0.0,0.0,0.0,0.0}),
1071 // Test case 6: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1072 InstructionFoldingCase<std::vector<double>>(
1073 Header() +
1074 "%main = OpFunction %void None %void_func\n" +
1075 "%main_lab = OpLabel\n" +
1076 "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" +
1077 "OpReturn\n" +
1078 "OpFunctionEnd",
1079 2, {10.0,20.0,30.0,40.0})
1080 ));
1081
1082 using FloatVectorInstructionFoldingTest =
1083 ::testing::TestWithParam<InstructionFoldingCase<std::vector<float>>>;
1084
TEST_P(FloatVectorInstructionFoldingTest,Case)1085 TEST_P(FloatVectorInstructionFoldingTest, Case) {
1086 const auto& tc = GetParam();
1087
1088 // Build module.
1089 std::unique_ptr<IRContext> context =
1090 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1091 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1092 ASSERT_NE(nullptr, context);
1093
1094 // Fold the instruction to test.
1095 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1096 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1097 SpvOp original_opcode = inst->opcode();
1098 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1099
1100 // Make sure the instruction folded as expected.
1101 EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode);
1102 if (succeeded && inst != nullptr) {
1103 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1104 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1105 std::vector<SpvOp> opcodes = {SpvOpConstantComposite};
1106 EXPECT_THAT(opcodes, Contains(inst->opcode()));
1107 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1108 const analysis::Constant* result = const_mrg->GetConstantFromInst(inst);
1109 EXPECT_NE(result, nullptr);
1110 if (result != nullptr) {
1111 const std::vector<const analysis::Constant*>& componenets =
1112 result->AsVectorConstant()->GetComponents();
1113 EXPECT_EQ(componenets.size(), tc.expected_result.size());
1114 for (size_t i = 0; i < componenets.size(); i++) {
1115 EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat());
1116 }
1117 }
1118 }
1119 }
1120
1121 // clang-format off
1122 INSTANTIATE_TEST_SUITE_P(TestCase, FloatVectorInstructionFoldingTest,
1123 ::testing::Values(
1124 // Test case 0: FMix {2.0, 2.0}, {2.0, 3.0} {0.2,0.5}
1125 InstructionFoldingCase<std::vector<float>>(
1126 Header() + "%main = OpFunction %void None %void_func\n" +
1127 "%main_lab = OpLabel\n" +
1128 "%2 = OpExtInst %v2float %1 FMix %v2float_2_3 %v2float_0_0 %v2float_0p2_0p5\n" +
1129 "OpReturn\n" +
1130 "OpFunctionEnd",
1131 2, {1.6f,1.5f}),
1132 // Test case 1: bit-cast unsigned int vector {0x3f800000, 0xbf800000} to
1133 // float vector
1134 InstructionFoldingCase<std::vector<float>>(
1135 Header() + "%main = OpFunction %void None %void_func\n" +
1136 "%main_lab = OpLabel\n" +
1137 "%2 = OpBitcast %v2float %v2uint_0x3f800000_0xbf800000\n" +
1138 "OpReturn\n" +
1139 "OpFunctionEnd",
1140 2, {1.0f,-1.0f}),
1141 // Test case 2: bit-cast long int 0xbf8000003f800000 to float vector
1142 InstructionFoldingCase<std::vector<float>>(
1143 Header() + "%main = OpFunction %void None %void_func\n" +
1144 "%main_lab = OpLabel\n" +
1145 "%2 = OpBitcast %v2float %long_0xbf8000003f800000\n" +
1146 "OpReturn\n" +
1147 "OpFunctionEnd",
1148 2, {1.0f,-1.0f}),
1149 // Test case 3: OpVectorTimesMatrix Non-Zero Zero {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {1.0, 2.0, 3.0, 4.0} {0.0, 0.0, 0.0, 0.0}
1150 InstructionFoldingCase<std::vector<float>>(
1151 Header() +
1152 "%main = OpFunction %void None %void_func\n" +
1153 "%main_lab = OpLabel\n" +
1154 "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_null\n" +
1155 "OpReturn\n" +
1156 "OpFunctionEnd",
1157 2, {0.0f,0.0f,0.0f,0.0f}),
1158 // Test case 4: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1159 InstructionFoldingCase<std::vector<float>>(
1160 Header() +
1161 "%main = OpFunction %void None %void_func\n" +
1162 "%main_lab = OpLabel\n" +
1163 "%2 = OpVectorTimesMatrix %v4float %v4float_null %mat4v4float_1_2_3_4\n" +
1164 "OpReturn\n" +
1165 "OpFunctionEnd",
1166 2, {0.0f,0.0f,0.0f,0.0f}),
1167 // Test case 5: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0}
1168 InstructionFoldingCase<std::vector<float>>(
1169 Header() +
1170 "%main = OpFunction %void None %void_func\n" +
1171 "%main_lab = OpLabel\n" +
1172 "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4\n" +
1173 "OpReturn\n" +
1174 "OpFunctionEnd",
1175 2, {30.0f,30.0f,30.0f,30.0f}),
1176 // Test case 6: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0}
1177 InstructionFoldingCase<std::vector<float>>(
1178 Header() +
1179 "%main = OpFunction %void None %void_func\n" +
1180 "%main_lab = OpLabel\n" +
1181 "%2 = OpMatrixTimesVector %v4float %mat4v4float_null %v4float_1_2_3_4\n" +
1182 "OpReturn\n" +
1183 "OpFunctionEnd",
1184 2, {0.0f,0.0f,0.0f,0.0f}),
1185 // Test case 7: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0}
1186 InstructionFoldingCase<std::vector<float>>(
1187 Header() +
1188 "%main = OpFunction %void None %void_func\n" +
1189 "%main_lab = OpLabel\n" +
1190 "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_null\n" +
1191 "OpReturn\n" +
1192 "OpFunctionEnd",
1193 2, {0.0f,0.0f,0.0f,0.0f}),
1194 // Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0}
1195 InstructionFoldingCase<std::vector<float>>(
1196 Header() +
1197 "%main = OpFunction %void None %void_func\n" +
1198 "%main_lab = OpLabel\n" +
1199 "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" +
1200 "OpReturn\n" +
1201 "OpFunctionEnd",
1202 2, {10.0f,20.0f,30.0f,40.0f})
1203 ));
1204 // clang-format on
1205 using BooleanInstructionFoldingTest =
1206 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
1207
TEST_P(BooleanInstructionFoldingTest,Case)1208 TEST_P(BooleanInstructionFoldingTest, Case) {
1209 const auto& tc = GetParam();
1210
1211 // Build module.
1212 std::unique_ptr<IRContext> context =
1213 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1214 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1215 ASSERT_NE(nullptr, context);
1216
1217 // Fold the instruction to test.
1218 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1219 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1220 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1221
1222 // Make sure the instruction folded as expected.
1223 EXPECT_TRUE(succeeded);
1224 if (inst != nullptr) {
1225 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1226 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1227 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
1228 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
1229 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1230 const analysis::BoolConstant* result =
1231 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
1232 EXPECT_NE(result, nullptr);
1233 if (result != nullptr) {
1234 EXPECT_EQ(result->value(), tc.expected_result);
1235 }
1236 }
1237 }
1238
1239 // clang-format off
1240 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTest,
1241 ::testing::Values(
1242 // Test case 0: fold true || n
1243 InstructionFoldingCase<bool>(
1244 Header() + "%main = OpFunction %void None %void_func\n" +
1245 "%main_lab = OpLabel\n" +
1246 "%n = OpVariable %_ptr_bool Function\n" +
1247 "%load = OpLoad %bool %n\n" +
1248 "%2 = OpLogicalOr %bool %true %load\n" +
1249 "OpReturn\n" +
1250 "OpFunctionEnd",
1251 2, true),
1252 // Test case 1: fold n || true
1253 InstructionFoldingCase<bool>(
1254 Header() + "%main = OpFunction %void None %void_func\n" +
1255 "%main_lab = OpLabel\n" +
1256 "%n = OpVariable %_ptr_bool Function\n" +
1257 "%load = OpLoad %bool %n\n" +
1258 "%2 = OpLogicalOr %bool %load %true\n" +
1259 "OpReturn\n" +
1260 "OpFunctionEnd",
1261 2, true),
1262 // Test case 2: fold false && n
1263 InstructionFoldingCase<bool>(
1264 Header() + "%main = OpFunction %void None %void_func\n" +
1265 "%main_lab = OpLabel\n" +
1266 "%n = OpVariable %_ptr_bool Function\n" +
1267 "%load = OpLoad %bool %n\n" +
1268 "%2 = OpLogicalAnd %bool %false %load\n" +
1269 "OpReturn\n" +
1270 "OpFunctionEnd",
1271 2, false),
1272 // Test case 3: fold n && false
1273 InstructionFoldingCase<bool>(
1274 Header() + "%main = OpFunction %void None %void_func\n" +
1275 "%main_lab = OpLabel\n" +
1276 "%n = OpVariable %_ptr_bool Function\n" +
1277 "%load = OpLoad %bool %n\n" +
1278 "%2 = OpLogicalAnd %bool %load %false\n" +
1279 "OpReturn\n" +
1280 "OpFunctionEnd",
1281 2, false),
1282 // Test case 4: fold n < 0 (unsigned)
1283 InstructionFoldingCase<bool>(
1284 Header() + "%main = OpFunction %void None %void_func\n" +
1285 "%main_lab = OpLabel\n" +
1286 "%n = OpVariable %_ptr_uint Function\n" +
1287 "%load = OpLoad %uint %n\n" +
1288 "%2 = OpULessThan %bool %load %uint_0\n" +
1289 "OpReturn\n" +
1290 "OpFunctionEnd",
1291 2, false),
1292 // Test case 5: fold UINT_MAX < n (unsigned)
1293 InstructionFoldingCase<bool>(
1294 Header() + "%main = OpFunction %void None %void_func\n" +
1295 "%main_lab = OpLabel\n" +
1296 "%n = OpVariable %_ptr_uint Function\n" +
1297 "%load = OpLoad %uint %n\n" +
1298 "%2 = OpULessThan %bool %uint_max %load\n" +
1299 "OpReturn\n" +
1300 "OpFunctionEnd",
1301 2, false),
1302 // Test case 6: fold INT_MAX < n (signed)
1303 InstructionFoldingCase<bool>(
1304 Header() + "%main = OpFunction %void None %void_func\n" +
1305 "%main_lab = OpLabel\n" +
1306 "%n = OpVariable %_ptr_int Function\n" +
1307 "%load = OpLoad %int %n\n" +
1308 "%2 = OpSLessThan %bool %int_max %load\n" +
1309 "OpReturn\n" +
1310 "OpFunctionEnd",
1311 2, false),
1312 // Test case 7: fold n < INT_MIN (signed)
1313 InstructionFoldingCase<bool>(
1314 Header() + "%main = OpFunction %void None %void_func\n" +
1315 "%main_lab = OpLabel\n" +
1316 "%n = OpVariable %_ptr_int Function\n" +
1317 "%load = OpLoad %int %n\n" +
1318 "%2 = OpSLessThan %bool %load %int_min\n" +
1319 "OpReturn\n" +
1320 "OpFunctionEnd",
1321 2, false),
1322 // Test case 8: fold 0 > n (unsigned)
1323 InstructionFoldingCase<bool>(
1324 Header() + "%main = OpFunction %void None %void_func\n" +
1325 "%main_lab = OpLabel\n" +
1326 "%n = OpVariable %_ptr_uint Function\n" +
1327 "%load = OpLoad %uint %n\n" +
1328 "%2 = OpUGreaterThan %bool %uint_0 %load\n" +
1329 "OpReturn\n" +
1330 "OpFunctionEnd",
1331 2, false),
1332 // Test case 9: fold n > UINT_MAX (unsigned)
1333 InstructionFoldingCase<bool>(
1334 Header() + "%main = OpFunction %void None %void_func\n" +
1335 "%main_lab = OpLabel\n" +
1336 "%n = OpVariable %_ptr_uint Function\n" +
1337 "%load = OpLoad %uint %n\n" +
1338 "%2 = OpUGreaterThan %bool %load %uint_max\n" +
1339 "OpReturn\n" +
1340 "OpFunctionEnd",
1341 2, false),
1342 // Test case 10: fold n > INT_MAX (signed)
1343 InstructionFoldingCase<bool>(
1344 Header() + "%main = OpFunction %void None %void_func\n" +
1345 "%main_lab = OpLabel\n" +
1346 "%n = OpVariable %_ptr_int Function\n" +
1347 "%load = OpLoad %int %n\n" +
1348 "%2 = OpSGreaterThan %bool %load %int_max\n" +
1349 "OpReturn\n" +
1350 "OpFunctionEnd",
1351 2, false),
1352 // Test case 11: fold INT_MIN > n (signed)
1353 InstructionFoldingCase<bool>(
1354 Header() + "%main = OpFunction %void None %void_func\n" +
1355 "%main_lab = OpLabel\n" +
1356 "%n = OpVariable %_ptr_uint Function\n" +
1357 "%load = OpLoad %uint %n\n" +
1358 "%2 = OpSGreaterThan %bool %int_min %load\n" +
1359 "OpReturn\n" +
1360 "OpFunctionEnd",
1361 2, false),
1362 // Test case 12: fold 0 <= n (unsigned)
1363 InstructionFoldingCase<bool>(
1364 Header() + "%main = OpFunction %void None %void_func\n" +
1365 "%main_lab = OpLabel\n" +
1366 "%n = OpVariable %_ptr_uint Function\n" +
1367 "%load = OpLoad %uint %n\n" +
1368 "%2 = OpULessThanEqual %bool %uint_0 %load\n" +
1369 "OpReturn\n" +
1370 "OpFunctionEnd",
1371 2, true),
1372 // Test case 13: fold n <= UINT_MAX (unsigned)
1373 InstructionFoldingCase<bool>(
1374 Header() + "%main = OpFunction %void None %void_func\n" +
1375 "%main_lab = OpLabel\n" +
1376 "%n = OpVariable %_ptr_uint Function\n" +
1377 "%load = OpLoad %uint %n\n" +
1378 "%2 = OpULessThanEqual %bool %load %uint_max\n" +
1379 "OpReturn\n" +
1380 "OpFunctionEnd",
1381 2, true),
1382 // Test case 14: fold INT_MIN <= n (signed)
1383 InstructionFoldingCase<bool>(
1384 Header() + "%main = OpFunction %void None %void_func\n" +
1385 "%main_lab = OpLabel\n" +
1386 "%n = OpVariable %_ptr_int Function\n" +
1387 "%load = OpLoad %int %n\n" +
1388 "%2 = OpSLessThanEqual %bool %int_min %load\n" +
1389 "OpReturn\n" +
1390 "OpFunctionEnd",
1391 2, true),
1392 // Test case 15: fold n <= INT_MAX (signed)
1393 InstructionFoldingCase<bool>(
1394 Header() + "%main = OpFunction %void None %void_func\n" +
1395 "%main_lab = OpLabel\n" +
1396 "%n = OpVariable %_ptr_int Function\n" +
1397 "%load = OpLoad %int %n\n" +
1398 "%2 = OpSLessThanEqual %bool %load %int_max\n" +
1399 "OpReturn\n" +
1400 "OpFunctionEnd",
1401 2, true),
1402 // Test case 16: fold n >= 0 (unsigned)
1403 InstructionFoldingCase<bool>(
1404 Header() + "%main = OpFunction %void None %void_func\n" +
1405 "%main_lab = OpLabel\n" +
1406 "%n = OpVariable %_ptr_uint Function\n" +
1407 "%load = OpLoad %uint %n\n" +
1408 "%2 = OpUGreaterThanEqual %bool %load %uint_0\n" +
1409 "OpReturn\n" +
1410 "OpFunctionEnd",
1411 2, true),
1412 // Test case 17: fold UINT_MAX >= n (unsigned)
1413 InstructionFoldingCase<bool>(
1414 Header() + "%main = OpFunction %void None %void_func\n" +
1415 "%main_lab = OpLabel\n" +
1416 "%n = OpVariable %_ptr_uint Function\n" +
1417 "%load = OpLoad %uint %n\n" +
1418 "%2 = OpUGreaterThanEqual %bool %uint_max %load\n" +
1419 "OpReturn\n" +
1420 "OpFunctionEnd",
1421 2, true),
1422 // Test case 18: fold n >= INT_MIN (signed)
1423 InstructionFoldingCase<bool>(
1424 Header() + "%main = OpFunction %void None %void_func\n" +
1425 "%main_lab = OpLabel\n" +
1426 "%n = OpVariable %_ptr_int Function\n" +
1427 "%load = OpLoad %int %n\n" +
1428 "%2 = OpSGreaterThanEqual %bool %load %int_min\n" +
1429 "OpReturn\n" +
1430 "OpFunctionEnd",
1431 2, true),
1432 // Test case 19: fold INT_MAX >= n (signed)
1433 InstructionFoldingCase<bool>(
1434 Header() + "%main = OpFunction %void None %void_func\n" +
1435 "%main_lab = OpLabel\n" +
1436 "%n = OpVariable %_ptr_int Function\n" +
1437 "%load = OpLoad %int %n\n" +
1438 "%2 = OpSGreaterThanEqual %bool %int_max %load\n" +
1439 "OpReturn\n" +
1440 "OpFunctionEnd",
1441 2, true)
1442 ));
1443
1444 INSTANTIATE_TEST_SUITE_P(FClampAndCmpLHS, BooleanInstructionFoldingTest,
1445 ::testing::Values(
1446 // Test case 0: fold 0.0 > clamp(n, 0.0, 1.0)
1447 InstructionFoldingCase<bool>(
1448 Header() + "%main = OpFunction %void None %void_func\n" +
1449 "%main_lab = OpLabel\n" +
1450 "%n = OpVariable %_ptr_float Function\n" +
1451 "%ld = OpLoad %float %n\n" +
1452 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1453 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1454 "OpReturn\n" +
1455 "OpFunctionEnd",
1456 2, false),
1457 // Test case 1: fold 0.0 > clamp(n, -1.0, -1.0)
1458 InstructionFoldingCase<bool>(
1459 Header() + "%main = OpFunction %void None %void_func\n" +
1460 "%main_lab = OpLabel\n" +
1461 "%n = OpVariable %_ptr_float Function\n" +
1462 "%ld = OpLoad %float %n\n" +
1463 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1464 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
1465 "OpReturn\n" +
1466 "OpFunctionEnd",
1467 2, true),
1468 // Test case 2: fold 0.0 >= clamp(n, 1, 2)
1469 InstructionFoldingCase<bool>(
1470 Header() + "%main = OpFunction %void None %void_func\n" +
1471 "%main_lab = OpLabel\n" +
1472 "%n = OpVariable %_ptr_float Function\n" +
1473 "%ld = OpLoad %float %n\n" +
1474 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1475 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1476 "OpReturn\n" +
1477 "OpFunctionEnd",
1478 2, false),
1479 // Test case 3: fold 0.0 >= clamp(n, -1.0, 0.0)
1480 InstructionFoldingCase<bool>(
1481 Header() + "%main = OpFunction %void None %void_func\n" +
1482 "%main_lab = OpLabel\n" +
1483 "%n = OpVariable %_ptr_float Function\n" +
1484 "%ld = OpLoad %float %n\n" +
1485 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1486 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
1487 "OpReturn\n" +
1488 "OpFunctionEnd",
1489 2, true),
1490 // Test case 4: fold 0.0 <= clamp(n, 0.0, 1.0)
1491 InstructionFoldingCase<bool>(
1492 Header() + "%main = OpFunction %void None %void_func\n" +
1493 "%main_lab = OpLabel\n" +
1494 "%n = OpVariable %_ptr_float Function\n" +
1495 "%ld = OpLoad %float %n\n" +
1496 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1497 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1498 "OpReturn\n" +
1499 "OpFunctionEnd",
1500 2, true),
1501 // Test case 5: fold 0.0 <= clamp(n, -1.0, -1.0)
1502 InstructionFoldingCase<bool>(
1503 Header() + "%main = OpFunction %void None %void_func\n" +
1504 "%main_lab = OpLabel\n" +
1505 "%n = OpVariable %_ptr_float Function\n" +
1506 "%ld = OpLoad %float %n\n" +
1507 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1508 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
1509 "OpReturn\n" +
1510 "OpFunctionEnd",
1511 2, false),
1512 // Test case 6: fold 0.0 < clamp(n, 1, 2)
1513 InstructionFoldingCase<bool>(
1514 Header() + "%main = OpFunction %void None %void_func\n" +
1515 "%main_lab = OpLabel\n" +
1516 "%n = OpVariable %_ptr_float Function\n" +
1517 "%ld = OpLoad %float %n\n" +
1518 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1519 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1520 "OpReturn\n" +
1521 "OpFunctionEnd",
1522 2, true),
1523 // Test case 7: fold 0.0 < clamp(n, -1.0, 0.0)
1524 InstructionFoldingCase<bool>(
1525 Header() + "%main = OpFunction %void None %void_func\n" +
1526 "%main_lab = OpLabel\n" +
1527 "%n = OpVariable %_ptr_float Function\n" +
1528 "%ld = OpLoad %float %n\n" +
1529 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1530 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
1531 "OpReturn\n" +
1532 "OpFunctionEnd",
1533 2, false),
1534 // Test case 8: fold 0.0 > clamp(n, 0.0, 1.0)
1535 InstructionFoldingCase<bool>(
1536 Header() + "%main = OpFunction %void None %void_func\n" +
1537 "%main_lab = OpLabel\n" +
1538 "%n = OpVariable %_ptr_float Function\n" +
1539 "%ld = OpLoad %float %n\n" +
1540 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1541 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1542 "OpReturn\n" +
1543 "OpFunctionEnd",
1544 2, false),
1545 // Test case 9: fold 0.0 > clamp(n, -1.0, -1.0)
1546 InstructionFoldingCase<bool>(
1547 Header() + "%main = OpFunction %void None %void_func\n" +
1548 "%main_lab = OpLabel\n" +
1549 "%n = OpVariable %_ptr_float Function\n" +
1550 "%ld = OpLoad %float %n\n" +
1551 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1552 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
1553 "OpReturn\n" +
1554 "OpFunctionEnd",
1555 2, true),
1556 // Test case 10: fold 0.0 >= clamp(n, 1, 2)
1557 InstructionFoldingCase<bool>(
1558 Header() + "%main = OpFunction %void None %void_func\n" +
1559 "%main_lab = OpLabel\n" +
1560 "%n = OpVariable %_ptr_float Function\n" +
1561 "%ld = OpLoad %float %n\n" +
1562 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1563 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1564 "OpReturn\n" +
1565 "OpFunctionEnd",
1566 2, false),
1567 // Test case 11: fold 0.0 >= clamp(n, -1.0, 0.0)
1568 InstructionFoldingCase<bool>(
1569 Header() + "%main = OpFunction %void None %void_func\n" +
1570 "%main_lab = OpLabel\n" +
1571 "%n = OpVariable %_ptr_float Function\n" +
1572 "%ld = OpLoad %float %n\n" +
1573 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1574 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
1575 "OpReturn\n" +
1576 "OpFunctionEnd",
1577 2, true),
1578 // Test case 12: fold 0.0 <= clamp(n, 0.0, 1.0)
1579 InstructionFoldingCase<bool>(
1580 Header() + "%main = OpFunction %void None %void_func\n" +
1581 "%main_lab = OpLabel\n" +
1582 "%n = OpVariable %_ptr_float Function\n" +
1583 "%ld = OpLoad %float %n\n" +
1584 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1585 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1586 "OpReturn\n" +
1587 "OpFunctionEnd",
1588 2, true),
1589 // Test case 13: fold 0.0 <= clamp(n, -1.0, -1.0)
1590 InstructionFoldingCase<bool>(
1591 Header() + "%main = OpFunction %void None %void_func\n" +
1592 "%main_lab = OpLabel\n" +
1593 "%n = OpVariable %_ptr_float Function\n" +
1594 "%ld = OpLoad %float %n\n" +
1595 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_n1\n" +
1596 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
1597 "OpReturn\n" +
1598 "OpFunctionEnd",
1599 2, false),
1600 // Test case 14: fold 0.0 < clamp(n, 1, 2)
1601 InstructionFoldingCase<bool>(
1602 Header() + "%main = OpFunction %void None %void_func\n" +
1603 "%main_lab = OpLabel\n" +
1604 "%n = OpVariable %_ptr_float Function\n" +
1605 "%ld = OpLoad %float %n\n" +
1606 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1607 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1608 "OpReturn\n" +
1609 "OpFunctionEnd",
1610 2, true),
1611 // Test case 15: fold 0.0 < clamp(n, -1.0, 0.0)
1612 InstructionFoldingCase<bool>(
1613 Header() + "%main = OpFunction %void None %void_func\n" +
1614 "%main_lab = OpLabel\n" +
1615 "%n = OpVariable %_ptr_float Function\n" +
1616 "%ld = OpLoad %float %n\n" +
1617 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1618 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
1619 "OpReturn\n" +
1620 "OpFunctionEnd",
1621 2, false)
1622 ));
1623
1624 INSTANTIATE_TEST_SUITE_P(FClampAndCmpRHS, BooleanInstructionFoldingTest,
1625 ::testing::Values(
1626 // Test case 0: fold clamp(n, 0.0, 1.0) > 1.0
1627 InstructionFoldingCase<bool>(
1628 Header() + "%main = OpFunction %void None %void_func\n" +
1629 "%main_lab = OpLabel\n" +
1630 "%n = OpVariable %_ptr_float Function\n" +
1631 "%ld = OpLoad %float %n\n" +
1632 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1633 "%2 = OpFOrdGreaterThan %bool %clamp %float_1\n" +
1634 "OpReturn\n" +
1635 "OpFunctionEnd",
1636 2, false),
1637 // Test case 1: fold clamp(n, 1.0, 1.0) > 0.0
1638 InstructionFoldingCase<bool>(
1639 Header() + "%main = OpFunction %void None %void_func\n" +
1640 "%main_lab = OpLabel\n" +
1641 "%n = OpVariable %_ptr_float Function\n" +
1642 "%ld = OpLoad %float %n\n" +
1643 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1644 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
1645 "OpReturn\n" +
1646 "OpFunctionEnd",
1647 2, true),
1648 // Test case 2: fold clamp(n, 1, 2) >= 0.0
1649 InstructionFoldingCase<bool>(
1650 Header() + "%main = OpFunction %void None %void_func\n" +
1651 "%main_lab = OpLabel\n" +
1652 "%n = OpVariable %_ptr_float Function\n" +
1653 "%ld = OpLoad %float %n\n" +
1654 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1655 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
1656 "OpReturn\n" +
1657 "OpFunctionEnd",
1658 2, true),
1659 // Test case 3: fold clamp(n, 1.0, 2.0) >= 3.0
1660 InstructionFoldingCase<bool>(
1661 Header() + "%main = OpFunction %void None %void_func\n" +
1662 "%main_lab = OpLabel\n" +
1663 "%n = OpVariable %_ptr_float Function\n" +
1664 "%ld = OpLoad %float %n\n" +
1665 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1666 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_3\n" +
1667 "OpReturn\n" +
1668 "OpFunctionEnd",
1669 2, false),
1670 // Test case 4: fold clamp(n, 0.0, 1.0) <= 1.0
1671 InstructionFoldingCase<bool>(
1672 Header() + "%main = OpFunction %void None %void_func\n" +
1673 "%main_lab = OpLabel\n" +
1674 "%n = OpVariable %_ptr_float Function\n" +
1675 "%ld = OpLoad %float %n\n" +
1676 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1677 "%2 = OpFOrdLessThanEqual %bool %clamp %float_1\n" +
1678 "OpReturn\n" +
1679 "OpFunctionEnd",
1680 2, true),
1681 // Test case 5: fold clamp(n, 1.0, 2.0) <= 0.0
1682 InstructionFoldingCase<bool>(
1683 Header() + "%main = OpFunction %void None %void_func\n" +
1684 "%main_lab = OpLabel\n" +
1685 "%n = OpVariable %_ptr_float Function\n" +
1686 "%ld = OpLoad %float %n\n" +
1687 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1688 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
1689 "OpReturn\n" +
1690 "OpFunctionEnd",
1691 2, false),
1692 // Test case 6: fold clamp(n, 1, 2) < 3
1693 InstructionFoldingCase<bool>(
1694 Header() + "%main = OpFunction %void None %void_func\n" +
1695 "%main_lab = OpLabel\n" +
1696 "%n = OpVariable %_ptr_float Function\n" +
1697 "%ld = OpLoad %float %n\n" +
1698 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1699 "%2 = OpFOrdLessThan %bool %clamp %float_3\n" +
1700 "OpReturn\n" +
1701 "OpFunctionEnd",
1702 2, true),
1703 // Test case 7: fold clamp(n, -1.0, 0.0) < -1.0
1704 InstructionFoldingCase<bool>(
1705 Header() + "%main = OpFunction %void None %void_func\n" +
1706 "%main_lab = OpLabel\n" +
1707 "%n = OpVariable %_ptr_float Function\n" +
1708 "%ld = OpLoad %float %n\n" +
1709 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1710 "%2 = OpFOrdLessThan %bool %clamp %float_n1\n" +
1711 "OpReturn\n" +
1712 "OpFunctionEnd",
1713 2, false),
1714 // Test case 8: fold clamp(n, 0.0, 1.0) > 1.0
1715 InstructionFoldingCase<bool>(
1716 Header() + "%main = OpFunction %void None %void_func\n" +
1717 "%main_lab = OpLabel\n" +
1718 "%n = OpVariable %_ptr_float Function\n" +
1719 "%ld = OpLoad %float %n\n" +
1720 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1721 "%2 = OpFUnordGreaterThan %bool %clamp %float_1\n" +
1722 "OpReturn\n" +
1723 "OpFunctionEnd",
1724 2, false),
1725 // Test case 9: fold clamp(n, 1.0, 2.0) > 0.0
1726 InstructionFoldingCase<bool>(
1727 Header() + "%main = OpFunction %void None %void_func\n" +
1728 "%main_lab = OpLabel\n" +
1729 "%n = OpVariable %_ptr_float Function\n" +
1730 "%ld = OpLoad %float %n\n" +
1731 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1732 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
1733 "OpReturn\n" +
1734 "OpFunctionEnd",
1735 2, true),
1736 // Test case 10: fold clamp(n, 1, 2) >= 3.0
1737 InstructionFoldingCase<bool>(
1738 Header() + "%main = OpFunction %void None %void_func\n" +
1739 "%main_lab = OpLabel\n" +
1740 "%n = OpVariable %_ptr_float Function\n" +
1741 "%ld = OpLoad %float %n\n" +
1742 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1743 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_3\n" +
1744 "OpReturn\n" +
1745 "OpFunctionEnd",
1746 2, false),
1747 // Test case 11: fold clamp(n, -1.0, 0.0) >= -1.0
1748 InstructionFoldingCase<bool>(
1749 Header() + "%main = OpFunction %void None %void_func\n" +
1750 "%main_lab = OpLabel\n" +
1751 "%n = OpVariable %_ptr_float Function\n" +
1752 "%ld = OpLoad %float %n\n" +
1753 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1754 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_n1\n" +
1755 "OpReturn\n" +
1756 "OpFunctionEnd",
1757 2, true),
1758 // Test case 12: fold clamp(n, 0.0, 1.0) <= 1.0
1759 InstructionFoldingCase<bool>(
1760 Header() + "%main = OpFunction %void None %void_func\n" +
1761 "%main_lab = OpLabel\n" +
1762 "%n = OpVariable %_ptr_float Function\n" +
1763 "%ld = OpLoad %float %n\n" +
1764 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
1765 "%2 = OpFUnordLessThanEqual %bool %clamp %float_1\n" +
1766 "OpReturn\n" +
1767 "OpFunctionEnd",
1768 2, true),
1769 // Test case 13: fold clamp(n, 1.0, 1.0) <= 0.0
1770 InstructionFoldingCase<bool>(
1771 Header() + "%main = OpFunction %void None %void_func\n" +
1772 "%main_lab = OpLabel\n" +
1773 "%n = OpVariable %_ptr_float Function\n" +
1774 "%ld = OpLoad %float %n\n" +
1775 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_1\n" +
1776 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
1777 "OpReturn\n" +
1778 "OpFunctionEnd",
1779 2, false),
1780 // Test case 14: fold clamp(n, 1, 2) < 3
1781 InstructionFoldingCase<bool>(
1782 Header() + "%main = OpFunction %void None %void_func\n" +
1783 "%main_lab = OpLabel\n" +
1784 "%n = OpVariable %_ptr_float Function\n" +
1785 "%ld = OpLoad %float %n\n" +
1786 "%clamp = OpExtInst %float %1 FClamp %ld %float_1 %float_2\n" +
1787 "%2 = OpFUnordLessThan %bool %clamp %float_3\n" +
1788 "OpReturn\n" +
1789 "OpFunctionEnd",
1790 2, true),
1791 // Test case 15: fold clamp(n, -1.0, 0.0) < -1.0
1792 InstructionFoldingCase<bool>(
1793 Header() + "%main = OpFunction %void None %void_func\n" +
1794 "%main_lab = OpLabel\n" +
1795 "%n = OpVariable %_ptr_float Function\n" +
1796 "%ld = OpLoad %float %n\n" +
1797 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
1798 "%2 = OpFUnordLessThan %bool %clamp %float_n1\n" +
1799 "OpReturn\n" +
1800 "OpFunctionEnd",
1801 2, false),
1802 // Test case 16: fold clamp(n, -1.0, 0.0) < -1.0 (one test for double)
1803 InstructionFoldingCase<bool>(
1804 Header() + "%main = OpFunction %void None %void_func\n" +
1805 "%main_lab = OpLabel\n" +
1806 "%n = OpVariable %_ptr_double Function\n" +
1807 "%ld = OpLoad %double %n\n" +
1808 "%clamp = OpExtInst %double %1 FClamp %ld %double_n1 %double_0\n" +
1809 "%2 = OpFUnordLessThan %bool %clamp %double_n1\n" +
1810 "OpReturn\n" +
1811 "OpFunctionEnd",
1812 2, false)
1813 ));
1814 // clang-format on
1815
1816 using FloatInstructionFoldingTest =
1817 ::testing::TestWithParam<InstructionFoldingCase<float>>;
1818
TEST_P(FloatInstructionFoldingTest,Case)1819 TEST_P(FloatInstructionFoldingTest, Case) {
1820 const auto& tc = GetParam();
1821
1822 // Build module.
1823 std::unique_ptr<IRContext> context =
1824 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
1825 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1826 ASSERT_NE(nullptr, context);
1827
1828 // Fold the instruction to test.
1829 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
1830 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
1831 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
1832
1833 // Make sure the instruction folded as expected.
1834 EXPECT_TRUE(succeeded);
1835 if (inst != nullptr) {
1836 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
1837 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
1838 EXPECT_EQ(inst->opcode(), SpvOpConstant);
1839 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
1840 const analysis::FloatConstant* result =
1841 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
1842 EXPECT_NE(result, nullptr);
1843 if (result != nullptr) {
1844 if (!std::isnan(tc.expected_result)) {
1845 EXPECT_EQ(result->GetFloatValue(), tc.expected_result);
1846 } else {
1847 EXPECT_TRUE(std::isnan(result->GetFloatValue()));
1848 }
1849 }
1850 }
1851 }
1852
1853 // Not testing NaNs because there are no expectations concerning NaNs according
1854 // to the "Precision and Operation of SPIR-V Instructions" section of the Vulkan
1855 // specification.
1856
1857 // clang-format off
1858 INSTANTIATE_TEST_SUITE_P(FloatConstantFoldingTest, FloatInstructionFoldingTest,
1859 ::testing::Values(
1860 // Test case 0: Fold 2.0 - 1.0
1861 InstructionFoldingCase<float>(
1862 Header() + "%main = OpFunction %void None %void_func\n" +
1863 "%main_lab = OpLabel\n" +
1864 "%2 = OpFSub %float %float_2 %float_1\n" +
1865 "OpReturn\n" +
1866 "OpFunctionEnd",
1867 2, 1.0),
1868 // Test case 1: Fold 2.0 + 1.0
1869 InstructionFoldingCase<float>(
1870 Header() + "%main = OpFunction %void None %void_func\n" +
1871 "%main_lab = OpLabel\n" +
1872 "%2 = OpFAdd %float %float_2 %float_1\n" +
1873 "OpReturn\n" +
1874 "OpFunctionEnd",
1875 2, 3.0),
1876 // Test case 2: Fold 3.0 * 2.0
1877 InstructionFoldingCase<float>(
1878 Header() + "%main = OpFunction %void None %void_func\n" +
1879 "%main_lab = OpLabel\n" +
1880 "%2 = OpFMul %float %float_3 %float_2\n" +
1881 "OpReturn\n" +
1882 "OpFunctionEnd",
1883 2, 6.0),
1884 // Test case 3: Fold 1.0 / 2.0
1885 InstructionFoldingCase<float>(
1886 Header() + "%main = OpFunction %void None %void_func\n" +
1887 "%main_lab = OpLabel\n" +
1888 "%2 = OpFDiv %float %float_1 %float_2\n" +
1889 "OpReturn\n" +
1890 "OpFunctionEnd",
1891 2, 0.5),
1892 // Test case 4: Fold 1.0 / 0.0
1893 InstructionFoldingCase<float>(
1894 Header() + "%main = OpFunction %void None %void_func\n" +
1895 "%main_lab = OpLabel\n" +
1896 "%2 = OpFDiv %float %float_1 %float_0\n" +
1897 "OpReturn\n" +
1898 "OpFunctionEnd",
1899 2, std::numeric_limits<float>::infinity()),
1900 // Test case 5: Fold -1.0 / 0.0
1901 InstructionFoldingCase<float>(
1902 Header() + "%main = OpFunction %void None %void_func\n" +
1903 "%main_lab = OpLabel\n" +
1904 "%2 = OpFDiv %float %float_n1 %float_0\n" +
1905 "OpReturn\n" +
1906 "OpFunctionEnd",
1907 2, -std::numeric_limits<float>::infinity()),
1908 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
1909 InstructionFoldingCase<float>(
1910 Header() + "%main = OpFunction %void None %void_func\n" +
1911 "%main_lab = OpLabel\n" +
1912 "%2 = OpDot %float %v2float_2_3 %v2float_2_0p5\n" +
1913 "OpReturn\n" +
1914 "OpFunctionEnd",
1915 2, 5.5f),
1916 // Test case 7: Fold (0.0, 0.0) dot v
1917 InstructionFoldingCase<float>(
1918 Header() + "%main = OpFunction %void None %void_func\n" +
1919 "%main_lab = OpLabel\n" +
1920 "%v = OpVariable %_ptr_v2float Function\n" +
1921 "%2 = OpLoad %v2float %v\n" +
1922 "%3 = OpDot %float %v2float_0_0 %2\n" +
1923 "OpReturn\n" +
1924 "OpFunctionEnd",
1925 3, 0.0f),
1926 // Test case 8: Fold v dot (0.0, 0.0)
1927 InstructionFoldingCase<float>(
1928 Header() + "%main = OpFunction %void None %void_func\n" +
1929 "%main_lab = OpLabel\n" +
1930 "%v = OpVariable %_ptr_v2float Function\n" +
1931 "%2 = OpLoad %v2float %v\n" +
1932 "%3 = OpDot %float %2 %v2float_0_0\n" +
1933 "OpReturn\n" +
1934 "OpFunctionEnd",
1935 3, 0.0f),
1936 // Test case 9: Fold Null dot v
1937 InstructionFoldingCase<float>(
1938 Header() + "%main = OpFunction %void None %void_func\n" +
1939 "%main_lab = OpLabel\n" +
1940 "%v = OpVariable %_ptr_v2float Function\n" +
1941 "%2 = OpLoad %v2float %v\n" +
1942 "%3 = OpDot %float %v2float_null %2\n" +
1943 "OpReturn\n" +
1944 "OpFunctionEnd",
1945 3, 0.0f),
1946 // Test case 10: Fold v dot Null
1947 InstructionFoldingCase<float>(
1948 Header() + "%main = OpFunction %void None %void_func\n" +
1949 "%main_lab = OpLabel\n" +
1950 "%v = OpVariable %_ptr_v2float Function\n" +
1951 "%2 = OpLoad %v2float %v\n" +
1952 "%3 = OpDot %float %2 %v2float_null\n" +
1953 "OpReturn\n" +
1954 "OpFunctionEnd",
1955 3, 0.0f),
1956 // Test case 11: Fold -2.0
1957 InstructionFoldingCase<float>(
1958 Header() + "%main = OpFunction %void None %void_func\n" +
1959 "%main_lab = OpLabel\n" +
1960 "%2 = OpFNegate %float %float_2\n" +
1961 "OpReturn\n" +
1962 "OpFunctionEnd",
1963 2, -2),
1964 // Test case 12: QuantizeToF16 1.0
1965 InstructionFoldingCase<float>(
1966 Header() + "%main = OpFunction %void None %void_func\n" +
1967 "%main_lab = OpLabel\n" +
1968 "%2 = OpQuantizeToF16 %float %float_1\n" +
1969 "OpReturn\n" +
1970 "OpFunctionEnd",
1971 2, 1.0),
1972 // Test case 13: QuantizeToF16 positive non exact
1973 InstructionFoldingCase<float>(
1974 Header() + "%main = OpFunction %void None %void_func\n" +
1975 "%main_lab = OpLabel\n" +
1976 "%2 = OpQuantizeToF16 %float %float_2049\n" +
1977 "OpReturn\n" +
1978 "OpFunctionEnd",
1979 2, 2048),
1980 // Test case 14: QuantizeToF16 negative non exact
1981 InstructionFoldingCase<float>(
1982 Header() + "%main = OpFunction %void None %void_func\n" +
1983 "%main_lab = OpLabel\n" +
1984 "%2 = OpQuantizeToF16 %float %float_n2049\n" +
1985 "OpReturn\n" +
1986 "OpFunctionEnd",
1987 2, -2048),
1988 // Test case 15: QuantizeToF16 large positive
1989 InstructionFoldingCase<float>(
1990 Header() + "%main = OpFunction %void None %void_func\n" +
1991 "%main_lab = OpLabel\n" +
1992 "%2 = OpQuantizeToF16 %float %float_1e16\n" +
1993 "OpReturn\n" +
1994 "OpFunctionEnd",
1995 2, std::numeric_limits<float>::infinity()),
1996 // Test case 16: QuantizeToF16 large negative
1997 InstructionFoldingCase<float>(
1998 Header() + "%main = OpFunction %void None %void_func\n" +
1999 "%main_lab = OpLabel\n" +
2000 "%2 = OpQuantizeToF16 %float %float_n1e16\n" +
2001 "OpReturn\n" +
2002 "OpFunctionEnd",
2003 2, -std::numeric_limits<float>::infinity()),
2004 // Test case 17: QuantizeToF16 small positive
2005 InstructionFoldingCase<float>(
2006 Header() + "%main = OpFunction %void None %void_func\n" +
2007 "%main_lab = OpLabel\n" +
2008 "%2 = OpQuantizeToF16 %float %float_1en16\n" +
2009 "OpReturn\n" +
2010 "OpFunctionEnd",
2011 2, 0.0),
2012 // Test case 18: QuantizeToF16 small negative
2013 InstructionFoldingCase<float>(
2014 Header() + "%main = OpFunction %void None %void_func\n" +
2015 "%main_lab = OpLabel\n" +
2016 "%2 = OpQuantizeToF16 %float %float_n1en16\n" +
2017 "OpReturn\n" +
2018 "OpFunctionEnd",
2019 2, 0.0),
2020 // Test case 19: QuantizeToF16 nan
2021 InstructionFoldingCase<float>(
2022 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
2023 "%main_lab = OpLabel\n" +
2024 "%2 = OpQuantizeToF16 %float %float_nan\n" +
2025 "OpReturn\n" +
2026 "OpFunctionEnd",
2027 2, std::numeric_limits<float>::quiet_NaN()),
2028 // Test case 20: FMix 1.0 4.0 0.2
2029 InstructionFoldingCase<float>(
2030 Header() + "%main = OpFunction %void None %void_func\n" +
2031 "%main_lab = OpLabel\n" +
2032 "%2 = OpExtInst %float %1 FMix %float_1 %float_4 %float_0p2\n" +
2033 "OpReturn\n" +
2034 "OpFunctionEnd",
2035 2, 1.6f),
2036 // Test case 21: FMin 1.0 4.0
2037 InstructionFoldingCase<float>(
2038 Header() + "%main = OpFunction %void None %void_func\n" +
2039 "%main_lab = OpLabel\n" +
2040 "%2 = OpExtInst %float %1 FMin %float_1 %float_4\n" +
2041 "OpReturn\n" +
2042 "OpFunctionEnd",
2043 2, 1.0f),
2044 // Test case 22: FMin 4.0 0.2
2045 InstructionFoldingCase<float>(
2046 Header() + "%main = OpFunction %void None %void_func\n" +
2047 "%main_lab = OpLabel\n" +
2048 "%2 = OpExtInst %float %1 FMin %float_4 %float_0p2\n" +
2049 "OpReturn\n" +
2050 "OpFunctionEnd",
2051 2, 0.2f),
2052 // Test case 23: FMax 1.0 4.0
2053 InstructionFoldingCase<float>(
2054 Header() + "%main = OpFunction %void None %void_func\n" +
2055 "%main_lab = OpLabel\n" +
2056 "%2 = OpExtInst %float %1 FMax %float_1 %float_4\n" +
2057 "OpReturn\n" +
2058 "OpFunctionEnd",
2059 2, 4.0f),
2060 // Test case 24: FMax 1.0 0.2
2061 InstructionFoldingCase<float>(
2062 Header() + "%main = OpFunction %void None %void_func\n" +
2063 "%main_lab = OpLabel\n" +
2064 "%2 = OpExtInst %float %1 FMax %float_1 %float_0p2\n" +
2065 "OpReturn\n" +
2066 "OpFunctionEnd",
2067 2, 1.0f),
2068 // Test case 25: FClamp 1.0 0.2 4.0
2069 InstructionFoldingCase<float>(
2070 Header() + "%main = OpFunction %void None %void_func\n" +
2071 "%main_lab = OpLabel\n" +
2072 "%2 = OpExtInst %float %1 FClamp %float_1 %float_0p2 %float_4\n" +
2073 "OpReturn\n" +
2074 "OpFunctionEnd",
2075 2, 1.0f),
2076 // Test case 26: FClamp 0.2 2.0 4.0
2077 InstructionFoldingCase<float>(
2078 Header() + "%main = OpFunction %void None %void_func\n" +
2079 "%main_lab = OpLabel\n" +
2080 "%2 = OpExtInst %float %1 FClamp %float_0p2 %float_2 %float_4\n" +
2081 "OpReturn\n" +
2082 "OpFunctionEnd",
2083 2, 2.0f),
2084 // Test case 27: FClamp 2049.0 2.0 4.0
2085 InstructionFoldingCase<float>(
2086 Header() + "%main = OpFunction %void None %void_func\n" +
2087 "%main_lab = OpLabel\n" +
2088 "%2 = OpExtInst %float %1 FClamp %float_2049 %float_2 %float_4\n" +
2089 "OpReturn\n" +
2090 "OpFunctionEnd",
2091 2, 4.0f),
2092 // Test case 28: FClamp 1.0 2.0 x
2093 InstructionFoldingCase<float>(
2094 Header() + "%main = OpFunction %void None %void_func\n" +
2095 "%main_lab = OpLabel\n" +
2096 "%undef = OpUndef %float\n" +
2097 "%2 = OpExtInst %float %1 FClamp %float_1 %float_2 %undef\n" +
2098 "OpReturn\n" +
2099 "OpFunctionEnd",
2100 2, 2.0),
2101 // Test case 29: FClamp 1.0 x 0.5
2102 InstructionFoldingCase<float>(
2103 Header() + "%main = OpFunction %void None %void_func\n" +
2104 "%main_lab = OpLabel\n" +
2105 "%undef = OpUndef %float\n" +
2106 "%2 = OpExtInst %float %1 FClamp %float_1 %undef %float_0p5\n" +
2107 "OpReturn\n" +
2108 "OpFunctionEnd",
2109 2, 0.5),
2110 // Test case 30: Sin 0.0
2111 InstructionFoldingCase<float>(
2112 Header() + "%main = OpFunction %void None %void_func\n" +
2113 "%main_lab = OpLabel\n" +
2114 "%2 = OpExtInst %float %1 Sin %float_0\n" +
2115 "OpReturn\n" +
2116 "OpFunctionEnd",
2117 2, 0.0),
2118 // Test case 31: Cos 0.0
2119 InstructionFoldingCase<float>(
2120 Header() + "%main = OpFunction %void None %void_func\n" +
2121 "%main_lab = OpLabel\n" +
2122 "%2 = OpExtInst %float %1 Cos %float_0\n" +
2123 "OpReturn\n" +
2124 "OpFunctionEnd",
2125 2, 1.0),
2126 // Test case 32: Tan 0.0
2127 InstructionFoldingCase<float>(
2128 Header() + "%main = OpFunction %void None %void_func\n" +
2129 "%main_lab = OpLabel\n" +
2130 "%2 = OpExtInst %float %1 Tan %float_0\n" +
2131 "OpReturn\n" +
2132 "OpFunctionEnd",
2133 2, 0.0),
2134 // Test case 33: Asin 0.0
2135 InstructionFoldingCase<float>(
2136 Header() + "%main = OpFunction %void None %void_func\n" +
2137 "%main_lab = OpLabel\n" +
2138 "%2 = OpExtInst %float %1 Asin %float_0\n" +
2139 "OpReturn\n" +
2140 "OpFunctionEnd",
2141 2, 0.0),
2142 // Test case 34: Acos 1.0
2143 InstructionFoldingCase<float>(
2144 Header() + "%main = OpFunction %void None %void_func\n" +
2145 "%main_lab = OpLabel\n" +
2146 "%2 = OpExtInst %float %1 Acos %float_1\n" +
2147 "OpReturn\n" +
2148 "OpFunctionEnd",
2149 2, 0.0),
2150 // Test case 35: Atan 0.0
2151 InstructionFoldingCase<float>(
2152 Header() + "%main = OpFunction %void None %void_func\n" +
2153 "%main_lab = OpLabel\n" +
2154 "%2 = OpExtInst %float %1 Atan %float_0\n" +
2155 "OpReturn\n" +
2156 "OpFunctionEnd",
2157 2, 0.0),
2158 // Test case 36: Exp 0.0
2159 InstructionFoldingCase<float>(
2160 Header() + "%main = OpFunction %void None %void_func\n" +
2161 "%main_lab = OpLabel\n" +
2162 "%2 = OpExtInst %float %1 Exp %float_0\n" +
2163 "OpReturn\n" +
2164 "OpFunctionEnd",
2165 2, 1.0),
2166 // Test case 37: Log 1.0
2167 InstructionFoldingCase<float>(
2168 Header() + "%main = OpFunction %void None %void_func\n" +
2169 "%main_lab = OpLabel\n" +
2170 "%2 = OpExtInst %float %1 Log %float_1\n" +
2171 "OpReturn\n" +
2172 "OpFunctionEnd",
2173 2, 0.0),
2174 // Test case 38: Exp2 2.0
2175 InstructionFoldingCase<float>(
2176 Header() + "%main = OpFunction %void None %void_func\n" +
2177 "%main_lab = OpLabel\n" +
2178 "%2 = OpExtInst %float %1 Exp2 %float_2\n" +
2179 "OpReturn\n" +
2180 "OpFunctionEnd",
2181 2, 4.0),
2182 // Test case 39: Log2 4.0
2183 InstructionFoldingCase<float>(
2184 Header() + "%main = OpFunction %void None %void_func\n" +
2185 "%main_lab = OpLabel\n" +
2186 "%2 = OpExtInst %float %1 Log2 %float_4\n" +
2187 "OpReturn\n" +
2188 "OpFunctionEnd",
2189 2, 2.0),
2190 // Test case 40: Sqrt 4.0
2191 InstructionFoldingCase<float>(
2192 Header() + "%main = OpFunction %void None %void_func\n" +
2193 "%main_lab = OpLabel\n" +
2194 "%2 = OpExtInst %float %1 Sqrt %float_4\n" +
2195 "OpReturn\n" +
2196 "OpFunctionEnd",
2197 2, 2.0),
2198 // Test case 41: Atan2 0.0 1.0
2199 InstructionFoldingCase<float>(
2200 Header() + "%main = OpFunction %void None %void_func\n" +
2201 "%main_lab = OpLabel\n" +
2202 "%2 = OpExtInst %float %1 Atan2 %float_0 %float_1\n" +
2203 "OpReturn\n" +
2204 "OpFunctionEnd",
2205 2, 0.0),
2206 // Test case 42: Pow 2.0 3.0
2207 InstructionFoldingCase<float>(
2208 Header() + "%main = OpFunction %void None %void_func\n" +
2209 "%main_lab = OpLabel\n" +
2210 "%2 = OpExtInst %float %1 Pow %float_2 %float_3\n" +
2211 "OpReturn\n" +
2212 "OpFunctionEnd",
2213 2, 8.0),
2214 // Test case 43: Fold 1.0 / -0.0.
2215 InstructionFoldingCase<float>(
2216 Header() + "%main = OpFunction %void None %void_func\n" +
2217 "%main_lab = OpLabel\n" +
2218 "%2 = OpFDiv %float %float_1 %float_n0\n" +
2219 "OpReturn\n" +
2220 "OpFunctionEnd",
2221 2, -std::numeric_limits<float>::infinity()),
2222 // Test case 44: Fold -1.0 / -0.0
2223 InstructionFoldingCase<float>(
2224 Header() + "%main = OpFunction %void None %void_func\n" +
2225 "%main_lab = OpLabel\n" +
2226 "%2 = OpFDiv %float %float_n1 %float_n0\n" +
2227 "OpReturn\n" +
2228 "OpFunctionEnd",
2229 2, std::numeric_limits<float>::infinity()),
2230 // Test case 45: Fold 0.0 / 0.0
2231 InstructionFoldingCase<float>(
2232 Header() + "%main = OpFunction %void None %void_func\n" +
2233 "%main_lab = OpLabel\n" +
2234 "%2 = OpFDiv %float %float_0 %float_0\n" +
2235 "OpReturn\n" +
2236 "OpFunctionEnd",
2237 2, std::numeric_limits<float>::quiet_NaN()),
2238 // Test case 46: Fold 0.0 / -0.0
2239 InstructionFoldingCase<float>(
2240 Header() + "%main = OpFunction %void None %void_func\n" +
2241 "%main_lab = OpLabel\n" +
2242 "%2 = OpFDiv %float %float_0 %float_n0\n" +
2243 "OpReturn\n" +
2244 "OpFunctionEnd",
2245 2, std::numeric_limits<float>::quiet_NaN())
2246 ));
2247 // clang-format on
2248
2249 using DoubleInstructionFoldingTest =
2250 ::testing::TestWithParam<InstructionFoldingCase<double>>;
2251
TEST_P(DoubleInstructionFoldingTest,Case)2252 TEST_P(DoubleInstructionFoldingTest, Case) {
2253 const auto& tc = GetParam();
2254
2255 // Build module.
2256 std::unique_ptr<IRContext> context =
2257 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
2258 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
2259 ASSERT_NE(nullptr, context);
2260
2261 // Fold the instruction to test.
2262 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
2263 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
2264 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
2265
2266 // Make sure the instruction folded as expected.
2267 EXPECT_TRUE(succeeded);
2268 if (inst != nullptr) {
2269 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
2270 inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0));
2271 EXPECT_EQ(inst->opcode(), SpvOpConstant);
2272 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
2273 const analysis::FloatConstant* result =
2274 const_mrg->GetConstantFromInst(inst)->AsFloatConstant();
2275 EXPECT_NE(result, nullptr);
2276 if (result != nullptr) {
2277 if (!std::isnan(tc.expected_result)) {
2278 EXPECT_EQ(result->GetDoubleValue(), tc.expected_result);
2279 } else {
2280 EXPECT_TRUE(std::isnan(result->GetDoubleValue()));
2281 }
2282 }
2283 }
2284 }
2285
2286 // clang-format off
2287 INSTANTIATE_TEST_SUITE_P(DoubleConstantFoldingTest, DoubleInstructionFoldingTest,
2288 ::testing::Values(
2289 // Test case 0: Fold 2.0 - 1.0
2290 InstructionFoldingCase<double>(
2291 Header() + "%main = OpFunction %void None %void_func\n" +
2292 "%main_lab = OpLabel\n" +
2293 "%2 = OpFSub %double %double_2 %double_1\n" +
2294 "OpReturn\n" +
2295 "OpFunctionEnd",
2296 2, 1.0),
2297 // Test case 1: Fold 2.0 + 1.0
2298 InstructionFoldingCase<double>(
2299 Header() + "%main = OpFunction %void None %void_func\n" +
2300 "%main_lab = OpLabel\n" +
2301 "%2 = OpFAdd %double %double_2 %double_1\n" +
2302 "OpReturn\n" +
2303 "OpFunctionEnd",
2304 2, 3.0),
2305 // Test case 2: Fold 3.0 * 2.0
2306 InstructionFoldingCase<double>(
2307 Header() + "%main = OpFunction %void None %void_func\n" +
2308 "%main_lab = OpLabel\n" +
2309 "%2 = OpFMul %double %double_3 %double_2\n" +
2310 "OpReturn\n" +
2311 "OpFunctionEnd",
2312 2, 6.0),
2313 // Test case 3: Fold 1.0 / 2.0
2314 InstructionFoldingCase<double>(
2315 Header() + "%main = OpFunction %void None %void_func\n" +
2316 "%main_lab = OpLabel\n" +
2317 "%2 = OpFDiv %double %double_1 %double_2\n" +
2318 "OpReturn\n" +
2319 "OpFunctionEnd",
2320 2, 0.5),
2321 // Test case 4: Fold 1.0 / 0.0
2322 InstructionFoldingCase<double>(
2323 Header() + "%main = OpFunction %void None %void_func\n" +
2324 "%main_lab = OpLabel\n" +
2325 "%2 = OpFDiv %double %double_1 %double_0\n" +
2326 "OpReturn\n" +
2327 "OpFunctionEnd",
2328 2, std::numeric_limits<double>::infinity()),
2329 // Test case 5: Fold -1.0 / 0.0
2330 InstructionFoldingCase<double>(
2331 Header() + "%main = OpFunction %void None %void_func\n" +
2332 "%main_lab = OpLabel\n" +
2333 "%2 = OpFDiv %double %double_n1 %double_0\n" +
2334 "OpReturn\n" +
2335 "OpFunctionEnd",
2336 2, -std::numeric_limits<double>::infinity()),
2337 // Test case 6: Fold (2.0, 3.0) dot (2.0, 0.5)
2338 InstructionFoldingCase<double>(
2339 Header() + "%main = OpFunction %void None %void_func\n" +
2340 "%main_lab = OpLabel\n" +
2341 "%2 = OpDot %double %v2double_2_3 %v2double_2_0p5\n" +
2342 "OpReturn\n" +
2343 "OpFunctionEnd",
2344 2, 5.5f),
2345 // Test case 7: Fold (0.0, 0.0) dot v
2346 InstructionFoldingCase<double>(
2347 Header() + "%main = OpFunction %void None %void_func\n" +
2348 "%main_lab = OpLabel\n" +
2349 "%v = OpVariable %_ptr_v2double Function\n" +
2350 "%2 = OpLoad %v2double %v\n" +
2351 "%3 = OpDot %double %v2double_0_0 %2\n" +
2352 "OpReturn\n" +
2353 "OpFunctionEnd",
2354 3, 0.0f),
2355 // Test case 8: Fold v dot (0.0, 0.0)
2356 InstructionFoldingCase<double>(
2357 Header() + "%main = OpFunction %void None %void_func\n" +
2358 "%main_lab = OpLabel\n" +
2359 "%v = OpVariable %_ptr_v2double Function\n" +
2360 "%2 = OpLoad %v2double %v\n" +
2361 "%3 = OpDot %double %2 %v2double_0_0\n" +
2362 "OpReturn\n" +
2363 "OpFunctionEnd",
2364 3, 0.0f),
2365 // Test case 9: Fold Null dot v
2366 InstructionFoldingCase<double>(
2367 Header() + "%main = OpFunction %void None %void_func\n" +
2368 "%main_lab = OpLabel\n" +
2369 "%v = OpVariable %_ptr_v2double Function\n" +
2370 "%2 = OpLoad %v2double %v\n" +
2371 "%3 = OpDot %double %v2double_null %2\n" +
2372 "OpReturn\n" +
2373 "OpFunctionEnd",
2374 3, 0.0f),
2375 // Test case 10: Fold v dot Null
2376 InstructionFoldingCase<double>(
2377 Header() + "%main = OpFunction %void None %void_func\n" +
2378 "%main_lab = OpLabel\n" +
2379 "%v = OpVariable %_ptr_v2double Function\n" +
2380 "%2 = OpLoad %v2double %v\n" +
2381 "%3 = OpDot %double %2 %v2double_null\n" +
2382 "OpReturn\n" +
2383 "OpFunctionEnd",
2384 3, 0.0f),
2385 // Test case 11: Fold -2.0
2386 InstructionFoldingCase<double>(
2387 Header() + "%main = OpFunction %void None %void_func\n" +
2388 "%main_lab = OpLabel\n" +
2389 "%2 = OpFNegate %double %double_2\n" +
2390 "OpReturn\n" +
2391 "OpFunctionEnd",
2392 2, -2),
2393 // Test case 12: FMin 1.0 4.0
2394 InstructionFoldingCase<double>(
2395 Header() + "%main = OpFunction %void None %void_func\n" +
2396 "%main_lab = OpLabel\n" +
2397 "%2 = OpExtInst %double %1 FMin %double_1 %double_4\n" +
2398 "OpReturn\n" +
2399 "OpFunctionEnd",
2400 2, 1.0),
2401 // Test case 13: FMin 4.0 0.2
2402 InstructionFoldingCase<double>(
2403 Header() + "%main = OpFunction %void None %void_func\n" +
2404 "%main_lab = OpLabel\n" +
2405 "%2 = OpExtInst %double %1 FMin %double_4 %double_0p2\n" +
2406 "OpReturn\n" +
2407 "OpFunctionEnd",
2408 2, 0.2),
2409 // Test case 14: FMax 1.0 4.0
2410 InstructionFoldingCase<double>(
2411 Header() + "%main = OpFunction %void None %void_func\n" +
2412 "%main_lab = OpLabel\n" +
2413 "%2 = OpExtInst %double %1 FMax %double_1 %double_4\n" +
2414 "OpReturn\n" +
2415 "OpFunctionEnd",
2416 2, 4.0),
2417 // Test case 15: FMax 1.0 0.2
2418 InstructionFoldingCase<double>(
2419 Header() + "%main = OpFunction %void None %void_func\n" +
2420 "%main_lab = OpLabel\n" +
2421 "%2 = OpExtInst %double %1 FMax %double_1 %double_0p2\n" +
2422 "OpReturn\n" +
2423 "OpFunctionEnd",
2424 2, 1.0),
2425 // Test case 16: FClamp 1.0 0.2 4.0
2426 InstructionFoldingCase<double>(
2427 Header() + "%main = OpFunction %void None %void_func\n" +
2428 "%main_lab = OpLabel\n" +
2429 "%2 = OpExtInst %double %1 FClamp %double_1 %double_0p2 %double_4\n" +
2430 "OpReturn\n" +
2431 "OpFunctionEnd",
2432 2, 1.0),
2433 // Test case 17: FClamp 0.2 2.0 4.0
2434 InstructionFoldingCase<double>(
2435 Header() + "%main = OpFunction %void None %void_func\n" +
2436 "%main_lab = OpLabel\n" +
2437 "%2 = OpExtInst %double %1 FClamp %double_0p2 %double_2 %double_4\n" +
2438 "OpReturn\n" +
2439 "OpFunctionEnd",
2440 2, 2.0),
2441 // Test case 18: FClamp 5.0 2.0 4.0
2442 InstructionFoldingCase<double>(
2443 Header() + "%main = OpFunction %void None %void_func\n" +
2444 "%main_lab = OpLabel\n" +
2445 "%2 = OpExtInst %double %1 FClamp %double_5 %double_2 %double_4\n" +
2446 "OpReturn\n" +
2447 "OpFunctionEnd",
2448 2, 4.0),
2449 // Test case 19: FClamp 1.0 2.0 x
2450 InstructionFoldingCase<double>(
2451 Header() + "%main = OpFunction %void None %void_func\n" +
2452 "%main_lab = OpLabel\n" +
2453 "%undef = OpUndef %double\n" +
2454 "%2 = OpExtInst %double %1 FClamp %double_1 %double_2 %undef\n" +
2455 "OpReturn\n" +
2456 "OpFunctionEnd",
2457 2, 2.0),
2458 // Test case 20: FClamp 1.0 x 0.5
2459 InstructionFoldingCase<double>(
2460 Header() + "%main = OpFunction %void None %void_func\n" +
2461 "%main_lab = OpLabel\n" +
2462 "%undef = OpUndef %double\n" +
2463 "%2 = OpExtInst %double %1 FClamp %double_1 %undef %double_0p5\n" +
2464 "OpReturn\n" +
2465 "OpFunctionEnd",
2466 2, 0.5),
2467 // Test case 21: Sqrt 4.0
2468 InstructionFoldingCase<double>(
2469 Header() + "%main = OpFunction %void None %void_func\n" +
2470 "%main_lab = OpLabel\n" +
2471 "%undef = OpUndef %double\n" +
2472 "%2 = OpExtInst %double %1 Sqrt %double_4\n" +
2473 "OpReturn\n" +
2474 "OpFunctionEnd",
2475 2, 2.0),
2476 // Test case 22: Pow 2.0 3.0
2477 InstructionFoldingCase<double>(
2478 Header() + "%main = OpFunction %void None %void_func\n" +
2479 "%main_lab = OpLabel\n" +
2480 "%undef = OpUndef %double\n" +
2481 "%2 = OpExtInst %double %1 Pow %double_2 %double_3\n" +
2482 "OpReturn\n" +
2483 "OpFunctionEnd",
2484 2, 8.0),
2485 // Test case 23: Fold 1.0 / -0.0.
2486 InstructionFoldingCase<double>(
2487 Header() + "%main = OpFunction %void None %void_func\n" +
2488 "%main_lab = OpLabel\n" +
2489 "%2 = OpFDiv %double %double_1 %double_n0\n" +
2490 "OpReturn\n" +
2491 "OpFunctionEnd",
2492 2, -std::numeric_limits<double>::infinity()),
2493 // Test case 24: Fold -1.0 / -0.0
2494 InstructionFoldingCase<double>(
2495 Header() + "%main = OpFunction %void None %void_func\n" +
2496 "%main_lab = OpLabel\n" +
2497 "%2 = OpFDiv %double %double_n1 %double_n0\n" +
2498 "OpReturn\n" +
2499 "OpFunctionEnd",
2500 2, std::numeric_limits<double>::infinity()),
2501 // Test case 25: Fold 0.0 / 0.0
2502 InstructionFoldingCase<double>(
2503 Header() + "%main = OpFunction %void None %void_func\n" +
2504 "%main_lab = OpLabel\n" +
2505 "%2 = OpFDiv %double %double_0 %double_0\n" +
2506 "OpReturn\n" +
2507 "OpFunctionEnd",
2508 2, std::numeric_limits<double>::quiet_NaN()),
2509 // Test case 26: Fold 0.0 / -0.0
2510 InstructionFoldingCase<double>(
2511 Header() + "%main = OpFunction %void None %void_func\n" +
2512 "%main_lab = OpLabel\n" +
2513 "%2 = OpFDiv %double %double_0 %double_n0\n" +
2514 "OpReturn\n" +
2515 "OpFunctionEnd",
2516 2, std::numeric_limits<double>::quiet_NaN())
2517 ));
2518 // clang-format on
2519
2520 // clang-format off
2521 INSTANTIATE_TEST_SUITE_P(DoubleOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2522 ::testing::Values(
2523 // Test case 0: fold 1.0 == 2.0
2524 InstructionFoldingCase<bool>(
2525 Header() + "%main = OpFunction %void None %void_func\n" +
2526 "%main_lab = OpLabel\n" +
2527 "%2 = OpFOrdEqual %bool %double_1 %double_2\n" +
2528 "OpReturn\n" +
2529 "OpFunctionEnd",
2530 2, false),
2531 // Test case 1: fold 1.0 != 2.0
2532 InstructionFoldingCase<bool>(
2533 Header() + "%main = OpFunction %void None %void_func\n" +
2534 "%main_lab = OpLabel\n" +
2535 "%2 = OpFOrdNotEqual %bool %double_1 %double_2\n" +
2536 "OpReturn\n" +
2537 "OpFunctionEnd",
2538 2, true),
2539 // Test case 2: fold 1.0 < 2.0
2540 InstructionFoldingCase<bool>(
2541 Header() + "%main = OpFunction %void None %void_func\n" +
2542 "%main_lab = OpLabel\n" +
2543 "%2 = OpFOrdLessThan %bool %double_1 %double_2\n" +
2544 "OpReturn\n" +
2545 "OpFunctionEnd",
2546 2, true),
2547 // Test case 3: fold 1.0 > 2.0
2548 InstructionFoldingCase<bool>(
2549 Header() + "%main = OpFunction %void None %void_func\n" +
2550 "%main_lab = OpLabel\n" +
2551 "%2 = OpFOrdGreaterThan %bool %double_1 %double_2\n" +
2552 "OpReturn\n" +
2553 "OpFunctionEnd",
2554 2, false),
2555 // Test case 4: fold 1.0 <= 2.0
2556 InstructionFoldingCase<bool>(
2557 Header() + "%main = OpFunction %void None %void_func\n" +
2558 "%main_lab = OpLabel\n" +
2559 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_2\n" +
2560 "OpReturn\n" +
2561 "OpFunctionEnd",
2562 2, true),
2563 // Test case 5: fold 1.0 >= 2.0
2564 InstructionFoldingCase<bool>(
2565 Header() + "%main = OpFunction %void None %void_func\n" +
2566 "%main_lab = OpLabel\n" +
2567 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_2\n" +
2568 "OpReturn\n" +
2569 "OpFunctionEnd",
2570 2, false),
2571 // Test case 6: fold 1.0 == 1.0
2572 InstructionFoldingCase<bool>(
2573 Header() + "%main = OpFunction %void None %void_func\n" +
2574 "%main_lab = OpLabel\n" +
2575 "%2 = OpFOrdEqual %bool %double_1 %double_1\n" +
2576 "OpReturn\n" +
2577 "OpFunctionEnd",
2578 2, true),
2579 // Test case 7: fold 1.0 != 1.0
2580 InstructionFoldingCase<bool>(
2581 Header() + "%main = OpFunction %void None %void_func\n" +
2582 "%main_lab = OpLabel\n" +
2583 "%2 = OpFOrdNotEqual %bool %double_1 %double_1\n" +
2584 "OpReturn\n" +
2585 "OpFunctionEnd",
2586 2, false),
2587 // Test case 8: fold 1.0 < 1.0
2588 InstructionFoldingCase<bool>(
2589 Header() + "%main = OpFunction %void None %void_func\n" +
2590 "%main_lab = OpLabel\n" +
2591 "%2 = OpFOrdLessThan %bool %double_1 %double_1\n" +
2592 "OpReturn\n" +
2593 "OpFunctionEnd",
2594 2, false),
2595 // Test case 9: fold 1.0 > 1.0
2596 InstructionFoldingCase<bool>(
2597 Header() + "%main = OpFunction %void None %void_func\n" +
2598 "%main_lab = OpLabel\n" +
2599 "%2 = OpFOrdGreaterThan %bool %double_1 %double_1\n" +
2600 "OpReturn\n" +
2601 "OpFunctionEnd",
2602 2, false),
2603 // Test case 10: fold 1.0 <= 1.0
2604 InstructionFoldingCase<bool>(
2605 Header() + "%main = OpFunction %void None %void_func\n" +
2606 "%main_lab = OpLabel\n" +
2607 "%2 = OpFOrdLessThanEqual %bool %double_1 %double_1\n" +
2608 "OpReturn\n" +
2609 "OpFunctionEnd",
2610 2, true),
2611 // Test case 11: fold 1.0 >= 1.0
2612 InstructionFoldingCase<bool>(
2613 Header() + "%main = OpFunction %void None %void_func\n" +
2614 "%main_lab = OpLabel\n" +
2615 "%2 = OpFOrdGreaterThanEqual %bool %double_1 %double_1\n" +
2616 "OpReturn\n" +
2617 "OpFunctionEnd",
2618 2, true),
2619 // Test case 12: fold 2.0 < 1.0
2620 InstructionFoldingCase<bool>(
2621 Header() + "%main = OpFunction %void None %void_func\n" +
2622 "%main_lab = OpLabel\n" +
2623 "%2 = OpFOrdLessThan %bool %double_2 %double_1\n" +
2624 "OpReturn\n" +
2625 "OpFunctionEnd",
2626 2, false),
2627 // Test case 13: fold 2.0 > 1.0
2628 InstructionFoldingCase<bool>(
2629 Header() + "%main = OpFunction %void None %void_func\n" +
2630 "%main_lab = OpLabel\n" +
2631 "%2 = OpFOrdGreaterThan %bool %double_2 %double_1\n" +
2632 "OpReturn\n" +
2633 "OpFunctionEnd",
2634 2, true),
2635 // Test case 14: fold 2.0 <= 1.0
2636 InstructionFoldingCase<bool>(
2637 Header() + "%main = OpFunction %void None %void_func\n" +
2638 "%main_lab = OpLabel\n" +
2639 "%2 = OpFOrdLessThanEqual %bool %double_2 %double_1\n" +
2640 "OpReturn\n" +
2641 "OpFunctionEnd",
2642 2, false),
2643 // Test case 15: fold 2.0 >= 1.0
2644 InstructionFoldingCase<bool>(
2645 Header() + "%main = OpFunction %void None %void_func\n" +
2646 "%main_lab = OpLabel\n" +
2647 "%2 = OpFOrdGreaterThanEqual %bool %double_2 %double_1\n" +
2648 "OpReturn\n" +
2649 "OpFunctionEnd",
2650 2, true)
2651 ));
2652
2653 INSTANTIATE_TEST_SUITE_P(DoubleUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2654 ::testing::Values(
2655 // Test case 0: fold 1.0 == 2.0
2656 InstructionFoldingCase<bool>(
2657 Header() + "%main = OpFunction %void None %void_func\n" +
2658 "%main_lab = OpLabel\n" +
2659 "%2 = OpFUnordEqual %bool %double_1 %double_2\n" +
2660 "OpReturn\n" +
2661 "OpFunctionEnd",
2662 2, false),
2663 // Test case 1: fold 1.0 != 2.0
2664 InstructionFoldingCase<bool>(
2665 Header() + "%main = OpFunction %void None %void_func\n" +
2666 "%main_lab = OpLabel\n" +
2667 "%2 = OpFUnordNotEqual %bool %double_1 %double_2\n" +
2668 "OpReturn\n" +
2669 "OpFunctionEnd",
2670 2, true),
2671 // Test case 2: fold 1.0 < 2.0
2672 InstructionFoldingCase<bool>(
2673 Header() + "%main = OpFunction %void None %void_func\n" +
2674 "%main_lab = OpLabel\n" +
2675 "%2 = OpFUnordLessThan %bool %double_1 %double_2\n" +
2676 "OpReturn\n" +
2677 "OpFunctionEnd",
2678 2, true),
2679 // Test case 3: fold 1.0 > 2.0
2680 InstructionFoldingCase<bool>(
2681 Header() + "%main = OpFunction %void None %void_func\n" +
2682 "%main_lab = OpLabel\n" +
2683 "%2 = OpFUnordGreaterThan %bool %double_1 %double_2\n" +
2684 "OpReturn\n" +
2685 "OpFunctionEnd",
2686 2, false),
2687 // Test case 4: fold 1.0 <= 2.0
2688 InstructionFoldingCase<bool>(
2689 Header() + "%main = OpFunction %void None %void_func\n" +
2690 "%main_lab = OpLabel\n" +
2691 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_2\n" +
2692 "OpReturn\n" +
2693 "OpFunctionEnd",
2694 2, true),
2695 // Test case 5: fold 1.0 >= 2.0
2696 InstructionFoldingCase<bool>(
2697 Header() + "%main = OpFunction %void None %void_func\n" +
2698 "%main_lab = OpLabel\n" +
2699 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_2\n" +
2700 "OpReturn\n" +
2701 "OpFunctionEnd",
2702 2, false),
2703 // Test case 6: fold 1.0 == 1.0
2704 InstructionFoldingCase<bool>(
2705 Header() + "%main = OpFunction %void None %void_func\n" +
2706 "%main_lab = OpLabel\n" +
2707 "%2 = OpFUnordEqual %bool %double_1 %double_1\n" +
2708 "OpReturn\n" +
2709 "OpFunctionEnd",
2710 2, true),
2711 // Test case 7: fold 1.0 != 1.0
2712 InstructionFoldingCase<bool>(
2713 Header() + "%main = OpFunction %void None %void_func\n" +
2714 "%main_lab = OpLabel\n" +
2715 "%2 = OpFUnordNotEqual %bool %double_1 %double_1\n" +
2716 "OpReturn\n" +
2717 "OpFunctionEnd",
2718 2, false),
2719 // Test case 8: fold 1.0 < 1.0
2720 InstructionFoldingCase<bool>(
2721 Header() + "%main = OpFunction %void None %void_func\n" +
2722 "%main_lab = OpLabel\n" +
2723 "%2 = OpFUnordLessThan %bool %double_1 %double_1\n" +
2724 "OpReturn\n" +
2725 "OpFunctionEnd",
2726 2, false),
2727 // Test case 9: fold 1.0 > 1.0
2728 InstructionFoldingCase<bool>(
2729 Header() + "%main = OpFunction %void None %void_func\n" +
2730 "%main_lab = OpLabel\n" +
2731 "%2 = OpFUnordGreaterThan %bool %double_1 %double_1\n" +
2732 "OpReturn\n" +
2733 "OpFunctionEnd",
2734 2, false),
2735 // Test case 10: fold 1.0 <= 1.0
2736 InstructionFoldingCase<bool>(
2737 Header() + "%main = OpFunction %void None %void_func\n" +
2738 "%main_lab = OpLabel\n" +
2739 "%2 = OpFUnordLessThanEqual %bool %double_1 %double_1\n" +
2740 "OpReturn\n" +
2741 "OpFunctionEnd",
2742 2, true),
2743 // Test case 11: fold 1.0 >= 1.0
2744 InstructionFoldingCase<bool>(
2745 Header() + "%main = OpFunction %void None %void_func\n" +
2746 "%main_lab = OpLabel\n" +
2747 "%2 = OpFUnordGreaterThanEqual %bool %double_1 %double_1\n" +
2748 "OpReturn\n" +
2749 "OpFunctionEnd",
2750 2, true),
2751 // Test case 12: fold 2.0 < 1.0
2752 InstructionFoldingCase<bool>(
2753 Header() + "%main = OpFunction %void None %void_func\n" +
2754 "%main_lab = OpLabel\n" +
2755 "%2 = OpFUnordLessThan %bool %double_2 %double_1\n" +
2756 "OpReturn\n" +
2757 "OpFunctionEnd",
2758 2, false),
2759 // Test case 13: fold 2.0 > 1.0
2760 InstructionFoldingCase<bool>(
2761 Header() + "%main = OpFunction %void None %void_func\n" +
2762 "%main_lab = OpLabel\n" +
2763 "%2 = OpFUnordGreaterThan %bool %double_2 %double_1\n" +
2764 "OpReturn\n" +
2765 "OpFunctionEnd",
2766 2, true),
2767 // Test case 14: fold 2.0 <= 1.0
2768 InstructionFoldingCase<bool>(
2769 Header() + "%main = OpFunction %void None %void_func\n" +
2770 "%main_lab = OpLabel\n" +
2771 "%2 = OpFUnordLessThanEqual %bool %double_2 %double_1\n" +
2772 "OpReturn\n" +
2773 "OpFunctionEnd",
2774 2, false),
2775 // Test case 15: fold 2.0 >= 1.0
2776 InstructionFoldingCase<bool>(
2777 Header() + "%main = OpFunction %void None %void_func\n" +
2778 "%main_lab = OpLabel\n" +
2779 "%2 = OpFUnordGreaterThanEqual %bool %double_2 %double_1\n" +
2780 "OpReturn\n" +
2781 "OpFunctionEnd",
2782 2, true)
2783 ));
2784
2785 INSTANTIATE_TEST_SUITE_P(FloatOrderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2786 ::testing::Values(
2787 // Test case 0: fold 1.0 == 2.0
2788 InstructionFoldingCase<bool>(
2789 Header() + "%main = OpFunction %void None %void_func\n" +
2790 "%main_lab = OpLabel\n" +
2791 "%2 = OpFOrdEqual %bool %float_1 %float_2\n" +
2792 "OpReturn\n" +
2793 "OpFunctionEnd",
2794 2, false),
2795 // Test case 1: fold 1.0 != 2.0
2796 InstructionFoldingCase<bool>(
2797 Header() + "%main = OpFunction %void None %void_func\n" +
2798 "%main_lab = OpLabel\n" +
2799 "%2 = OpFOrdNotEqual %bool %float_1 %float_2\n" +
2800 "OpReturn\n" +
2801 "OpFunctionEnd",
2802 2, true),
2803 // Test case 2: fold 1.0 < 2.0
2804 InstructionFoldingCase<bool>(
2805 Header() + "%main = OpFunction %void None %void_func\n" +
2806 "%main_lab = OpLabel\n" +
2807 "%2 = OpFOrdLessThan %bool %float_1 %float_2\n" +
2808 "OpReturn\n" +
2809 "OpFunctionEnd",
2810 2, true),
2811 // Test case 3: fold 1.0 > 2.0
2812 InstructionFoldingCase<bool>(
2813 Header() + "%main = OpFunction %void None %void_func\n" +
2814 "%main_lab = OpLabel\n" +
2815 "%2 = OpFOrdGreaterThan %bool %float_1 %float_2\n" +
2816 "OpReturn\n" +
2817 "OpFunctionEnd",
2818 2, false),
2819 // Test case 4: fold 1.0 <= 2.0
2820 InstructionFoldingCase<bool>(
2821 Header() + "%main = OpFunction %void None %void_func\n" +
2822 "%main_lab = OpLabel\n" +
2823 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_2\n" +
2824 "OpReturn\n" +
2825 "OpFunctionEnd",
2826 2, true),
2827 // Test case 5: fold 1.0 >= 2.0
2828 InstructionFoldingCase<bool>(
2829 Header() + "%main = OpFunction %void None %void_func\n" +
2830 "%main_lab = OpLabel\n" +
2831 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_2\n" +
2832 "OpReturn\n" +
2833 "OpFunctionEnd",
2834 2, false),
2835 // Test case 6: fold 1.0 == 1.0
2836 InstructionFoldingCase<bool>(
2837 Header() + "%main = OpFunction %void None %void_func\n" +
2838 "%main_lab = OpLabel\n" +
2839 "%2 = OpFOrdEqual %bool %float_1 %float_1\n" +
2840 "OpReturn\n" +
2841 "OpFunctionEnd",
2842 2, true),
2843 // Test case 7: fold 1.0 != 1.0
2844 InstructionFoldingCase<bool>(
2845 Header() + "%main = OpFunction %void None %void_func\n" +
2846 "%main_lab = OpLabel\n" +
2847 "%2 = OpFOrdNotEqual %bool %float_1 %float_1\n" +
2848 "OpReturn\n" +
2849 "OpFunctionEnd",
2850 2, false),
2851 // Test case 8: fold 1.0 < 1.0
2852 InstructionFoldingCase<bool>(
2853 Header() + "%main = OpFunction %void None %void_func\n" +
2854 "%main_lab = OpLabel\n" +
2855 "%2 = OpFOrdLessThan %bool %float_1 %float_1\n" +
2856 "OpReturn\n" +
2857 "OpFunctionEnd",
2858 2, false),
2859 // Test case 9: fold 1.0 > 1.0
2860 InstructionFoldingCase<bool>(
2861 Header() + "%main = OpFunction %void None %void_func\n" +
2862 "%main_lab = OpLabel\n" +
2863 "%2 = OpFOrdGreaterThan %bool %float_1 %float_1\n" +
2864 "OpReturn\n" +
2865 "OpFunctionEnd",
2866 2, false),
2867 // Test case 10: fold 1.0 <= 1.0
2868 InstructionFoldingCase<bool>(
2869 Header() + "%main = OpFunction %void None %void_func\n" +
2870 "%main_lab = OpLabel\n" +
2871 "%2 = OpFOrdLessThanEqual %bool %float_1 %float_1\n" +
2872 "OpReturn\n" +
2873 "OpFunctionEnd",
2874 2, true),
2875 // Test case 11: fold 1.0 >= 1.0
2876 InstructionFoldingCase<bool>(
2877 Header() + "%main = OpFunction %void None %void_func\n" +
2878 "%main_lab = OpLabel\n" +
2879 "%2 = OpFOrdGreaterThanEqual %bool %float_1 %float_1\n" +
2880 "OpReturn\n" +
2881 "OpFunctionEnd",
2882 2, true),
2883 // Test case 12: fold 2.0 < 1.0
2884 InstructionFoldingCase<bool>(
2885 Header() + "%main = OpFunction %void None %void_func\n" +
2886 "%main_lab = OpLabel\n" +
2887 "%2 = OpFOrdLessThan %bool %float_2 %float_1\n" +
2888 "OpReturn\n" +
2889 "OpFunctionEnd",
2890 2, false),
2891 // Test case 13: fold 2.0 > 1.0
2892 InstructionFoldingCase<bool>(
2893 Header() + "%main = OpFunction %void None %void_func\n" +
2894 "%main_lab = OpLabel\n" +
2895 "%2 = OpFOrdGreaterThan %bool %float_2 %float_1\n" +
2896 "OpReturn\n" +
2897 "OpFunctionEnd",
2898 2, true),
2899 // Test case 14: fold 2.0 <= 1.0
2900 InstructionFoldingCase<bool>(
2901 Header() + "%main = OpFunction %void None %void_func\n" +
2902 "%main_lab = OpLabel\n" +
2903 "%2 = OpFOrdLessThanEqual %bool %float_2 %float_1\n" +
2904 "OpReturn\n" +
2905 "OpFunctionEnd",
2906 2, false),
2907 // Test case 15: fold 2.0 >= 1.0
2908 InstructionFoldingCase<bool>(
2909 Header() + "%main = OpFunction %void None %void_func\n" +
2910 "%main_lab = OpLabel\n" +
2911 "%2 = OpFOrdGreaterThanEqual %bool %float_2 %float_1\n" +
2912 "OpReturn\n" +
2913 "OpFunctionEnd",
2914 2, true)
2915 ));
2916
2917 INSTANTIATE_TEST_SUITE_P(FloatUnorderedCompareConstantFoldingTest, BooleanInstructionFoldingTest,
2918 ::testing::Values(
2919 // Test case 0: fold 1.0 == 2.0
2920 InstructionFoldingCase<bool>(
2921 Header() + "%main = OpFunction %void None %void_func\n" +
2922 "%main_lab = OpLabel\n" +
2923 "%2 = OpFUnordEqual %bool %float_1 %float_2\n" +
2924 "OpReturn\n" +
2925 "OpFunctionEnd",
2926 2, false),
2927 // Test case 1: fold 1.0 != 2.0
2928 InstructionFoldingCase<bool>(
2929 Header() + "%main = OpFunction %void None %void_func\n" +
2930 "%main_lab = OpLabel\n" +
2931 "%2 = OpFUnordNotEqual %bool %float_1 %float_2\n" +
2932 "OpReturn\n" +
2933 "OpFunctionEnd",
2934 2, true),
2935 // Test case 2: fold 1.0 < 2.0
2936 InstructionFoldingCase<bool>(
2937 Header() + "%main = OpFunction %void None %void_func\n" +
2938 "%main_lab = OpLabel\n" +
2939 "%2 = OpFUnordLessThan %bool %float_1 %float_2\n" +
2940 "OpReturn\n" +
2941 "OpFunctionEnd",
2942 2, true),
2943 // Test case 3: fold 1.0 > 2.0
2944 InstructionFoldingCase<bool>(
2945 Header() + "%main = OpFunction %void None %void_func\n" +
2946 "%main_lab = OpLabel\n" +
2947 "%2 = OpFUnordGreaterThan %bool %float_1 %float_2\n" +
2948 "OpReturn\n" +
2949 "OpFunctionEnd",
2950 2, false),
2951 // Test case 4: fold 1.0 <= 2.0
2952 InstructionFoldingCase<bool>(
2953 Header() + "%main = OpFunction %void None %void_func\n" +
2954 "%main_lab = OpLabel\n" +
2955 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_2\n" +
2956 "OpReturn\n" +
2957 "OpFunctionEnd",
2958 2, true),
2959 // Test case 5: fold 1.0 >= 2.0
2960 InstructionFoldingCase<bool>(
2961 Header() + "%main = OpFunction %void None %void_func\n" +
2962 "%main_lab = OpLabel\n" +
2963 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_2\n" +
2964 "OpReturn\n" +
2965 "OpFunctionEnd",
2966 2, false),
2967 // Test case 6: fold 1.0 == 1.0
2968 InstructionFoldingCase<bool>(
2969 Header() + "%main = OpFunction %void None %void_func\n" +
2970 "%main_lab = OpLabel\n" +
2971 "%2 = OpFUnordEqual %bool %float_1 %float_1\n" +
2972 "OpReturn\n" +
2973 "OpFunctionEnd",
2974 2, true),
2975 // Test case 7: fold 1.0 != 1.0
2976 InstructionFoldingCase<bool>(
2977 Header() + "%main = OpFunction %void None %void_func\n" +
2978 "%main_lab = OpLabel\n" +
2979 "%2 = OpFUnordNotEqual %bool %float_1 %float_1\n" +
2980 "OpReturn\n" +
2981 "OpFunctionEnd",
2982 2, false),
2983 // Test case 8: fold 1.0 < 1.0
2984 InstructionFoldingCase<bool>(
2985 Header() + "%main = OpFunction %void None %void_func\n" +
2986 "%main_lab = OpLabel\n" +
2987 "%2 = OpFUnordLessThan %bool %float_1 %float_1\n" +
2988 "OpReturn\n" +
2989 "OpFunctionEnd",
2990 2, false),
2991 // Test case 9: fold 1.0 > 1.0
2992 InstructionFoldingCase<bool>(
2993 Header() + "%main = OpFunction %void None %void_func\n" +
2994 "%main_lab = OpLabel\n" +
2995 "%2 = OpFUnordGreaterThan %bool %float_1 %float_1\n" +
2996 "OpReturn\n" +
2997 "OpFunctionEnd",
2998 2, false),
2999 // Test case 10: fold 1.0 <= 1.0
3000 InstructionFoldingCase<bool>(
3001 Header() + "%main = OpFunction %void None %void_func\n" +
3002 "%main_lab = OpLabel\n" +
3003 "%2 = OpFUnordLessThanEqual %bool %float_1 %float_1\n" +
3004 "OpReturn\n" +
3005 "OpFunctionEnd",
3006 2, true),
3007 // Test case 11: fold 1.0 >= 1.0
3008 InstructionFoldingCase<bool>(
3009 Header() + "%main = OpFunction %void None %void_func\n" +
3010 "%main_lab = OpLabel\n" +
3011 "%2 = OpFUnordGreaterThanEqual %bool %float_1 %float_1\n" +
3012 "OpReturn\n" +
3013 "OpFunctionEnd",
3014 2, true),
3015 // Test case 12: fold 2.0 < 1.0
3016 InstructionFoldingCase<bool>(
3017 Header() + "%main = OpFunction %void None %void_func\n" +
3018 "%main_lab = OpLabel\n" +
3019 "%2 = OpFUnordLessThan %bool %float_2 %float_1\n" +
3020 "OpReturn\n" +
3021 "OpFunctionEnd",
3022 2, false),
3023 // Test case 13: fold 2.0 > 1.0
3024 InstructionFoldingCase<bool>(
3025 Header() + "%main = OpFunction %void None %void_func\n" +
3026 "%main_lab = OpLabel\n" +
3027 "%2 = OpFUnordGreaterThan %bool %float_2 %float_1\n" +
3028 "OpReturn\n" +
3029 "OpFunctionEnd",
3030 2, true),
3031 // Test case 14: fold 2.0 <= 1.0
3032 InstructionFoldingCase<bool>(
3033 Header() + "%main = OpFunction %void None %void_func\n" +
3034 "%main_lab = OpLabel\n" +
3035 "%2 = OpFUnordLessThanEqual %bool %float_2 %float_1\n" +
3036 "OpReturn\n" +
3037 "OpFunctionEnd",
3038 2, false),
3039 // Test case 15: fold 2.0 >= 1.0
3040 InstructionFoldingCase<bool>(
3041 Header() + "%main = OpFunction %void None %void_func\n" +
3042 "%main_lab = OpLabel\n" +
3043 "%2 = OpFUnordGreaterThanEqual %bool %float_2 %float_1\n" +
3044 "OpReturn\n" +
3045 "OpFunctionEnd",
3046 2, true)
3047 ));
3048
3049 INSTANTIATE_TEST_SUITE_P(DoubleNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3050 ::testing::Values(
3051 // Test case 0: fold NaN == 0 (ord)
3052 InstructionFoldingCase<bool>(
3053 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3054 "%main_lab = OpLabel\n" +
3055 "%2 = OpFOrdEqual %bool %double_nan %double_0\n" +
3056 "OpReturn\n" +
3057 "OpFunctionEnd",
3058 2, false),
3059 // Test case 1: fold NaN == NaN (unord)
3060 InstructionFoldingCase<bool>(
3061 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3062 "%main_lab = OpLabel\n" +
3063 "%2 = OpFUnordEqual %bool %double_nan %double_0\n" +
3064 "OpReturn\n" +
3065 "OpFunctionEnd",
3066 2, true),
3067 // Test case 2: fold NaN != NaN (ord)
3068 InstructionFoldingCase<bool>(
3069 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3070 "%main_lab = OpLabel\n" +
3071 "%2 = OpFOrdNotEqual %bool %double_nan %double_0\n" +
3072 "OpReturn\n" +
3073 "OpFunctionEnd",
3074 2, false),
3075 // Test case 3: fold NaN != NaN (unord)
3076 InstructionFoldingCase<bool>(
3077 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3078 "%main_lab = OpLabel\n" +
3079 "%2 = OpFUnordNotEqual %bool %double_nan %double_0\n" +
3080 "OpReturn\n" +
3081 "OpFunctionEnd",
3082 2, true)
3083 ));
3084
3085 INSTANTIATE_TEST_SUITE_P(FloatNaNCompareConstantFoldingTest, BooleanInstructionFoldingTest,
3086 ::testing::Values(
3087 // Test case 0: fold NaN == 0 (ord)
3088 InstructionFoldingCase<bool>(
3089 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3090 "%main_lab = OpLabel\n" +
3091 "%2 = OpFOrdEqual %bool %float_nan %float_0\n" +
3092 "OpReturn\n" +
3093 "OpFunctionEnd",
3094 2, false),
3095 // Test case 1: fold NaN == NaN (unord)
3096 InstructionFoldingCase<bool>(
3097 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3098 "%main_lab = OpLabel\n" +
3099 "%2 = OpFUnordEqual %bool %float_nan %float_0\n" +
3100 "OpReturn\n" +
3101 "OpFunctionEnd",
3102 2, true),
3103 // Test case 2: fold NaN != NaN (ord)
3104 InstructionFoldingCase<bool>(
3105 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3106 "%main_lab = OpLabel\n" +
3107 "%2 = OpFOrdNotEqual %bool %float_nan %float_0\n" +
3108 "OpReturn\n" +
3109 "OpFunctionEnd",
3110 2, false),
3111 // Test case 3: fold NaN != NaN (unord)
3112 InstructionFoldingCase<bool>(
3113 HeaderWithNaN() + "%main = OpFunction %void None %void_func\n" +
3114 "%main_lab = OpLabel\n" +
3115 "%2 = OpFUnordNotEqual %bool %float_nan %float_0\n" +
3116 "OpReturn\n" +
3117 "OpFunctionEnd",
3118 2, true)
3119 ));
3120 // clang-format on
3121
3122 template <class ResultType>
3123 struct InstructionFoldingCaseWithMap {
InstructionFoldingCaseWithMapspvtools::opt::__anon28d0f2160111::InstructionFoldingCaseWithMap3124 InstructionFoldingCaseWithMap(const std::string& tb, uint32_t id,
3125 ResultType result,
3126 std::function<uint32_t(uint32_t)> map)
3127 : test_body(tb), id_to_fold(id), expected_result(result), id_map(map) {}
3128
3129 std::string test_body;
3130 uint32_t id_to_fold;
3131 ResultType expected_result;
3132 std::function<uint32_t(uint32_t)> id_map;
3133 };
3134
3135 using IntegerInstructionFoldingTestWithMap =
3136 ::testing::TestWithParam<InstructionFoldingCaseWithMap<uint32_t>>;
3137
TEST_P(IntegerInstructionFoldingTestWithMap,Case)3138 TEST_P(IntegerInstructionFoldingTestWithMap, Case) {
3139 const auto& tc = GetParam();
3140
3141 // Build module.
3142 std::unique_ptr<IRContext> context =
3143 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3144 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3145 ASSERT_NE(nullptr, context);
3146
3147 // Fold the instruction to test.
3148 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3149 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3150 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3151 tc.id_map);
3152
3153 // Make sure the instruction folded as expected.
3154 EXPECT_NE(inst, nullptr);
3155 if (inst != nullptr) {
3156 EXPECT_EQ(inst->opcode(), SpvOpConstant);
3157 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3158 const analysis::IntConstant* result =
3159 const_mrg->GetConstantFromInst(inst)->AsIntConstant();
3160 EXPECT_NE(result, nullptr);
3161 if (result != nullptr) {
3162 EXPECT_EQ(result->GetU32BitValue(), tc.expected_result);
3163 }
3164 }
3165 }
3166 // clang-format off
3167 INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap,
3168 ::testing::Values(
3169 // Test case 0: fold %3 = 0; %3 * n
3170 InstructionFoldingCaseWithMap<uint32_t>(
3171 Header() + "%main = OpFunction %void None %void_func\n" +
3172 "%main_lab = OpLabel\n" +
3173 "%n = OpVariable %_ptr_int Function\n" +
3174 "%load = OpLoad %int %n\n" +
3175 "%3 = OpCopyObject %int %int_0\n"
3176 "%2 = OpIMul %int %3 %load\n" +
3177 "OpReturn\n" +
3178 "OpFunctionEnd",
__anon28d0f2160202(uint32_t id) 3179 2, 0, [](uint32_t id) {return (id == 3 ? INT_0_ID : id);})
3180 ));
3181 // clang-format on
3182
3183 using BooleanInstructionFoldingTestWithMap =
3184 ::testing::TestWithParam<InstructionFoldingCaseWithMap<bool>>;
3185
TEST_P(BooleanInstructionFoldingTestWithMap,Case)3186 TEST_P(BooleanInstructionFoldingTestWithMap, Case) {
3187 const auto& tc = GetParam();
3188
3189 // Build module.
3190 std::unique_ptr<IRContext> context =
3191 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3192 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3193 ASSERT_NE(nullptr, context);
3194
3195 // Fold the instruction to test.
3196 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3197 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3198 inst = context->get_instruction_folder().FoldInstructionToConstant(inst,
3199 tc.id_map);
3200
3201 // Make sure the instruction folded as expected.
3202 EXPECT_NE(inst, nullptr);
3203 if (inst != nullptr) {
3204 std::vector<SpvOp> bool_opcodes = {SpvOpConstantTrue, SpvOpConstantFalse};
3205 EXPECT_THAT(bool_opcodes, Contains(inst->opcode()));
3206 analysis::ConstantManager* const_mrg = context->get_constant_mgr();
3207 const analysis::BoolConstant* result =
3208 const_mrg->GetConstantFromInst(inst)->AsBoolConstant();
3209 EXPECT_NE(result, nullptr);
3210 if (result != nullptr) {
3211 EXPECT_EQ(result->value(), tc.expected_result);
3212 }
3213 }
3214 }
3215
3216 // clang-format off
3217 INSTANTIATE_TEST_SUITE_P(TestCase, BooleanInstructionFoldingTestWithMap,
3218 ::testing::Values(
3219 // Test case 0: fold %3 = true; %3 || n
3220 InstructionFoldingCaseWithMap<bool>(
3221 Header() + "%main = OpFunction %void None %void_func\n" +
3222 "%main_lab = OpLabel\n" +
3223 "%n = OpVariable %_ptr_bool Function\n" +
3224 "%load = OpLoad %bool %n\n" +
3225 "%3 = OpCopyObject %bool %true\n" +
3226 "%2 = OpLogicalOr %bool %3 %load\n" +
3227 "OpReturn\n" +
3228 "OpFunctionEnd",
__anon28d0f2160302(uint32_t id) 3229 2, true, [](uint32_t id) {return (id == 3 ? TRUE_ID : id);})
3230 ));
3231 // clang-format on
3232
3233 using GeneralInstructionFoldingTest =
3234 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
3235
TEST_P(GeneralInstructionFoldingTest,Case)3236 TEST_P(GeneralInstructionFoldingTest, Case) {
3237 const auto& tc = GetParam();
3238
3239 // Build module.
3240 std::unique_ptr<IRContext> context =
3241 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
3242 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
3243 ASSERT_NE(nullptr, context);
3244
3245 // Fold the instruction to test.
3246 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
3247 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
3248 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
3249 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
3250
3251 // Make sure the instruction folded as expected.
3252 EXPECT_EQ(inst->result_id(), original_inst->result_id());
3253 EXPECT_EQ(inst->type_id(), original_inst->type_id());
3254 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
3255 if (succeeded) {
3256 EXPECT_EQ(inst->opcode(), SpvOpCopyObject);
3257 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
3258 } else {
3259 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
3260 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
3261 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
3262 }
3263 }
3264 }
3265
3266 // clang-format off
3267 INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTest,
3268 ::testing::Values(
3269 // Test case 0: Don't fold n * m
3270 InstructionFoldingCase<uint32_t>(
3271 Header() + "%main = OpFunction %void None %void_func\n" +
3272 "%main_lab = OpLabel\n" +
3273 "%n = OpVariable %_ptr_int Function\n" +
3274 "%m = OpVariable %_ptr_int Function\n" +
3275 "%load_n = OpLoad %int %n\n" +
3276 "%load_m = OpLoad %int %m\n" +
3277 "%2 = OpIMul %int %load_n %load_m\n" +
3278 "OpReturn\n" +
3279 "OpFunctionEnd",
3280 2, 0),
3281 // Test case 1: Don't fold n / m (unsigned)
3282 InstructionFoldingCase<uint32_t>(
3283 Header() + "%main = OpFunction %void None %void_func\n" +
3284 "%main_lab = OpLabel\n" +
3285 "%n = OpVariable %_ptr_uint Function\n" +
3286 "%m = OpVariable %_ptr_uint Function\n" +
3287 "%load_n = OpLoad %uint %n\n" +
3288 "%load_m = OpLoad %uint %m\n" +
3289 "%2 = OpUDiv %uint %load_n %load_m\n" +
3290 "OpReturn\n" +
3291 "OpFunctionEnd",
3292 2, 0),
3293 // Test case 2: Don't fold n / m (signed)
3294 InstructionFoldingCase<uint32_t>(
3295 Header() + "%main = OpFunction %void None %void_func\n" +
3296 "%main_lab = OpLabel\n" +
3297 "%n = OpVariable %_ptr_int Function\n" +
3298 "%m = OpVariable %_ptr_int Function\n" +
3299 "%load_n = OpLoad %int %n\n" +
3300 "%load_m = OpLoad %int %m\n" +
3301 "%2 = OpSDiv %int %load_n %load_m\n" +
3302 "OpReturn\n" +
3303 "OpFunctionEnd",
3304 2, 0),
3305 // Test case 3: Don't fold n remainder m
3306 InstructionFoldingCase<uint32_t>(
3307 Header() + "%main = OpFunction %void None %void_func\n" +
3308 "%main_lab = OpLabel\n" +
3309 "%n = OpVariable %_ptr_int Function\n" +
3310 "%m = OpVariable %_ptr_int Function\n" +
3311 "%load_n = OpLoad %int %n\n" +
3312 "%load_m = OpLoad %int %m\n" +
3313 "%2 = OpSRem %int %load_n %load_m\n" +
3314 "OpReturn\n" +
3315 "OpFunctionEnd",
3316 2, 0),
3317 // Test case 4: Don't fold n % m (signed)
3318 InstructionFoldingCase<uint32_t>(
3319 Header() + "%main = OpFunction %void None %void_func\n" +
3320 "%main_lab = OpLabel\n" +
3321 "%n = OpVariable %_ptr_int Function\n" +
3322 "%m = OpVariable %_ptr_int Function\n" +
3323 "%load_n = OpLoad %int %n\n" +
3324 "%load_m = OpLoad %int %m\n" +
3325 "%2 = OpSMod %int %load_n %load_m\n" +
3326 "OpReturn\n" +
3327 "OpFunctionEnd",
3328 2, 0),
3329 // Test case 5: Don't fold n % m (unsigned)
3330 InstructionFoldingCase<uint32_t>(
3331 Header() + "%main = OpFunction %void None %void_func\n" +
3332 "%main_lab = OpLabel\n" +
3333 "%n = OpVariable %_ptr_uint Function\n" +
3334 "%m = OpVariable %_ptr_uint Function\n" +
3335 "%load_n = OpLoad %uint %n\n" +
3336 "%load_m = OpLoad %uint %m\n" +
3337 "%2 = OpUMod %int %load_n %load_m\n" +
3338 "OpReturn\n" +
3339 "OpFunctionEnd",
3340 2, 0),
3341 // Test case 6: Don't fold n << m
3342 InstructionFoldingCase<uint32_t>(
3343 Header() + "%main = OpFunction %void None %void_func\n" +
3344 "%main_lab = OpLabel\n" +
3345 "%n = OpVariable %_ptr_uint Function\n" +
3346 "%m = OpVariable %_ptr_uint Function\n" +
3347 "%load_n = OpLoad %uint %n\n" +
3348 "%load_m = OpLoad %uint %m\n" +
3349 "%2 = OpShiftRightLogical %int %load_n %load_m\n" +
3350 "OpReturn\n" +
3351 "OpFunctionEnd",
3352 2, 0),
3353 // Test case 7: Don't fold n >> m
3354 InstructionFoldingCase<uint32_t>(
3355 Header() + "%main = OpFunction %void None %void_func\n" +
3356 "%main_lab = OpLabel\n" +
3357 "%n = OpVariable %_ptr_uint Function\n" +
3358 "%m = OpVariable %_ptr_uint Function\n" +
3359 "%load_n = OpLoad %uint %n\n" +
3360 "%load_m = OpLoad %uint %m\n" +
3361 "%2 = OpShiftLeftLogical %int %load_n %load_m\n" +
3362 "OpReturn\n" +
3363 "OpFunctionEnd",
3364 2, 0),
3365 // Test case 8: Don't fold n | m
3366 InstructionFoldingCase<uint32_t>(
3367 Header() + "%main = OpFunction %void None %void_func\n" +
3368 "%main_lab = OpLabel\n" +
3369 "%n = OpVariable %_ptr_uint Function\n" +
3370 "%m = OpVariable %_ptr_uint Function\n" +
3371 "%load_n = OpLoad %uint %n\n" +
3372 "%load_m = OpLoad %uint %m\n" +
3373 "%2 = OpBitwiseOr %int %load_n %load_m\n" +
3374 "OpReturn\n" +
3375 "OpFunctionEnd",
3376 2, 0),
3377 // Test case 9: Don't fold n & m
3378 InstructionFoldingCase<uint32_t>(
3379 Header() + "%main = OpFunction %void None %void_func\n" +
3380 "%main_lab = OpLabel\n" +
3381 "%n = OpVariable %_ptr_uint Function\n" +
3382 "%m = OpVariable %_ptr_uint Function\n" +
3383 "%load_n = OpLoad %uint %n\n" +
3384 "%load_m = OpLoad %uint %m\n" +
3385 "%2 = OpBitwiseAnd %int %load_n %load_m\n" +
3386 "OpReturn\n" +
3387 "OpFunctionEnd",
3388 2, 0),
3389 // Test case 10: Don't fold n < m (unsigned)
3390 InstructionFoldingCase<uint32_t>(
3391 Header() + "%main = OpFunction %void None %void_func\n" +
3392 "%main_lab = OpLabel\n" +
3393 "%n = OpVariable %_ptr_uint Function\n" +
3394 "%m = OpVariable %_ptr_uint Function\n" +
3395 "%load_n = OpLoad %uint %n\n" +
3396 "%load_m = OpLoad %uint %m\n" +
3397 "%2 = OpULessThan %bool %load_n %load_m\n" +
3398 "OpReturn\n" +
3399 "OpFunctionEnd",
3400 2, 0),
3401 // Test case 11: Don't fold n > m (unsigned)
3402 InstructionFoldingCase<uint32_t>(
3403 Header() + "%main = OpFunction %void None %void_func\n" +
3404 "%main_lab = OpLabel\n" +
3405 "%n = OpVariable %_ptr_uint Function\n" +
3406 "%m = OpVariable %_ptr_uint Function\n" +
3407 "%load_n = OpLoad %uint %n\n" +
3408 "%load_m = OpLoad %uint %m\n" +
3409 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3410 "OpReturn\n" +
3411 "OpFunctionEnd",
3412 2, 0),
3413 // Test case 12: Don't fold n <= m (unsigned)
3414 InstructionFoldingCase<uint32_t>(
3415 Header() + "%main = OpFunction %void None %void_func\n" +
3416 "%main_lab = OpLabel\n" +
3417 "%n = OpVariable %_ptr_uint Function\n" +
3418 "%m = OpVariable %_ptr_uint Function\n" +
3419 "%load_n = OpLoad %uint %n\n" +
3420 "%load_m = OpLoad %uint %m\n" +
3421 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3422 "OpReturn\n" +
3423 "OpFunctionEnd",
3424 2, 0),
3425 // Test case 13: Don't fold n >= m (unsigned)
3426 InstructionFoldingCase<uint32_t>(
3427 Header() + "%main = OpFunction %void None %void_func\n" +
3428 "%main_lab = OpLabel\n" +
3429 "%n = OpVariable %_ptr_uint Function\n" +
3430 "%m = OpVariable %_ptr_uint Function\n" +
3431 "%load_n = OpLoad %uint %n\n" +
3432 "%load_m = OpLoad %uint %m\n" +
3433 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3434 "OpReturn\n" +
3435 "OpFunctionEnd",
3436 2, 0),
3437 // Test case 14: Don't fold n < m (signed)
3438 InstructionFoldingCase<uint32_t>(
3439 Header() + "%main = OpFunction %void None %void_func\n" +
3440 "%main_lab = OpLabel\n" +
3441 "%n = OpVariable %_ptr_int Function\n" +
3442 "%m = OpVariable %_ptr_int Function\n" +
3443 "%load_n = OpLoad %int %n\n" +
3444 "%load_m = OpLoad %int %m\n" +
3445 "%2 = OpULessThan %bool %load_n %load_m\n" +
3446 "OpReturn\n" +
3447 "OpFunctionEnd",
3448 2, 0),
3449 // Test case 15: Don't fold n > m (signed)
3450 InstructionFoldingCase<uint32_t>(
3451 Header() + "%main = OpFunction %void None %void_func\n" +
3452 "%main_lab = OpLabel\n" +
3453 "%n = OpVariable %_ptr_int Function\n" +
3454 "%m = OpVariable %_ptr_int Function\n" +
3455 "%load_n = OpLoad %int %n\n" +
3456 "%load_m = OpLoad %int %m\n" +
3457 "%2 = OpUGreaterThan %bool %load_n %load_m\n" +
3458 "OpReturn\n" +
3459 "OpFunctionEnd",
3460 2, 0),
3461 // Test case 16: Don't fold n <= m (signed)
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 "%m = OpVariable %_ptr_int Function\n" +
3467 "%load_n = OpLoad %int %n\n" +
3468 "%load_m = OpLoad %int %m\n" +
3469 "%2 = OpULessThanEqual %bool %load_n %load_m\n" +
3470 "OpReturn\n" +
3471 "OpFunctionEnd",
3472 2, 0),
3473 // Test case 17: Don't fold n >= m (signed)
3474 InstructionFoldingCase<uint32_t>(
3475 Header() + "%main = OpFunction %void None %void_func\n" +
3476 "%main_lab = OpLabel\n" +
3477 "%n = OpVariable %_ptr_int Function\n" +
3478 "%m = OpVariable %_ptr_int Function\n" +
3479 "%load_n = OpLoad %int %n\n" +
3480 "%load_m = OpLoad %int %m\n" +
3481 "%2 = OpUGreaterThanEqual %bool %load_n %load_m\n" +
3482 "OpReturn\n" +
3483 "OpFunctionEnd",
3484 2, 0),
3485 // Test case 18: Don't fold n || m
3486 InstructionFoldingCase<uint32_t>(
3487 Header() + "%main = OpFunction %void None %void_func\n" +
3488 "%main_lab = OpLabel\n" +
3489 "%n = OpVariable %_ptr_bool Function\n" +
3490 "%m = OpVariable %_ptr_bool Function\n" +
3491 "%load_n = OpLoad %bool %n\n" +
3492 "%load_m = OpLoad %bool %m\n" +
3493 "%2 = OpLogicalOr %bool %load_n %load_m\n" +
3494 "OpReturn\n" +
3495 "OpFunctionEnd",
3496 2, 0),
3497 // Test case 19: Don't fold n && m
3498 InstructionFoldingCase<uint32_t>(
3499 Header() + "%main = OpFunction %void None %void_func\n" +
3500 "%main_lab = OpLabel\n" +
3501 "%n = OpVariable %_ptr_bool Function\n" +
3502 "%m = OpVariable %_ptr_bool Function\n" +
3503 "%load_n = OpLoad %bool %n\n" +
3504 "%load_m = OpLoad %bool %m\n" +
3505 "%2 = OpLogicalAnd %bool %load_n %load_m\n" +
3506 "OpReturn\n" +
3507 "OpFunctionEnd",
3508 2, 0),
3509 // Test case 20: Don't fold n * 3
3510 InstructionFoldingCase<uint32_t>(
3511 Header() + "%main = OpFunction %void None %void_func\n" +
3512 "%main_lab = OpLabel\n" +
3513 "%n = OpVariable %_ptr_int Function\n" +
3514 "%load_n = OpLoad %int %n\n" +
3515 "%2 = OpIMul %int %load_n %int_3\n" +
3516 "OpReturn\n" +
3517 "OpFunctionEnd",
3518 2, 0),
3519 // Test case 21: Don't fold n / 3 (unsigned)
3520 InstructionFoldingCase<uint32_t>(
3521 Header() + "%main = OpFunction %void None %void_func\n" +
3522 "%main_lab = OpLabel\n" +
3523 "%n = OpVariable %_ptr_uint Function\n" +
3524 "%load_n = OpLoad %uint %n\n" +
3525 "%2 = OpUDiv %uint %load_n %uint_3\n" +
3526 "OpReturn\n" +
3527 "OpFunctionEnd",
3528 2, 0),
3529 // Test case 22: Don't fold n / 3 (signed)
3530 InstructionFoldingCase<uint32_t>(
3531 Header() + "%main = OpFunction %void None %void_func\n" +
3532 "%main_lab = OpLabel\n" +
3533 "%n = OpVariable %_ptr_int Function\n" +
3534 "%load_n = OpLoad %int %n\n" +
3535 "%2 = OpSDiv %int %load_n %int_3\n" +
3536 "OpReturn\n" +
3537 "OpFunctionEnd",
3538 2, 0),
3539 // Test case 23: Don't fold n remainder 3
3540 InstructionFoldingCase<uint32_t>(
3541 Header() + "%main = OpFunction %void None %void_func\n" +
3542 "%main_lab = OpLabel\n" +
3543 "%n = OpVariable %_ptr_int Function\n" +
3544 "%load_n = OpLoad %int %n\n" +
3545 "%2 = OpSRem %int %load_n %int_3\n" +
3546 "OpReturn\n" +
3547 "OpFunctionEnd",
3548 2, 0),
3549 // Test case 24: Don't fold n % 3 (signed)
3550 InstructionFoldingCase<uint32_t>(
3551 Header() + "%main = OpFunction %void None %void_func\n" +
3552 "%main_lab = OpLabel\n" +
3553 "%n = OpVariable %_ptr_int Function\n" +
3554 "%load_n = OpLoad %int %n\n" +
3555 "%2 = OpSMod %int %load_n %int_3\n" +
3556 "OpReturn\n" +
3557 "OpFunctionEnd",
3558 2, 0),
3559 // Test case 25: Don't fold n % 3 (unsigned)
3560 InstructionFoldingCase<uint32_t>(
3561 Header() + "%main = OpFunction %void None %void_func\n" +
3562 "%main_lab = OpLabel\n" +
3563 "%n = OpVariable %_ptr_uint Function\n" +
3564 "%load_n = OpLoad %uint %n\n" +
3565 "%2 = OpUMod %int %load_n %int_3\n" +
3566 "OpReturn\n" +
3567 "OpFunctionEnd",
3568 2, 0),
3569 // Test case 26: Don't fold n << 3
3570 InstructionFoldingCase<uint32_t>(
3571 Header() + "%main = OpFunction %void None %void_func\n" +
3572 "%main_lab = OpLabel\n" +
3573 "%n = OpVariable %_ptr_uint Function\n" +
3574 "%load_n = OpLoad %uint %n\n" +
3575 "%2 = OpShiftRightLogical %int %load_n %int_3\n" +
3576 "OpReturn\n" +
3577 "OpFunctionEnd",
3578 2, 0),
3579 // Test case 27: Don't fold n >> 3
3580 InstructionFoldingCase<uint32_t>(
3581 Header() + "%main = OpFunction %void None %void_func\n" +
3582 "%main_lab = OpLabel\n" +
3583 "%n = OpVariable %_ptr_uint Function\n" +
3584 "%load_n = OpLoad %uint %n\n" +
3585 "%2 = OpShiftLeftLogical %int %load_n %int_3\n" +
3586 "OpReturn\n" +
3587 "OpFunctionEnd",
3588 2, 0),
3589 // Test case 28: Don't fold n | 3
3590 InstructionFoldingCase<uint32_t>(
3591 Header() + "%main = OpFunction %void None %void_func\n" +
3592 "%main_lab = OpLabel\n" +
3593 "%n = OpVariable %_ptr_uint Function\n" +
3594 "%load_n = OpLoad %uint %n\n" +
3595 "%2 = OpBitwiseOr %int %load_n %int_3\n" +
3596 "OpReturn\n" +
3597 "OpFunctionEnd",
3598 2, 0),
3599 // Test case 29: Don't fold n & 3
3600 InstructionFoldingCase<uint32_t>(
3601 Header() + "%main = OpFunction %void None %void_func\n" +
3602 "%main_lab = OpLabel\n" +
3603 "%n = OpVariable %_ptr_uint Function\n" +
3604 "%load_n = OpLoad %uint %n\n" +
3605 "%2 = OpBitwiseAnd %uint %load_n %uint_3\n" +
3606 "OpReturn\n" +
3607 "OpFunctionEnd",
3608 2, 0),
3609 // Test case 30: Don't fold n < 3 (unsigned)
3610 InstructionFoldingCase<uint32_t>(
3611 Header() + "%main = OpFunction %void None %void_func\n" +
3612 "%main_lab = OpLabel\n" +
3613 "%n = OpVariable %_ptr_uint Function\n" +
3614 "%load_n = OpLoad %uint %n\n" +
3615 "%2 = OpULessThan %bool %load_n %uint_3\n" +
3616 "OpReturn\n" +
3617 "OpFunctionEnd",
3618 2, 0),
3619 // Test case 31: Don't fold n > 3 (unsigned)
3620 InstructionFoldingCase<uint32_t>(
3621 Header() + "%main = OpFunction %void None %void_func\n" +
3622 "%main_lab = OpLabel\n" +
3623 "%n = OpVariable %_ptr_uint Function\n" +
3624 "%load_n = OpLoad %uint %n\n" +
3625 "%2 = OpUGreaterThan %bool %load_n %uint_3\n" +
3626 "OpReturn\n" +
3627 "OpFunctionEnd",
3628 2, 0),
3629 // Test case 32: Don't fold n <= 3 (unsigned)
3630 InstructionFoldingCase<uint32_t>(
3631 Header() + "%main = OpFunction %void None %void_func\n" +
3632 "%main_lab = OpLabel\n" +
3633 "%n = OpVariable %_ptr_uint Function\n" +
3634 "%load_n = OpLoad %uint %n\n" +
3635 "%2 = OpULessThanEqual %bool %load_n %uint_3\n" +
3636 "OpReturn\n" +
3637 "OpFunctionEnd",
3638 2, 0),
3639 // Test case 33: Don't fold n >= 3 (unsigned)
3640 InstructionFoldingCase<uint32_t>(
3641 Header() + "%main = OpFunction %void None %void_func\n" +
3642 "%main_lab = OpLabel\n" +
3643 "%n = OpVariable %_ptr_uint Function\n" +
3644 "%load_n = OpLoad %uint %n\n" +
3645 "%2 = OpUGreaterThanEqual %bool %load_n %uint_3\n" +
3646 "OpReturn\n" +
3647 "OpFunctionEnd",
3648 2, 0),
3649 // Test case 34: Don't fold n < 3 (signed)
3650 InstructionFoldingCase<uint32_t>(
3651 Header() + "%main = OpFunction %void None %void_func\n" +
3652 "%main_lab = OpLabel\n" +
3653 "%n = OpVariable %_ptr_int Function\n" +
3654 "%load_n = OpLoad %int %n\n" +
3655 "%2 = OpULessThan %bool %load_n %int_3\n" +
3656 "OpReturn\n" +
3657 "OpFunctionEnd",
3658 2, 0),
3659 // Test case 35: Don't fold n > 3 (signed)
3660 InstructionFoldingCase<uint32_t>(
3661 Header() + "%main = OpFunction %void None %void_func\n" +
3662 "%main_lab = OpLabel\n" +
3663 "%n = OpVariable %_ptr_int Function\n" +
3664 "%load_n = OpLoad %int %n\n" +
3665 "%2 = OpUGreaterThan %bool %load_n %int_3\n" +
3666 "OpReturn\n" +
3667 "OpFunctionEnd",
3668 2, 0),
3669 // Test case 36: Don't fold n <= 3 (signed)
3670 InstructionFoldingCase<uint32_t>(
3671 Header() + "%main = OpFunction %void None %void_func\n" +
3672 "%main_lab = OpLabel\n" +
3673 "%n = OpVariable %_ptr_int Function\n" +
3674 "%load_n = OpLoad %int %n\n" +
3675 "%2 = OpULessThanEqual %bool %load_n %int_3\n" +
3676 "OpReturn\n" +
3677 "OpFunctionEnd",
3678 2, 0),
3679 // Test case 37: Don't fold n >= 3 (signed)
3680 InstructionFoldingCase<uint32_t>(
3681 Header() + "%main = OpFunction %void None %void_func\n" +
3682 "%main_lab = OpLabel\n" +
3683 "%n = OpVariable %_ptr_int Function\n" +
3684 "%load_n = OpLoad %int %n\n" +
3685 "%2 = OpUGreaterThanEqual %bool %load_n %int_3\n" +
3686 "OpReturn\n" +
3687 "OpFunctionEnd",
3688 2, 0),
3689 // Test case 38: Don't fold 2 + 3 (long), bad length
3690 InstructionFoldingCase<uint32_t>(
3691 Header() + "%main = OpFunction %void None %void_func\n" +
3692 "%main_lab = OpLabel\n" +
3693 "%2 = OpIAdd %long %long_2 %long_3\n" +
3694 "OpReturn\n" +
3695 "OpFunctionEnd",
3696 2, 0),
3697 // Test case 39: Don't fold 2 + 3 (short), bad length
3698 InstructionFoldingCase<uint32_t>(
3699 Header() + "%main = OpFunction %void None %void_func\n" +
3700 "%main_lab = OpLabel\n" +
3701 "%2 = OpIAdd %short %short_2 %short_3\n" +
3702 "OpReturn\n" +
3703 "OpFunctionEnd",
3704 2, 0),
3705 // Test case 40: fold 1*n
3706 InstructionFoldingCase<uint32_t>(
3707 Header() + "%main = OpFunction %void None %void_func\n" +
3708 "%main_lab = OpLabel\n" +
3709 "%n = OpVariable %_ptr_int Function\n" +
3710 "%3 = OpLoad %int %n\n" +
3711 "%2 = OpIMul %int %int_1 %3\n" +
3712 "OpReturn\n" +
3713 "OpFunctionEnd",
3714 2, 3),
3715 // Test case 41: fold n*1
3716 InstructionFoldingCase<uint32_t>(
3717 Header() + "%main = OpFunction %void None %void_func\n" +
3718 "%main_lab = OpLabel\n" +
3719 "%n = OpVariable %_ptr_int Function\n" +
3720 "%3 = OpLoad %int %n\n" +
3721 "%2 = OpIMul %int %3 %int_1\n" +
3722 "OpReturn\n" +
3723 "OpFunctionEnd",
3724 2, 3),
3725 // Test case 42: Don't fold comparisons of 64-bit types
3726 // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343).
3727 InstructionFoldingCase<uint32_t>(
3728 Header() + "%main = OpFunction %void None %void_func\n" +
3729 "%main_lab = OpLabel\n" +
3730 "%2 = OpSLessThan %bool %long_0 %long_2\n" +
3731 "OpReturn\n" +
3732 "OpFunctionEnd",
3733 2, 0)
3734 ));
3735
3736 INSTANTIATE_TEST_SUITE_P(CompositeExtractFoldingTest, GeneralInstructionFoldingTest,
3737 ::testing::Values(
3738 // Test case 0: fold Insert feeding extract
3739 InstructionFoldingCase<uint32_t>(
3740 Header() + "%main = OpFunction %void None %void_func\n" +
3741 "%main_lab = OpLabel\n" +
3742 "%n = OpVariable %_ptr_int Function\n" +
3743 "%2 = OpLoad %int %n\n" +
3744 "%3 = OpCompositeInsert %v4int %2 %v4int_0_0_0_0 0\n" +
3745 "%4 = OpCompositeInsert %v4int %int_1 %3 1\n" +
3746 "%5 = OpCompositeInsert %v4int %int_1 %4 2\n" +
3747 "%6 = OpCompositeInsert %v4int %int_1 %5 3\n" +
3748 "%7 = OpCompositeExtract %int %6 0\n" +
3749 "OpReturn\n" +
3750 "OpFunctionEnd",
3751 7, 2),
3752 // Test case 1: fold Composite construct feeding extract (position 0)
3753 InstructionFoldingCase<uint32_t>(
3754 Header() + "%main = OpFunction %void None %void_func\n" +
3755 "%main_lab = OpLabel\n" +
3756 "%n = OpVariable %_ptr_int Function\n" +
3757 "%2 = OpLoad %int %n\n" +
3758 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %int_0\n" +
3759 "%4 = OpCompositeExtract %int %3 0\n" +
3760 "OpReturn\n" +
3761 "OpFunctionEnd",
3762 4, 2),
3763 // Test case 2: fold Composite construct feeding extract (position 3)
3764 InstructionFoldingCase<uint32_t>(
3765 Header() + "%main = OpFunction %void None %void_func\n" +
3766 "%main_lab = OpLabel\n" +
3767 "%n = OpVariable %_ptr_int Function\n" +
3768 "%2 = OpLoad %int %n\n" +
3769 "%3 = OpCompositeConstruct %v4int %2 %int_0 %int_0 %100\n" +
3770 "%4 = OpCompositeExtract %int %3 3\n" +
3771 "OpReturn\n" +
3772 "OpFunctionEnd",
3773 4, INT_0_ID),
3774 // Test case 3: fold Composite construct with vectors feeding extract (scalar element)
3775 InstructionFoldingCase<uint32_t>(
3776 Header() + "%main = OpFunction %void None %void_func\n" +
3777 "%main_lab = OpLabel\n" +
3778 "%n = OpVariable %_ptr_int Function\n" +
3779 "%2 = OpLoad %int %n\n" +
3780 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
3781 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3782 "%5 = OpCompositeExtract %int %4 3\n" +
3783 "OpReturn\n" +
3784 "OpFunctionEnd",
3785 5, INT_0_ID),
3786 // Test case 4: fold Composite construct with vectors feeding extract (start of vector element)
3787 InstructionFoldingCase<uint32_t>(
3788 Header() + "%main = OpFunction %void None %void_func\n" +
3789 "%main_lab = OpLabel\n" +
3790 "%n = OpVariable %_ptr_int Function\n" +
3791 "%2 = OpLoad %int %n\n" +
3792 "%3 = OpCompositeConstruct %v2int %2 %int_0\n" +
3793 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3794 "%5 = OpCompositeExtract %int %4 0\n" +
3795 "OpReturn\n" +
3796 "OpFunctionEnd",
3797 5, 2),
3798 // Test case 5: fold Composite construct with vectors feeding extract (middle of vector element)
3799 InstructionFoldingCase<uint32_t>(
3800 Header() + "%main = OpFunction %void None %void_func\n" +
3801 "%main_lab = OpLabel\n" +
3802 "%n = OpVariable %_ptr_int Function\n" +
3803 "%2 = OpLoad %int %n\n" +
3804 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
3805 "%4 = OpCompositeConstruct %v4int %3 %int_0 %100\n" +
3806 "%5 = OpCompositeExtract %int %4 1\n" +
3807 "OpReturn\n" +
3808 "OpFunctionEnd",
3809 5, 2),
3810 // Test case 6: fold Composite construct with multiple indices.
3811 InstructionFoldingCase<uint32_t>(
3812 Header() + "%main = OpFunction %void None %void_func\n" +
3813 "%main_lab = OpLabel\n" +
3814 "%n = OpVariable %_ptr_int Function\n" +
3815 "%2 = OpLoad %int %n\n" +
3816 "%3 = OpCompositeConstruct %v2int %int_0 %2\n" +
3817 "%4 = OpCompositeConstruct %struct_v2int_int_int %3 %int_0 %100\n" +
3818 "%5 = OpCompositeExtract %int %4 0 1\n" +
3819 "OpReturn\n" +
3820 "OpFunctionEnd",
3821 5, 2),
3822 // Test case 7: fold constant extract.
3823 InstructionFoldingCase<uint32_t>(
3824 Header() + "%main = OpFunction %void None %void_func\n" +
3825 "%main_lab = OpLabel\n" +
3826 "%2 = OpCompositeExtract %int %102 1\n" +
3827 "OpReturn\n" +
3828 "OpFunctionEnd",
3829 2, INT_7_ID),
3830 // Test case 8: constant struct has OpUndef
3831 InstructionFoldingCase<uint32_t>(
3832 Header() + "%main = OpFunction %void None %void_func\n" +
3833 "%main_lab = OpLabel\n" +
3834 "%2 = OpCompositeExtract %int %struct_undef_0_0 0 1\n" +
3835 "OpReturn\n" +
3836 "OpFunctionEnd",
3837 2, 0),
3838 // Test case 9: Extracting a member of element inserted via Insert
3839 InstructionFoldingCase<uint32_t>(
3840 Header() + "%main = OpFunction %void None %void_func\n" +
3841 "%main_lab = OpLabel\n" +
3842 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
3843 "%2 = OpLoad %struct_v2int_int_int %n\n" +
3844 "%3 = OpCompositeInsert %struct_v2int_int_int %102 %2 0\n" +
3845 "%4 = OpCompositeExtract %int %3 0 1\n" +
3846 "OpReturn\n" +
3847 "OpFunctionEnd",
3848 4, 103),
3849 // Test case 10: Extracting a element that is partially changed by Insert. (Don't fold)
3850 InstructionFoldingCase<uint32_t>(
3851 Header() + "%main = OpFunction %void None %void_func\n" +
3852 "%main_lab = OpLabel\n" +
3853 "%n = OpVariable %_ptr_struct_v2int_int_int Function\n" +
3854 "%2 = OpLoad %struct_v2int_int_int %n\n" +
3855 "%3 = OpCompositeInsert %struct_v2int_int_int %int_0 %2 0 1\n" +
3856 "%4 = OpCompositeExtract %v2int %3 0\n" +
3857 "OpReturn\n" +
3858 "OpFunctionEnd",
3859 4, 0),
3860 // Test case 11: Extracting from result of vector shuffle (first input)
3861 InstructionFoldingCase<uint32_t>(
3862 Header() + "%main = OpFunction %void None %void_func\n" +
3863 "%main_lab = OpLabel\n" +
3864 "%n = OpVariable %_ptr_v2int Function\n" +
3865 "%2 = OpLoad %v2int %n\n" +
3866 "%3 = OpVectorShuffle %v2int %102 %2 3 0\n" +
3867 "%4 = OpCompositeExtract %int %3 1\n" +
3868 "OpReturn\n" +
3869 "OpFunctionEnd",
3870 4, INT_7_ID),
3871 // Test case 12: Extracting from result of vector shuffle (second input)
3872 InstructionFoldingCase<uint32_t>(
3873 Header() + "%main = OpFunction %void None %void_func\n" +
3874 "%main_lab = OpLabel\n" +
3875 "%n = OpVariable %_ptr_v2int Function\n" +
3876 "%2 = OpLoad %v2int %n\n" +
3877 "%3 = OpVectorShuffle %v2int %2 %102 2 0\n" +
3878 "%4 = OpCompositeExtract %int %3 0\n" +
3879 "OpReturn\n" +
3880 "OpFunctionEnd",
3881 4, INT_7_ID),
3882 // Test case 13: https://github.com/KhronosGroup/SPIRV-Tools/issues/2608
3883 // Out of bounds access. Do not fold.
3884 InstructionFoldingCase<uint32_t>(
3885 Header() + "%main = OpFunction %void None %void_func\n" +
3886 "%main_lab = OpLabel\n" +
3887 "%2 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" +
3888 "%3 = OpCompositeExtract %float %2 4\n" +
3889 "OpReturn\n" +
3890 "OpFunctionEnd",
3891 3, 0),
3892 // Test case 14: https://github.com/KhronosGroup/SPIRV-Tools/issues/3631
3893 // Extract the component right after the vector constituent.
3894 InstructionFoldingCase<uint32_t>(
3895 Header() + "%main = OpFunction %void None %void_func\n" +
3896 "%main_lab = OpLabel\n" +
3897 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
3898 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
3899 "%4 = OpCompositeExtract %int %3 2\n" +
3900 "OpReturn\n" +
3901 "OpFunctionEnd",
3902 4, INT_0_ID),
3903 // Test case 15:
3904 // Don't fold extract fed by construct with vector result if the index is
3905 // past the last element.
3906 InstructionFoldingCase<uint32_t>(
3907 Header() + "%main = OpFunction %void None %void_func\n" +
3908 "%main_lab = OpLabel\n" +
3909 "%2 = OpCompositeConstruct %v2int %int_0 %int_0\n" +
3910 "%3 = OpCompositeConstruct %v4int %2 %100 %int_0\n" +
3911 "%4 = OpCompositeExtract %int %3 4\n" +
3912 "OpReturn\n" +
3913 "OpFunctionEnd",
3914 4, 0)
3915 ));
3916
3917 INSTANTIATE_TEST_SUITE_P(CompositeConstructFoldingTest, GeneralInstructionFoldingTest,
3918 ::testing::Values(
3919 // Test case 0: fold Extracts feeding construct
3920 InstructionFoldingCase<uint32_t>(
3921 Header() + "%main = OpFunction %void None %void_func\n" +
3922 "%main_lab = OpLabel\n" +
3923 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3924 "%3 = OpCompositeExtract %int %2 0\n" +
3925 "%4 = OpCompositeExtract %int %2 1\n" +
3926 "%5 = OpCompositeExtract %int %2 2\n" +
3927 "%6 = OpCompositeExtract %int %2 3\n" +
3928 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3929 "OpReturn\n" +
3930 "OpFunctionEnd",
3931 7, 2),
3932 // Test case 1: Don't fold Extracts feeding construct (Different source)
3933 InstructionFoldingCase<uint32_t>(
3934 Header() + "%main = OpFunction %void None %void_func\n" +
3935 "%main_lab = OpLabel\n" +
3936 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3937 "%3 = OpCompositeExtract %int %2 0\n" +
3938 "%4 = OpCompositeExtract %int %2 1\n" +
3939 "%5 = OpCompositeExtract %int %2 2\n" +
3940 "%6 = OpCompositeExtract %int %v4int_0_0_0_0 3\n" +
3941 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3942 "OpReturn\n" +
3943 "OpFunctionEnd",
3944 7, 0),
3945 // Test case 2: Don't fold Extracts feeding construct (bad indices)
3946 InstructionFoldingCase<uint32_t>(
3947 Header() + "%main = OpFunction %void None %void_func\n" +
3948 "%main_lab = OpLabel\n" +
3949 "%2 = OpCopyObject %v4int %v4int_0_0_0_0\n" +
3950 "%3 = OpCompositeExtract %int %2 0\n" +
3951 "%4 = OpCompositeExtract %int %2 0\n" +
3952 "%5 = OpCompositeExtract %int %2 2\n" +
3953 "%6 = OpCompositeExtract %int %2 3\n" +
3954 "%7 = OpCompositeConstruct %v4int %3 %4 %5 %6\n" +
3955 "OpReturn\n" +
3956 "OpFunctionEnd",
3957 7, 0),
3958 // Test case 3: Don't fold Extracts feeding construct (different type)
3959 InstructionFoldingCase<uint32_t>(
3960 Header() + "%main = OpFunction %void None %void_func\n" +
3961 "%main_lab = OpLabel\n" +
3962 "%2 = OpCopyObject %struct_v2int_int_int %struct_v2int_int_int_null\n" +
3963 "%3 = OpCompositeExtract %v2int %2 0\n" +
3964 "%4 = OpCompositeExtract %int %2 1\n" +
3965 "%5 = OpCompositeExtract %int %2 2\n" +
3966 "%7 = OpCompositeConstruct %v4int %3 %4 %5\n" +
3967 "OpReturn\n" +
3968 "OpFunctionEnd",
3969 7, 0),
3970 // Test case 4: Fold construct with constants to constant.
3971 InstructionFoldingCase<uint32_t>(
3972 Header() + "%main = OpFunction %void None %void_func\n" +
3973 "%main_lab = OpLabel\n" +
3974 "%2 = OpCompositeConstruct %v2int %103 %103\n" +
3975 "OpReturn\n" +
3976 "OpFunctionEnd",
3977 2, VEC2_0_ID),
3978 // Test case 5: Don't segfault when trying to fold an OpCompositeConstruct
3979 // for an empty struct, and we reached the id limit.
3980 InstructionFoldingCase<uint32_t>(
3981 Header() + "%empty_struct = OpTypeStruct\n" +
3982 "%main = OpFunction %void None %void_func\n" +
3983 "%main_lab = OpLabel\n" +
3984 "%4194303 = OpCompositeConstruct %empty_struct\n" +
3985 "OpReturn\n" +
3986 "OpFunctionEnd",
3987 4194303, 0)
3988 ));
3989
3990 INSTANTIATE_TEST_SUITE_P(PhiFoldingTest, GeneralInstructionFoldingTest,
3991 ::testing::Values(
3992 // Test case 0: Fold phi with the same values for all edges.
3993 InstructionFoldingCase<uint32_t>(
3994 Header() + "%main = OpFunction %void None %void_func\n" +
3995 "%main_lab = OpLabel\n" +
3996 " OpBranchConditional %true %l1 %l2\n" +
3997 "%l1 = OpLabel\n" +
3998 " OpBranch %merge_lab\n" +
3999 "%l2 = OpLabel\n" +
4000 " OpBranch %merge_lab\n" +
4001 "%merge_lab = OpLabel\n" +
4002 "%2 = OpPhi %int %100 %l1 %100 %l2\n" +
4003 "OpReturn\n" +
4004 "OpFunctionEnd",
4005 2, INT_0_ID),
4006 // Test case 1: Fold phi in pass through loop.
4007 InstructionFoldingCase<uint32_t>(
4008 Header() + "%main = OpFunction %void None %void_func\n" +
4009 "%main_lab = OpLabel\n" +
4010 " OpBranch %l1\n" +
4011 "%l1 = OpLabel\n" +
4012 "%2 = OpPhi %int %100 %main_lab %2 %l1\n" +
4013 " OpBranchConditional %true %l1 %merge_lab\n" +
4014 "%merge_lab = OpLabel\n" +
4015 "OpReturn\n" +
4016 "OpFunctionEnd",
4017 2, INT_0_ID),
4018 // Test case 2: Don't Fold phi because of different values.
4019 InstructionFoldingCase<uint32_t>(
4020 Header() + "%main = OpFunction %void None %void_func\n" +
4021 "%main_lab = OpLabel\n" +
4022 " OpBranch %l1\n" +
4023 "%l1 = OpLabel\n" +
4024 "%2 = OpPhi %int %int_0 %main_lab %int_3 %l1\n" +
4025 " OpBranchConditional %true %l1 %merge_lab\n" +
4026 "%merge_lab = OpLabel\n" +
4027 "OpReturn\n" +
4028 "OpFunctionEnd",
4029 2, 0)
4030 ));
4031
4032 INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTest,
4033 ::testing::Values(
4034 // Test case 0: Don't fold n + 1.0
4035 InstructionFoldingCase<uint32_t>(
4036 Header() + "%main = OpFunction %void None %void_func\n" +
4037 "%main_lab = OpLabel\n" +
4038 "%n = OpVariable %_ptr_float Function\n" +
4039 "%3 = OpLoad %float %n\n" +
4040 "%2 = OpFAdd %float %3 %float_2\n" +
4041 "OpReturn\n" +
4042 "OpFunctionEnd",
4043 2, 0),
4044 // Test case 1: Don't fold n - 1.0
4045 InstructionFoldingCase<uint32_t>(
4046 Header() + "%main = OpFunction %void None %void_func\n" +
4047 "%main_lab = OpLabel\n" +
4048 "%n = OpVariable %_ptr_float Function\n" +
4049 "%3 = OpLoad %float %n\n" +
4050 "%2 = OpFSub %float %3 %float_2\n" +
4051 "OpReturn\n" +
4052 "OpFunctionEnd",
4053 2, 0),
4054 // Test case 2: Don't fold n * 2.0
4055 InstructionFoldingCase<uint32_t>(
4056 Header() + "%main = OpFunction %void None %void_func\n" +
4057 "%main_lab = OpLabel\n" +
4058 "%n = OpVariable %_ptr_float Function\n" +
4059 "%3 = OpLoad %float %n\n" +
4060 "%2 = OpFMul %float %3 %float_2\n" +
4061 "OpReturn\n" +
4062 "OpFunctionEnd",
4063 2, 0),
4064 // Test case 3: Fold n + 0.0
4065 InstructionFoldingCase<uint32_t>(
4066 Header() + "%main = OpFunction %void None %void_func\n" +
4067 "%main_lab = OpLabel\n" +
4068 "%n = OpVariable %_ptr_float Function\n" +
4069 "%3 = OpLoad %float %n\n" +
4070 "%2 = OpFAdd %float %3 %float_0\n" +
4071 "OpReturn\n" +
4072 "OpFunctionEnd",
4073 2, 3),
4074 // Test case 4: Fold 0.0 + n
4075 InstructionFoldingCase<uint32_t>(
4076 Header() + "%main = OpFunction %void None %void_func\n" +
4077 "%main_lab = OpLabel\n" +
4078 "%n = OpVariable %_ptr_float Function\n" +
4079 "%3 = OpLoad %float %n\n" +
4080 "%2 = OpFAdd %float %float_0 %3\n" +
4081 "OpReturn\n" +
4082 "OpFunctionEnd",
4083 2, 3),
4084 // Test case 5: Fold n - 0.0
4085 InstructionFoldingCase<uint32_t>(
4086 Header() + "%main = OpFunction %void None %void_func\n" +
4087 "%main_lab = OpLabel\n" +
4088 "%n = OpVariable %_ptr_float Function\n" +
4089 "%3 = OpLoad %float %n\n" +
4090 "%2 = OpFSub %float %3 %float_0\n" +
4091 "OpReturn\n" +
4092 "OpFunctionEnd",
4093 2, 3),
4094 // Test case 6: Fold n * 1.0
4095 InstructionFoldingCase<uint32_t>(
4096 Header() + "%main = OpFunction %void None %void_func\n" +
4097 "%main_lab = OpLabel\n" +
4098 "%n = OpVariable %_ptr_float Function\n" +
4099 "%3 = OpLoad %float %n\n" +
4100 "%2 = OpFMul %float %3 %float_1\n" +
4101 "OpReturn\n" +
4102 "OpFunctionEnd",
4103 2, 3),
4104 // Test case 7: Fold 1.0 * n
4105 InstructionFoldingCase<uint32_t>(
4106 Header() + "%main = OpFunction %void None %void_func\n" +
4107 "%main_lab = OpLabel\n" +
4108 "%n = OpVariable %_ptr_float Function\n" +
4109 "%3 = OpLoad %float %n\n" +
4110 "%2 = OpFMul %float %float_1 %3\n" +
4111 "OpReturn\n" +
4112 "OpFunctionEnd",
4113 2, 3),
4114 // Test case 8: Fold n / 1.0
4115 InstructionFoldingCase<uint32_t>(
4116 Header() + "%main = OpFunction %void None %void_func\n" +
4117 "%main_lab = OpLabel\n" +
4118 "%n = OpVariable %_ptr_float Function\n" +
4119 "%3 = OpLoad %float %n\n" +
4120 "%2 = OpFDiv %float %3 %float_1\n" +
4121 "OpReturn\n" +
4122 "OpFunctionEnd",
4123 2, 3),
4124 // Test case 9: Fold n * 0.0
4125 InstructionFoldingCase<uint32_t>(
4126 Header() + "%main = OpFunction %void None %void_func\n" +
4127 "%main_lab = OpLabel\n" +
4128 "%n = OpVariable %_ptr_float Function\n" +
4129 "%3 = OpLoad %float %n\n" +
4130 "%2 = OpFMul %float %3 %104\n" +
4131 "OpReturn\n" +
4132 "OpFunctionEnd",
4133 2, FLOAT_0_ID),
4134 // Test case 10: Fold 0.0 * n
4135 InstructionFoldingCase<uint32_t>(
4136 Header() + "%main = OpFunction %void None %void_func\n" +
4137 "%main_lab = OpLabel\n" +
4138 "%n = OpVariable %_ptr_float Function\n" +
4139 "%3 = OpLoad %float %n\n" +
4140 "%2 = OpFMul %float %104 %3\n" +
4141 "OpReturn\n" +
4142 "OpFunctionEnd",
4143 2, FLOAT_0_ID),
4144 // Test case 11: Fold 0.0 / n
4145 InstructionFoldingCase<uint32_t>(
4146 Header() + "%main = OpFunction %void None %void_func\n" +
4147 "%main_lab = OpLabel\n" +
4148 "%n = OpVariable %_ptr_float Function\n" +
4149 "%3 = OpLoad %float %n\n" +
4150 "%2 = OpFDiv %float %104 %3\n" +
4151 "OpReturn\n" +
4152 "OpFunctionEnd",
4153 2, FLOAT_0_ID),
4154 // Test case 12: Don't fold mix(a, b, 2.0)
4155 InstructionFoldingCase<uint32_t>(
4156 Header() + "%main = OpFunction %void None %void_func\n" +
4157 "%main_lab = OpLabel\n" +
4158 "%a = OpVariable %_ptr_float Function\n" +
4159 "%b = OpVariable %_ptr_float Function\n" +
4160 "%3 = OpLoad %float %a\n" +
4161 "%4 = OpLoad %float %b\n" +
4162 "%2 = OpExtInst %float %1 FMix %3 %4 %float_2\n" +
4163 "OpReturn\n" +
4164 "OpFunctionEnd",
4165 2, 0),
4166 // Test case 13: Fold mix(a, b, 0.0)
4167 InstructionFoldingCase<uint32_t>(
4168 Header() + "%main = OpFunction %void None %void_func\n" +
4169 "%main_lab = OpLabel\n" +
4170 "%a = OpVariable %_ptr_float Function\n" +
4171 "%b = OpVariable %_ptr_float Function\n" +
4172 "%3 = OpLoad %float %a\n" +
4173 "%4 = OpLoad %float %b\n" +
4174 "%2 = OpExtInst %float %1 FMix %3 %4 %float_0\n" +
4175 "OpReturn\n" +
4176 "OpFunctionEnd",
4177 2, 3),
4178 // Test case 14: Fold mix(a, b, 1.0)
4179 InstructionFoldingCase<uint32_t>(
4180 Header() + "%main = OpFunction %void None %void_func\n" +
4181 "%main_lab = OpLabel\n" +
4182 "%a = OpVariable %_ptr_float Function\n" +
4183 "%b = OpVariable %_ptr_float Function\n" +
4184 "%3 = OpLoad %float %a\n" +
4185 "%4 = OpLoad %float %b\n" +
4186 "%2 = OpExtInst %float %1 FMix %3 %4 %float_1\n" +
4187 "OpReturn\n" +
4188 "OpFunctionEnd",
4189 2, 4),
4190 // Test case 15: Fold vector fadd with null
4191 InstructionFoldingCase<uint32_t>(
4192 Header() + "%main = OpFunction %void None %void_func\n" +
4193 "%main_lab = OpLabel\n" +
4194 "%a = OpVariable %_ptr_v2float Function\n" +
4195 "%2 = OpLoad %v2float %a\n" +
4196 "%3 = OpFAdd %v2float %2 %v2float_null\n" +
4197 "OpReturn\n" +
4198 "OpFunctionEnd",
4199 3, 2),
4200 // Test case 16: Fold vector fadd with null
4201 InstructionFoldingCase<uint32_t>(
4202 Header() + "%main = OpFunction %void None %void_func\n" +
4203 "%main_lab = OpLabel\n" +
4204 "%a = OpVariable %_ptr_v2float Function\n" +
4205 "%2 = OpLoad %v2float %a\n" +
4206 "%3 = OpFAdd %v2float %v2float_null %2\n" +
4207 "OpReturn\n" +
4208 "OpFunctionEnd",
4209 3, 2),
4210 // Test case 17: Fold vector fsub with null
4211 InstructionFoldingCase<uint32_t>(
4212 Header() + "%main = OpFunction %void None %void_func\n" +
4213 "%main_lab = OpLabel\n" +
4214 "%a = OpVariable %_ptr_v2float Function\n" +
4215 "%2 = OpLoad %v2float %a\n" +
4216 "%3 = OpFSub %v2float %2 %v2float_null\n" +
4217 "OpReturn\n" +
4218 "OpFunctionEnd",
4219 3, 2),
4220 // Test case 18: Fold 0.0(half) * n
4221 InstructionFoldingCase<uint32_t>(
4222 Header() + "%main = OpFunction %void None %void_func\n" +
4223 "%main_lab = OpLabel\n" +
4224 "%n = OpVariable %_ptr_half Function\n" +
4225 "%3 = OpLoad %half %n\n" +
4226 "%2 = OpFMul %half %108 %3\n" +
4227 "OpReturn\n" +
4228 "OpFunctionEnd",
4229 2, HALF_0_ID),
4230 // Test case 19: Don't fold 1.0(half) * n
4231 InstructionFoldingCase<uint32_t>(
4232 Header() + "%main = OpFunction %void None %void_func\n" +
4233 "%main_lab = OpLabel\n" +
4234 "%n = OpVariable %_ptr_half Function\n" +
4235 "%3 = OpLoad %half %n\n" +
4236 "%2 = OpFMul %half %half_1 %3\n" +
4237 "OpReturn\n" +
4238 "OpFunctionEnd",
4239 2, 0),
4240 // Test case 20: Don't fold 1.0 * 1.0 (half)
4241 InstructionFoldingCase<uint32_t>(
4242 Header() + "%main = OpFunction %void None %void_func\n" +
4243 "%main_lab = OpLabel\n" +
4244 "%2 = OpFMul %half %half_1 %half_1\n" +
4245 "OpReturn\n" +
4246 "OpFunctionEnd",
4247 2, 0),
4248 // Test case 21: Don't fold (0.0, 1.0) * (0.0, 1.0) (half)
4249 InstructionFoldingCase<uint32_t>(
4250 Header() + "%main = OpFunction %void None %void_func\n" +
4251 "%main_lab = OpLabel\n" +
4252 "%2 = OpFMul %v2half %half_0_1 %half_0_1\n" +
4253 "OpReturn\n" +
4254 "OpFunctionEnd",
4255 2, 0),
4256 // Test case 22: Don't fold (0.0, 1.0) dotp (0.0, 1.0) (half)
4257 InstructionFoldingCase<uint32_t>(
4258 Header() + "%main = OpFunction %void None %void_func\n" +
4259 "%main_lab = OpLabel\n" +
4260 "%2 = OpDot %half %half_0_1 %half_0_1\n" +
4261 "OpReturn\n" +
4262 "OpFunctionEnd",
4263 2, 0)
4264 ));
4265
4266 INSTANTIATE_TEST_SUITE_P(DoubleRedundantFoldingTest, GeneralInstructionFoldingTest,
4267 ::testing::Values(
4268 // Test case 0: Don't fold n + 1.0
4269 InstructionFoldingCase<uint32_t>(
4270 Header() + "%main = OpFunction %void None %void_func\n" +
4271 "%main_lab = OpLabel\n" +
4272 "%n = OpVariable %_ptr_double Function\n" +
4273 "%3 = OpLoad %double %n\n" +
4274 "%2 = OpFAdd %double %3 %double_2\n" +
4275 "OpReturn\n" +
4276 "OpFunctionEnd",
4277 2, 0),
4278 // Test case 1: Don't fold n - 1.0
4279 InstructionFoldingCase<uint32_t>(
4280 Header() + "%main = OpFunction %void None %void_func\n" +
4281 "%main_lab = OpLabel\n" +
4282 "%n = OpVariable %_ptr_double Function\n" +
4283 "%3 = OpLoad %double %n\n" +
4284 "%2 = OpFSub %double %3 %double_2\n" +
4285 "OpReturn\n" +
4286 "OpFunctionEnd",
4287 2, 0),
4288 // Test case 2: Don't fold n * 2.0
4289 InstructionFoldingCase<uint32_t>(
4290 Header() + "%main = OpFunction %void None %void_func\n" +
4291 "%main_lab = OpLabel\n" +
4292 "%n = OpVariable %_ptr_double Function\n" +
4293 "%3 = OpLoad %double %n\n" +
4294 "%2 = OpFMul %double %3 %double_2\n" +
4295 "OpReturn\n" +
4296 "OpFunctionEnd",
4297 2, 0),
4298 // Test case 3: Fold n + 0.0
4299 InstructionFoldingCase<uint32_t>(
4300 Header() + "%main = OpFunction %void None %void_func\n" +
4301 "%main_lab = OpLabel\n" +
4302 "%n = OpVariable %_ptr_double Function\n" +
4303 "%3 = OpLoad %double %n\n" +
4304 "%2 = OpFAdd %double %3 %double_0\n" +
4305 "OpReturn\n" +
4306 "OpFunctionEnd",
4307 2, 3),
4308 // Test case 4: Fold 0.0 + n
4309 InstructionFoldingCase<uint32_t>(
4310 Header() + "%main = OpFunction %void None %void_func\n" +
4311 "%main_lab = OpLabel\n" +
4312 "%n = OpVariable %_ptr_double Function\n" +
4313 "%3 = OpLoad %double %n\n" +
4314 "%2 = OpFAdd %double %double_0 %3\n" +
4315 "OpReturn\n" +
4316 "OpFunctionEnd",
4317 2, 3),
4318 // Test case 5: Fold n - 0.0
4319 InstructionFoldingCase<uint32_t>(
4320 Header() + "%main = OpFunction %void None %void_func\n" +
4321 "%main_lab = OpLabel\n" +
4322 "%n = OpVariable %_ptr_double Function\n" +
4323 "%3 = OpLoad %double %n\n" +
4324 "%2 = OpFSub %double %3 %double_0\n" +
4325 "OpReturn\n" +
4326 "OpFunctionEnd",
4327 2, 3),
4328 // Test case 6: Fold n * 1.0
4329 InstructionFoldingCase<uint32_t>(
4330 Header() + "%main = OpFunction %void None %void_func\n" +
4331 "%main_lab = OpLabel\n" +
4332 "%n = OpVariable %_ptr_double Function\n" +
4333 "%3 = OpLoad %double %n\n" +
4334 "%2 = OpFMul %double %3 %double_1\n" +
4335 "OpReturn\n" +
4336 "OpFunctionEnd",
4337 2, 3),
4338 // Test case 7: Fold 1.0 * n
4339 InstructionFoldingCase<uint32_t>(
4340 Header() + "%main = OpFunction %void None %void_func\n" +
4341 "%main_lab = OpLabel\n" +
4342 "%n = OpVariable %_ptr_double Function\n" +
4343 "%3 = OpLoad %double %n\n" +
4344 "%2 = OpFMul %double %double_1 %3\n" +
4345 "OpReturn\n" +
4346 "OpFunctionEnd",
4347 2, 3),
4348 // Test case 8: Fold n / 1.0
4349 InstructionFoldingCase<uint32_t>(
4350 Header() + "%main = OpFunction %void None %void_func\n" +
4351 "%main_lab = OpLabel\n" +
4352 "%n = OpVariable %_ptr_double Function\n" +
4353 "%3 = OpLoad %double %n\n" +
4354 "%2 = OpFDiv %double %3 %double_1\n" +
4355 "OpReturn\n" +
4356 "OpFunctionEnd",
4357 2, 3),
4358 // Test case 9: Fold n * 0.0
4359 InstructionFoldingCase<uint32_t>(
4360 Header() + "%main = OpFunction %void None %void_func\n" +
4361 "%main_lab = OpLabel\n" +
4362 "%n = OpVariable %_ptr_double Function\n" +
4363 "%3 = OpLoad %double %n\n" +
4364 "%2 = OpFMul %double %3 %105\n" +
4365 "OpReturn\n" +
4366 "OpFunctionEnd",
4367 2, DOUBLE_0_ID),
4368 // Test case 10: Fold 0.0 * n
4369 InstructionFoldingCase<uint32_t>(
4370 Header() + "%main = OpFunction %void None %void_func\n" +
4371 "%main_lab = OpLabel\n" +
4372 "%n = OpVariable %_ptr_double Function\n" +
4373 "%3 = OpLoad %double %n\n" +
4374 "%2 = OpFMul %double %105 %3\n" +
4375 "OpReturn\n" +
4376 "OpFunctionEnd",
4377 2, DOUBLE_0_ID),
4378 // Test case 11: Fold 0.0 / n
4379 InstructionFoldingCase<uint32_t>(
4380 Header() + "%main = OpFunction %void None %void_func\n" +
4381 "%main_lab = OpLabel\n" +
4382 "%n = OpVariable %_ptr_double Function\n" +
4383 "%3 = OpLoad %double %n\n" +
4384 "%2 = OpFDiv %double %105 %3\n" +
4385 "OpReturn\n" +
4386 "OpFunctionEnd",
4387 2, DOUBLE_0_ID),
4388 // Test case 12: Don't fold mix(a, b, 2.0)
4389 InstructionFoldingCase<uint32_t>(
4390 Header() + "%main = OpFunction %void None %void_func\n" +
4391 "%main_lab = OpLabel\n" +
4392 "%a = OpVariable %_ptr_double Function\n" +
4393 "%b = OpVariable %_ptr_double Function\n" +
4394 "%3 = OpLoad %double %a\n" +
4395 "%4 = OpLoad %double %b\n" +
4396 "%2 = OpExtInst %double %1 FMix %3 %4 %double_2\n" +
4397 "OpReturn\n" +
4398 "OpFunctionEnd",
4399 2, 0),
4400 // Test case 13: Fold mix(a, b, 0.0)
4401 InstructionFoldingCase<uint32_t>(
4402 Header() + "%main = OpFunction %void None %void_func\n" +
4403 "%main_lab = OpLabel\n" +
4404 "%a = OpVariable %_ptr_double Function\n" +
4405 "%b = OpVariable %_ptr_double Function\n" +
4406 "%3 = OpLoad %double %a\n" +
4407 "%4 = OpLoad %double %b\n" +
4408 "%2 = OpExtInst %double %1 FMix %3 %4 %double_0\n" +
4409 "OpReturn\n" +
4410 "OpFunctionEnd",
4411 2, 3),
4412 // Test case 14: Fold mix(a, b, 1.0)
4413 InstructionFoldingCase<uint32_t>(
4414 Header() + "%main = OpFunction %void None %void_func\n" +
4415 "%main_lab = OpLabel\n" +
4416 "%a = OpVariable %_ptr_double Function\n" +
4417 "%b = OpVariable %_ptr_double Function\n" +
4418 "%3 = OpLoad %double %a\n" +
4419 "%4 = OpLoad %double %b\n" +
4420 "%2 = OpExtInst %double %1 FMix %3 %4 %double_1\n" +
4421 "OpReturn\n" +
4422 "OpFunctionEnd",
4423 2, 4)
4424 ));
4425
4426 INSTANTIATE_TEST_SUITE_P(FloatVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4427 ::testing::Values(
4428 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4429 InstructionFoldingCase<uint32_t>(
4430 Header() + "%main = OpFunction %void None %void_func\n" +
4431 "%main_lab = OpLabel\n" +
4432 "%n = OpVariable %_ptr_v4float Function\n" +
4433 "%3 = OpLoad %v4float %n\n" +
4434 "%2 = OpFMul %v4float %3 %v4float_0_0_0_1\n" +
4435 "OpReturn\n" +
4436 "OpFunctionEnd",
4437 2, 0),
4438 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4439 InstructionFoldingCase<uint32_t>(
4440 Header() + "%main = OpFunction %void None %void_func\n" +
4441 "%main_lab = OpLabel\n" +
4442 "%n = OpVariable %_ptr_v4float Function\n" +
4443 "%3 = OpLoad %v4float %n\n" +
4444 "%2 = OpFMul %v4float %3 %106\n" +
4445 "OpReturn\n" +
4446 "OpFunctionEnd",
4447 2, VEC4_0_ID),
4448 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4449 InstructionFoldingCase<uint32_t>(
4450 Header() + "%main = OpFunction %void None %void_func\n" +
4451 "%main_lab = OpLabel\n" +
4452 "%n = OpVariable %_ptr_v4float Function\n" +
4453 "%3 = OpLoad %v4float %n\n" +
4454 "%2 = OpFMul %v4float %3 %v4float_1_1_1_1\n" +
4455 "OpReturn\n" +
4456 "OpFunctionEnd",
4457 2, 3)
4458 ));
4459
4460 INSTANTIATE_TEST_SUITE_P(DoubleVectorRedundantFoldingTest, GeneralInstructionFoldingTest,
4461 ::testing::Values(
4462 // Test case 0: Don't fold a * vec4(0.0, 0.0, 0.0, 1.0)
4463 InstructionFoldingCase<uint32_t>(
4464 Header() + "%main = OpFunction %void None %void_func\n" +
4465 "%main_lab = OpLabel\n" +
4466 "%n = OpVariable %_ptr_v4double Function\n" +
4467 "%3 = OpLoad %v4double %n\n" +
4468 "%2 = OpFMul %v4double %3 %v4double_0_0_0_1\n" +
4469 "OpReturn\n" +
4470 "OpFunctionEnd",
4471 2, 0),
4472 // Test case 1: Fold a * vec4(0.0, 0.0, 0.0, 0.0)
4473 InstructionFoldingCase<uint32_t>(
4474 Header() + "%main = OpFunction %void None %void_func\n" +
4475 "%main_lab = OpLabel\n" +
4476 "%n = OpVariable %_ptr_v4double Function\n" +
4477 "%3 = OpLoad %v4double %n\n" +
4478 "%2 = OpFMul %v4double %3 %106\n" +
4479 "OpReturn\n" +
4480 "OpFunctionEnd",
4481 2, DVEC4_0_ID),
4482 // Test case 2: Fold a * vec4(1.0, 1.0, 1.0, 1.0)
4483 InstructionFoldingCase<uint32_t>(
4484 Header() + "%main = OpFunction %void None %void_func\n" +
4485 "%main_lab = OpLabel\n" +
4486 "%n = OpVariable %_ptr_v4double Function\n" +
4487 "%3 = OpLoad %v4double %n\n" +
4488 "%2 = OpFMul %v4double %3 %v4double_1_1_1_1\n" +
4489 "OpReturn\n" +
4490 "OpFunctionEnd",
4491 2, 3)
4492 ));
4493
4494 INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingTest,
4495 ::testing::Values(
4496 // Test case 0: Don't fold n + 1
4497 InstructionFoldingCase<uint32_t>(
4498 Header() + "%main = OpFunction %void None %void_func\n" +
4499 "%main_lab = OpLabel\n" +
4500 "%n = OpVariable %_ptr_uint Function\n" +
4501 "%3 = OpLoad %uint %n\n" +
4502 "%2 = OpIAdd %uint %3 %uint_1\n" +
4503 "OpReturn\n" +
4504 "OpFunctionEnd",
4505 2, 0),
4506 // Test case 1: Don't fold 1 + n
4507 InstructionFoldingCase<uint32_t>(
4508 Header() + "%main = OpFunction %void None %void_func\n" +
4509 "%main_lab = OpLabel\n" +
4510 "%n = OpVariable %_ptr_uint Function\n" +
4511 "%3 = OpLoad %uint %n\n" +
4512 "%2 = OpIAdd %uint %uint_1 %3\n" +
4513 "OpReturn\n" +
4514 "OpFunctionEnd",
4515 2, 0),
4516 // Test case 2: Fold n + 0
4517 InstructionFoldingCase<uint32_t>(
4518 Header() + "%main = OpFunction %void None %void_func\n" +
4519 "%main_lab = OpLabel\n" +
4520 "%n = OpVariable %_ptr_uint Function\n" +
4521 "%3 = OpLoad %uint %n\n" +
4522 "%2 = OpIAdd %uint %3 %uint_0\n" +
4523 "OpReturn\n" +
4524 "OpFunctionEnd",
4525 2, 3),
4526 // Test case 3: Fold 0 + n
4527 InstructionFoldingCase<uint32_t>(
4528 Header() + "%main = OpFunction %void None %void_func\n" +
4529 "%main_lab = OpLabel\n" +
4530 "%n = OpVariable %_ptr_uint Function\n" +
4531 "%3 = OpLoad %uint %n\n" +
4532 "%2 = OpIAdd %uint %uint_0 %3\n" +
4533 "OpReturn\n" +
4534 "OpFunctionEnd",
4535 2, 3),
4536 // Test case 4: Don't fold n + (1,0)
4537 InstructionFoldingCase<uint32_t>(
4538 Header() + "%main = OpFunction %void None %void_func\n" +
4539 "%main_lab = OpLabel\n" +
4540 "%n = OpVariable %_ptr_v2int Function\n" +
4541 "%3 = OpLoad %v2int %n\n" +
4542 "%2 = OpIAdd %v2int %3 %v2int_1_0\n" +
4543 "OpReturn\n" +
4544 "OpFunctionEnd",
4545 2, 0),
4546 // Test case 5: Don't fold (1,0) + n
4547 InstructionFoldingCase<uint32_t>(
4548 Header() + "%main = OpFunction %void None %void_func\n" +
4549 "%main_lab = OpLabel\n" +
4550 "%n = OpVariable %_ptr_v2int Function\n" +
4551 "%3 = OpLoad %v2int %n\n" +
4552 "%2 = OpIAdd %v2int %v2int_1_0 %3\n" +
4553 "OpReturn\n" +
4554 "OpFunctionEnd",
4555 2, 0),
4556 // Test case 6: Fold n + (0,0)
4557 InstructionFoldingCase<uint32_t>(
4558 Header() + "%main = OpFunction %void None %void_func\n" +
4559 "%main_lab = OpLabel\n" +
4560 "%n = OpVariable %_ptr_v2int Function\n" +
4561 "%3 = OpLoad %v2int %n\n" +
4562 "%2 = OpIAdd %v2int %3 %v2int_0_0\n" +
4563 "OpReturn\n" +
4564 "OpFunctionEnd",
4565 2, 3),
4566 // Test case 7: Fold (0,0) + n
4567 InstructionFoldingCase<uint32_t>(
4568 Header() + "%main = OpFunction %void None %void_func\n" +
4569 "%main_lab = OpLabel\n" +
4570 "%n = OpVariable %_ptr_v2int Function\n" +
4571 "%3 = OpLoad %v2int %n\n" +
4572 "%2 = OpIAdd %v2int %v2int_0_0 %3\n" +
4573 "OpReturn\n" +
4574 "OpFunctionEnd",
4575 2, 3)
4576 ));
4577
4578 INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest,
4579 ::testing::Values(
4580 // Test case 0: Don't Fold 0.0 < clamp(-1, 1)
4581 InstructionFoldingCase<uint32_t>(
4582 Header() + "%main = OpFunction %void None %void_func\n" +
4583 "%main_lab = OpLabel\n" +
4584 "%n = OpVariable %_ptr_float Function\n" +
4585 "%ld = OpLoad %float %n\n" +
4586 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4587 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4588 "OpReturn\n" +
4589 "OpFunctionEnd",
4590 2, 0),
4591 // Test case 1: Don't Fold 0.0 < clamp(-1, 1)
4592 InstructionFoldingCase<uint32_t>(
4593 Header() + "%main = OpFunction %void None %void_func\n" +
4594 "%main_lab = OpLabel\n" +
4595 "%n = OpVariable %_ptr_float Function\n" +
4596 "%ld = OpLoad %float %n\n" +
4597 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4598 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4599 "OpReturn\n" +
4600 "OpFunctionEnd",
4601 2, 0),
4602 // Test case 2: Don't Fold 0.0 <= clamp(-1, 1)
4603 InstructionFoldingCase<uint32_t>(
4604 Header() + "%main = OpFunction %void None %void_func\n" +
4605 "%main_lab = OpLabel\n" +
4606 "%n = OpVariable %_ptr_float Function\n" +
4607 "%ld = OpLoad %float %n\n" +
4608 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4609 "%2 = OpFUnordLessThanEqual %bool %float_0 %clamp\n" +
4610 "OpReturn\n" +
4611 "OpFunctionEnd",
4612 2, 0),
4613 // Test case 3: Don't Fold 0.0 <= clamp(-1, 1)
4614 InstructionFoldingCase<uint32_t>(
4615 Header() + "%main = OpFunction %void None %void_func\n" +
4616 "%main_lab = OpLabel\n" +
4617 "%n = OpVariable %_ptr_float Function\n" +
4618 "%ld = OpLoad %float %n\n" +
4619 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4620 "%2 = OpFOrdLessThanEqual %bool %float_0 %clamp\n" +
4621 "OpReturn\n" +
4622 "OpFunctionEnd",
4623 2, 0),
4624 // Test case 4: Don't Fold 0.0 > clamp(-1, 1)
4625 InstructionFoldingCase<uint32_t>(
4626 Header() + "%main = OpFunction %void None %void_func\n" +
4627 "%main_lab = OpLabel\n" +
4628 "%n = OpVariable %_ptr_float Function\n" +
4629 "%ld = OpLoad %float %n\n" +
4630 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4631 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4632 "OpReturn\n" +
4633 "OpFunctionEnd",
4634 2, 0),
4635 // Test case 5: Don't Fold 0.0 > clamp(-1, 1)
4636 InstructionFoldingCase<uint32_t>(
4637 Header() + "%main = OpFunction %void None %void_func\n" +
4638 "%main_lab = OpLabel\n" +
4639 "%n = OpVariable %_ptr_float Function\n" +
4640 "%ld = OpLoad %float %n\n" +
4641 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4642 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4643 "OpReturn\n" +
4644 "OpFunctionEnd",
4645 2, 0),
4646 // Test case 6: Don't Fold 0.0 >= clamp(-1, 1)
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 "%ld = OpLoad %float %n\n" +
4652 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4653 "%2 = OpFUnordGreaterThanEqual %bool %float_0 %clamp\n" +
4654 "OpReturn\n" +
4655 "OpFunctionEnd",
4656 2, 0),
4657 // Test case 7: Don't Fold 0.0 >= clamp(-1, 1)
4658 InstructionFoldingCase<uint32_t>(
4659 Header() + "%main = OpFunction %void None %void_func\n" +
4660 "%main_lab = OpLabel\n" +
4661 "%n = OpVariable %_ptr_float Function\n" +
4662 "%ld = OpLoad %float %n\n" +
4663 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4664 "%2 = OpFOrdGreaterThanEqual %bool %float_0 %clamp\n" +
4665 "OpReturn\n" +
4666 "OpFunctionEnd",
4667 2, 0),
4668 // Test case 8: Don't Fold 0.0 < clamp(0, 1)
4669 InstructionFoldingCase<uint32_t>(
4670 Header() + "%main = OpFunction %void None %void_func\n" +
4671 "%main_lab = OpLabel\n" +
4672 "%n = OpVariable %_ptr_float Function\n" +
4673 "%ld = OpLoad %float %n\n" +
4674 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4675 "%2 = OpFUnordLessThan %bool %float_0 %clamp\n" +
4676 "OpReturn\n" +
4677 "OpFunctionEnd",
4678 2, 0),
4679 // Test case 9: Don't Fold 0.0 < clamp(0, 1)
4680 InstructionFoldingCase<uint32_t>(
4681 Header() + "%main = OpFunction %void None %void_func\n" +
4682 "%main_lab = OpLabel\n" +
4683 "%n = OpVariable %_ptr_float Function\n" +
4684 "%ld = OpLoad %float %n\n" +
4685 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4686 "%2 = OpFOrdLessThan %bool %float_0 %clamp\n" +
4687 "OpReturn\n" +
4688 "OpFunctionEnd",
4689 2, 0),
4690 // Test case 10: Don't Fold 0.0 > clamp(-1, 0)
4691 InstructionFoldingCase<uint32_t>(
4692 Header() + "%main = OpFunction %void None %void_func\n" +
4693 "%main_lab = OpLabel\n" +
4694 "%n = OpVariable %_ptr_float Function\n" +
4695 "%ld = OpLoad %float %n\n" +
4696 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4697 "%2 = OpFUnordGreaterThan %bool %float_0 %clamp\n" +
4698 "OpReturn\n" +
4699 "OpFunctionEnd",
4700 2, 0),
4701 // Test case 11: Don't Fold 0.0 > clamp(-1, 0)
4702 InstructionFoldingCase<uint32_t>(
4703 Header() + "%main = OpFunction %void None %void_func\n" +
4704 "%main_lab = OpLabel\n" +
4705 "%n = OpVariable %_ptr_float Function\n" +
4706 "%ld = OpLoad %float %n\n" +
4707 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4708 "%2 = OpFOrdGreaterThan %bool %float_0 %clamp\n" +
4709 "OpReturn\n" +
4710 "OpFunctionEnd",
4711 2, 0)
4712 ));
4713
4714 INSTANTIATE_TEST_SUITE_P(ClampAndCmpRHS, GeneralInstructionFoldingTest,
4715 ::testing::Values(
4716 // Test case 0: Don't Fold clamp(-1, 1) < 0.0
4717 InstructionFoldingCase<uint32_t>(
4718 Header() + "%main = OpFunction %void None %void_func\n" +
4719 "%main_lab = OpLabel\n" +
4720 "%n = OpVariable %_ptr_float Function\n" +
4721 "%ld = OpLoad %float %n\n" +
4722 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4723 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4724 "OpReturn\n" +
4725 "OpFunctionEnd",
4726 2, 0),
4727 // Test case 1: Don't Fold clamp(-1, 1) < 0.0
4728 InstructionFoldingCase<uint32_t>(
4729 Header() + "%main = OpFunction %void None %void_func\n" +
4730 "%main_lab = OpLabel\n" +
4731 "%n = OpVariable %_ptr_float Function\n" +
4732 "%ld = OpLoad %float %n\n" +
4733 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4734 "%2 = OpFOrdLessThan %bool %clamp %float_0\n" +
4735 "OpReturn\n" +
4736 "OpFunctionEnd",
4737 2, 0),
4738 // Test case 2: Don't Fold clamp(-1, 1) <= 0.0
4739 InstructionFoldingCase<uint32_t>(
4740 Header() + "%main = OpFunction %void None %void_func\n" +
4741 "%main_lab = OpLabel\n" +
4742 "%n = OpVariable %_ptr_float Function\n" +
4743 "%ld = OpLoad %float %n\n" +
4744 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4745 "%2 = OpFUnordLessThanEqual %bool %clamp %float_0\n" +
4746 "OpReturn\n" +
4747 "OpFunctionEnd",
4748 2, 0),
4749 // Test case 3: Don't Fold clamp(-1, 1) <= 0.0
4750 InstructionFoldingCase<uint32_t>(
4751 Header() + "%main = OpFunction %void None %void_func\n" +
4752 "%main_lab = OpLabel\n" +
4753 "%n = OpVariable %_ptr_float Function\n" +
4754 "%ld = OpLoad %float %n\n" +
4755 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4756 "%2 = OpFOrdLessThanEqual %bool %clamp %float_0\n" +
4757 "OpReturn\n" +
4758 "OpFunctionEnd",
4759 2, 0),
4760 // Test case 4: Don't Fold clamp(-1, 1) > 0.0
4761 InstructionFoldingCase<uint32_t>(
4762 Header() + "%main = OpFunction %void None %void_func\n" +
4763 "%main_lab = OpLabel\n" +
4764 "%n = OpVariable %_ptr_float Function\n" +
4765 "%ld = OpLoad %float %n\n" +
4766 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4767 "%2 = OpFUnordGreaterThan %bool %clamp %float_0\n" +
4768 "OpReturn\n" +
4769 "OpFunctionEnd",
4770 2, 0),
4771 // Test case 5: Don't Fold clamp(-1, 1) > 0.0
4772 InstructionFoldingCase<uint32_t>(
4773 Header() + "%main = OpFunction %void None %void_func\n" +
4774 "%main_lab = OpLabel\n" +
4775 "%n = OpVariable %_ptr_float Function\n" +
4776 "%ld = OpLoad %float %n\n" +
4777 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4778 "%2 = OpFOrdGreaterThan %bool %clamp %float_0\n" +
4779 "OpReturn\n" +
4780 "OpFunctionEnd",
4781 2, 0),
4782 // Test case 6: Don't Fold clamp(-1, 1) >= 0.0
4783 InstructionFoldingCase<uint32_t>(
4784 Header() + "%main = OpFunction %void None %void_func\n" +
4785 "%main_lab = OpLabel\n" +
4786 "%n = OpVariable %_ptr_float Function\n" +
4787 "%ld = OpLoad %float %n\n" +
4788 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4789 "%2 = OpFUnordGreaterThanEqual %bool %clamp %float_0\n" +
4790 "OpReturn\n" +
4791 "OpFunctionEnd",
4792 2, 0),
4793 // Test case 7: Don't Fold clamp(-1, 1) >= 0.0
4794 InstructionFoldingCase<uint32_t>(
4795 Header() + "%main = OpFunction %void None %void_func\n" +
4796 "%main_lab = OpLabel\n" +
4797 "%n = OpVariable %_ptr_float Function\n" +
4798 "%ld = OpLoad %float %n\n" +
4799 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_1\n" +
4800 "%2 = OpFOrdGreaterThanEqual %bool %clamp %float_0\n" +
4801 "OpReturn\n" +
4802 "OpFunctionEnd",
4803 2, 0),
4804 // Test case 8: Don't Fold clamp(-1, 0) < 0.0
4805 InstructionFoldingCase<uint32_t>(
4806 Header() + "%main = OpFunction %void None %void_func\n" +
4807 "%main_lab = OpLabel\n" +
4808 "%n = OpVariable %_ptr_float Function\n" +
4809 "%ld = OpLoad %float %n\n" +
4810 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4811 "%2 = OpFUnordLessThan %bool %clamp %float_0\n" +
4812 "OpReturn\n" +
4813 "OpFunctionEnd",
4814 2, 0),
4815 // Test case 9: Don't Fold clamp(0, 1) < 1
4816 InstructionFoldingCase<uint32_t>(
4817 Header() + "%main = OpFunction %void None %void_func\n" +
4818 "%main_lab = OpLabel\n" +
4819 "%n = OpVariable %_ptr_float Function\n" +
4820 "%ld = OpLoad %float %n\n" +
4821 "%clamp = OpExtInst %float %1 FClamp %ld %float_0 %float_1\n" +
4822 "%2 = OpFOrdLessThan %bool %clamp %float_1\n" +
4823 "OpReturn\n" +
4824 "OpFunctionEnd",
4825 2, 0),
4826 // Test case 10: Don't Fold clamp(-1, 0) > -1
4827 InstructionFoldingCase<uint32_t>(
4828 Header() + "%main = OpFunction %void None %void_func\n" +
4829 "%main_lab = OpLabel\n" +
4830 "%n = OpVariable %_ptr_float Function\n" +
4831 "%ld = OpLoad %float %n\n" +
4832 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4833 "%2 = OpFUnordGreaterThan %bool %clamp %float_n1\n" +
4834 "OpReturn\n" +
4835 "OpFunctionEnd",
4836 2, 0),
4837 // Test case 11: Don't Fold clamp(-1, 0) > -1
4838 InstructionFoldingCase<uint32_t>(
4839 Header() + "%main = OpFunction %void None %void_func\n" +
4840 "%main_lab = OpLabel\n" +
4841 "%n = OpVariable %_ptr_float Function\n" +
4842 "%ld = OpLoad %float %n\n" +
4843 "%clamp = OpExtInst %float %1 FClamp %ld %float_n1 %float_0\n" +
4844 "%2 = OpFOrdGreaterThan %bool %clamp %float_n1\n" +
4845 "OpReturn\n" +
4846 "OpFunctionEnd",
4847 2, 0)
4848 ));
4849
4850 INSTANTIATE_TEST_SUITE_P(FToIConstantFoldingTest, IntegerInstructionFoldingTest,
4851 ::testing::Values(
4852 // Test case 0: Fold int(3.0)
4853 InstructionFoldingCase<uint32_t>(
4854 Header() + "%main = OpFunction %void None %void_func\n" +
4855 "%main_lab = OpLabel\n" +
4856 "%2 = OpConvertFToS %int %float_3\n" +
4857 "OpReturn\n" +
4858 "OpFunctionEnd",
4859 2, 3),
4860 // Test case 1: Fold uint(3.0)
4861 InstructionFoldingCase<uint32_t>(
4862 Header() + "%main = OpFunction %void None %void_func\n" +
4863 "%main_lab = OpLabel\n" +
4864 "%2 = OpConvertFToU %int %float_3\n" +
4865 "OpReturn\n" +
4866 "OpFunctionEnd",
4867 2, 3)
4868 ));
4869
4870 INSTANTIATE_TEST_SUITE_P(IToFConstantFoldingTest, FloatInstructionFoldingTest,
4871 ::testing::Values(
4872 // Test case 0: Fold float(3)
4873 InstructionFoldingCase<float>(
4874 Header() + "%main = OpFunction %void None %void_func\n" +
4875 "%main_lab = OpLabel\n" +
4876 "%2 = OpConvertSToF %float %int_3\n" +
4877 "OpReturn\n" +
4878 "OpFunctionEnd",
4879 2, 3.0),
4880 // Test case 1: Fold float(3u)
4881 InstructionFoldingCase<float>(
4882 Header() + "%main = OpFunction %void None %void_func\n" +
4883 "%main_lab = OpLabel\n" +
4884 "%2 = OpConvertUToF %float %uint_3\n" +
4885 "OpReturn\n" +
4886 "OpFunctionEnd",
4887 2, 3.0)
4888 ));
4889 // clang-format on
4890
4891 using ToNegateFoldingTest =
4892 ::testing::TestWithParam<InstructionFoldingCase<uint32_t>>;
4893
TEST_P(ToNegateFoldingTest,Case)4894 TEST_P(ToNegateFoldingTest, Case) {
4895 const auto& tc = GetParam();
4896
4897 // Build module.
4898 std::unique_ptr<IRContext> context =
4899 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
4900 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
4901 ASSERT_NE(nullptr, context);
4902
4903 // Fold the instruction to test.
4904 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
4905 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
4906 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
4907 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
4908
4909 // Make sure the instruction folded as expected.
4910 EXPECT_EQ(inst->result_id(), original_inst->result_id());
4911 EXPECT_EQ(inst->type_id(), original_inst->type_id());
4912 EXPECT_TRUE((!succeeded) == (tc.expected_result == 0));
4913 if (succeeded) {
4914 EXPECT_EQ(inst->opcode(), SpvOpFNegate);
4915 EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result);
4916 } else {
4917 EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands());
4918 for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
4919 EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i));
4920 }
4921 }
4922 }
4923
4924 // clang-format off
4925 INSTANTIATE_TEST_SUITE_P(FloatRedundantSubFoldingTest, ToNegateFoldingTest,
4926 ::testing::Values(
4927 // Test case 0: Don't fold 1.0 - n
4928 InstructionFoldingCase<uint32_t>(
4929 Header() + "%main = OpFunction %void None %void_func\n" +
4930 "%main_lab = OpLabel\n" +
4931 "%n = OpVariable %_ptr_float Function\n" +
4932 "%3 = OpLoad %float %n\n" +
4933 "%2 = OpFSub %float %float_1 %3\n" +
4934 "OpReturn\n" +
4935 "OpFunctionEnd",
4936 2, 0),
4937 // Test case 1: Fold 0.0 - n
4938 InstructionFoldingCase<uint32_t>(
4939 Header() + "%main = OpFunction %void None %void_func\n" +
4940 "%main_lab = OpLabel\n" +
4941 "%n = OpVariable %_ptr_float Function\n" +
4942 "%3 = OpLoad %float %n\n" +
4943 "%2 = OpFSub %float %float_0 %3\n" +
4944 "OpReturn\n" +
4945 "OpFunctionEnd",
4946 2, 3),
4947 // Test case 2: Don't fold (0,0,0,1) - n
4948 InstructionFoldingCase<uint32_t>(
4949 Header() + "%main = OpFunction %void None %void_func\n" +
4950 "%main_lab = OpLabel\n" +
4951 "%n = OpVariable %_ptr_v4float Function\n" +
4952 "%3 = OpLoad %v4float %n\n" +
4953 "%2 = OpFSub %v4float %v4float_0_0_0_1 %3\n" +
4954 "OpReturn\n" +
4955 "OpFunctionEnd",
4956 2, 0),
4957 // Test case 3: Fold (0,0,0,0) - n
4958 InstructionFoldingCase<uint32_t>(
4959 Header() + "%main = OpFunction %void None %void_func\n" +
4960 "%main_lab = OpLabel\n" +
4961 "%n = OpVariable %_ptr_v4float Function\n" +
4962 "%3 = OpLoad %v4float %n\n" +
4963 "%2 = OpFSub %v4float %v4float_0_0_0_0 %3\n" +
4964 "OpReturn\n" +
4965 "OpFunctionEnd",
4966 2, 3)
4967 ));
4968
4969 INSTANTIATE_TEST_SUITE_P(DoubleRedundantSubFoldingTest, ToNegateFoldingTest,
4970 ::testing::Values(
4971 // Test case 0: Don't fold 1.0 - n
4972 InstructionFoldingCase<uint32_t>(
4973 Header() + "%main = OpFunction %void None %void_func\n" +
4974 "%main_lab = OpLabel\n" +
4975 "%n = OpVariable %_ptr_double Function\n" +
4976 "%3 = OpLoad %double %n\n" +
4977 "%2 = OpFSub %double %double_1 %3\n" +
4978 "OpReturn\n" +
4979 "OpFunctionEnd",
4980 2, 0),
4981 // Test case 1: Fold 0.0 - n
4982 InstructionFoldingCase<uint32_t>(
4983 Header() + "%main = OpFunction %void None %void_func\n" +
4984 "%main_lab = OpLabel\n" +
4985 "%n = OpVariable %_ptr_double Function\n" +
4986 "%3 = OpLoad %double %n\n" +
4987 "%2 = OpFSub %double %double_0 %3\n" +
4988 "OpReturn\n" +
4989 "OpFunctionEnd",
4990 2, 3),
4991 // Test case 2: Don't fold (0,0,0,1) - n
4992 InstructionFoldingCase<uint32_t>(
4993 Header() + "%main = OpFunction %void None %void_func\n" +
4994 "%main_lab = OpLabel\n" +
4995 "%n = OpVariable %_ptr_v4double Function\n" +
4996 "%3 = OpLoad %v4double %n\n" +
4997 "%2 = OpFSub %v4double %v4double_0_0_0_1 %3\n" +
4998 "OpReturn\n" +
4999 "OpFunctionEnd",
5000 2, 0),
5001 // Test case 3: Fold (0,0,0,0) - n
5002 InstructionFoldingCase<uint32_t>(
5003 Header() + "%main = OpFunction %void None %void_func\n" +
5004 "%main_lab = OpLabel\n" +
5005 "%n = OpVariable %_ptr_v4double Function\n" +
5006 "%3 = OpLoad %v4double %n\n" +
5007 "%2 = OpFSub %v4double %v4double_0_0_0_0 %3\n" +
5008 "OpReturn\n" +
5009 "OpFunctionEnd",
5010 2, 3)
5011 ));
5012
5013 using MatchingInstructionFoldingTest =
5014 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
5015
TEST_P(MatchingInstructionFoldingTest,Case)5016 TEST_P(MatchingInstructionFoldingTest, Case) {
5017 const auto& tc = GetParam();
5018
5019 // Build module.
5020 std::unique_ptr<IRContext> context =
5021 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
5022 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
5023 ASSERT_NE(nullptr, context);
5024
5025 // Fold the instruction to test.
5026 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
5027 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
5028 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
5029 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
5030 EXPECT_EQ(succeeded, tc.expected_result);
5031 if (succeeded) {
5032 Match(tc.test_body, context.get());
5033 }
5034 }
5035
5036 INSTANTIATE_TEST_SUITE_P(RedundantIntegerMatching, MatchingInstructionFoldingTest,
5037 ::testing::Values(
5038 // Test case 0: Fold 0 + n (change sign)
5039 InstructionFoldingCase<bool>(
5040 Header() +
5041 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5042 "; CHECK: %2 = OpBitcast [[uint]] %3\n" +
5043 "%main = OpFunction %void None %void_func\n" +
5044 "%main_lab = OpLabel\n" +
5045 "%n = OpVariable %_ptr_int Function\n" +
5046 "%3 = OpLoad %uint %n\n" +
5047 "%2 = OpIAdd %uint %int_0 %3\n" +
5048 "OpReturn\n" +
5049 "OpFunctionEnd\n",
5050 2, true),
5051 // Test case 0: Fold 0 + n (change sign)
5052 InstructionFoldingCase<bool>(
5053 Header() +
5054 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5055 "; CHECK: %2 = OpBitcast [[int]] %3\n" +
5056 "%main = OpFunction %void None %void_func\n" +
5057 "%main_lab = OpLabel\n" +
5058 "%n = OpVariable %_ptr_int Function\n" +
5059 "%3 = OpLoad %int %n\n" +
5060 "%2 = OpIAdd %int %uint_0 %3\n" +
5061 "OpReturn\n" +
5062 "OpFunctionEnd\n",
5063 2, true)
5064 ));
5065
5066 INSTANTIATE_TEST_SUITE_P(MergeNegateTest, MatchingInstructionFoldingTest,
5067 ::testing::Values(
5068 // Test case 0: fold consecutive fnegate
5069 // -(-x) = x
5070 InstructionFoldingCase<bool>(
5071 Header() +
5072 "; CHECK: [[ld:%\\w+]] = OpLoad [[float:%\\w+]]\n" +
5073 "; CHECK: %4 = OpCopyObject [[float]] [[ld]]\n" +
5074 "%main = OpFunction %void None %void_func\n" +
5075 "%main_lab = OpLabel\n" +
5076 "%var = OpVariable %_ptr_float Function\n" +
5077 "%2 = OpLoad %float %var\n" +
5078 "%3 = OpFNegate %float %2\n" +
5079 "%4 = OpFNegate %float %3\n" +
5080 "OpReturn\n" +
5081 "OpFunctionEnd",
5082 4, true),
5083 // Test case 1: fold fnegate(fmul with const).
5084 // -(x * 2.0) = x * -2.0
5085 InstructionFoldingCase<bool>(
5086 Header() +
5087 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5088 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5089 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5090 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5091 "%main = OpFunction %void None %void_func\n" +
5092 "%main_lab = OpLabel\n" +
5093 "%var = OpVariable %_ptr_float Function\n" +
5094 "%2 = OpLoad %float %var\n" +
5095 "%3 = OpFMul %float %2 %float_2\n" +
5096 "%4 = OpFNegate %float %3\n" +
5097 "OpReturn\n" +
5098 "OpFunctionEnd",
5099 4, true),
5100 // Test case 2: fold fnegate(fmul with const).
5101 // -(2.0 * x) = x * 2.0
5102 InstructionFoldingCase<bool>(
5103 Header() +
5104 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5105 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5106 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5107 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n2]]\n" +
5108 "%main = OpFunction %void None %void_func\n" +
5109 "%main_lab = OpLabel\n" +
5110 "%var = OpVariable %_ptr_float Function\n" +
5111 "%2 = OpLoad %float %var\n" +
5112 "%3 = OpFMul %float %float_2 %2\n" +
5113 "%4 = OpFNegate %float %3\n" +
5114 "OpReturn\n" +
5115 "OpFunctionEnd",
5116 4, true),
5117 // Test case 3: fold fnegate(fdiv with const).
5118 // -(x / 2.0) = x * -0.5
5119 InstructionFoldingCase<bool>(
5120 Header() +
5121 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5122 "; CHECK: [[float_n0p5:%\\w+]] = OpConstant [[float]] -0.5\n" +
5123 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5124 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_n0p5]]\n" +
5125 "%main = OpFunction %void None %void_func\n" +
5126 "%main_lab = OpLabel\n" +
5127 "%var = OpVariable %_ptr_float Function\n" +
5128 "%2 = OpLoad %float %var\n" +
5129 "%3 = OpFDiv %float %2 %float_2\n" +
5130 "%4 = OpFNegate %float %3\n" +
5131 "OpReturn\n" +
5132 "OpFunctionEnd",
5133 4, true),
5134 // Test case 4: fold fnegate(fdiv with const).
5135 // -(2.0 / x) = -2.0 / x
5136 InstructionFoldingCase<bool>(
5137 Header() +
5138 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5139 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5140 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5141 "; CHECK: %4 = OpFDiv [[float]] [[float_n2]] [[ld]]\n" +
5142 "%main = OpFunction %void None %void_func\n" +
5143 "%main_lab = OpLabel\n" +
5144 "%var = OpVariable %_ptr_float Function\n" +
5145 "%2 = OpLoad %float %var\n" +
5146 "%3 = OpFDiv %float %float_2 %2\n" +
5147 "%4 = OpFNegate %float %3\n" +
5148 "OpReturn\n" +
5149 "OpFunctionEnd",
5150 4, true),
5151 // Test case 5: fold fnegate(fadd with const).
5152 // -(2.0 + x) = -2.0 - x
5153 InstructionFoldingCase<bool>(
5154 Header() +
5155 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5156 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5157 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5158 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5159 "%main = OpFunction %void None %void_func\n" +
5160 "%main_lab = OpLabel\n" +
5161 "%var = OpVariable %_ptr_float Function\n" +
5162 "%2 = OpLoad %float %var\n" +
5163 "%3 = OpFAdd %float %float_2 %2\n" +
5164 "%4 = OpFNegate %float %3\n" +
5165 "OpReturn\n" +
5166 "OpFunctionEnd",
5167 4, true),
5168 // Test case 6: fold fnegate(fadd with const).
5169 // -(x + 2.0) = -2.0 - x
5170 InstructionFoldingCase<bool>(
5171 Header() +
5172 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5173 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5174 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5175 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
5176 "%main = OpFunction %void None %void_func\n" +
5177 "%main_lab = OpLabel\n" +
5178 "%var = OpVariable %_ptr_float Function\n" +
5179 "%2 = OpLoad %float %var\n" +
5180 "%3 = OpFAdd %float %2 %float_2\n" +
5181 "%4 = OpFNegate %float %3\n" +
5182 "OpReturn\n" +
5183 "OpFunctionEnd",
5184 4, true),
5185 // Test case 7: fold fnegate(fsub with const).
5186 // -(2.0 - x) = x - 2.0
5187 InstructionFoldingCase<bool>(
5188 Header() +
5189 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5190 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5191 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5192 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_2]]\n" +
5193 "%main = OpFunction %void None %void_func\n" +
5194 "%main_lab = OpLabel\n" +
5195 "%var = OpVariable %_ptr_float Function\n" +
5196 "%2 = OpLoad %float %var\n" +
5197 "%3 = OpFSub %float %float_2 %2\n" +
5198 "%4 = OpFNegate %float %3\n" +
5199 "OpReturn\n" +
5200 "OpFunctionEnd",
5201 4, true),
5202 // Test case 8: fold fnegate(fsub with const).
5203 // -(x - 2.0) = 2.0 - x
5204 InstructionFoldingCase<bool>(
5205 Header() +
5206 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5207 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5208 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5209 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
5210 "%main = OpFunction %void None %void_func\n" +
5211 "%main_lab = OpLabel\n" +
5212 "%var = OpVariable %_ptr_float Function\n" +
5213 "%2 = OpLoad %float %var\n" +
5214 "%3 = OpFSub %float %2 %float_2\n" +
5215 "%4 = OpFNegate %float %3\n" +
5216 "OpReturn\n" +
5217 "OpFunctionEnd",
5218 4, true),
5219 // Test case 9: fold consecutive snegate
5220 // -(-x) = x
5221 InstructionFoldingCase<bool>(
5222 Header() +
5223 "; CHECK: [[ld:%\\w+]] = OpLoad [[int:%\\w+]]\n" +
5224 "; CHECK: %4 = OpCopyObject [[int]] [[ld]]\n" +
5225 "%main = OpFunction %void None %void_func\n" +
5226 "%main_lab = OpLabel\n" +
5227 "%var = OpVariable %_ptr_int Function\n" +
5228 "%2 = OpLoad %int %var\n" +
5229 "%3 = OpSNegate %int %2\n" +
5230 "%4 = OpSNegate %int %3\n" +
5231 "OpReturn\n" +
5232 "OpFunctionEnd",
5233 4, true),
5234 // Test case 10: fold consecutive vector negate
5235 // -(-x) = x
5236 InstructionFoldingCase<bool>(
5237 Header() +
5238 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float:%\\w+]]\n" +
5239 "; CHECK: %4 = OpCopyObject [[v2float]] [[ld]]\n" +
5240 "%main = OpFunction %void None %void_func\n" +
5241 "%main_lab = OpLabel\n" +
5242 "%var = OpVariable %_ptr_v2float Function\n" +
5243 "%2 = OpLoad %v2float %var\n" +
5244 "%3 = OpFNegate %v2float %2\n" +
5245 "%4 = OpFNegate %v2float %3\n" +
5246 "OpReturn\n" +
5247 "OpFunctionEnd",
5248 4, true),
5249 // Test case 11: fold snegate(iadd with const).
5250 // -(2 + x) = -2 - x
5251 InstructionFoldingCase<bool>(
5252 Header() +
5253 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5254 "; CHECK: OpConstant [[int]] -2147483648\n" +
5255 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5256 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5257 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5258 "%main = OpFunction %void None %void_func\n" +
5259 "%main_lab = OpLabel\n" +
5260 "%var = OpVariable %_ptr_int Function\n" +
5261 "%2 = OpLoad %int %var\n" +
5262 "%3 = OpIAdd %int %int_2 %2\n" +
5263 "%4 = OpSNegate %int %3\n" +
5264 "OpReturn\n" +
5265 "OpFunctionEnd",
5266 4, true),
5267 // Test case 12: fold snegate(iadd with const).
5268 // -(x + 2) = -2 - x
5269 InstructionFoldingCase<bool>(
5270 Header() +
5271 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5272 "; CHECK: OpConstant [[int]] -2147483648\n" +
5273 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5274 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5275 "; CHECK: %4 = OpISub [[int]] [[int_n2]] [[ld]]\n" +
5276 "%main = OpFunction %void None %void_func\n" +
5277 "%main_lab = OpLabel\n" +
5278 "%var = OpVariable %_ptr_int Function\n" +
5279 "%2 = OpLoad %int %var\n" +
5280 "%3 = OpIAdd %int %2 %int_2\n" +
5281 "%4 = OpSNegate %int %3\n" +
5282 "OpReturn\n" +
5283 "OpFunctionEnd",
5284 4, true),
5285 // Test case 13: fold snegate(isub with const).
5286 // -(2 - x) = x - 2
5287 InstructionFoldingCase<bool>(
5288 Header() +
5289 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5290 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5291 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5292 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_2]]\n" +
5293 "%main = OpFunction %void None %void_func\n" +
5294 "%main_lab = OpLabel\n" +
5295 "%var = OpVariable %_ptr_int Function\n" +
5296 "%2 = OpLoad %int %var\n" +
5297 "%3 = OpISub %int %int_2 %2\n" +
5298 "%4 = OpSNegate %int %3\n" +
5299 "OpReturn\n" +
5300 "OpFunctionEnd",
5301 4, true),
5302 // Test case 14: fold snegate(isub with const).
5303 // -(x - 2) = 2 - x
5304 InstructionFoldingCase<bool>(
5305 Header() +
5306 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5307 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5308 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5309 "; CHECK: %4 = OpISub [[int]] [[int_2]] [[ld]]\n" +
5310 "%main = OpFunction %void None %void_func\n" +
5311 "%main_lab = OpLabel\n" +
5312 "%var = OpVariable %_ptr_int Function\n" +
5313 "%2 = OpLoad %int %var\n" +
5314 "%3 = OpISub %int %2 %int_2\n" +
5315 "%4 = OpSNegate %int %3\n" +
5316 "OpReturn\n" +
5317 "OpFunctionEnd",
5318 4, true),
5319 // Test case 15: fold snegate(iadd with const).
5320 // -(x + 2) = -2 - x
5321 InstructionFoldingCase<bool>(
5322 Header() +
5323 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5324 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
5325 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5326 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
5327 "%main = OpFunction %void None %void_func\n" +
5328 "%main_lab = OpLabel\n" +
5329 "%var = OpVariable %_ptr_long Function\n" +
5330 "%2 = OpLoad %long %var\n" +
5331 "%3 = OpIAdd %long %2 %long_2\n" +
5332 "%4 = OpSNegate %long %3\n" +
5333 "OpReturn\n" +
5334 "OpFunctionEnd",
5335 4, true),
5336 // Test case 16: fold snegate(isub with const).
5337 // -(2 - x) = x - 2
5338 InstructionFoldingCase<bool>(
5339 Header() +
5340 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5341 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5342 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5343 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_2]]\n" +
5344 "%main = OpFunction %void None %void_func\n" +
5345 "%main_lab = OpLabel\n" +
5346 "%var = OpVariable %_ptr_long Function\n" +
5347 "%2 = OpLoad %long %var\n" +
5348 "%3 = OpISub %long %long_2 %2\n" +
5349 "%4 = OpSNegate %long %3\n" +
5350 "OpReturn\n" +
5351 "OpFunctionEnd",
5352 4, true),
5353 // Test case 17: fold snegate(isub with const).
5354 // -(x - 2) = 2 - x
5355 InstructionFoldingCase<bool>(
5356 Header() +
5357 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
5358 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5359 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5360 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
5361 "%main = OpFunction %void None %void_func\n" +
5362 "%main_lab = OpLabel\n" +
5363 "%var = OpVariable %_ptr_long Function\n" +
5364 "%2 = OpLoad %long %var\n" +
5365 "%3 = OpISub %long %2 %long_2\n" +
5366 "%4 = OpSNegate %long %3\n" +
5367 "OpReturn\n" +
5368 "OpFunctionEnd",
5369 4, true),
5370 // Test case 18: fold -vec4(-1.0, 2.0, 1.0, 3.0)
5371 InstructionFoldingCase<bool>(
5372 Header() +
5373 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5374 "; CHECK: [[v4float:%\\w+]] = OpTypeVector [[float]] 4{{[[:space:]]}}\n" +
5375 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1{{[[:space:]]}}\n" +
5376 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1{{[[:space:]]}}\n" +
5377 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
5378 "; CHECK: [[float_n3:%\\w+]] = OpConstant [[float]] -3{{[[:space:]]}}\n" +
5379 "; CHECK: [[v4float_1_n2_n1_n3:%\\w+]] = OpConstantComposite [[v4float]] [[float_1]] [[float_n2]] [[float_n1]] [[float_n3]]\n" +
5380 "; CHECK: %2 = OpCopyObject [[v4float]] [[v4float_1_n2_n1_n3]]\n" +
5381 "%main = OpFunction %void None %void_func\n" +
5382 "%main_lab = OpLabel\n" +
5383 "%2 = OpFNegate %v4float %v4float_n1_2_1_3\n" +
5384 "OpReturn\n" +
5385 "OpFunctionEnd",
5386 2, true),
5387 // Test case 19: fold vector fnegate with null
5388 InstructionFoldingCase<bool>(
5389 Header() +
5390 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5391 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5392 "; CHECK: [[double_n0:%\\w+]] = OpConstant [[double]] -0\n" +
5393 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_n0]] [[double_n0]]\n" +
5394 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5395 "%main = OpFunction %void None %void_func\n" +
5396 "%main_lab = OpLabel\n" +
5397 "%2 = OpFNegate %v2double %v2double_null\n" +
5398 "OpReturn\n" +
5399 "OpFunctionEnd",
5400 2, true)
5401 ));
5402
5403 INSTANTIATE_TEST_SUITE_P(ReciprocalFDivTest, MatchingInstructionFoldingTest,
5404 ::testing::Values(
5405 // Test case 0: scalar reicprocal
5406 // x / 0.5 = x * 2.0
5407 InstructionFoldingCase<bool>(
5408 Header() +
5409 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5410 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5411 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5412 "; CHECK: %3 = OpFMul [[float]] [[ld]] [[float_2]]\n" +
5413 "%main = OpFunction %void None %void_func\n" +
5414 "%main_lab = OpLabel\n" +
5415 "%var = OpVariable %_ptr_float Function\n" +
5416 "%2 = OpLoad %float %var\n" +
5417 "%3 = OpFDiv %float %2 %float_0p5\n" +
5418 "OpReturn\n" +
5419 "OpFunctionEnd\n",
5420 3, true),
5421 // Test case 1: Unfoldable
5422 InstructionFoldingCase<bool>(
5423 Header() +
5424 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5425 "; CHECK: [[float_0:%\\w+]] = OpConstant [[float]] 0\n" +
5426 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5427 "; CHECK: %3 = OpFDiv [[float]] [[ld]] [[float_0]]\n" +
5428 "%main = OpFunction %void None %void_func\n" +
5429 "%main_lab = OpLabel\n" +
5430 "%var = OpVariable %_ptr_float Function\n" +
5431 "%2 = OpLoad %float %var\n" +
5432 "%3 = OpFDiv %float %2 %104\n" +
5433 "OpReturn\n" +
5434 "OpFunctionEnd\n",
5435 3, false),
5436 // Test case 2: Vector reciprocal
5437 // x / {2.0, 0.5} = x * {0.5, 2.0}
5438 InstructionFoldingCase<bool>(
5439 Header() +
5440 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5441 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5442 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5443 "; CHECK: [[float_0p5:%\\w+]] = OpConstant [[float]] 0.5\n" +
5444 "; CHECK: [[v2float_0p5_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_0p5]] [[float_2]]\n" +
5445 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5446 "; CHECK: %3 = OpFMul [[v2float]] [[ld]] [[v2float_0p5_2]]\n" +
5447 "%main = OpFunction %void None %void_func\n" +
5448 "%main_lab = OpLabel\n" +
5449 "%var = OpVariable %_ptr_v2float Function\n" +
5450 "%2 = OpLoad %v2float %var\n" +
5451 "%3 = OpFDiv %v2float %2 %v2float_2_0p5\n" +
5452 "OpReturn\n" +
5453 "OpFunctionEnd\n",
5454 3, true),
5455 // Test case 3: double reciprocal
5456 // x / 2.0 = x * 0.5
5457 InstructionFoldingCase<bool>(
5458 Header() +
5459 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5460 "; CHECK: [[double_0p5:%\\w+]] = OpConstant [[double]] 0.5\n" +
5461 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5462 "; CHECK: %3 = OpFMul [[double]] [[ld]] [[double_0p5]]\n" +
5463 "%main = OpFunction %void None %void_func\n" +
5464 "%main_lab = OpLabel\n" +
5465 "%var = OpVariable %_ptr_double Function\n" +
5466 "%2 = OpLoad %double %var\n" +
5467 "%3 = OpFDiv %double %2 %double_2\n" +
5468 "OpReturn\n" +
5469 "OpFunctionEnd\n",
5470 3, true),
5471 // Test case 4: don't fold x / 0.
5472 InstructionFoldingCase<bool>(
5473 Header() +
5474 "%main = OpFunction %void None %void_func\n" +
5475 "%main_lab = OpLabel\n" +
5476 "%var = OpVariable %_ptr_v2float Function\n" +
5477 "%2 = OpLoad %v2float %var\n" +
5478 "%3 = OpFDiv %v2float %2 %v2float_null\n" +
5479 "OpReturn\n" +
5480 "OpFunctionEnd\n",
5481 3, false)
5482 ));
5483
5484 INSTANTIATE_TEST_SUITE_P(MergeMulTest, MatchingInstructionFoldingTest,
5485 ::testing::Values(
5486 // Test case 0: fold consecutive fmuls
5487 // (x * 3.0) * 2.0 = x * 6.0
5488 InstructionFoldingCase<bool>(
5489 Header() +
5490 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5491 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5492 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5493 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5494 "%main = OpFunction %void None %void_func\n" +
5495 "%main_lab = OpLabel\n" +
5496 "%var = OpVariable %_ptr_float Function\n" +
5497 "%2 = OpLoad %float %var\n" +
5498 "%3 = OpFMul %float %2 %float_3\n" +
5499 "%4 = OpFMul %float %3 %float_2\n" +
5500 "OpReturn\n" +
5501 "OpFunctionEnd\n",
5502 4, true),
5503 // Test case 1: fold consecutive fmuls
5504 // 2.0 * (x * 3.0) = x * 6.0
5505 InstructionFoldingCase<bool>(
5506 Header() +
5507 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5508 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5509 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5510 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5511 "%main = OpFunction %void None %void_func\n" +
5512 "%main_lab = OpLabel\n" +
5513 "%var = OpVariable %_ptr_float Function\n" +
5514 "%2 = OpLoad %float %var\n" +
5515 "%3 = OpFMul %float %2 %float_3\n" +
5516 "%4 = OpFMul %float %float_2 %3\n" +
5517 "OpReturn\n" +
5518 "OpFunctionEnd\n",
5519 4, true),
5520 // Test case 2: fold consecutive fmuls
5521 // (3.0 * x) * 2.0 = x * 6.0
5522 InstructionFoldingCase<bool>(
5523 Header() +
5524 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5525 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5526 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5527 "; CHECK: %4 = OpFMul [[float]] [[ld]] [[float_6]]\n" +
5528 "%main = OpFunction %void None %void_func\n" +
5529 "%main_lab = OpLabel\n" +
5530 "%var = OpVariable %_ptr_float Function\n" +
5531 "%2 = OpLoad %float %var\n" +
5532 "%3 = OpFMul %float %float_3 %2\n" +
5533 "%4 = OpFMul %float %float_2 %3\n" +
5534 "OpReturn\n" +
5535 "OpFunctionEnd\n",
5536 4, true),
5537 // Test case 3: fold vector fmul
5538 InstructionFoldingCase<bool>(
5539 Header() +
5540 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5541 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5542 "; CHECK: [[float_6:%\\w+]] = OpConstant [[float]] 6\n" +
5543 "; CHECK: [[v2float_6_6:%\\w+]] = OpConstantComposite [[v2float]] [[float_6]] [[float_6]]\n" +
5544 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5545 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_6_6]]\n" +
5546 "%main = OpFunction %void None %void_func\n" +
5547 "%main_lab = OpLabel\n" +
5548 "%var = OpVariable %_ptr_v2float Function\n" +
5549 "%2 = OpLoad %v2float %var\n" +
5550 "%3 = OpFMul %v2float %2 %v2float_2_3\n" +
5551 "%4 = OpFMul %v2float %3 %v2float_3_2\n" +
5552 "OpReturn\n" +
5553 "OpFunctionEnd\n",
5554 4, true),
5555 // Test case 4: fold double fmuls
5556 // (x * 3.0) * 2.0 = x * 6.0
5557 InstructionFoldingCase<bool>(
5558 Header() +
5559 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5560 "; CHECK: [[double_6:%\\w+]] = OpConstant [[double]] 6\n" +
5561 "; CHECK: [[ld:%\\w+]] = OpLoad [[double]]\n" +
5562 "; CHECK: %4 = OpFMul [[double]] [[ld]] [[double_6]]\n" +
5563 "%main = OpFunction %void None %void_func\n" +
5564 "%main_lab = OpLabel\n" +
5565 "%var = OpVariable %_ptr_double Function\n" +
5566 "%2 = OpLoad %double %var\n" +
5567 "%3 = OpFMul %double %2 %double_3\n" +
5568 "%4 = OpFMul %double %3 %double_2\n" +
5569 "OpReturn\n" +
5570 "OpFunctionEnd\n",
5571 4, true),
5572 // Test case 5: fold 32 bit imuls
5573 // (x * 3) * 2 = x * 6
5574 InstructionFoldingCase<bool>(
5575 Header() +
5576 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5577 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5578 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5579 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_6]]\n" +
5580 "%main = OpFunction %void None %void_func\n" +
5581 "%main_lab = OpLabel\n" +
5582 "%var = OpVariable %_ptr_int Function\n" +
5583 "%2 = OpLoad %int %var\n" +
5584 "%3 = OpIMul %int %2 %int_3\n" +
5585 "%4 = OpIMul %int %3 %int_2\n" +
5586 "OpReturn\n" +
5587 "OpFunctionEnd\n",
5588 4, true),
5589 // Test case 6: fold 64 bit imuls
5590 // (x * 3) * 2 = x * 6
5591 InstructionFoldingCase<bool>(
5592 Header() +
5593 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5594 "; CHECK: [[long_6:%\\w+]] = OpConstant [[long]] 6\n" +
5595 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5596 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_6]]\n" +
5597 "%main = OpFunction %void None %void_func\n" +
5598 "%main_lab = OpLabel\n" +
5599 "%var = OpVariable %_ptr_long Function\n" +
5600 "%2 = OpLoad %long %var\n" +
5601 "%3 = OpIMul %long %2 %long_3\n" +
5602 "%4 = OpIMul %long %3 %long_2\n" +
5603 "OpReturn\n" +
5604 "OpFunctionEnd\n",
5605 4, true),
5606 // Test case 7: merge vector integer mults
5607 InstructionFoldingCase<bool>(
5608 Header() +
5609 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5610 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
5611 "; CHECK: [[int_6:%\\w+]] = OpConstant [[int]] 6\n" +
5612 "; CHECK: [[v2int_6_6:%\\w+]] = OpConstantComposite [[v2int]] [[int_6]] [[int_6]]\n" +
5613 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5614 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_6_6]]\n" +
5615 "%main = OpFunction %void None %void_func\n" +
5616 "%main_lab = OpLabel\n" +
5617 "%var = OpVariable %_ptr_v2int Function\n" +
5618 "%2 = OpLoad %v2int %var\n" +
5619 "%3 = OpIMul %v2int %2 %v2int_2_3\n" +
5620 "%4 = OpIMul %v2int %3 %v2int_3_2\n" +
5621 "OpReturn\n" +
5622 "OpFunctionEnd\n",
5623 4, true),
5624 // Test case 8: merge fmul of fdiv
5625 // 2.0 * (2.0 / x) = 4.0 / x
5626 InstructionFoldingCase<bool>(
5627 Header() +
5628 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5629 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5630 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5631 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5632 "%main = OpFunction %void None %void_func\n" +
5633 "%main_lab = OpLabel\n" +
5634 "%var = OpVariable %_ptr_float Function\n" +
5635 "%2 = OpLoad %float %var\n" +
5636 "%3 = OpFDiv %float %float_2 %2\n" +
5637 "%4 = OpFMul %float %float_2 %3\n" +
5638 "OpReturn\n" +
5639 "OpFunctionEnd\n",
5640 4, true),
5641 // Test case 9: merge fmul of fdiv
5642 // (2.0 / x) * 2.0 = 4.0 / x
5643 InstructionFoldingCase<bool>(
5644 Header() +
5645 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5646 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5647 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
5648 "; CHECK: %4 = OpFDiv [[float]] [[float_4]] [[ld]]\n" +
5649 "%main = OpFunction %void None %void_func\n" +
5650 "%main_lab = OpLabel\n" +
5651 "%var = OpVariable %_ptr_float Function\n" +
5652 "%2 = OpLoad %float %var\n" +
5653 "%3 = OpFDiv %float %float_2 %2\n" +
5654 "%4 = OpFMul %float %3 %float_2\n" +
5655 "OpReturn\n" +
5656 "OpFunctionEnd\n",
5657 4, true),
5658 // Test case 10: Do not merge imul of sdiv
5659 // 4 * (x / 2)
5660 InstructionFoldingCase<bool>(
5661 Header() +
5662 "%main = OpFunction %void None %void_func\n" +
5663 "%main_lab = OpLabel\n" +
5664 "%var = OpVariable %_ptr_int Function\n" +
5665 "%2 = OpLoad %int %var\n" +
5666 "%3 = OpSDiv %int %2 %int_2\n" +
5667 "%4 = OpIMul %int %int_4 %3\n" +
5668 "OpReturn\n" +
5669 "OpFunctionEnd\n",
5670 4, false),
5671 // Test case 11: Do not merge imul of sdiv
5672 // (x / 2) * 4
5673 InstructionFoldingCase<bool>(
5674 Header() +
5675 "%main = OpFunction %void None %void_func\n" +
5676 "%main_lab = OpLabel\n" +
5677 "%var = OpVariable %_ptr_int Function\n" +
5678 "%2 = OpLoad %int %var\n" +
5679 "%3 = OpSDiv %int %2 %int_2\n" +
5680 "%4 = OpIMul %int %3 %int_4\n" +
5681 "OpReturn\n" +
5682 "OpFunctionEnd\n",
5683 4, false),
5684 // Test case 12: Do not merge imul of udiv
5685 // 4 * (x / 2)
5686 InstructionFoldingCase<bool>(
5687 Header() +
5688 "%main = OpFunction %void None %void_func\n" +
5689 "%main_lab = OpLabel\n" +
5690 "%var = OpVariable %_ptr_uint Function\n" +
5691 "%2 = OpLoad %uint %var\n" +
5692 "%3 = OpUDiv %uint %2 %uint_2\n" +
5693 "%4 = OpIMul %uint %uint_4 %3\n" +
5694 "OpReturn\n" +
5695 "OpFunctionEnd\n",
5696 4, false),
5697 // Test case 13: Do not merge imul of udiv
5698 // (x / 2) * 4
5699 InstructionFoldingCase<bool>(
5700 Header() +
5701 "%main = OpFunction %void None %void_func\n" +
5702 "%main_lab = OpLabel\n" +
5703 "%var = OpVariable %_ptr_uint Function\n" +
5704 "%2 = OpLoad %uint %var\n" +
5705 "%3 = OpUDiv %uint %2 %uint_2\n" +
5706 "%4 = OpIMul %uint %3 %uint_4\n" +
5707 "OpReturn\n" +
5708 "OpFunctionEnd\n",
5709 4, false),
5710 // Test case 14: Don't fold
5711 // (x / 3) * 4
5712 InstructionFoldingCase<bool>(
5713 Header() +
5714 "%main = OpFunction %void None %void_func\n" +
5715 "%main_lab = OpLabel\n" +
5716 "%var = OpVariable %_ptr_uint Function\n" +
5717 "%2 = OpLoad %uint %var\n" +
5718 "%3 = OpUDiv %uint %2 %uint_3\n" +
5719 "%4 = OpIMul %uint %3 %uint_4\n" +
5720 "OpReturn\n" +
5721 "OpFunctionEnd\n",
5722 4, false),
5723 // Test case 15: merge vector fmul of fdiv
5724 // (x / {2,2}) * {4,4} = x * {2,2}
5725 InstructionFoldingCase<bool>(
5726 Header() +
5727 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5728 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5729 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
5730 "; CHECK: [[v2float_2_2:%\\w+]] = OpConstantComposite [[v2float]] [[float_2]] [[float_2]]\n" +
5731 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2float]]\n" +
5732 "; CHECK: %4 = OpFMul [[v2float]] [[ld]] [[v2float_2_2]]\n" +
5733 "%main = OpFunction %void None %void_func\n" +
5734 "%main_lab = OpLabel\n" +
5735 "%var = OpVariable %_ptr_v2float Function\n" +
5736 "%2 = OpLoad %v2float %var\n" +
5737 "%3 = OpFDiv %v2float %2 %v2float_2_2\n" +
5738 "%4 = OpFMul %v2float %3 %v2float_4_4\n" +
5739 "OpReturn\n" +
5740 "OpFunctionEnd\n",
5741 4, true),
5742 // Test case 16: merge vector imul of snegate
5743 // (-x) * {2,2} = x * {-2,-2}
5744 InstructionFoldingCase<bool>(
5745 Header() +
5746 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5747 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
5748 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
5749 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5750 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
5751 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5752 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
5753 "%main = OpFunction %void None %void_func\n" +
5754 "%main_lab = OpLabel\n" +
5755 "%var = OpVariable %_ptr_v2int Function\n" +
5756 "%2 = OpLoad %v2int %var\n" +
5757 "%3 = OpSNegate %v2int %2\n" +
5758 "%4 = OpIMul %v2int %3 %v2int_2_2\n" +
5759 "OpReturn\n" +
5760 "OpFunctionEnd\n",
5761 4, true),
5762 // Test case 17: merge vector imul of snegate
5763 // {2,2} * (-x) = x * {-2,-2}
5764 InstructionFoldingCase<bool>(
5765 Header() +
5766 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
5767 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
5768 "; CHECK: OpConstant [[int]] -2147483648{{[[:space:]]}}\n" +
5769 "; CHECK: [[int_n2:%\\w+]] = OpConstant [[int]] -2{{[[:space:]]}}\n" +
5770 "; CHECK: [[v2int_n2_n2:%\\w+]] = OpConstantComposite [[v2int]] [[int_n2]] [[int_n2]]\n" +
5771 "; CHECK: [[ld:%\\w+]] = OpLoad [[v2int]]\n" +
5772 "; CHECK: %4 = OpIMul [[v2int]] [[ld]] [[v2int_n2_n2]]\n" +
5773 "%main = OpFunction %void None %void_func\n" +
5774 "%main_lab = OpLabel\n" +
5775 "%var = OpVariable %_ptr_v2int Function\n" +
5776 "%2 = OpLoad %v2int %var\n" +
5777 "%3 = OpSNegate %v2int %2\n" +
5778 "%4 = OpIMul %v2int %v2int_2_2 %3\n" +
5779 "OpReturn\n" +
5780 "OpFunctionEnd\n",
5781 4, true),
5782 // Test case 18: Fold OpVectorTimesScalar
5783 // {4,4} = OpVectorTimesScalar v2float {2,2} 2
5784 InstructionFoldingCase<bool>(
5785 Header() +
5786 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5787 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5788 "; CHECK: [[float_4:%\\w+]] = OpConstant [[float]] 4\n" +
5789 "; CHECK: [[v2float_4_4:%\\w+]] = OpConstantComposite [[v2float]] [[float_4]] [[float_4]]\n" +
5790 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_4_4]]\n" +
5791 "%main = OpFunction %void None %void_func\n" +
5792 "%main_lab = OpLabel\n" +
5793 "%2 = OpVectorTimesScalar %v2float %v2float_2_2 %float_2\n" +
5794 "OpReturn\n" +
5795 "OpFunctionEnd",
5796 2, true),
5797 // Test case 19: Fold OpVectorTimesScalar
5798 // {0,0} = OpVectorTimesScalar v2float v2float_null -1
5799 InstructionFoldingCase<bool>(
5800 Header() +
5801 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5802 "; CHECK: [[v2float:%\\w+]] = OpTypeVector [[float]] 2\n" +
5803 "; CHECK: [[v2float_null:%\\w+]] = OpConstantNull [[v2float]]\n" +
5804 "; CHECK: %2 = OpCopyObject [[v2float]] [[v2float_null]]\n" +
5805 "%main = OpFunction %void None %void_func\n" +
5806 "%main_lab = OpLabel\n" +
5807 "%2 = OpVectorTimesScalar %v2float %v2float_null %float_n1\n" +
5808 "OpReturn\n" +
5809 "OpFunctionEnd",
5810 2, true),
5811 // Test case 20: Fold OpVectorTimesScalar
5812 // {4,4} = OpVectorTimesScalar v2double {2,2} 2
5813 InstructionFoldingCase<bool>(
5814 Header() +
5815 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5816 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5817 "; CHECK: [[double_4:%\\w+]] = OpConstant [[double]] 4\n" +
5818 "; CHECK: [[v2double_4_4:%\\w+]] = OpConstantComposite [[v2double]] [[double_4]] [[double_4]]\n" +
5819 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_4_4]]\n" +
5820 "%main = OpFunction %void None %void_func\n" +
5821 "%main_lab = OpLabel\n" +
5822 "%2 = OpVectorTimesScalar %v2double %v2double_2_2 %double_2\n" +
5823 "OpReturn\n" +
5824 "OpFunctionEnd",
5825 2, true),
5826 // Test case 21: Fold OpVectorTimesScalar
5827 // {0,0} = OpVectorTimesScalar v2double {0,0} n
5828 InstructionFoldingCase<bool>(
5829 Header() +
5830 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5831 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5832 "; CHECK: {{%\\w+}} = OpConstant [[double]] 0\n" +
5833 "; CHECK: [[double_0:%\\w+]] = OpConstant [[double]] 0\n" +
5834 "; CHECK: [[v2double_0_0:%\\w+]] = OpConstantComposite [[v2double]] [[double_0]] [[double_0]]\n" +
5835 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_0_0]]\n" +
5836 "%main = OpFunction %void None %void_func\n" +
5837 "%main_lab = OpLabel\n" +
5838 "%n = OpVariable %_ptr_double Function\n" +
5839 "%load = OpLoad %double %n\n" +
5840 "%2 = OpVectorTimesScalar %v2double %v2double_0_0 %load\n" +
5841 "OpReturn\n" +
5842 "OpFunctionEnd",
5843 2, true),
5844 // Test case 22: Fold OpVectorTimesScalar
5845 // {0,0} = OpVectorTimesScalar v2double n 0
5846 InstructionFoldingCase<bool>(
5847 Header() +
5848 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
5849 "; CHECK: [[v2double:%\\w+]] = OpTypeVector [[double]] 2\n" +
5850 "; CHECK: [[v2double_null:%\\w+]] = OpConstantNull [[v2double]]\n" +
5851 "; CHECK: %2 = OpCopyObject [[v2double]] [[v2double_null]]\n" +
5852 "%main = OpFunction %void None %void_func\n" +
5853 "%main_lab = OpLabel\n" +
5854 "%n = OpVariable %_ptr_v2double Function\n" +
5855 "%load = OpLoad %v2double %n\n" +
5856 "%2 = OpVectorTimesScalar %v2double %load %double_0\n" +
5857 "OpReturn\n" +
5858 "OpFunctionEnd",
5859 2, true),
5860 // Test case 23: merge fmul of fdiv
5861 // x * (y / x) = y
5862 InstructionFoldingCase<bool>(
5863 Header() +
5864 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5865 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5866 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5867 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5868 "%main = OpFunction %void None %void_func\n" +
5869 "%main_lab = OpLabel\n" +
5870 "%x = OpVariable %_ptr_float Function\n" +
5871 "%y = OpVariable %_ptr_float Function\n" +
5872 "%2 = OpLoad %float %x\n" +
5873 "%3 = OpLoad %float %y\n" +
5874 "%4 = OpFDiv %float %3 %2\n" +
5875 "%5 = OpFMul %float %2 %4\n" +
5876 "OpReturn\n" +
5877 "OpFunctionEnd\n",
5878 5, true),
5879 // Test case 24: merge fmul of fdiv
5880 // (y / x) * x = y
5881 InstructionFoldingCase<bool>(
5882 Header() +
5883 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
5884 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
5885 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
5886 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
5887 "%main = OpFunction %void None %void_func\n" +
5888 "%main_lab = OpLabel\n" +
5889 "%x = OpVariable %_ptr_float Function\n" +
5890 "%y = OpVariable %_ptr_float Function\n" +
5891 "%2 = OpLoad %float %x\n" +
5892 "%3 = OpLoad %float %y\n" +
5893 "%4 = OpFDiv %float %3 %2\n" +
5894 "%5 = OpFMul %float %4 %2\n" +
5895 "OpReturn\n" +
5896 "OpFunctionEnd\n",
5897 5, true),
5898 // Test case 25: fold overflowing signed 32 bit imuls
5899 // (x * 1073741824) * 2 = x * int_min
5900 InstructionFoldingCase<bool>(
5901 Header() +
5902 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
5903 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
5904 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5905 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_min]]\n" +
5906 "%main = OpFunction %void None %void_func\n" +
5907 "%main_lab = OpLabel\n" +
5908 "%var = OpVariable %_ptr_int Function\n" +
5909 "%2 = OpLoad %int %var\n" +
5910 "%3 = OpIMul %int %2 %int_1073741824\n" +
5911 "%4 = OpIMul %int %3 %int_2\n" +
5912 "OpReturn\n" +
5913 "OpFunctionEnd\n",
5914 4, true),
5915 // Test case 26: fold overflowing signed 64 bit imuls
5916 // (x * 4611686018427387904) * 2 = x * long_min
5917 InstructionFoldingCase<bool>(
5918 Header() +
5919 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5920 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
5921 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5922 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_min]]\n" +
5923 "%main = OpFunction %void None %void_func\n" +
5924 "%main_lab = OpLabel\n" +
5925 "%var = OpVariable %_ptr_long Function\n" +
5926 "%2 = OpLoad %long %var\n" +
5927 "%3 = OpIMul %long %2 %long_4611686018427387904\n" +
5928 "%4 = OpIMul %long %3 %long_2\n" +
5929 "OpReturn\n" +
5930 "OpFunctionEnd\n",
5931 4, true),
5932 // Test case 27: fold overflowing 32 bit unsigned imuls
5933 // (x * 2147483649) * 2 = x * 2
5934 InstructionFoldingCase<bool>(
5935 Header() +
5936 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
5937 "; CHECK: [[uint_2:%\\w+]] = OpConstant [[uint]] 2\n" +
5938 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
5939 "; CHECK: %4 = OpIMul [[uint]] [[ld]] [[uint_2]]\n" +
5940 "%main = OpFunction %void None %void_func\n" +
5941 "%main_lab = OpLabel\n" +
5942 "%var = OpVariable %_ptr_uint Function\n" +
5943 "%2 = OpLoad %uint %var\n" +
5944 "%3 = OpIMul %uint %2 %uint_2147483649\n" +
5945 "%4 = OpIMul %uint %3 %uint_2\n" +
5946 "OpReturn\n" +
5947 "OpFunctionEnd\n",
5948 4, true),
5949 // Test case 28: fold overflowing 64 bit unsigned imuls
5950 // (x * 9223372036854775809) * 2 = x * 2
5951 InstructionFoldingCase<bool>(
5952 Header() +
5953 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
5954 "; CHECK: [[ulong_2:%\\w+]] = OpConstant [[ulong]] 2\n" +
5955 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
5956 "; CHECK: %4 = OpIMul [[ulong]] [[ld]] [[ulong_2]]\n" +
5957 "%main = OpFunction %void None %void_func\n" +
5958 "%main_lab = OpLabel\n" +
5959 "%var = OpVariable %_ptr_ulong Function\n" +
5960 "%2 = OpLoad %ulong %var\n" +
5961 "%3 = OpIMul %ulong %2 %ulong_9223372036854775809\n" +
5962 "%4 = OpIMul %ulong %3 %ulong_2\n" +
5963 "OpReturn\n" +
5964 "OpFunctionEnd\n",
5965 4, true),
5966 // Test case 29: fold underflowing signed 32 bit imuls
5967 // (x * (-858993459)) * 10 = x * 2
5968 InstructionFoldingCase<bool>(
5969 Header() +
5970 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
5971 "; CHECK: [[int_2:%\\w+]] = OpConstant [[int]] 2\n" +
5972 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
5973 "; CHECK: %4 = OpIMul [[int]] [[ld]] [[int_2]]\n" +
5974 "%main = OpFunction %void None %void_func\n" +
5975 "%main_lab = OpLabel\n" +
5976 "%var = OpVariable %_ptr_int Function\n" +
5977 "%2 = OpLoad %int %var\n" +
5978 "%3 = OpIMul %int %2 %int_n858993459\n" +
5979 "%4 = OpIMul %int %3 %int_10\n" +
5980 "OpReturn\n" +
5981 "OpFunctionEnd\n",
5982 4, true),
5983 // Test case 30: fold underflowing signed 64 bit imuls
5984 // (x * (-3689348814741910323)) * 10 = x * 2
5985 InstructionFoldingCase<bool>(
5986 Header() +
5987 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
5988 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
5989 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
5990 "; CHECK: %4 = OpIMul [[long]] [[ld]] [[long_2]]\n" +
5991 "%main = OpFunction %void None %void_func\n" +
5992 "%main_lab = OpLabel\n" +
5993 "%var = OpVariable %_ptr_long Function\n" +
5994 "%2 = OpLoad %long %var\n" +
5995 "%3 = OpIMul %long %2 %long_n3689348814741910323\n" +
5996 "%4 = OpIMul %long %3 %long_10\n" +
5997 "OpReturn\n" +
5998 "OpFunctionEnd\n",
5999 4, true)
6000 ));
6001
6002 INSTANTIATE_TEST_SUITE_P(MergeDivTest, MatchingInstructionFoldingTest,
6003 ::testing::Values(
6004 // Test case 0: merge consecutive fdiv
6005 // 4.0 / (2.0 / x) = 2.0 * x
6006 InstructionFoldingCase<bool>(
6007 Header() +
6008 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6009 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6010 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6011 "; CHECK: %4 = OpFMul [[float]] [[float_2]] [[ld]]\n" +
6012 "%main = OpFunction %void None %void_func\n" +
6013 "%main_lab = OpLabel\n" +
6014 "%var = OpVariable %_ptr_float Function\n" +
6015 "%2 = OpLoad %float %var\n" +
6016 "%3 = OpFDiv %float %float_2 %2\n" +
6017 "%4 = OpFDiv %float %float_4 %3\n" +
6018 "OpReturn\n" +
6019 "OpFunctionEnd\n",
6020 4, true),
6021 // Test case 1: merge consecutive fdiv
6022 // 4.0 / (x / 2.0) = 8.0 / x
6023 InstructionFoldingCase<bool>(
6024 Header() +
6025 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6026 "; CHECK: [[float_8:%\\w+]] = OpConstant [[float]] 8\n" +
6027 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6028 "; CHECK: %4 = OpFDiv [[float]] [[float_8]] [[ld]]\n" +
6029 "%main = OpFunction %void None %void_func\n" +
6030 "%main_lab = OpLabel\n" +
6031 "%var = OpVariable %_ptr_float Function\n" +
6032 "%2 = OpLoad %float %var\n" +
6033 "%3 = OpFDiv %float %2 %float_2\n" +
6034 "%4 = OpFDiv %float %float_4 %3\n" +
6035 "OpReturn\n" +
6036 "OpFunctionEnd\n",
6037 4, true),
6038 // Test case 2: merge consecutive fdiv
6039 // (4.0 / x) / 2.0 = 2.0 / x
6040 InstructionFoldingCase<bool>(
6041 Header() +
6042 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6043 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6044 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6045 "; CHECK: %4 = OpFDiv [[float]] [[float_2]] [[ld]]\n" +
6046 "%main = OpFunction %void None %void_func\n" +
6047 "%main_lab = OpLabel\n" +
6048 "%var = OpVariable %_ptr_float Function\n" +
6049 "%2 = OpLoad %float %var\n" +
6050 "%3 = OpFDiv %float %float_4 %2\n" +
6051 "%4 = OpFDiv %float %3 %float_2\n" +
6052 "OpReturn\n" +
6053 "OpFunctionEnd\n",
6054 4, true),
6055 // Test case 3: Do not merge consecutive sdiv
6056 // 4 / (2 / x)
6057 InstructionFoldingCase<bool>(
6058 Header() +
6059 "%main = OpFunction %void None %void_func\n" +
6060 "%main_lab = OpLabel\n" +
6061 "%var = OpVariable %_ptr_int Function\n" +
6062 "%2 = OpLoad %int %var\n" +
6063 "%3 = OpSDiv %int %int_2 %2\n" +
6064 "%4 = OpSDiv %int %int_4 %3\n" +
6065 "OpReturn\n" +
6066 "OpFunctionEnd\n",
6067 4, false),
6068 // Test case 4: Do not merge consecutive sdiv
6069 // 4 / (x / 2)
6070 InstructionFoldingCase<bool>(
6071 Header() +
6072 "%main = OpFunction %void None %void_func\n" +
6073 "%main_lab = OpLabel\n" +
6074 "%var = OpVariable %_ptr_int Function\n" +
6075 "%2 = OpLoad %int %var\n" +
6076 "%3 = OpSDiv %int %2 %int_2\n" +
6077 "%4 = OpSDiv %int %int_4 %3\n" +
6078 "OpReturn\n" +
6079 "OpFunctionEnd\n",
6080 4, false),
6081 // Test case 5: Do not merge consecutive sdiv
6082 // (4 / x) / 2
6083 InstructionFoldingCase<bool>(
6084 Header() +
6085 "%main = OpFunction %void None %void_func\n" +
6086 "%main_lab = OpLabel\n" +
6087 "%var = OpVariable %_ptr_int Function\n" +
6088 "%2 = OpLoad %int %var\n" +
6089 "%3 = OpSDiv %int %int_4 %2\n" +
6090 "%4 = OpSDiv %int %3 %int_2\n" +
6091 "OpReturn\n" +
6092 "OpFunctionEnd\n",
6093 4, false),
6094 // Test case 6: Do not merge consecutive sdiv
6095 // (x / 4) / 2
6096 InstructionFoldingCase<bool>(
6097 Header() +
6098 "%main = OpFunction %void None %void_func\n" +
6099 "%main_lab = OpLabel\n" +
6100 "%var = OpVariable %_ptr_int Function\n" +
6101 "%2 = OpLoad %int %var\n" +
6102 "%3 = OpSDiv %int %2 %int_4\n" +
6103 "%4 = OpSDiv %int %3 %int_2\n" +
6104 "OpReturn\n" +
6105 "OpFunctionEnd\n",
6106 4, false),
6107 // Test case 7: Do not merge sdiv of imul
6108 // 4 / (2 * x)
6109 InstructionFoldingCase<bool>(
6110 Header() +
6111 "%main = OpFunction %void None %void_func\n" +
6112 "%main_lab = OpLabel\n" +
6113 "%var = OpVariable %_ptr_int Function\n" +
6114 "%2 = OpLoad %int %var\n" +
6115 "%3 = OpIMul %int %int_2 %2\n" +
6116 "%4 = OpSDiv %int %int_4 %3\n" +
6117 "OpReturn\n" +
6118 "OpFunctionEnd\n",
6119 4, false),
6120 // Test case 8: Do not merge sdiv of imul
6121 // 4 / (x * 2)
6122 InstructionFoldingCase<bool>(
6123 Header() +
6124 "%main = OpFunction %void None %void_func\n" +
6125 "%main_lab = OpLabel\n" +
6126 "%var = OpVariable %_ptr_int Function\n" +
6127 "%2 = OpLoad %int %var\n" +
6128 "%3 = OpIMul %int %2 %int_2\n" +
6129 "%4 = OpSDiv %int %int_4 %3\n" +
6130 "OpReturn\n" +
6131 "OpFunctionEnd\n",
6132 4, false),
6133 // Test case 9: Do not merge sdiv of imul
6134 // (4 * x) / 2
6135 InstructionFoldingCase<bool>(
6136 Header() +
6137 "%main = OpFunction %void None %void_func\n" +
6138 "%main_lab = OpLabel\n" +
6139 "%var = OpVariable %_ptr_int Function\n" +
6140 "%2 = OpLoad %int %var\n" +
6141 "%3 = OpIMul %int %int_4 %2\n" +
6142 "%4 = OpSDiv %int %3 %int_2\n" +
6143 "OpReturn\n" +
6144 "OpFunctionEnd\n",
6145 4, false),
6146 // Test case 10: Do not merge sdiv of imul
6147 // (x * 4) / 2
6148 InstructionFoldingCase<bool>(
6149 Header() +
6150 "%main = OpFunction %void None %void_func\n" +
6151 "%main_lab = OpLabel\n" +
6152 "%var = OpVariable %_ptr_int Function\n" +
6153 "%2 = OpLoad %int %var\n" +
6154 "%3 = OpIMul %int %2 %int_4\n" +
6155 "%4 = OpSDiv %int %3 %int_2\n" +
6156 "OpReturn\n" +
6157 "OpFunctionEnd\n",
6158 4, false),
6159 // Test case 11: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
6160 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
6161 // Specifically, (-INT_MIN) / 2 != INT_MIN / -2.
6162 InstructionFoldingCase<bool>(
6163 Header() +
6164 "%main = OpFunction %void None %void_func\n" +
6165 "%main_lab = OpLabel\n" +
6166 "%var = OpVariable %_ptr_int Function\n" +
6167 "%2 = OpLoad %int %var\n" +
6168 "%3 = OpSNegate %int %2\n" +
6169 "%4 = OpSDiv %int %3 %int_2\n" +
6170 "OpReturn\n" +
6171 "OpFunctionEnd\n",
6172 4, false),
6173 // Test case 12: Do not merge sdiv of snegate. If %2 is INT_MIN, then the
6174 // sign of %3 will be the same as %2. This cannot be accounted for in OpSDiv.
6175 // Specifically, 2 / (-INT_MIN) != -2 / INT_MIN.
6176 InstructionFoldingCase<bool>(
6177 Header() +
6178 "%main = OpFunction %void None %void_func\n" +
6179 "%main_lab = OpLabel\n" +
6180 "%var = OpVariable %_ptr_int Function\n" +
6181 "%2 = OpLoad %int %var\n" +
6182 "%3 = OpSNegate %int %2\n" +
6183 "%4 = OpSDiv %int %int_2 %3\n" +
6184 "OpReturn\n" +
6185 "OpFunctionEnd\n",
6186 4, false),
6187 // Test case 13: Don't merge
6188 // (x / {null}) / {null}
6189 InstructionFoldingCase<bool>(
6190 Header() +
6191 "%main = OpFunction %void None %void_func\n" +
6192 "%main_lab = OpLabel\n" +
6193 "%var = OpVariable %_ptr_v2float Function\n" +
6194 "%2 = OpLoad %float %var\n" +
6195 "%3 = OpFDiv %float %2 %v2float_null\n" +
6196 "%4 = OpFDiv %float %3 %v2float_null\n" +
6197 "OpReturn\n" +
6198 "OpFunctionEnd\n",
6199 4, false),
6200 // Test case 14: merge fmul of fdiv
6201 // (y * x) / x = y
6202 InstructionFoldingCase<bool>(
6203 Header() +
6204 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6205 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6206 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6207 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6208 "%main = OpFunction %void None %void_func\n" +
6209 "%main_lab = OpLabel\n" +
6210 "%x = OpVariable %_ptr_float Function\n" +
6211 "%y = OpVariable %_ptr_float Function\n" +
6212 "%2 = OpLoad %float %x\n" +
6213 "%3 = OpLoad %float %y\n" +
6214 "%4 = OpFMul %float %3 %2\n" +
6215 "%5 = OpFDiv %float %4 %2\n" +
6216 "OpReturn\n" +
6217 "OpFunctionEnd\n",
6218 5, true),
6219 // Test case 15: merge fmul of fdiv
6220 // (x * y) / x = y
6221 InstructionFoldingCase<bool>(
6222 Header() +
6223 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6224 "; CHECK: [[ldx:%\\w+]] = OpLoad [[float]]\n" +
6225 "; CHECK: [[ldy:%\\w+]] = OpLoad [[float]] [[y:%\\w+]]\n" +
6226 "; CHECK: %5 = OpCopyObject [[float]] [[ldy]]\n" +
6227 "%main = OpFunction %void None %void_func\n" +
6228 "%main_lab = OpLabel\n" +
6229 "%x = OpVariable %_ptr_float Function\n" +
6230 "%y = OpVariable %_ptr_float Function\n" +
6231 "%2 = OpLoad %float %x\n" +
6232 "%3 = OpLoad %float %y\n" +
6233 "%4 = OpFMul %float %2 %3\n" +
6234 "%5 = OpFDiv %float %4 %2\n" +
6235 "OpReturn\n" +
6236 "OpFunctionEnd\n",
6237 5, true),
6238 // Test case 16: Do not merge udiv of snegate
6239 // (-x) / 2u
6240 InstructionFoldingCase<bool>(
6241 Header() +
6242 "%main = OpFunction %void None %void_func\n" +
6243 "%main_lab = OpLabel\n" +
6244 "%var = OpVariable %_ptr_uint Function\n" +
6245 "%2 = OpLoad %uint %var\n" +
6246 "%3 = OpSNegate %uint %2\n" +
6247 "%4 = OpUDiv %uint %3 %uint_2\n" +
6248 "OpReturn\n" +
6249 "OpFunctionEnd\n",
6250 4, false),
6251 // Test case 17: Do not merge udiv of snegate
6252 // 2u / (-x)
6253 InstructionFoldingCase<bool>(
6254 Header() +
6255 "%main = OpFunction %void None %void_func\n" +
6256 "%main_lab = OpLabel\n" +
6257 "%var = OpVariable %_ptr_uint Function\n" +
6258 "%2 = OpLoad %uint %var\n" +
6259 "%3 = OpSNegate %uint %2\n" +
6260 "%4 = OpUDiv %uint %uint_2 %3\n" +
6261 "OpReturn\n" +
6262 "OpFunctionEnd\n",
6263 4, false)
6264 ));
6265
6266 INSTANTIATE_TEST_SUITE_P(MergeAddTest, MatchingInstructionFoldingTest,
6267 ::testing::Values(
6268 // Test case 0: merge add of negate
6269 // (-x) + 2 = 2 - x
6270 InstructionFoldingCase<bool>(
6271 Header() +
6272 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6273 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6274 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6275 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6276 "%main = OpFunction %void None %void_func\n" +
6277 "%main_lab = OpLabel\n" +
6278 "%var = OpVariable %_ptr_float Function\n" +
6279 "%2 = OpLoad %float %var\n" +
6280 "%3 = OpFNegate %float %2\n" +
6281 "%4 = OpFAdd %float %3 %float_2\n" +
6282 "OpReturn\n" +
6283 "OpFunctionEnd\n",
6284 4, true),
6285 // Test case 1: merge add of negate
6286 // 2 + (-x) = 2 - x
6287 InstructionFoldingCase<bool>(
6288 Header() +
6289 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6290 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6291 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6292 "; CHECK: %4 = OpFSub [[float]] [[float_2]] [[ld]]\n" +
6293 "%main = OpFunction %void None %void_func\n" +
6294 "%main_lab = OpLabel\n" +
6295 "%var = OpVariable %_ptr_float Function\n" +
6296 "%2 = OpLoad %float %var\n" +
6297 "%3 = OpSNegate %float %2\n" +
6298 "%4 = OpIAdd %float %float_2 %3\n" +
6299 "OpReturn\n" +
6300 "OpFunctionEnd\n",
6301 4, true),
6302 // Test case 2: merge add of negate
6303 // (-x) + 2 = 2 - x
6304 InstructionFoldingCase<bool>(
6305 Header() +
6306 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6307 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6308 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6309 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6310 "%main = OpFunction %void None %void_func\n" +
6311 "%main_lab = OpLabel\n" +
6312 "%var = OpVariable %_ptr_long Function\n" +
6313 "%2 = OpLoad %long %var\n" +
6314 "%3 = OpSNegate %long %2\n" +
6315 "%4 = OpIAdd %long %3 %long_2\n" +
6316 "OpReturn\n" +
6317 "OpFunctionEnd\n",
6318 4, true),
6319 // Test case 3: merge add of negate
6320 // 2 + (-x) = 2 - x
6321 InstructionFoldingCase<bool>(
6322 Header() +
6323 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6324 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6325 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6326 "; CHECK: %4 = OpISub [[long]] [[long_2]] [[ld]]\n" +
6327 "%main = OpFunction %void None %void_func\n" +
6328 "%main_lab = OpLabel\n" +
6329 "%var = OpVariable %_ptr_long Function\n" +
6330 "%2 = OpLoad %long %var\n" +
6331 "%3 = OpSNegate %long %2\n" +
6332 "%4 = OpIAdd %long %long_2 %3\n" +
6333 "OpReturn\n" +
6334 "OpFunctionEnd\n",
6335 4, true),
6336 // Test case 4: merge add of subtract
6337 // (x - 1) + 2 = x + 1
6338 InstructionFoldingCase<bool>(
6339 Header() +
6340 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6341 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6342 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6343 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6344 "%main = OpFunction %void None %void_func\n" +
6345 "%main_lab = OpLabel\n" +
6346 "%var = OpVariable %_ptr_float Function\n" +
6347 "%2 = OpLoad %float %var\n" +
6348 "%3 = OpFSub %float %2 %float_1\n" +
6349 "%4 = OpFAdd %float %3 %float_2\n" +
6350 "OpReturn\n" +
6351 "OpFunctionEnd\n",
6352 4, true),
6353 // Test case 5: merge add of subtract
6354 // (1 - x) + 2 = 3 - x
6355 InstructionFoldingCase<bool>(
6356 Header() +
6357 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6358 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6359 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6360 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6361 "%main = OpFunction %void None %void_func\n" +
6362 "%main_lab = OpLabel\n" +
6363 "%var = OpVariable %_ptr_float Function\n" +
6364 "%2 = OpLoad %float %var\n" +
6365 "%3 = OpFSub %float %float_1 %2\n" +
6366 "%4 = OpFAdd %float %3 %float_2\n" +
6367 "OpReturn\n" +
6368 "OpFunctionEnd\n",
6369 4, true),
6370 // Test case 6: merge add of subtract
6371 // 2 + (x - 1) = x + 1
6372 InstructionFoldingCase<bool>(
6373 Header() +
6374 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6375 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6376 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6377 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6378 "%main = OpFunction %void None %void_func\n" +
6379 "%main_lab = OpLabel\n" +
6380 "%var = OpVariable %_ptr_float Function\n" +
6381 "%2 = OpLoad %float %var\n" +
6382 "%3 = OpFSub %float %2 %float_1\n" +
6383 "%4 = OpFAdd %float %float_2 %3\n" +
6384 "OpReturn\n" +
6385 "OpFunctionEnd\n",
6386 4, true),
6387 // Test case 7: merge add of subtract
6388 // 2 + (1 - x) = 3 - x
6389 InstructionFoldingCase<bool>(
6390 Header() +
6391 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6392 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6393 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6394 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6395 "%main = OpFunction %void None %void_func\n" +
6396 "%main_lab = OpLabel\n" +
6397 "%var = OpVariable %_ptr_float Function\n" +
6398 "%2 = OpLoad %float %var\n" +
6399 "%3 = OpFSub %float %float_1 %2\n" +
6400 "%4 = OpFAdd %float %float_2 %3\n" +
6401 "OpReturn\n" +
6402 "OpFunctionEnd\n",
6403 4, true),
6404 // Test case 8: merge add of add
6405 // (x + 1) + 2 = x + 3
6406 InstructionFoldingCase<bool>(
6407 Header() +
6408 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6409 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6410 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6411 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6412 "%main = OpFunction %void None %void_func\n" +
6413 "%main_lab = OpLabel\n" +
6414 "%var = OpVariable %_ptr_float Function\n" +
6415 "%2 = OpLoad %float %var\n" +
6416 "%3 = OpFAdd %float %2 %float_1\n" +
6417 "%4 = OpFAdd %float %3 %float_2\n" +
6418 "OpReturn\n" +
6419 "OpFunctionEnd\n",
6420 4, true),
6421 // Test case 9: merge add of add
6422 // (1 + x) + 2 = 3 + x
6423 InstructionFoldingCase<bool>(
6424 Header() +
6425 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6426 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6427 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6428 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6429 "%main = OpFunction %void None %void_func\n" +
6430 "%main_lab = OpLabel\n" +
6431 "%var = OpVariable %_ptr_float Function\n" +
6432 "%2 = OpLoad %float %var\n" +
6433 "%3 = OpFAdd %float %float_1 %2\n" +
6434 "%4 = OpFAdd %float %3 %float_2\n" +
6435 "OpReturn\n" +
6436 "OpFunctionEnd\n",
6437 4, true),
6438 // Test case 10: merge add of add
6439 // 2 + (x + 1) = x + 1
6440 InstructionFoldingCase<bool>(
6441 Header() +
6442 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6443 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6444 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6445 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6446 "%main = OpFunction %void None %void_func\n" +
6447 "%main_lab = OpLabel\n" +
6448 "%var = OpVariable %_ptr_float Function\n" +
6449 "%2 = OpLoad %float %var\n" +
6450 "%3 = OpFAdd %float %2 %float_1\n" +
6451 "%4 = OpFAdd %float %float_2 %3\n" +
6452 "OpReturn\n" +
6453 "OpFunctionEnd\n",
6454 4, true),
6455 // Test case 11: merge add of add
6456 // 2 + (1 + x) = 3 - x
6457 InstructionFoldingCase<bool>(
6458 Header() +
6459 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6460 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6461 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6462 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_3]]\n" +
6463 "%main = OpFunction %void None %void_func\n" +
6464 "%main_lab = OpLabel\n" +
6465 "%var = OpVariable %_ptr_float Function\n" +
6466 "%2 = OpLoad %float %var\n" +
6467 "%3 = OpFAdd %float %float_1 %2\n" +
6468 "%4 = OpFAdd %float %float_2 %3\n" +
6469 "OpReturn\n" +
6470 "OpFunctionEnd\n",
6471 4, true),
6472 // Test case 12: fold overflowing signed 32 bit iadds
6473 // (x + int_max) + 1 = x + int_min
6474 InstructionFoldingCase<bool>(
6475 Header() +
6476 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6477 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6478 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6479 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_min]]\n" +
6480 "%main = OpFunction %void None %void_func\n" +
6481 "%main_lab = OpLabel\n" +
6482 "%var = OpVariable %_ptr_int Function\n" +
6483 "%2 = OpLoad %int %var\n" +
6484 "%3 = OpIAdd %int %2 %int_max\n" +
6485 "%4 = OpIAdd %int %3 %int_1\n" +
6486 "OpReturn\n" +
6487 "OpFunctionEnd\n",
6488 4, true),
6489 // Test case 13: fold overflowing signed 64 bit iadds
6490 // (x + long_max) + 1 = x + long_min
6491 InstructionFoldingCase<bool>(
6492 Header() +
6493 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6494 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6495 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6496 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_min]]\n" +
6497 "%main = OpFunction %void None %void_func\n" +
6498 "%main_lab = OpLabel\n" +
6499 "%var = OpVariable %_ptr_long Function\n" +
6500 "%2 = OpLoad %long %var\n" +
6501 "%3 = OpIAdd %long %2 %long_max\n" +
6502 "%4 = OpIAdd %long %3 %long_1\n" +
6503 "OpReturn\n" +
6504 "OpFunctionEnd\n",
6505 4, true),
6506 // Test case 14: fold overflowing 32 bit unsigned iadds
6507 // (x + uint_max) + 2 = x + 1
6508 InstructionFoldingCase<bool>(
6509 Header() +
6510 "; CHECK: [[uint:%\\w+]] = OpTypeInt 32 0\n" +
6511 "; CHECK: [[uint_1:%\\w+]] = OpConstant [[uint]] 1\n" +
6512 "; CHECK: [[ld:%\\w+]] = OpLoad [[uint]]\n" +
6513 "; CHECK: %4 = OpIAdd [[uint]] [[ld]] [[uint_1]]\n" +
6514 "%main = OpFunction %void None %void_func\n" +
6515 "%main_lab = OpLabel\n" +
6516 "%var = OpVariable %_ptr_uint Function\n" +
6517 "%2 = OpLoad %uint %var\n" +
6518 "%3 = OpIAdd %uint %2 %uint_max\n" +
6519 "%4 = OpIAdd %uint %3 %uint_2\n" +
6520 "OpReturn\n" +
6521 "OpFunctionEnd\n",
6522 4, true),
6523 // Test case 15: fold overflowing 64 bit unsigned iadds
6524 // (x + ulong_max) + 2 = x + 1
6525 InstructionFoldingCase<bool>(
6526 Header() +
6527 "; CHECK: [[ulong:%\\w+]] = OpTypeInt 64 0\n" +
6528 "; CHECK: [[ulong_1:%\\w+]] = OpConstant [[ulong]] 1\n" +
6529 "; CHECK: [[ld:%\\w+]] = OpLoad [[ulong]]\n" +
6530 "; CHECK: %4 = OpIAdd [[ulong]] [[ld]] [[ulong_1]]\n" +
6531 "%main = OpFunction %void None %void_func\n" +
6532 "%main_lab = OpLabel\n" +
6533 "%var = OpVariable %_ptr_ulong Function\n" +
6534 "%2 = OpLoad %ulong %var\n" +
6535 "%3 = OpIAdd %ulong %2 %ulong_max\n" +
6536 "%4 = OpIAdd %ulong %3 %ulong_2\n" +
6537 "OpReturn\n" +
6538 "OpFunctionEnd\n",
6539 4, true),
6540 // Test case 16: fold underflowing signed 32 bit iadds
6541 // (x + int_min) + (-1) = x + int_max
6542 InstructionFoldingCase<bool>(
6543 Header() +
6544 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6545 "; CHECK: [[int_max:%\\w+]] = OpConstant [[int]] 2147483647\n" +
6546 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6547 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_max]]\n" +
6548 "%main = OpFunction %void None %void_func\n" +
6549 "%main_lab = OpLabel\n" +
6550 "%var = OpVariable %_ptr_int Function\n" +
6551 "%2 = OpLoad %int %var\n" +
6552 "%3 = OpIAdd %int %2 %int_min\n" +
6553 "%4 = OpIAdd %int %3 %int_n1\n" +
6554 "OpReturn\n" +
6555 "OpFunctionEnd\n",
6556 4, true),
6557 // Test case 17: fold underflowing signed 64 bit iadds
6558 // (x + long_min) + (-1) = x + long_max
6559 InstructionFoldingCase<bool>(
6560 Header() +
6561 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6562 "; CHECK: [[long_max:%\\w+]] = OpConstant [[long]] 9223372036854775807\n" +
6563 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6564 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_max]]\n" +
6565 "%main = OpFunction %void None %void_func\n" +
6566 "%main_lab = OpLabel\n" +
6567 "%var = OpVariable %_ptr_long Function\n" +
6568 "%2 = OpLoad %long %var\n" +
6569 "%3 = OpIAdd %long %2 %long_min\n" +
6570 "%4 = OpIAdd %long %3 %long_n1\n" +
6571 "OpReturn\n" +
6572 "OpFunctionEnd\n",
6573 4, true)
6574 ));
6575
6576 INSTANTIATE_TEST_SUITE_P(MergeGenericAddSub, MatchingInstructionFoldingTest,
6577 ::testing::Values(
6578 // Test case 0: merge of add of sub
6579 // (a - b) + b => a
6580 InstructionFoldingCase<bool>(
6581 Header() +
6582 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6583 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6584 "%main = OpFunction %void None %void_func\n" +
6585 "%main_lab = OpLabel\n" +
6586 "%var0 = OpVariable %_ptr_float Function\n" +
6587 "%var1 = OpVariable %_ptr_float Function\n" +
6588 "%3 = OpLoad %float %var0\n" +
6589 "%4 = OpLoad %float %var1\n" +
6590 "%5 = OpFSub %float %3 %4\n" +
6591 "%6 = OpFAdd %float %5 %4\n" +
6592 "OpReturn\n" +
6593 "OpFunctionEnd\n",
6594 6, true),
6595 // Test case 1: merge of add of sub
6596 // b + (a - b) => a
6597 InstructionFoldingCase<bool>(
6598 Header() +
6599 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6600 "; CHECK: %6 = OpCopyObject [[float]] %3\n" +
6601 "%main = OpFunction %void None %void_func\n" +
6602 "%main_lab = OpLabel\n" +
6603 "%var0 = OpVariable %_ptr_float Function\n" +
6604 "%var1 = OpVariable %_ptr_float Function\n" +
6605 "%3 = OpLoad %float %var0\n" +
6606 "%4 = OpLoad %float %var1\n" +
6607 "%5 = OpFSub %float %3 %4\n" +
6608 "%6 = OpFAdd %float %4 %5\n" +
6609 "OpReturn\n" +
6610 "OpFunctionEnd\n",
6611 6, true)
6612 ));
6613
6614 INSTANTIATE_TEST_SUITE_P(FactorAddMul, MatchingInstructionFoldingTest,
6615 ::testing::Values(
6616 // Test case 0: factor of add of muls
6617 // (a * b) + (a * c) => a * (b + c)
6618 InstructionFoldingCase<bool>(
6619 Header() +
6620 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6621 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6622 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6623 "%main = OpFunction %void None %void_func\n" +
6624 "%main_lab = OpLabel\n" +
6625 "%var0 = OpVariable %_ptr_float Function\n" +
6626 "%var1 = OpVariable %_ptr_float Function\n" +
6627 "%var2 = OpVariable %_ptr_float Function\n" +
6628 "%4 = OpLoad %float %var0\n" +
6629 "%5 = OpLoad %float %var1\n" +
6630 "%6 = OpLoad %float %var2\n" +
6631 "%7 = OpFMul %float %6 %4\n" +
6632 "%8 = OpFMul %float %6 %5\n" +
6633 "%9 = OpFAdd %float %7 %8\n" +
6634 "OpReturn\n" +
6635 "OpFunctionEnd\n",
6636 9, true),
6637 // Test case 1: factor of add of muls
6638 // (b * a) + (a * c) => a * (b + c)
6639 InstructionFoldingCase<bool>(
6640 Header() +
6641 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6642 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6643 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6644 "%main = OpFunction %void None %void_func\n" +
6645 "%main_lab = OpLabel\n" +
6646 "%var0 = OpVariable %_ptr_float Function\n" +
6647 "%var1 = OpVariable %_ptr_float Function\n" +
6648 "%var2 = OpVariable %_ptr_float Function\n" +
6649 "%4 = OpLoad %float %var0\n" +
6650 "%5 = OpLoad %float %var1\n" +
6651 "%6 = OpLoad %float %var2\n" +
6652 "%7 = OpFMul %float %4 %6\n" +
6653 "%8 = OpFMul %float %6 %5\n" +
6654 "%9 = OpFAdd %float %7 %8\n" +
6655 "OpReturn\n" +
6656 "OpFunctionEnd\n",
6657 9, true),
6658 // Test case 2: factor of add of muls
6659 // (a * b) + (c * a) => a * (b + c)
6660 InstructionFoldingCase<bool>(
6661 Header() +
6662 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6663 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6664 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6665 "%main = OpFunction %void None %void_func\n" +
6666 "%main_lab = OpLabel\n" +
6667 "%var0 = OpVariable %_ptr_float Function\n" +
6668 "%var1 = OpVariable %_ptr_float Function\n" +
6669 "%var2 = OpVariable %_ptr_float Function\n" +
6670 "%4 = OpLoad %float %var0\n" +
6671 "%5 = OpLoad %float %var1\n" +
6672 "%6 = OpLoad %float %var2\n" +
6673 "%7 = OpFMul %float %6 %4\n" +
6674 "%8 = OpFMul %float %5 %6\n" +
6675 "%9 = OpFAdd %float %7 %8\n" +
6676 "OpReturn\n" +
6677 "OpFunctionEnd\n",
6678 9, true),
6679 // Test case 3: factor of add of muls
6680 // (b * a) + (c * a) => a * (b + c)
6681 InstructionFoldingCase<bool>(
6682 Header() +
6683 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6684 "; CHECK: [[newadd:%\\w+]] = OpFAdd [[float]] %4 %5\n" +
6685 "; CHECK: %9 = OpFMul [[float]] %6 [[newadd]]\n" +
6686 "%main = OpFunction %void None %void_func\n" +
6687 "%main_lab = OpLabel\n" +
6688 "%var0 = OpVariable %_ptr_float Function\n" +
6689 "%var1 = OpVariable %_ptr_float Function\n" +
6690 "%var2 = OpVariable %_ptr_float Function\n" +
6691 "%4 = OpLoad %float %var0\n" +
6692 "%5 = OpLoad %float %var1\n" +
6693 "%6 = OpLoad %float %var2\n" +
6694 "%7 = OpFMul %float %4 %6\n" +
6695 "%8 = OpFMul %float %5 %6\n" +
6696 "%9 = OpFAdd %float %7 %8\n" +
6697 "OpReturn\n" +
6698 "OpFunctionEnd\n",
6699 9, true)
6700 ));
6701
6702 INSTANTIATE_TEST_SUITE_P(MergeSubTest, MatchingInstructionFoldingTest,
6703 ::testing::Values(
6704 // Test case 0: merge sub of negate
6705 // (-x) - 2 = -2 - x
6706 InstructionFoldingCase<bool>(
6707 Header() +
6708 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6709 "; CHECK: [[float_n2:%\\w+]] = OpConstant [[float]] -2{{[[:space:]]}}\n" +
6710 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6711 "; CHECK: %4 = OpFSub [[float]] [[float_n2]] [[ld]]\n" +
6712 "%main = OpFunction %void None %void_func\n" +
6713 "%main_lab = OpLabel\n" +
6714 "%var = OpVariable %_ptr_float Function\n" +
6715 "%2 = OpLoad %float %var\n" +
6716 "%3 = OpFNegate %float %2\n" +
6717 "%4 = OpFSub %float %3 %float_2\n" +
6718 "OpReturn\n" +
6719 "OpFunctionEnd\n",
6720 4, true),
6721 // Test case 1: merge sub of negate
6722 // 2 - (-x) = x + 2
6723 InstructionFoldingCase<bool>(
6724 Header() +
6725 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6726 "; CHECK: [[float_2:%\\w+]] = OpConstant [[float]] 2\n" +
6727 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6728 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_2]]\n" +
6729 "%main = OpFunction %void None %void_func\n" +
6730 "%main_lab = OpLabel\n" +
6731 "%var = OpVariable %_ptr_float Function\n" +
6732 "%2 = OpLoad %float %var\n" +
6733 "%3 = OpFNegate %float %2\n" +
6734 "%4 = OpFSub %float %float_2 %3\n" +
6735 "OpReturn\n" +
6736 "OpFunctionEnd\n",
6737 4, true),
6738 // Test case 2: merge sub of negate
6739 // (-x) - 2 = -2 - x
6740 InstructionFoldingCase<bool>(
6741 Header() +
6742 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6743 "; CHECK: [[long_n2:%\\w+]] = OpConstant [[long]] -2{{[[:space:]]}}\n" +
6744 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6745 "; CHECK: %4 = OpISub [[long]] [[long_n2]] [[ld]]\n" +
6746 "%main = OpFunction %void None %void_func\n" +
6747 "%main_lab = OpLabel\n" +
6748 "%var = OpVariable %_ptr_long Function\n" +
6749 "%2 = OpLoad %long %var\n" +
6750 "%3 = OpSNegate %long %2\n" +
6751 "%4 = OpISub %long %3 %long_2\n" +
6752 "OpReturn\n" +
6753 "OpFunctionEnd\n",
6754 4, true),
6755 // Test case 3: merge sub of negate
6756 // 2 - (-x) = x + 2
6757 InstructionFoldingCase<bool>(
6758 Header() +
6759 "; CHECK: [[long:%\\w+]] = OpTypeInt 64 1\n" +
6760 "; CHECK: [[long_2:%\\w+]] = OpConstant [[long]] 2\n" +
6761 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6762 "; CHECK: %4 = OpIAdd [[long]] [[ld]] [[long_2]]\n" +
6763 "%main = OpFunction %void None %void_func\n" +
6764 "%main_lab = OpLabel\n" +
6765 "%var = OpVariable %_ptr_long Function\n" +
6766 "%2 = OpLoad %long %var\n" +
6767 "%3 = OpSNegate %long %2\n" +
6768 "%4 = OpISub %long %long_2 %3\n" +
6769 "OpReturn\n" +
6770 "OpFunctionEnd\n",
6771 4, true),
6772 // Test case 4: merge add of subtract
6773 // (x + 2) - 1 = x + 1
6774 InstructionFoldingCase<bool>(
6775 Header() +
6776 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6777 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6778 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6779 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6780 "%main = OpFunction %void None %void_func\n" +
6781 "%main_lab = OpLabel\n" +
6782 "%var = OpVariable %_ptr_float Function\n" +
6783 "%2 = OpLoad %float %var\n" +
6784 "%3 = OpFAdd %float %2 %float_2\n" +
6785 "%4 = OpFSub %float %3 %float_1\n" +
6786 "OpReturn\n" +
6787 "OpFunctionEnd\n",
6788 4, true),
6789 // Test case 5: merge add of subtract
6790 // (2 + x) - 1 = x + 1
6791 InstructionFoldingCase<bool>(
6792 Header() +
6793 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6794 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6795 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6796 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6797 "%main = OpFunction %void None %void_func\n" +
6798 "%main_lab = OpLabel\n" +
6799 "%var = OpVariable %_ptr_float Function\n" +
6800 "%2 = OpLoad %float %var\n" +
6801 "%3 = OpFAdd %float %float_2 %2\n" +
6802 "%4 = OpFSub %float %3 %float_1\n" +
6803 "OpReturn\n" +
6804 "OpFunctionEnd\n",
6805 4, true),
6806 // Test case 6: merge add of subtract
6807 // 2 - (x + 1) = 1 - x
6808 InstructionFoldingCase<bool>(
6809 Header() +
6810 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6811 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6812 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6813 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6814 "%main = OpFunction %void None %void_func\n" +
6815 "%main_lab = OpLabel\n" +
6816 "%var = OpVariable %_ptr_float Function\n" +
6817 "%2 = OpLoad %float %var\n" +
6818 "%3 = OpFAdd %float %2 %float_1\n" +
6819 "%4 = OpFSub %float %float_2 %3\n" +
6820 "OpReturn\n" +
6821 "OpFunctionEnd\n",
6822 4, true),
6823 // Test case 7: merge add of subtract
6824 // 2 - (1 + x) = 1 - x
6825 InstructionFoldingCase<bool>(
6826 Header() +
6827 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6828 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6829 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6830 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6831 "%main = OpFunction %void None %void_func\n" +
6832 "%main_lab = OpLabel\n" +
6833 "%var = OpVariable %_ptr_float Function\n" +
6834 "%2 = OpLoad %float %var\n" +
6835 "%3 = OpFAdd %float %float_1 %2\n" +
6836 "%4 = OpFSub %float %float_2 %3\n" +
6837 "OpReturn\n" +
6838 "OpFunctionEnd\n",
6839 4, true),
6840 // Test case 8: merge subtract of subtract
6841 // (x - 2) - 1 = x - 3
6842 InstructionFoldingCase<bool>(
6843 Header() +
6844 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6845 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6846 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6847 "; CHECK: %4 = OpFSub [[float]] [[ld]] [[float_3]]\n" +
6848 "%main = OpFunction %void None %void_func\n" +
6849 "%main_lab = OpLabel\n" +
6850 "%var = OpVariable %_ptr_float Function\n" +
6851 "%2 = OpLoad %float %var\n" +
6852 "%3 = OpFSub %float %2 %float_2\n" +
6853 "%4 = OpFSub %float %3 %float_1\n" +
6854 "OpReturn\n" +
6855 "OpFunctionEnd\n",
6856 4, true),
6857 // Test case 9: merge subtract of subtract
6858 // (2 - x) - 1 = 1 - x
6859 InstructionFoldingCase<bool>(
6860 Header() +
6861 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6862 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6863 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6864 "; CHECK: %4 = OpFSub [[float]] [[float_1]] [[ld]]\n" +
6865 "%main = OpFunction %void None %void_func\n" +
6866 "%main_lab = OpLabel\n" +
6867 "%var = OpVariable %_ptr_float Function\n" +
6868 "%2 = OpLoad %float %var\n" +
6869 "%3 = OpFSub %float %float_2 %2\n" +
6870 "%4 = OpFSub %float %3 %float_1\n" +
6871 "OpReturn\n" +
6872 "OpFunctionEnd\n",
6873 4, true),
6874 // Test case 10: merge subtract of subtract
6875 // 2 - (x - 1) = 3 - x
6876 InstructionFoldingCase<bool>(
6877 Header() +
6878 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6879 "; CHECK: [[float_3:%\\w+]] = OpConstant [[float]] 3\n" +
6880 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6881 "; CHECK: %4 = OpFSub [[float]] [[float_3]] [[ld]]\n" +
6882 "%main = OpFunction %void None %void_func\n" +
6883 "%main_lab = OpLabel\n" +
6884 "%var = OpVariable %_ptr_float Function\n" +
6885 "%2 = OpLoad %float %var\n" +
6886 "%3 = OpFSub %float %2 %float_1\n" +
6887 "%4 = OpFSub %float %float_2 %3\n" +
6888 "OpReturn\n" +
6889 "OpFunctionEnd\n",
6890 4, true),
6891 // Test case 11: merge subtract of subtract
6892 // 1 - (2 - x) = x + (-1)
6893 InstructionFoldingCase<bool>(
6894 Header() +
6895 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6896 "; CHECK: [[float_n1:%\\w+]] = OpConstant [[float]] -1\n" +
6897 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6898 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_n1]]\n" +
6899 "%main = OpFunction %void None %void_func\n" +
6900 "%main_lab = OpLabel\n" +
6901 "%var = OpVariable %_ptr_float Function\n" +
6902 "%2 = OpLoad %float %var\n" +
6903 "%3 = OpFSub %float %float_2 %2\n" +
6904 "%4 = OpFSub %float %float_1 %3\n" +
6905 "OpReturn\n" +
6906 "OpFunctionEnd\n",
6907 4, true),
6908 // Test case 12: merge subtract of subtract
6909 // 2 - (1 - x) = x + 1
6910 InstructionFoldingCase<bool>(
6911 Header() +
6912 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
6913 "; CHECK: [[float_1:%\\w+]] = OpConstant [[float]] 1\n" +
6914 "; CHECK: [[ld:%\\w+]] = OpLoad [[float]]\n" +
6915 "; CHECK: %4 = OpFAdd [[float]] [[ld]] [[float_1]]\n" +
6916 "%main = OpFunction %void None %void_func\n" +
6917 "%main_lab = OpLabel\n" +
6918 "%var = OpVariable %_ptr_float Function\n" +
6919 "%2 = OpLoad %float %var\n" +
6920 "%3 = OpFSub %float %float_1 %2\n" +
6921 "%4 = OpFSub %float %float_2 %3\n" +
6922 "OpReturn\n" +
6923 "OpFunctionEnd\n",
6924 4, true),
6925 // Test case 13: merge subtract of subtract with mixed types.
6926 // 2 - (1 - x) = x + 1
6927 InstructionFoldingCase<bool>(
6928 Header() +
6929 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6930 "; CHECK: [[int_1:%\\w+]] = OpConstant [[int]] 1\n" +
6931 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6932 "; CHECK: %4 = OpIAdd [[int]] [[ld]] [[int_1]]\n" +
6933 "%main = OpFunction %void None %void_func\n" +
6934 "%main_lab = OpLabel\n" +
6935 "%var = OpVariable %_ptr_int Function\n" +
6936 "%2 = OpLoad %int %var\n" +
6937 "%3 = OpISub %int %uint_1 %2\n" +
6938 "%4 = OpISub %int %int_2 %3\n" +
6939 "OpReturn\n" +
6940 "OpFunctionEnd\n",
6941 4, true),
6942 // Test case 14: fold overflowing signed 32 bit isubs
6943 // (x - int_max) - 1 = x - int_min
6944 InstructionFoldingCase<bool>(
6945 Header() +
6946 "; CHECK: [[int:%\\w+]] = OpTypeInt 32\n" +
6947 "; CHECK: [[int_min:%\\w+]] = OpConstant [[int]] -2147483648\n" +
6948 "; CHECK: [[ld:%\\w+]] = OpLoad [[int]]\n" +
6949 "; CHECK: %4 = OpISub [[int]] [[ld]] [[int_min]]\n" +
6950 "%main = OpFunction %void None %void_func\n" +
6951 "%main_lab = OpLabel\n" +
6952 "%var = OpVariable %_ptr_int Function\n" +
6953 "%2 = OpLoad %int %var\n" +
6954 "%3 = OpISub %int %2 %int_max\n" +
6955 "%4 = OpISub %int %3 %int_1\n" +
6956 "OpReturn\n" +
6957 "OpFunctionEnd\n",
6958 4, true),
6959 // Test case 15: fold overflowing signed 64 bit isubs
6960 // (x - long_max) - 1 = x - long_min
6961 InstructionFoldingCase<bool>(
6962 Header() +
6963 "; CHECK: [[long:%\\w+]] = OpTypeInt 64\n" +
6964 "; CHECK: [[long_min:%\\w+]] = OpConstant [[long]] -9223372036854775808\n" +
6965 "; CHECK: [[ld:%\\w+]] = OpLoad [[long]]\n" +
6966 "; CHECK: %4 = OpISub [[long]] [[ld]] [[long_min]]\n" +
6967 "%main = OpFunction %void None %void_func\n" +
6968 "%main_lab = OpLabel\n" +
6969 "%var = OpVariable %_ptr_long Function\n" +
6970 "%2 = OpLoad %long %var\n" +
6971 "%3 = OpISub %long %2 %long_max\n" +
6972 "%4 = OpISub %long %3 %long_1\n" +
6973 "OpReturn\n" +
6974 "OpFunctionEnd\n",
6975 4, true)
6976 ));
6977
6978 INSTANTIATE_TEST_SUITE_P(SelectFoldingTest, MatchingInstructionFoldingTest,
6979 ::testing::Values(
6980 // Test case 0: Fold select with the same values for both sides
6981 InstructionFoldingCase<bool>(
6982 Header() +
6983 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6984 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6985 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
6986 "%main = OpFunction %void None %void_func\n" +
6987 "%main_lab = OpLabel\n" +
6988 "%n = OpVariable %_ptr_bool Function\n" +
6989 "%load = OpLoad %bool %n\n" +
6990 "%2 = OpSelect %int %load %100 %100\n" +
6991 "OpReturn\n" +
6992 "OpFunctionEnd",
6993 2, true),
6994 // Test case 1: Fold select true to left side
6995 InstructionFoldingCase<bool>(
6996 Header() +
6997 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
6998 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
6999 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7000 "%main = OpFunction %void None %void_func\n" +
7001 "%main_lab = OpLabel\n" +
7002 "%n = OpVariable %_ptr_int Function\n" +
7003 "%load = OpLoad %bool %n\n" +
7004 "%2 = OpSelect %int %true %100 %n\n" +
7005 "OpReturn\n" +
7006 "OpFunctionEnd",
7007 2, true),
7008 // Test case 2: Fold select false to right side
7009 InstructionFoldingCase<bool>(
7010 Header() +
7011 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7012 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7013 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7014 "%main = OpFunction %void None %void_func\n" +
7015 "%main_lab = OpLabel\n" +
7016 "%n = OpVariable %_ptr_int Function\n" +
7017 "%load = OpLoad %bool %n\n" +
7018 "%2 = OpSelect %int %false %n %100\n" +
7019 "OpReturn\n" +
7020 "OpFunctionEnd",
7021 2, true),
7022 // Test case 3: Fold select null to right side
7023 InstructionFoldingCase<bool>(
7024 Header() +
7025 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7026 "; CHECK: [[int0:%\\w+]] = OpConstant [[int]] 0\n" +
7027 "; CHECK: %2 = OpCopyObject [[int]] [[int0]]\n" +
7028 "%main = OpFunction %void None %void_func\n" +
7029 "%main_lab = OpLabel\n" +
7030 "%n = OpVariable %_ptr_int Function\n" +
7031 "%load = OpLoad %int %n\n" +
7032 "%2 = OpSelect %int %bool_null %load %100\n" +
7033 "OpReturn\n" +
7034 "OpFunctionEnd",
7035 2, true),
7036 // Test case 4: vector null
7037 InstructionFoldingCase<bool>(
7038 Header() +
7039 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7040 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7041 "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7042 "; CHECK: [[v2int2_2:%\\w+]] = OpConstantComposite [[v2int]] [[int2]] [[int2]]\n" +
7043 "; CHECK: %2 = OpCopyObject [[v2int]] [[v2int2_2]]\n" +
7044 "%main = OpFunction %void None %void_func\n" +
7045 "%main_lab = OpLabel\n" +
7046 "%n = OpVariable %_ptr_v2int Function\n" +
7047 "%load = OpLoad %v2int %n\n" +
7048 "%2 = OpSelect %v2int %v2bool_null %load %v2int_2_2\n" +
7049 "OpReturn\n" +
7050 "OpFunctionEnd",
7051 2, true),
7052 // Test case 5: vector select
7053 InstructionFoldingCase<bool>(
7054 Header() +
7055 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7056 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7057 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 0 3\n" +
7058 "%main = OpFunction %void None %void_func\n" +
7059 "%main_lab = OpLabel\n" +
7060 "%m = OpVariable %_ptr_v2int Function\n" +
7061 "%n = OpVariable %_ptr_v2int Function\n" +
7062 "%2 = OpLoad %v2int %n\n" +
7063 "%3 = OpLoad %v2int %n\n" +
7064 "%4 = OpSelect %v2int %v2bool_true_false %2 %3\n" +
7065 "OpReturn\n" +
7066 "OpFunctionEnd",
7067 4, true),
7068 // Test case 6: vector select
7069 InstructionFoldingCase<bool>(
7070 Header() +
7071 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7072 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2\n" +
7073 "; CHECK: %4 = OpVectorShuffle [[v2int]] %2 %3 2 1\n" +
7074 "%main = OpFunction %void None %void_func\n" +
7075 "%main_lab = OpLabel\n" +
7076 "%m = OpVariable %_ptr_v2int Function\n" +
7077 "%n = OpVariable %_ptr_v2int Function\n" +
7078 "%2 = OpLoad %v2int %n\n" +
7079 "%3 = OpLoad %v2int %n\n" +
7080 "%4 = OpSelect %v2int %v2bool_false_true %2 %3\n" +
7081 "OpReturn\n" +
7082 "OpFunctionEnd",
7083 4, true)
7084 ));
7085
7086 INSTANTIATE_TEST_SUITE_P(CompositeExtractOrInsertMatchingTest, MatchingInstructionFoldingTest,
7087 ::testing::Values(
7088 // Test case 0: Extracting from result of consecutive shuffles of differing
7089 // size.
7090 InstructionFoldingCase<bool>(
7091 Header() +
7092 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7093 "; CHECK: %5 = OpCompositeExtract [[int]] %2 2\n" +
7094 "%main = OpFunction %void None %void_func\n" +
7095 "%main_lab = OpLabel\n" +
7096 "%n = OpVariable %_ptr_v4int Function\n" +
7097 "%2 = OpLoad %v4int %n\n" +
7098 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7099 "%4 = OpVectorShuffle %v4int %2 %3 0 4 2 5\n" +
7100 "%5 = OpCompositeExtract %int %4 1\n" +
7101 "OpReturn\n" +
7102 "OpFunctionEnd",
7103 5, true),
7104 // Test case 1: Extracting from result of vector shuffle of differing
7105 // input and result sizes.
7106 InstructionFoldingCase<bool>(
7107 Header() +
7108 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7109 "; CHECK: %4 = OpCompositeExtract [[int]] %2 2\n" +
7110 "%main = OpFunction %void None %void_func\n" +
7111 "%main_lab = OpLabel\n" +
7112 "%n = OpVariable %_ptr_v4int Function\n" +
7113 "%2 = OpLoad %v4int %n\n" +
7114 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7115 "%4 = OpCompositeExtract %int %3 0\n" +
7116 "OpReturn\n" +
7117 "OpFunctionEnd",
7118 4, true),
7119 // Test case 2: Extracting from result of vector shuffle of differing
7120 // input and result sizes.
7121 InstructionFoldingCase<bool>(
7122 Header() +
7123 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7124 "; CHECK: %4 = OpCompositeExtract [[int]] %2 3\n" +
7125 "%main = OpFunction %void None %void_func\n" +
7126 "%main_lab = OpLabel\n" +
7127 "%n = OpVariable %_ptr_v4int Function\n" +
7128 "%2 = OpLoad %v4int %n\n" +
7129 "%3 = OpVectorShuffle %v2int %2 %2 2 3\n" +
7130 "%4 = OpCompositeExtract %int %3 1\n" +
7131 "OpReturn\n" +
7132 "OpFunctionEnd",
7133 4, true),
7134 // Test case 3: Using fmix feeding extract with a 1 in the a position.
7135 InstructionFoldingCase<bool>(
7136 Header() +
7137 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7138 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7139 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7140 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7141 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7142 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[n]]\n" +
7143 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 1\n" +
7144 "%main = OpFunction %void None %void_func\n" +
7145 "%main_lab = OpLabel\n" +
7146 "%m = OpVariable %_ptr_v4double Function\n" +
7147 "%n = OpVariable %_ptr_v4double Function\n" +
7148 "%2 = OpLoad %v4double %m\n" +
7149 "%3 = OpLoad %v4double %n\n" +
7150 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7151 "%5 = OpCompositeExtract %double %4 1\n" +
7152 "OpReturn\n" +
7153 "OpFunctionEnd",
7154 5, true),
7155 // Test case 4: Using fmix feeding extract with a 0 in the a position.
7156 InstructionFoldingCase<bool>(
7157 Header() +
7158 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7159 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7160 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7161 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7162 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7163 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7164 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 2\n" +
7165 "%main = OpFunction %void None %void_func\n" +
7166 "%main_lab = OpLabel\n" +
7167 "%m = OpVariable %_ptr_v4double Function\n" +
7168 "%n = OpVariable %_ptr_v4double Function\n" +
7169 "%2 = OpLoad %v4double %m\n" +
7170 "%3 = OpLoad %v4double %n\n" +
7171 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_0_1_0_0\n" +
7172 "%5 = OpCompositeExtract %double %4 2\n" +
7173 "OpReturn\n" +
7174 "OpFunctionEnd",
7175 5, true),
7176 // Test case 5: Using fmix feeding extract with a null for the alpha
7177 InstructionFoldingCase<bool>(
7178 Header() +
7179 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7180 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 4\n" +
7181 "; CHECK: [[ptr_v4double:%\\w+]] = OpTypePointer Function [[v4double]]\n" +
7182 "; CHECK: [[m:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7183 "; CHECK: [[n:%\\w+]] = OpVariable [[ptr_v4double]] Function\n" +
7184 "; CHECK: [[ld:%\\w+]] = OpLoad [[v4double]] [[m]]\n" +
7185 "; CHECK: %5 = OpCompositeExtract [[double]] [[ld]] 0\n" +
7186 "%main = OpFunction %void None %void_func\n" +
7187 "%main_lab = OpLabel\n" +
7188 "%m = OpVariable %_ptr_v4double Function\n" +
7189 "%n = OpVariable %_ptr_v4double Function\n" +
7190 "%2 = OpLoad %v4double %m\n" +
7191 "%3 = OpLoad %v4double %n\n" +
7192 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_null\n" +
7193 "%5 = OpCompositeExtract %double %4 0\n" +
7194 "OpReturn\n" +
7195 "OpFunctionEnd",
7196 5, true),
7197 // Test case 6: Don't fold: Using fmix feeding extract with 0.5 in the a
7198 // position.
7199 InstructionFoldingCase<bool>(
7200 Header() +
7201 "%main = OpFunction %void None %void_func\n" +
7202 "%main_lab = OpLabel\n" +
7203 "%m = OpVariable %_ptr_v4double Function\n" +
7204 "%n = OpVariable %_ptr_v4double Function\n" +
7205 "%2 = OpLoad %v4double %m\n" +
7206 "%3 = OpLoad %v4double %n\n" +
7207 "%4 = OpExtInst %v4double %1 FMix %2 %3 %v4double_1_1_1_0p5\n" +
7208 "%5 = OpCompositeExtract %double %4 3\n" +
7209 "OpReturn\n" +
7210 "OpFunctionEnd",
7211 5, false),
7212 // Test case 7: Extracting the undefined literal value from a vector
7213 // shuffle.
7214 InstructionFoldingCase<bool>(
7215 Header() +
7216 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7217 "; CHECK: %4 = OpUndef [[int]]\n" +
7218 "%main = OpFunction %void None %void_func\n" +
7219 "%main_lab = OpLabel\n" +
7220 "%n = OpVariable %_ptr_v4int Function\n" +
7221 "%2 = OpLoad %v4int %n\n" +
7222 "%3 = OpVectorShuffle %v2int %2 %2 2 4294967295\n" +
7223 "%4 = OpCompositeExtract %int %3 1\n" +
7224 "OpReturn\n" +
7225 "OpFunctionEnd",
7226 4, true),
7227 // Test case 8: Inserting every element of a vector turns into a composite construct.
7228 InstructionFoldingCase<bool>(
7229 Header() +
7230 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7231 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7232 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7233 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7234 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7235 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7236 "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7237 "%main = OpFunction %void None %void_func\n" +
7238 "%main_lab = OpLabel\n" +
7239 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7240 "%3 = OpCompositeInsert %v4int %int_1 %2 1\n" +
7241 "%4 = OpCompositeInsert %v4int %int_2 %3 2\n" +
7242 "%5 = OpCompositeInsert %v4int %int_3 %4 3\n" +
7243 "OpReturn\n" +
7244 "OpFunctionEnd",
7245 5, true),
7246 // Test case 9: Inserting every element of a vector turns into a composite construct in a different order.
7247 InstructionFoldingCase<bool>(
7248 Header() +
7249 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7250 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7251 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7252 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7253 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7254 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7255 "; CHECK: %5 = OpCopyObject [[v4]] [[construct]]\n" +
7256 "%main = OpFunction %void None %void_func\n" +
7257 "%main_lab = OpLabel\n" +
7258 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7259 "%4 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7260 "%3 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7261 "%5 = OpCompositeInsert %v4int %int_3 %3 3\n" +
7262 "OpReturn\n" +
7263 "OpFunctionEnd",
7264 5, true),
7265 // Test case 10: Check multiple inserts to the same position are handled correctly.
7266 InstructionFoldingCase<bool>(
7267 Header() +
7268 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7269 "; CHECK-DAG: [[v4:%\\w+]] = OpTypeVector [[int]] 4\n" +
7270 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7271 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7272 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7273 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v4]] %100 [[int1]] [[int2]] [[int3]]\n" +
7274 "; CHECK: %6 = OpCopyObject [[v4]] [[construct]]\n" +
7275 "%main = OpFunction %void None %void_func\n" +
7276 "%main_lab = OpLabel\n" +
7277 "%2 = OpCompositeInsert %v4int %100 %v4int_undef 0\n" +
7278 "%3 = OpCompositeInsert %v4int %int_2 %2 2\n" +
7279 "%4 = OpCompositeInsert %v4int %int_4 %3 1\n" +
7280 "%5 = OpCompositeInsert %v4int %int_1 %4 1\n" +
7281 "%6 = OpCompositeInsert %v4int %int_3 %5 3\n" +
7282 "OpReturn\n" +
7283 "OpFunctionEnd",
7284 6, true),
7285 // Test case 11: The last indexes are 0 and 1, but they have different first indexes. This should not be folded.
7286 InstructionFoldingCase<bool>(
7287 Header() +
7288 "%main = OpFunction %void None %void_func\n" +
7289 "%main_lab = OpLabel\n" +
7290 "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7291 "%3 = OpCompositeInsert %m2x2int %int_1 %2 1 1\n" +
7292 "OpReturn\n" +
7293 "OpFunctionEnd",
7294 3, false),
7295 // Test case 12: Don't fold when there is a partial insertion.
7296 InstructionFoldingCase<bool>(
7297 Header() +
7298 "%main = OpFunction %void None %void_func\n" +
7299 "%main_lab = OpLabel\n" +
7300 "%2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0\n" +
7301 "%3 = OpCompositeInsert %m2x2int %int_4 %2 0 0\n" +
7302 "%4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1\n" +
7303 "OpReturn\n" +
7304 "OpFunctionEnd",
7305 4, false),
7306 // Test case 13: Insert into a column of a matrix
7307 InstructionFoldingCase<bool>(
7308 Header() +
7309 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7310 "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7311 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7312 "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7313 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7314 // We keep this insert in the chain. DeadInsertElimPass should remove it.
7315 "; CHECK: [[insert:%\\w+]] = OpCompositeInsert [[m2x2]] %100 [[m2x2_undef]] 0 0\n" +
7316 "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7317 "; CHECK: %3 = OpCompositeInsert [[m2x2]] [[construct]] [[insert]] 0\n" +
7318 "%main = OpFunction %void None %void_func\n" +
7319 "%main_lab = OpLabel\n" +
7320 "%2 = OpCompositeInsert %m2x2int %100 %m2x2int_undef 0 0\n" +
7321 "%3 = OpCompositeInsert %m2x2int %int_1 %2 0 1\n" +
7322 "OpReturn\n" +
7323 "OpFunctionEnd",
7324 3, true),
7325 // Test case 14: Insert all elements of the matrix.
7326 InstructionFoldingCase<bool>(
7327 Header() +
7328 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7329 "; CHECK-DAG: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7330 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7331 "; CHECK-DAG: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7332 "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" +
7333 "; CHECK-DAG: [[int2:%\\w+]] = OpConstant [[int]] 2\n" +
7334 "; CHECK-DAG: [[int3:%\\w+]] = OpConstant [[int]] 3\n" +
7335 "; CHECK: [[c0:%\\w+]] = OpCompositeConstruct [[v2]] %100 [[int1]]\n" +
7336 "; CHECK: [[c1:%\\w+]] = OpCompositeConstruct [[v2]] [[int2]] [[int3]]\n" +
7337 "; CHECK: [[matrix:%\\w+]] = OpCompositeConstruct [[m2x2]] [[c0]] [[c1]]\n" +
7338 "; CHECK: %5 = OpCopyObject [[m2x2]] [[matrix]]\n" +
7339 "%main = OpFunction %void None %void_func\n" +
7340 "%main_lab = OpLabel\n" +
7341 "%2 = OpCompositeConstruct %v2int %100 %int_1\n" +
7342 "%3 = OpCompositeInsert %m2x2int %2 %m2x2int_undef 0\n" +
7343 "%4 = OpCompositeInsert %m2x2int %int_2 %3 1 0\n" +
7344 "%5 = OpCompositeInsert %m2x2int %int_3 %4 1 1\n" +
7345 "OpReturn\n" +
7346 "OpFunctionEnd",
7347 5, true),
7348 // Test case 15: Replace construct with extract when reconstructing a member
7349 // of another object.
7350 InstructionFoldingCase<bool>(
7351 Header() +
7352 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7353 "; CHECK: [[v2:%\\w+]] = OpTypeVector [[int]] 2\n" +
7354 "; CHECK: [[m2x2:%\\w+]] = OpTypeMatrix [[v2]] 2\n" +
7355 "; CHECK: [[m2x2_undef:%\\w+]] = OpUndef [[m2x2]]\n" +
7356 "; CHECK: %5 = OpCompositeExtract [[v2]] [[m2x2_undef]]\n" +
7357 "%main = OpFunction %void None %void_func\n" +
7358 "%main_lab = OpLabel\n" +
7359 "%3 = OpCompositeExtract %int %m2x2int_undef 1 0\n" +
7360 "%4 = OpCompositeExtract %int %m2x2int_undef 1 1\n" +
7361 "%5 = OpCompositeConstruct %v2int %3 %4\n" +
7362 "OpReturn\n" +
7363 "OpFunctionEnd",
7364 5, true)
7365 ));
7366
7367 INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest,
7368 ::testing::Values(
7369 // Test case 0: Using OpDot to extract last element.
7370 InstructionFoldingCase<bool>(
7371 Header() +
7372 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7373 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7374 "%main = OpFunction %void None %void_func\n" +
7375 "%main_lab = OpLabel\n" +
7376 "%n = OpVariable %_ptr_v4float Function\n" +
7377 "%2 = OpLoad %v4float %n\n" +
7378 "%3 = OpDot %float %2 %v4float_0_0_0_1\n" +
7379 "OpReturn\n" +
7380 "OpFunctionEnd",
7381 3, true),
7382 // Test case 1: Using OpDot to extract last element.
7383 InstructionFoldingCase<bool>(
7384 Header() +
7385 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7386 "; CHECK: %3 = OpCompositeExtract [[float]] %2 3\n" +
7387 "%main = OpFunction %void None %void_func\n" +
7388 "%main_lab = OpLabel\n" +
7389 "%n = OpVariable %_ptr_v4float Function\n" +
7390 "%2 = OpLoad %v4float %n\n" +
7391 "%3 = OpDot %float %v4float_0_0_0_1 %2\n" +
7392 "OpReturn\n" +
7393 "OpFunctionEnd",
7394 3, true),
7395 // Test case 2: Using OpDot to extract second element.
7396 InstructionFoldingCase<bool>(
7397 Header() +
7398 "; CHECK: [[float:%\\w+]] = OpTypeFloat 32\n" +
7399 "; CHECK: %3 = OpCompositeExtract [[float]] %2 1\n" +
7400 "%main = OpFunction %void None %void_func\n" +
7401 "%main_lab = OpLabel\n" +
7402 "%n = OpVariable %_ptr_v4float Function\n" +
7403 "%2 = OpLoad %v4float %n\n" +
7404 "%3 = OpDot %float %v4float_0_1_0_0 %2\n" +
7405 "OpReturn\n" +
7406 "OpFunctionEnd",
7407 3, true),
7408 // Test case 3: Using OpDot to extract last element.
7409 InstructionFoldingCase<bool>(
7410 Header() +
7411 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7412 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7413 "%main = OpFunction %void None %void_func\n" +
7414 "%main_lab = OpLabel\n" +
7415 "%n = OpVariable %_ptr_v4double Function\n" +
7416 "%2 = OpLoad %v4double %n\n" +
7417 "%3 = OpDot %double %2 %v4double_0_0_0_1\n" +
7418 "OpReturn\n" +
7419 "OpFunctionEnd",
7420 3, true),
7421 // Test case 4: Using OpDot to extract last element.
7422 InstructionFoldingCase<bool>(
7423 Header() +
7424 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7425 "; CHECK: %3 = OpCompositeExtract [[double]] %2 3\n" +
7426 "%main = OpFunction %void None %void_func\n" +
7427 "%main_lab = OpLabel\n" +
7428 "%n = OpVariable %_ptr_v4double Function\n" +
7429 "%2 = OpLoad %v4double %n\n" +
7430 "%3 = OpDot %double %v4double_0_0_0_1 %2\n" +
7431 "OpReturn\n" +
7432 "OpFunctionEnd",
7433 3, true),
7434 // Test case 5: Using OpDot to extract second element.
7435 InstructionFoldingCase<bool>(
7436 Header() +
7437 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7438 "; CHECK: %3 = OpCompositeExtract [[double]] %2 1\n" +
7439 "%main = OpFunction %void None %void_func\n" +
7440 "%main_lab = OpLabel\n" +
7441 "%n = OpVariable %_ptr_v4double Function\n" +
7442 "%2 = OpLoad %v4double %n\n" +
7443 "%3 = OpDot %double %v4double_0_1_0_0 %2\n" +
7444 "OpReturn\n" +
7445 "OpFunctionEnd",
7446 3, true)
7447 ));
7448
7449 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionFoldingTest,
7450 ::testing::Values(
7451 // Test case 0: Using OpDot to extract last element.
7452 InstructionFoldingCase<bool>(
7453 Header() +
7454 "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" +
7455 "; CHECK: [[v2int:%\\w+]] = OpTypeVector [[int]] 2{{[[:space:]]}}\n" +
7456 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v2int]]\n" +
7457 "; CHECK: OpVectorShuffle\n" +
7458 "; CHECK: %3 = OpVectorShuffle [[v2int]] [[null]] {{%\\w+}} 4294967295 2\n" +
7459 "%main = OpFunction %void None %void_func\n" +
7460 "%main_lab = OpLabel\n" +
7461 "%n = OpVariable %_ptr_int Function\n" +
7462 "%load = OpLoad %int %n\n" +
7463 "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 3 0xFFFFFFFF \n" +
7464 "%3 = OpVectorShuffle %v2int %2 %v2int_2_3 1 2 \n" +
7465 "OpReturn\n" +
7466 "OpFunctionEnd",
7467 3, true)
7468 ));
7469
7470 INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest,
7471 ::testing::Values(
7472 // Test case 0: (x * y) + a = Fma(x, y, a)
7473 InstructionFoldingCase<bool>(
7474 Header() +
7475 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7476 "; CHECK: OpFunction\n" +
7477 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7478 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7479 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7480 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7481 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7482 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7483 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7484 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7485 "%main = OpFunction %void None %void_func\n" +
7486 "%main_lab = OpLabel\n" +
7487 "%x = OpVariable %_ptr_float Function\n" +
7488 "%y = OpVariable %_ptr_float Function\n" +
7489 "%a = OpVariable %_ptr_float Function\n" +
7490 "%lx = OpLoad %float %x\n" +
7491 "%ly = OpLoad %float %y\n" +
7492 "%mul = OpFMul %float %lx %ly\n" +
7493 "%la = OpLoad %float %a\n" +
7494 "%3 = OpFAdd %float %mul %la\n" +
7495 "OpStore %a %3\n" +
7496 "OpReturn\n" +
7497 "OpFunctionEnd",
7498 3, true),
7499 // Test case 1: a + (x * y) = Fma(x, y, a)
7500 InstructionFoldingCase<bool>(
7501 Header() +
7502 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7503 "; CHECK: OpFunction\n" +
7504 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7505 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7506 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7507 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7508 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7509 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7510 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7511 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7512 "%main = OpFunction %void None %void_func\n" +
7513 "%main_lab = OpLabel\n" +
7514 "%x = OpVariable %_ptr_float Function\n" +
7515 "%y = OpVariable %_ptr_float Function\n" +
7516 "%a = OpVariable %_ptr_float Function\n" +
7517 "%lx = OpLoad %float %x\n" +
7518 "%ly = OpLoad %float %y\n" +
7519 "%mul = OpFMul %float %lx %ly\n" +
7520 "%la = OpLoad %float %a\n" +
7521 "%3 = OpFAdd %float %la %mul\n" +
7522 "OpStore %a %3\n" +
7523 "OpReturn\n" +
7524 "OpFunctionEnd",
7525 3, true),
7526 // Test case 2: (x * y) + a = Fma(x, y, a) with vectors
7527 InstructionFoldingCase<bool>(
7528 Header() +
7529 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7530 "; CHECK: OpFunction\n" +
7531 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7532 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7533 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7534 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7535 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7536 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7537 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7538 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7539 "%main = OpFunction %void None %void_func\n" +
7540 "%main_lab = OpLabel\n" +
7541 "%x = OpVariable %_ptr_v4float Function\n" +
7542 "%y = OpVariable %_ptr_v4float Function\n" +
7543 "%a = OpVariable %_ptr_v4float Function\n" +
7544 "%lx = OpLoad %v4float %x\n" +
7545 "%ly = OpLoad %v4float %y\n" +
7546 "%mul = OpFMul %v4float %lx %ly\n" +
7547 "%la = OpLoad %v4float %a\n" +
7548 "%3 = OpFAdd %v4float %mul %la\n" +
7549 "OpStore %a %3\n" +
7550 "OpReturn\n" +
7551 "OpFunctionEnd",
7552 3, true),
7553 // Test case 3: a + (x * y) = Fma(x, y, a) with vectors
7554 InstructionFoldingCase<bool>(
7555 Header() +
7556 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7557 "; CHECK: OpFunction\n" +
7558 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7559 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7560 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7561 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7562 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7563 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7564 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7565 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7566 "%main = OpFunction %void None %void_func\n" +
7567 "%main_lab = OpLabel\n" +
7568 "%x = OpVariable %_ptr_float Function\n" +
7569 "%y = OpVariable %_ptr_float Function\n" +
7570 "%a = OpVariable %_ptr_float Function\n" +
7571 "%lx = OpLoad %float %x\n" +
7572 "%ly = OpLoad %float %y\n" +
7573 "%mul = OpFMul %float %lx %ly\n" +
7574 "%la = OpLoad %float %a\n" +
7575 "%3 = OpFAdd %float %la %mul\n" +
7576 "OpStore %a %3\n" +
7577 "OpReturn\n" +
7578 "OpFunctionEnd",
7579 3, true),
7580 // Test 4: that the OpExtInstImport instruction is generated if it is missing.
7581 InstructionFoldingCase<bool>(
7582 std::string() +
7583 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7584 "; CHECK: OpFunction\n" +
7585 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7586 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7587 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7588 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7589 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7590 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7591 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" +
7592 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7593 "OpCapability Shader\n" +
7594 "OpMemoryModel Logical GLSL450\n" +
7595 "OpEntryPoint Fragment %main \"main\"\n" +
7596 "OpExecutionMode %main OriginUpperLeft\n" +
7597 "OpSource GLSL 140\n" +
7598 "OpName %main \"main\"\n" +
7599 "%void = OpTypeVoid\n" +
7600 "%void_func = OpTypeFunction %void\n" +
7601 "%bool = OpTypeBool\n" +
7602 "%float = OpTypeFloat 32\n" +
7603 "%_ptr_float = OpTypePointer Function %float\n" +
7604 "%main = OpFunction %void None %void_func\n" +
7605 "%main_lab = OpLabel\n" +
7606 "%x = OpVariable %_ptr_float Function\n" +
7607 "%y = OpVariable %_ptr_float Function\n" +
7608 "%a = OpVariable %_ptr_float Function\n" +
7609 "%lx = OpLoad %float %x\n" +
7610 "%ly = OpLoad %float %y\n" +
7611 "%mul = OpFMul %float %lx %ly\n" +
7612 "%la = OpLoad %float %a\n" +
7613 "%3 = OpFAdd %float %mul %la\n" +
7614 "OpStore %a %3\n" +
7615 "OpReturn\n" +
7616 "OpFunctionEnd",
7617 3, true),
7618 // Test 5: Don't fold if the multiple is marked no contract.
7619 InstructionFoldingCase<bool>(
7620 std::string() +
7621 "OpCapability Shader\n" +
7622 "OpMemoryModel Logical GLSL450\n" +
7623 "OpEntryPoint Fragment %main \"main\"\n" +
7624 "OpExecutionMode %main OriginUpperLeft\n" +
7625 "OpSource GLSL 140\n" +
7626 "OpName %main \"main\"\n" +
7627 "OpDecorate %mul NoContraction\n" +
7628 "%void = OpTypeVoid\n" +
7629 "%void_func = OpTypeFunction %void\n" +
7630 "%bool = OpTypeBool\n" +
7631 "%float = OpTypeFloat 32\n" +
7632 "%_ptr_float = OpTypePointer Function %float\n" +
7633 "%main = OpFunction %void None %void_func\n" +
7634 "%main_lab = OpLabel\n" +
7635 "%x = OpVariable %_ptr_float Function\n" +
7636 "%y = OpVariable %_ptr_float Function\n" +
7637 "%a = OpVariable %_ptr_float Function\n" +
7638 "%lx = OpLoad %float %x\n" +
7639 "%ly = OpLoad %float %y\n" +
7640 "%mul = OpFMul %float %lx %ly\n" +
7641 "%la = OpLoad %float %a\n" +
7642 "%3 = OpFAdd %float %mul %la\n" +
7643 "OpStore %a %3\n" +
7644 "OpReturn\n" +
7645 "OpFunctionEnd",
7646 3, false),
7647 // Test 6: Don't fold if the add is marked no contract.
7648 InstructionFoldingCase<bool>(
7649 std::string() +
7650 "OpCapability Shader\n" +
7651 "OpMemoryModel Logical GLSL450\n" +
7652 "OpEntryPoint Fragment %main \"main\"\n" +
7653 "OpExecutionMode %main OriginUpperLeft\n" +
7654 "OpSource GLSL 140\n" +
7655 "OpName %main \"main\"\n" +
7656 "OpDecorate %3 NoContraction\n" +
7657 "%void = OpTypeVoid\n" +
7658 "%void_func = OpTypeFunction %void\n" +
7659 "%bool = OpTypeBool\n" +
7660 "%float = OpTypeFloat 32\n" +
7661 "%_ptr_float = OpTypePointer Function %float\n" +
7662 "%main = OpFunction %void None %void_func\n" +
7663 "%main_lab = OpLabel\n" +
7664 "%x = OpVariable %_ptr_float Function\n" +
7665 "%y = OpVariable %_ptr_float Function\n" +
7666 "%a = OpVariable %_ptr_float Function\n" +
7667 "%lx = OpLoad %float %x\n" +
7668 "%ly = OpLoad %float %y\n" +
7669 "%mul = OpFMul %float %lx %ly\n" +
7670 "%la = OpLoad %float %a\n" +
7671 "%3 = OpFAdd %float %mul %la\n" +
7672 "OpStore %a %3\n" +
7673 "OpReturn\n" +
7674 "OpFunctionEnd",
7675 3, false),
7676 // Test case 7: (x * y) - a = Fma(x, y, -a)
7677 InstructionFoldingCase<bool>(
7678 Header() +
7679 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7680 "; CHECK: OpFunction\n" +
7681 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7682 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7683 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7684 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7685 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7686 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7687 "; CHECK: [[na:%\\w+]] = OpFNegate {{%\\w+}} [[la]]\n" +
7688 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[na]]\n" +
7689 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7690 "%main = OpFunction %void None %void_func\n" +
7691 "%main_lab = OpLabel\n" +
7692 "%x = OpVariable %_ptr_float Function\n" +
7693 "%y = OpVariable %_ptr_float Function\n" +
7694 "%a = OpVariable %_ptr_float Function\n" +
7695 "%lx = OpLoad %float %x\n" +
7696 "%ly = OpLoad %float %y\n" +
7697 "%mul = OpFMul %float %lx %ly\n" +
7698 "%la = OpLoad %float %a\n" +
7699 "%3 = OpFSub %float %mul %la\n" +
7700 "OpStore %a %3\n" +
7701 "OpReturn\n" +
7702 "OpFunctionEnd",
7703 3, true),
7704 // Test case 8: a - (x * y) = Fma(-x, y, a)
7705 InstructionFoldingCase<bool>(
7706 Header() +
7707 "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" +
7708 "; CHECK: OpFunction\n" +
7709 "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7710 "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7711 "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" +
7712 "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" +
7713 "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" +
7714 "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" +
7715 "; CHECK: [[nx:%\\w+]] = OpFNegate {{%\\w+}} [[lx]]\n" +
7716 "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[nx]] [[ly]] [[la]]\n" +
7717 "; CHECK: OpStore {{%\\w+}} [[fma]]\n" +
7718 "%main = OpFunction %void None %void_func\n" +
7719 "%main_lab = OpLabel\n" +
7720 "%x = OpVariable %_ptr_float Function\n" +
7721 "%y = OpVariable %_ptr_float Function\n" +
7722 "%a = OpVariable %_ptr_float Function\n" +
7723 "%lx = OpLoad %float %x\n" +
7724 "%ly = OpLoad %float %y\n" +
7725 "%mul = OpFMul %float %lx %ly\n" +
7726 "%la = OpLoad %float %a\n" +
7727 "%3 = OpFSub %float %la %mul\n" +
7728 "OpStore %a %3\n" +
7729 "OpReturn\n" +
7730 "OpFunctionEnd",
7731 3, true)
7732 ));
7733
7734 using MatchingInstructionWithNoResultFoldingTest =
7735 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
7736
7737 // Test folding instructions that do not have a result. The instruction
7738 // that will be folded is the last instruction before the return. If there
7739 // are multiple returns, there is not guarantee which one is used.
TEST_P(MatchingInstructionWithNoResultFoldingTest,Case)7740 TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) {
7741 const auto& tc = GetParam();
7742
7743 // Build module.
7744 std::unique_ptr<IRContext> context =
7745 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
7746 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
7747 ASSERT_NE(nullptr, context);
7748
7749 // Fold the instruction to test.
7750 Instruction* inst = nullptr;
7751 Function* func = &*context->module()->begin();
7752 for (auto& bb : *func) {
7753 Instruction* terminator = bb.terminator();
7754 if (terminator->IsReturnOrAbort()) {
7755 inst = terminator->PreviousNode();
7756 break;
7757 }
7758 }
7759 assert(inst && "Invalid test. Could not find instruction to fold.");
7760 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
7761 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
7762 EXPECT_EQ(succeeded, tc.expected_result);
7763 if (succeeded) {
7764 Match(tc.test_body, context.get());
7765 }
7766 }
7767
7768 INSTANTIATE_TEST_SUITE_P(StoreMatchingTest, MatchingInstructionWithNoResultFoldingTest,
7769 ::testing::Values(
7770 // Test case 0: Remove store of undef.
7771 InstructionFoldingCase<bool>(
7772 Header() +
7773 "; CHECK: OpLabel\n" +
7774 "; CHECK-NOT: OpStore\n" +
7775 "; CHECK: OpReturn\n" +
7776 "%main = OpFunction %void None %void_func\n" +
7777 "%main_lab = OpLabel\n" +
7778 "%n = OpVariable %_ptr_v4double Function\n" +
7779 "%undef = OpUndef %v4double\n" +
7780 "OpStore %n %undef\n" +
7781 "OpReturn\n" +
7782 "OpFunctionEnd",
7783 0 /* OpStore */, true),
7784 // Test case 1: Keep volatile store.
7785 InstructionFoldingCase<bool>(
7786 Header() +
7787 "%main = OpFunction %void None %void_func\n" +
7788 "%main_lab = OpLabel\n" +
7789 "%n = OpVariable %_ptr_v4double Function\n" +
7790 "%undef = OpUndef %v4double\n" +
7791 "OpStore %n %undef Volatile\n" +
7792 "OpReturn\n" +
7793 "OpFunctionEnd",
7794 0 /* OpStore */, false)
7795 ));
7796
7797 INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoResultFoldingTest,
7798 ::testing::Values(
7799 // Test case 0: Basic test 1
7800 InstructionFoldingCase<bool>(
7801 Header() +
7802 "; CHECK: OpVectorShuffle\n" +
7803 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 3 6 7\n" +
7804 "; CHECK: OpReturn\n" +
7805 "%main = OpFunction %void None %void_func\n" +
7806 "%main_lab = OpLabel\n" +
7807 "%2 = OpVariable %_ptr_v4double Function\n" +
7808 "%3 = OpVariable %_ptr_v4double Function\n" +
7809 "%4 = OpVariable %_ptr_v4double Function\n" +
7810 "%5 = OpLoad %v4double %2\n" +
7811 "%6 = OpLoad %v4double %3\n" +
7812 "%7 = OpLoad %v4double %4\n" +
7813 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7814 "%9 = OpVectorShuffle %v4double %7 %8 2 3 4 5\n" +
7815 "OpReturn\n" +
7816 "OpFunctionEnd",
7817 9, true),
7818 // Test case 1: Basic test 2
7819 InstructionFoldingCase<bool>(
7820 Header() +
7821 "; CHECK: OpVectorShuffle\n" +
7822 "; CHECK: OpVectorShuffle {{%\\w+}} %6 %7 0 1 4 5\n" +
7823 "; CHECK: OpReturn\n" +
7824 "%main = OpFunction %void None %void_func\n" +
7825 "%main_lab = OpLabel\n" +
7826 "%2 = OpVariable %_ptr_v4double Function\n" +
7827 "%3 = OpVariable %_ptr_v4double Function\n" +
7828 "%4 = OpVariable %_ptr_v4double Function\n" +
7829 "%5 = OpLoad %v4double %2\n" +
7830 "%6 = OpLoad %v4double %3\n" +
7831 "%7 = OpLoad %v4double %4\n" +
7832 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7833 "%9 = OpVectorShuffle %v4double %8 %7 2 3 4 5\n" +
7834 "OpReturn\n" +
7835 "OpFunctionEnd",
7836 9, true),
7837 // Test case 2: Basic test 3
7838 InstructionFoldingCase<bool>(
7839 Header() +
7840 "; CHECK: OpVectorShuffle\n" +
7841 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 2 4 5\n" +
7842 "; CHECK: OpReturn\n" +
7843 "%main = OpFunction %void None %void_func\n" +
7844 "%main_lab = OpLabel\n" +
7845 "%2 = OpVariable %_ptr_v4double Function\n" +
7846 "%3 = OpVariable %_ptr_v4double Function\n" +
7847 "%4 = OpVariable %_ptr_v4double Function\n" +
7848 "%5 = OpLoad %v4double %2\n" +
7849 "%6 = OpLoad %v4double %3\n" +
7850 "%7 = OpLoad %v4double %4\n" +
7851 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7852 "%9 = OpVectorShuffle %v4double %8 %7 1 0 4 5\n" +
7853 "OpReturn\n" +
7854 "OpFunctionEnd",
7855 9, true),
7856 // Test case 3: Basic test 4
7857 InstructionFoldingCase<bool>(
7858 Header() +
7859 "; CHECK: OpVectorShuffle\n" +
7860 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %6 2 3 5 4\n" +
7861 "; CHECK: OpReturn\n" +
7862 "%main = OpFunction %void None %void_func\n" +
7863 "%main_lab = OpLabel\n" +
7864 "%2 = OpVariable %_ptr_v4double Function\n" +
7865 "%3 = OpVariable %_ptr_v4double Function\n" +
7866 "%4 = OpVariable %_ptr_v4double Function\n" +
7867 "%5 = OpLoad %v4double %2\n" +
7868 "%6 = OpLoad %v4double %3\n" +
7869 "%7 = OpLoad %v4double %4\n" +
7870 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7871 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 6\n" +
7872 "OpReturn\n" +
7873 "OpFunctionEnd",
7874 9, true),
7875 // Test case 4: Don't fold, need both operands of the feeder.
7876 InstructionFoldingCase<bool>(
7877 Header() +
7878 "%main = OpFunction %void None %void_func\n" +
7879 "%main_lab = OpLabel\n" +
7880 "%2 = OpVariable %_ptr_v4double Function\n" +
7881 "%3 = OpVariable %_ptr_v4double Function\n" +
7882 "%4 = OpVariable %_ptr_v4double Function\n" +
7883 "%5 = OpLoad %v4double %2\n" +
7884 "%6 = OpLoad %v4double %3\n" +
7885 "%7 = OpLoad %v4double %4\n" +
7886 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7887 "%9 = OpVectorShuffle %v4double %7 %8 2 3 7 5\n" +
7888 "OpReturn\n" +
7889 "OpFunctionEnd",
7890 9, false),
7891 // Test case 5: Don't fold, need both operands of the feeder.
7892 InstructionFoldingCase<bool>(
7893 Header() +
7894 "%main = OpFunction %void None %void_func\n" +
7895 "%main_lab = OpLabel\n" +
7896 "%2 = OpVariable %_ptr_v4double Function\n" +
7897 "%3 = OpVariable %_ptr_v4double Function\n" +
7898 "%4 = OpVariable %_ptr_v4double Function\n" +
7899 "%5 = OpLoad %v4double %2\n" +
7900 "%6 = OpLoad %v4double %3\n" +
7901 "%7 = OpLoad %v4double %4\n" +
7902 "%8 = OpVectorShuffle %v4double %5 %6 2 3 4 5\n" +
7903 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7904 "OpReturn\n" +
7905 "OpFunctionEnd",
7906 9, false),
7907 // Test case 6: Fold, need both operands of the feeder, but they are the same.
7908 InstructionFoldingCase<bool>(
7909 Header() +
7910 "; CHECK: OpVectorShuffle\n" +
7911 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 2 7 5\n" +
7912 "; CHECK: OpReturn\n" +
7913 "%main = OpFunction %void None %void_func\n" +
7914 "%main_lab = OpLabel\n" +
7915 "%2 = OpVariable %_ptr_v4double Function\n" +
7916 "%3 = OpVariable %_ptr_v4double Function\n" +
7917 "%4 = OpVariable %_ptr_v4double Function\n" +
7918 "%5 = OpLoad %v4double %2\n" +
7919 "%6 = OpLoad %v4double %3\n" +
7920 "%7 = OpLoad %v4double %4\n" +
7921 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
7922 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7923 "OpReturn\n" +
7924 "OpFunctionEnd",
7925 9, true),
7926 // Test case 7: Fold, need both operands of the feeder, but they are the same.
7927 InstructionFoldingCase<bool>(
7928 Header() +
7929 "; CHECK: OpVectorShuffle\n" +
7930 "; CHECK: OpVectorShuffle {{%\\w+}} %7 %5 2 0 5 7\n" +
7931 "; CHECK: OpReturn\n" +
7932 "%main = OpFunction %void None %void_func\n" +
7933 "%main_lab = OpLabel\n" +
7934 "%2 = OpVariable %_ptr_v4double Function\n" +
7935 "%3 = OpVariable %_ptr_v4double Function\n" +
7936 "%4 = OpVariable %_ptr_v4double Function\n" +
7937 "%5 = OpLoad %v4double %2\n" +
7938 "%6 = OpLoad %v4double %3\n" +
7939 "%7 = OpLoad %v4double %4\n" +
7940 "%8 = OpVectorShuffle %v4double %5 %5 2 3 4 5\n" +
7941 "%9 = OpVectorShuffle %v4double %7 %8 2 0 7 5\n" +
7942 "OpReturn\n" +
7943 "OpFunctionEnd",
7944 9, true),
7945 // Test case 8: Replace first operand with a smaller vector.
7946 InstructionFoldingCase<bool>(
7947 Header() +
7948 "; CHECK: OpVectorShuffle\n" +
7949 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 0 5 3\n" +
7950 "; CHECK: OpReturn\n" +
7951 "%main = OpFunction %void None %void_func\n" +
7952 "%main_lab = OpLabel\n" +
7953 "%2 = OpVariable %_ptr_v2double Function\n" +
7954 "%3 = OpVariable %_ptr_v4double Function\n" +
7955 "%4 = OpVariable %_ptr_v4double Function\n" +
7956 "%5 = OpLoad %v2double %2\n" +
7957 "%6 = OpLoad %v4double %3\n" +
7958 "%7 = OpLoad %v4double %4\n" +
7959 "%8 = OpVectorShuffle %v4double %5 %5 0 1 2 3\n" +
7960 "%9 = OpVectorShuffle %v4double %8 %7 2 0 7 5\n" +
7961 "OpReturn\n" +
7962 "OpFunctionEnd",
7963 9, true),
7964 // Test case 9: Replace first operand with a larger vector.
7965 InstructionFoldingCase<bool>(
7966 Header() +
7967 "; CHECK: OpVectorShuffle\n" +
7968 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 3 0 7 5\n" +
7969 "; CHECK: OpReturn\n" +
7970 "%main = OpFunction %void None %void_func\n" +
7971 "%main_lab = OpLabel\n" +
7972 "%2 = OpVariable %_ptr_v4double Function\n" +
7973 "%3 = OpVariable %_ptr_v4double Function\n" +
7974 "%4 = OpVariable %_ptr_v4double Function\n" +
7975 "%5 = OpLoad %v4double %2\n" +
7976 "%6 = OpLoad %v4double %3\n" +
7977 "%7 = OpLoad %v4double %4\n" +
7978 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
7979 "%9 = OpVectorShuffle %v4double %8 %7 1 0 5 3\n" +
7980 "OpReturn\n" +
7981 "OpFunctionEnd",
7982 9, true),
7983 // Test case 10: Replace unused operand with null.
7984 InstructionFoldingCase<bool>(
7985 Header() +
7986 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
7987 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
7988 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
7989 "; CHECK: OpVectorShuffle\n" +
7990 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %7 4 2 5 3\n" +
7991 "; CHECK: OpReturn\n" +
7992 "%main = OpFunction %void None %void_func\n" +
7993 "%main_lab = OpLabel\n" +
7994 "%2 = OpVariable %_ptr_v4double Function\n" +
7995 "%3 = OpVariable %_ptr_v4double Function\n" +
7996 "%4 = OpVariable %_ptr_v4double Function\n" +
7997 "%5 = OpLoad %v4double %2\n" +
7998 "%6 = OpLoad %v4double %3\n" +
7999 "%7 = OpLoad %v4double %4\n" +
8000 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8001 "%9 = OpVectorShuffle %v4double %8 %7 4 2 5 3\n" +
8002 "OpReturn\n" +
8003 "OpFunctionEnd",
8004 9, true),
8005 // Test case 11: Replace unused operand with null.
8006 InstructionFoldingCase<bool>(
8007 Header() +
8008 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8009 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8010 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8011 "; CHECK: OpVectorShuffle\n" +
8012 "; CHECK: OpVectorShuffle {{%\\w+}} [[null]] %5 2 2 5 5\n" +
8013 "; CHECK: OpReturn\n" +
8014 "%main = OpFunction %void None %void_func\n" +
8015 "%main_lab = OpLabel\n" +
8016 "%2 = OpVariable %_ptr_v4double Function\n" +
8017 "%3 = OpVariable %_ptr_v4double Function\n" +
8018 "%5 = OpLoad %v4double %2\n" +
8019 "%6 = OpLoad %v4double %3\n" +
8020 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8021 "%9 = OpVectorShuffle %v4double %8 %8 2 2 3 3\n" +
8022 "OpReturn\n" +
8023 "OpFunctionEnd",
8024 9, true),
8025 // Test case 12: Replace unused operand with null.
8026 InstructionFoldingCase<bool>(
8027 Header() +
8028 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8029 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8030 "; CHECK: [[null:%\\w+]] = OpConstantNull [[v4double]]\n" +
8031 "; CHECK: OpVectorShuffle\n" +
8032 "; CHECK: OpVectorShuffle {{%\\w+}} %7 [[null]] 2 0 1 3\n" +
8033 "; CHECK: OpReturn\n" +
8034 "%main = OpFunction %void None %void_func\n" +
8035 "%main_lab = OpLabel\n" +
8036 "%2 = OpVariable %_ptr_v4double Function\n" +
8037 "%3 = OpVariable %_ptr_v4double Function\n" +
8038 "%4 = OpVariable %_ptr_v4double Function\n" +
8039 "%5 = OpLoad %v4double %2\n" +
8040 "%6 = OpLoad %v4double %3\n" +
8041 "%7 = OpLoad %v4double %4\n" +
8042 "%8 = OpVectorShuffle %v2double %5 %5 0 3\n" +
8043 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 3\n" +
8044 "OpReturn\n" +
8045 "OpFunctionEnd",
8046 9, true),
8047 // Test case 13: Shuffle with undef literal.
8048 InstructionFoldingCase<bool>(
8049 Header() +
8050 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8051 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8052 "; CHECK: OpVectorShuffle\n" +
8053 "; CHECK: OpVectorShuffle {{%\\w+}} %7 {{%\\w+}} 2 0 1 4294967295\n" +
8054 "; CHECK: OpReturn\n" +
8055 "%main = OpFunction %void None %void_func\n" +
8056 "%main_lab = OpLabel\n" +
8057 "%2 = OpVariable %_ptr_v4double Function\n" +
8058 "%3 = OpVariable %_ptr_v4double Function\n" +
8059 "%4 = OpVariable %_ptr_v4double Function\n" +
8060 "%5 = OpLoad %v4double %2\n" +
8061 "%6 = OpLoad %v4double %3\n" +
8062 "%7 = OpLoad %v4double %4\n" +
8063 "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8064 "%9 = OpVectorShuffle %v4double %7 %8 2 0 1 4294967295\n" +
8065 "OpReturn\n" +
8066 "OpFunctionEnd",
8067 9, true),
8068 // Test case 14: Shuffle with undef literal and change size of first input vector.
8069 InstructionFoldingCase<bool>(
8070 Header() +
8071 "; CHECK: [[double:%\\w+]] = OpTypeFloat 64\n" +
8072 "; CHECK: [[v4double:%\\w+]] = OpTypeVector [[double]] 2\n" +
8073 "; CHECK: OpVectorShuffle\n" +
8074 "; CHECK: OpVectorShuffle {{%\\w+}} %5 %7 0 1 4 4294967295\n" +
8075 "; CHECK: OpReturn\n" +
8076 "%main = OpFunction %void None %void_func\n" +
8077 "%main_lab = OpLabel\n" +
8078 "%2 = OpVariable %_ptr_v4double Function\n" +
8079 "%3 = OpVariable %_ptr_v4double Function\n" +
8080 "%4 = OpVariable %_ptr_v4double Function\n" +
8081 "%5 = OpLoad %v4double %2\n" +
8082 "%6 = OpLoad %v4double %3\n" +
8083 "%7 = OpLoad %v4double %4\n" +
8084 "%8 = OpVectorShuffle %v2double %5 %5 0 1\n" +
8085 "%9 = OpVectorShuffle %v4double %8 %7 0 1 2 4294967295\n" +
8086 "OpReturn\n" +
8087 "OpFunctionEnd",
8088 9, true)
8089 ));
8090
8091 using EntryPointFoldingTest =
8092 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8093
TEST_P(EntryPointFoldingTest,Case)8094 TEST_P(EntryPointFoldingTest, Case) {
8095 const auto& tc = GetParam();
8096
8097 // Build module.
8098 std::unique_ptr<IRContext> context =
8099 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body,
8100 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8101 ASSERT_NE(nullptr, context);
8102
8103 // Fold the instruction to test.
8104 Instruction* inst = nullptr;
8105 inst = &*context->module()->entry_points().begin();
8106 assert(inst && "Invalid test. Could not find entry point instruction to fold.");
8107 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8108 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8109 EXPECT_EQ(succeeded, tc.expected_result);
8110 if (succeeded) {
8111 Match(tc.test_body, context.get());
8112 }
8113 }
8114
8115 INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest,
8116 ::testing::Values(
8117 // Test case 0: Basic test 1
8118 InstructionFoldingCase<bool>(std::string() +
8119 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" +
8120 "OpCapability Shader\n" +
8121 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8122 "OpMemoryModel Logical GLSL450\n" +
8123 "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" +
8124 "OpExecutionMode %2 OriginUpperLeft\n" +
8125 "OpSource GLSL 430\n" +
8126 "OpDecorate %3 Location 0\n" +
8127 "%void = OpTypeVoid\n" +
8128 "%5 = OpTypeFunction %void\n" +
8129 "%float = OpTypeFloat 32\n" +
8130 "%v4float = OpTypeVector %float 4\n" +
8131 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8132 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8133 "%int = OpTypeInt 32 1\n" +
8134 "%int_0 = OpConstant %int 0\n" +
8135 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8136 "%2 = OpFunction %void None %5\n" +
8137 "%12 = OpLabel\n" +
8138 "OpReturn\n" +
8139 "OpFunctionEnd\n",
8140 9, true),
8141 InstructionFoldingCase<bool>(std::string() +
8142 "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" +
8143 "OpCapability Shader\n" +
8144 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8145 "OpMemoryModel Logical GLSL450\n" +
8146 "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" +
8147 "OpExecutionMode %2 OriginUpperLeft\n" +
8148 "OpSource GLSL 430\n" +
8149 "OpDecorate %3 Location 0\n" +
8150 "%void = OpTypeVoid\n" +
8151 "%5 = OpTypeFunction %void\n" +
8152 "%float = OpTypeFloat 32\n" +
8153 "%v4float = OpTypeVector %float 4\n" +
8154 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8155 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8156 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8157 "%int = OpTypeInt 32 1\n" +
8158 "%int_0 = OpConstant %int 0\n" +
8159 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8160 "%2 = OpFunction %void None %5\n" +
8161 "%12 = OpLabel\n" +
8162 "OpReturn\n" +
8163 "OpFunctionEnd\n",
8164 9, true),
8165 InstructionFoldingCase<bool>(std::string() +
8166 "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" +
8167 "OpCapability Shader\n" +
8168 "%1 = OpExtInstImport \"GLSL.std.450\"\n" +
8169 "OpMemoryModel Logical GLSL450\n" +
8170 "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" +
8171 "OpExecutionMode %2 OriginUpperLeft\n" +
8172 "OpSource GLSL 430\n" +
8173 "OpDecorate %3 Location 0\n" +
8174 "%void = OpTypeVoid\n" +
8175 "%5 = OpTypeFunction %void\n" +
8176 "%float = OpTypeFloat 32\n" +
8177 "%v4float = OpTypeVector %float 4\n" +
8178 "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" +
8179 "%3 = OpVariable %_ptr_Output_v4float Output\n" +
8180 "%4 = OpVariable %_ptr_Output_v4float Output\n" +
8181 "%int = OpTypeInt 32 1\n" +
8182 "%int_0 = OpConstant %int 0\n" +
8183 "%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" +
8184 "%2 = OpFunction %void None %5\n" +
8185 "%12 = OpLabel\n" +
8186 "OpReturn\n" +
8187 "OpFunctionEnd\n",
8188 9, true)
8189 ));
8190
8191 using SPV14FoldingTest =
8192 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8193
TEST_P(SPV14FoldingTest,Case)8194 TEST_P(SPV14FoldingTest, Case) {
8195 const auto& tc = GetParam();
8196
8197 // Build module.
8198 std::unique_ptr<IRContext> context =
8199 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8200 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8201 ASSERT_NE(nullptr, context);
8202
8203 // Fold the instruction to test.
8204 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8205 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8206 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8207 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8208 EXPECT_EQ(succeeded, tc.expected_result);
8209 if (succeeded) {
8210 Match(tc.test_body, context.get());
8211 }
8212 }
8213
8214 INSTANTIATE_TEST_SUITE_P(SPV14FoldingTest, SPV14FoldingTest,
8215 ::testing::Values(
8216 // Test case 0: select vectors with scalar condition.
8217 InstructionFoldingCase<bool>(std::string() +
8218 "; CHECK-NOT: OpSelect\n" +
8219 "; CHECK: %3 = OpCopyObject {{%\\w+}} %1\n" +
8220 "OpCapability Shader\n" +
8221 "OpCapability Linkage\n" +
8222 "%void = OpTypeVoid\n" +
8223 "%bool = OpTypeBool\n" +
8224 "%true = OpConstantTrue %bool\n" +
8225 "%int = OpTypeInt 32 0\n" +
8226 "%int4 = OpTypeVector %int 4\n" +
8227 "%int_0 = OpConstant %int 0\n" +
8228 "%int_1 = OpConstant %int 1\n" +
8229 "%1 = OpUndef %int4\n" +
8230 "%2 = OpUndef %int4\n" +
8231 "%void_fn = OpTypeFunction %void\n" +
8232 "%func = OpFunction %void None %void_fn\n" +
8233 "%entry = OpLabel\n" +
8234 "%3 = OpSelect %int4 %true %1 %2\n" +
8235 "OpReturn\n" +
8236 "OpFunctionEnd\n"
8237 ,
8238 3, true),
8239 // Test case 1: select struct with scalar condition.
8240 InstructionFoldingCase<bool>(std::string() +
8241 "; CHECK-NOT: OpSelect\n" +
8242 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8243 "OpCapability Shader\n" +
8244 "OpCapability Linkage\n" +
8245 "%void = OpTypeVoid\n" +
8246 "%bool = OpTypeBool\n" +
8247 "%true = OpConstantFalse %bool\n" +
8248 "%int = OpTypeInt 32 0\n" +
8249 "%struct = OpTypeStruct %int %int %int %int\n" +
8250 "%int_0 = OpConstant %int 0\n" +
8251 "%int_1 = OpConstant %int 1\n" +
8252 "%1 = OpUndef %struct\n" +
8253 "%2 = OpUndef %struct\n" +
8254 "%void_fn = OpTypeFunction %void\n" +
8255 "%func = OpFunction %void None %void_fn\n" +
8256 "%entry = OpLabel\n" +
8257 "%3 = OpSelect %struct %true %1 %2\n" +
8258 "OpReturn\n" +
8259 "OpFunctionEnd\n"
8260 ,
8261 3, true),
8262 // Test case 1: select array with scalar condition.
8263 InstructionFoldingCase<bool>(std::string() +
8264 "; CHECK-NOT: OpSelect\n" +
8265 "; CHECK: %3 = OpCopyObject {{%\\w+}} %2\n" +
8266 "OpCapability Shader\n" +
8267 "OpCapability Linkage\n" +
8268 "%void = OpTypeVoid\n" +
8269 "%bool = OpTypeBool\n" +
8270 "%true = OpConstantFalse %bool\n" +
8271 "%int = OpTypeInt 32 0\n" +
8272 "%int_0 = OpConstant %int 0\n" +
8273 "%int_1 = OpConstant %int 1\n" +
8274 "%int_4 = OpConstant %int 4\n" +
8275 "%array = OpTypeStruct %int %int %int %int\n" +
8276 "%1 = OpUndef %array\n" +
8277 "%2 = OpUndef %array\n" +
8278 "%void_fn = OpTypeFunction %void\n" +
8279 "%func = OpFunction %void None %void_fn\n" +
8280 "%entry = OpLabel\n" +
8281 "%3 = OpSelect %array %true %1 %2\n" +
8282 "OpReturn\n" +
8283 "OpFunctionEnd\n"
8284 ,
8285 3, true)
8286 ));
8287
FloatControlsHeader(const std::string & capabilities)8288 std::string FloatControlsHeader(const std::string& capabilities) {
8289 std::string header = R"(
8290 OpCapability Shader
8291 )" + capabilities + R"(
8292 %void = OpTypeVoid
8293 %float = OpTypeFloat 32
8294 %float_0 = OpConstant %float 0
8295 %float_1 = OpConstant %float 1
8296 %void_fn = OpTypeFunction %void
8297 %func = OpFunction %void None %void_fn
8298 %entry = OpLabel
8299 )";
8300
8301 return header;
8302 }
8303
8304 using FloatControlsFoldingTest =
8305 ::testing::TestWithParam<InstructionFoldingCase<bool>>;
8306
TEST_P(FloatControlsFoldingTest,Case)8307 TEST_P(FloatControlsFoldingTest, Case) {
8308 const auto& tc = GetParam();
8309
8310 // Build module.
8311 std::unique_ptr<IRContext> context =
8312 BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body,
8313 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
8314 ASSERT_NE(nullptr, context);
8315
8316 // Fold the instruction to test.
8317 analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr();
8318 Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold);
8319 std::unique_ptr<Instruction> original_inst(inst->Clone(context.get()));
8320 bool succeeded = context->get_instruction_folder().FoldInstruction(inst);
8321 EXPECT_EQ(succeeded, tc.expected_result);
8322 if (succeeded) {
8323 Match(tc.test_body, context.get());
8324 }
8325 }
8326
8327 INSTANTIATE_TEST_SUITE_P(FloatControlsFoldingTest, FloatControlsFoldingTest,
8328 ::testing::Values(
8329 // Test case 0: no folding with DenormPreserve
8330 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormPreserve") +
8331 "%1 = OpFAdd %float %float_0 %float_1\n" +
8332 "OpReturn\n" +
8333 "OpFunctionEnd\n"
8334 ,
8335 1, false),
8336 // Test case 1: no folding with DenormFlushToZero
8337 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability DenormFlushToZero") +
8338 "%1 = OpFAdd %float %float_0 %float_1\n" +
8339 "OpReturn\n" +
8340 "OpFunctionEnd\n"
8341 ,
8342 1, false),
8343 // Test case 2: no folding with SignedZeroInfNanPreserve
8344 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability SignedZeroInfNanPreserve") +
8345 "%1 = OpFAdd %float %float_0 %float_1\n" +
8346 "OpReturn\n" +
8347 "OpFunctionEnd\n"
8348 ,
8349 1, false),
8350 // Test case 3: no folding with RoundingModeRTE
8351 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTE") +
8352 "%1 = OpFAdd %float %float_0 %float_1\n" +
8353 "OpReturn\n" +
8354 "OpFunctionEnd\n"
8355 ,
8356 1, false),
8357 // Test case 4: no folding with RoundingModeRTZ
8358 InstructionFoldingCase<bool>(FloatControlsHeader("OpCapability RoundingModeRTZ") +
8359 "%1 = OpFAdd %float %float_0 %float_1\n" +
8360 "OpReturn\n" +
8361 "OpFunctionEnd\n"
8362 ,
8363 1, false)
8364 ));
8365
ImageOperandsTestBody(const std::string & image_instruction)8366 std::string ImageOperandsTestBody(const std::string& image_instruction) {
8367 std::string body = R"(
8368 OpCapability Shader
8369 OpCapability ImageGatherExtended
8370 OpMemoryModel Logical GLSL450
8371 OpEntryPoint Fragment %main "main"
8372 OpExecutionMode %main OriginUpperLeft
8373 OpDecorate %Texture DescriptorSet 0
8374 OpDecorate %Texture Binding 0
8375 %int = OpTypeInt 32 1
8376 %int_n1 = OpConstant %int -1
8377 %5 = OpConstant %int 0
8378 %float = OpTypeFloat 32
8379 %float_0 = OpConstant %float 0
8380 %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown
8381 %type_sampled_image = OpTypeSampledImage %type_2d_image
8382 %type_sampler = OpTypeSampler
8383 %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler
8384 %_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image
8385 %_ptr_int = OpTypePointer Function %int
8386 %v2int = OpTypeVector %int 2
8387 %10 = OpTypeVector %float 4
8388 %void = OpTypeVoid
8389 %22 = OpTypeFunction %void
8390 %v2float = OpTypeVector %float 2
8391 %v3int = OpTypeVector %int 3
8392 %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
8393 %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant
8394 %101 = OpConstantComposite %v2int %int_n1 %int_n1
8395 %20 = OpConstantComposite %v2float %float_0 %float_0
8396 %main = OpFunction %void None %22
8397 %23 = OpLabel
8398 %var = OpVariable %_ptr_int Function
8399 %88 = OpLoad %type_2d_image %Texture
8400 %val = OpLoad %int %var
8401 %sampler = OpLoad %type_sampler %gSampler
8402 %26 = OpSampledImage %type_sampled_image %88 %sampler
8403 )" + image_instruction + R"(
8404 OpReturn
8405 OpFunctionEnd
8406 )";
8407
8408 return body;
8409 }
8410
8411 INSTANTIATE_TEST_SUITE_P(ImageOperandsBitmaskFoldingTest, MatchingInstructionWithNoResultFoldingTest,
8412 ::testing::Values(
8413 // Test case 0: OpImageFetch without Offset
8414 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8415 "%89 = OpImageFetch %10 %88 %101 Lod %5 \n")
8416 , 89, false),
8417 // Test case 1: OpImageFetch with non-const offset
8418 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8419 "%89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %val \n")
8420 , 89, false),
8421 // Test case 2: OpImageFetch with Lod and Offset
8422 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8423 " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %101 \n"
8424 "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod|ConstOffset %5 %101 \n")
8425 , 89, true),
8426 // Test case 3: OpImageFetch with Bias and Offset
8427 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8428 " %89 = OpImageFetch %10 %88 %101 Bias|Offset %5 %101 \n"
8429 "; CHECK: %89 = OpImageFetch %10 %88 %101 Bias|ConstOffset %5 %101 \n")
8430 , 89, true),
8431 // Test case 4: OpImageFetch with Grad and Offset.
8432 // Grad adds 2 operands to the instruction.
8433 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8434 " %89 = OpImageFetch %10 %88 %101 Grad|Offset %5 %5 %101 \n"
8435 "; CHECK: %89 = OpImageFetch %10 %88 %101 Grad|ConstOffset %5 %5 %101 \n")
8436 , 89, true),
8437 // Test case 5: OpImageFetch with Offset and MinLod.
8438 // This is an example of a case where the bitmask bit-offset is larger than
8439 // that of the Offset.
8440 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8441 " %89 = OpImageFetch %10 %88 %101 Offset|MinLod %101 %5 \n"
8442 "; CHECK: %89 = OpImageFetch %10 %88 %101 ConstOffset|MinLod %101 %5 \n")
8443 , 89, true),
8444 // Test case 6: OpImageGather with constant Offset
8445 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8446 " %89 = OpImageGather %10 %26 %20 %5 Offset %101 \n"
8447 "; CHECK: %89 = OpImageGather %10 %26 %20 %5 ConstOffset %101 \n")
8448 , 89, true),
8449 // Test case 7: OpImageWrite with constant Offset
8450 InstructionFoldingCase<bool>(ImageOperandsTestBody(
8451 " OpImageWrite %88 %5 %101 Offset %101 \n"
8452 "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n")
8453 , 0 /* No result-id */, true)
8454 ));
8455
8456 } // namespace
8457 } // namespace opt
8458 } // namespace spvtools
8459