1 // Copyright (c) 2016 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string>
16 #include <tuple>
17 #include <unordered_set>
18 #include <utility>
19 #include <vector>
20
21 #include "test/opt/assembly_builder.h"
22 #include "test/opt/pass_fixture.h"
23 #include "test/opt/pass_utils.h"
24
25 namespace spvtools {
26 namespace opt {
27 namespace {
28
29 // Returns the types defining instructions commonly used in many tests.
CommonTypes()30 std::vector<std::string> CommonTypes() {
31 return std::vector<std::string>{
32 // clang-format off
33 // scalar types
34 "%bool = OpTypeBool",
35 "%uint = OpTypeInt 32 0",
36 "%int = OpTypeInt 32 1",
37 "%uint64 = OpTypeInt 64 0",
38 "%int64 = OpTypeInt 64 1",
39 "%float = OpTypeFloat 32",
40 "%double = OpTypeFloat 64",
41 // vector types
42 "%v2bool = OpTypeVector %bool 2",
43 "%v2uint = OpTypeVector %uint 2",
44 "%v2int = OpTypeVector %int 2",
45 "%v3int = OpTypeVector %int 3",
46 "%v4int = OpTypeVector %int 4",
47 "%v2float = OpTypeVector %float 2",
48 "%v3float = OpTypeVector %float 3",
49 "%v2double = OpTypeVector %double 2",
50 // struct types
51 "%inner_struct = OpTypeStruct %bool %float",
52 "%outer_struct = OpTypeStruct %inner_struct %int %double",
53 "%flat_struct = OpTypeStruct %bool %int %float %double",
54 // variable pointer types
55 "%_pf_bool = OpTypePointer Function %bool",
56 "%_pf_uint = OpTypePointer Function %uint",
57 "%_pf_int = OpTypePointer Function %int",
58 "%_pf_uint64 = OpTypePointer Function %uint64",
59 "%_pf_int64 = OpTypePointer Function %int64",
60 "%_pf_float = OpTypePointer Function %float",
61 "%_pf_double = OpTypePointer Function %double",
62 "%_pf_v2int = OpTypePointer Function %v2int",
63 "%_pf_v3int = OpTypePointer Function %v3int",
64 "%_pf_v4int = OpTypePointer Function %v4int",
65 "%_pf_v2float = OpTypePointer Function %v2float",
66 "%_pf_v3float = OpTypePointer Function %v3float",
67 "%_pf_v2double = OpTypePointer Function %v2double",
68 "%_pf_inner_struct = OpTypePointer Function %inner_struct",
69 "%_pf_outer_struct = OpTypePointer Function %outer_struct",
70 "%_pf_flat_struct = OpTypePointer Function %flat_struct",
71 // clang-format on
72 };
73 }
74
75 // A helper function to strip OpName instructions from the given string of
76 // disassembly code and put those debug instructions to a set. Returns the
77 // string with all OpName instruction stripped and a set of OpName
78 // instructions.
79 std::tuple<std::string, std::unordered_set<std::string>>
StripOpNameInstructionsToSet(const std::string & str)80 StripOpNameInstructionsToSet(const std::string& str) {
81 std::stringstream ss(str);
82 std::ostringstream oss;
83 std::string inst_str;
84 std::unordered_set<std::string> opname_instructions;
85 while (std::getline(ss, inst_str, '\n')) {
86 if (inst_str.find("OpName %") == std::string::npos) {
87 oss << inst_str << '\n';
88 } else {
89 opname_instructions.insert(inst_str);
90 }
91 }
92 return std::make_tuple(oss.str(), std::move(opname_instructions));
93 }
94
95 // The test fixture for all tests of UnifyConstantPass. This fixture defines
96 // the rule of checking: all the optimized code should be exactly the same as
97 // the expected code, except the OpName instructions, which can be different in
98 // order.
99 template <typename T>
100 class UnifyConstantTest : public PassTest<T> {
101 protected:
102 // Runs UnifyConstantPass on the code built from the given |test_builder|,
103 // and checks whether the optimization result matches with the code built
104 // from |expected_builder|.
Check(const AssemblyBuilder & expected_builder,const AssemblyBuilder & test_builder)105 void Check(const AssemblyBuilder& expected_builder,
106 const AssemblyBuilder& test_builder) {
107 // unoptimized code
108 const std::string original_before_strip = test_builder.GetCode();
109 std::string original_without_opnames;
110 std::unordered_set<std::string> original_opnames;
111 std::tie(original_without_opnames, original_opnames) =
112 StripOpNameInstructionsToSet(original_before_strip);
113
114 // expected code
115 std::string expected_without_opnames;
116 std::unordered_set<std::string> expected_opnames;
117 std::tie(expected_without_opnames, expected_opnames) =
118 StripOpNameInstructionsToSet(expected_builder.GetCode());
119
120 // optimized code
121 std::string optimized_before_strip;
122 auto status = Pass::Status::SuccessWithoutChange;
123 std::tie(optimized_before_strip, status) =
124 this->template SinglePassRunAndDisassemble<UnifyConstantPass>(
125 test_builder.GetCode(),
126 /* skip_nop = */ true, /* do_validation = */ false);
127 std::string optimized_without_opnames;
128 std::unordered_set<std::string> optimized_opnames;
129 std::tie(optimized_without_opnames, optimized_opnames) =
130 StripOpNameInstructionsToSet(optimized_before_strip);
131
132 // Flag "status" should be returned correctly.
133 EXPECT_NE(Pass::Status::Failure, status);
134 EXPECT_EQ(expected_without_opnames == original_without_opnames,
135 status == Pass::Status::SuccessWithoutChange);
136 // Code except OpName instructions should be exactly the same.
137 EXPECT_EQ(expected_without_opnames, optimized_without_opnames);
138 // OpName instructions can be in different order, but the content must be
139 // the same.
140 EXPECT_EQ(expected_opnames, optimized_opnames);
141 }
142 };
143
144 using UnifyFrontEndConstantSingleTest =
145 UnifyConstantTest<PassTest<::testing::Test>>;
146
TEST_F(UnifyFrontEndConstantSingleTest,Basic)147 TEST_F(UnifyFrontEndConstantSingleTest, Basic) {
148 AssemblyBuilder test_builder;
149 AssemblyBuilder expected_builder;
150
151 test_builder
152 .AppendTypesConstantsGlobals({
153 "%uint = OpTypeInt 32 0", "%_pf_uint = OpTypePointer Function %uint",
154 "%unsigned_1 = OpConstant %uint 1",
155 "%unsigned_1_duplicate = OpConstant %uint 1", // duplicated constant
156 })
157 .AppendInMain({
158 "%uint_var = OpVariable %_pf_uint Function",
159 "OpStore %uint_var %unsigned_1_duplicate",
160 });
161
162 expected_builder
163 .AppendTypesConstantsGlobals({
164 "%uint = OpTypeInt 32 0",
165 "%_pf_uint = OpTypePointer Function %uint",
166 "%unsigned_1 = OpConstant %uint 1",
167 })
168 .AppendInMain({
169 "%uint_var = OpVariable %_pf_uint Function",
170 "OpStore %uint_var %unsigned_1",
171 })
172 .AppendNames({
173 "OpName %unsigned_1 \"unsigned_1_duplicate\"", // the OpName
174 // instruction of the
175 // removed duplicated
176 // constant won't be
177 // erased.
178 });
179 Check(expected_builder, test_builder);
180 }
181
TEST_F(UnifyFrontEndConstantSingleTest,SkipWhenResultIdHasDecorations)182 TEST_F(UnifyFrontEndConstantSingleTest, SkipWhenResultIdHasDecorations) {
183 AssemblyBuilder test_builder;
184 AssemblyBuilder expected_builder;
185
186 test_builder
187 .AppendAnnotations({
188 // So far we don't have valid decorations for constants. This is
189 // preparing for the future updates of SPIR-V.
190 // TODO(qining): change to a valid decoration once they are available.
191 "OpDecorate %f_1 RelaxedPrecision",
192 "OpDecorate %f_2_dup RelaxedPrecision",
193 })
194 .AppendTypesConstantsGlobals({
195 // clang-format off
196 "%float = OpTypeFloat 32",
197 "%_pf_float = OpTypePointer Function %float",
198 "%f_1 = OpConstant %float 1",
199 // %f_1 has decoration, so %f_1 will not be used to replace %f_1_dup.
200 "%f_1_dup = OpConstant %float 1",
201 "%f_2 = OpConstant %float 2",
202 // %_2_dup has decoration, so %f_2 will not replace %f_2_dup.
203 "%f_2_dup = OpConstant %float 2",
204 // no decoration for %f_3 or %f_3_dup, %f_3_dup should be replaced.
205 "%f_3 = OpConstant %float 3",
206 "%f_3_dup = OpConstant %float 3",
207 // clang-format on
208 })
209 .AppendInMain({
210 // clang-format off
211 "%f_var = OpVariable %_pf_float Function",
212 "OpStore %f_var %f_1_dup",
213 "OpStore %f_var %f_2_dup",
214 "OpStore %f_var %f_3_dup",
215 // clang-format on
216 });
217
218 expected_builder
219 .AppendAnnotations({
220 "OpDecorate %f_1 RelaxedPrecision",
221 "OpDecorate %f_2_dup RelaxedPrecision",
222 })
223 .AppendTypesConstantsGlobals({
224 // clang-format off
225 "%float = OpTypeFloat 32",
226 "%_pf_float = OpTypePointer Function %float",
227 "%f_1 = OpConstant %float 1",
228 "%f_1_dup = OpConstant %float 1",
229 "%f_2 = OpConstant %float 2",
230 "%f_2_dup = OpConstant %float 2",
231 "%f_3 = OpConstant %float 3",
232 // clang-format on
233 })
234 .AppendInMain({
235 // clang-format off
236 "%f_var = OpVariable %_pf_float Function",
237 "OpStore %f_var %f_1_dup",
238 "OpStore %f_var %f_2_dup",
239 "OpStore %f_var %f_3",
240 // clang-format on
241 })
242 .AppendNames({
243 "OpName %f_3 \"f_3_dup\"",
244 });
245
246 Check(expected_builder, test_builder);
247 }
248
TEST_F(UnifyFrontEndConstantSingleTest,UnifyWithDecorationOnTypes)249 TEST_F(UnifyFrontEndConstantSingleTest, UnifyWithDecorationOnTypes) {
250 AssemblyBuilder test_builder;
251 AssemblyBuilder expected_builder;
252
253 test_builder
254 .AppendAnnotations({
255 "OpMemberDecorate %flat_d 1 RelaxedPrecision",
256 })
257 .AppendTypesConstantsGlobals({
258 // clang-format off
259 "%int = OpTypeInt 32 1",
260 "%float = OpTypeFloat 32",
261 "%flat = OpTypeStruct %int %float",
262 "%_pf_flat = OpTypePointer Function %flat",
263 // decorated flat struct
264 "%flat_d = OpTypeStruct %int %float",
265 "%_pf_flat_d = OpTypePointer Function %flat_d",
266 // perserved contants. %flat_1 and %flat_d has same members, but
267 // their type are different in decorations, so they should not be
268 // used to replace each other.
269 "%int_1 = OpConstant %int 1",
270 "%float_1 = OpConstant %float 1",
271 "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
272 "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
273 // duplicated constants.
274 "%flat_1_dup = OpConstantComposite %flat %int_1 %float_1",
275 "%flat_d_1_dup = OpConstantComposite %flat_d %int_1 %float_1",
276 // clang-format on
277 })
278 .AppendInMain({
279 "%flat_var = OpVariable %_pf_flat Function",
280 "OpStore %flat_var %flat_1_dup",
281 "%flat_d_var = OpVariable %_pf_flat_d Function",
282 "OpStore %flat_d_var %flat_d_1_dup",
283 });
284
285 expected_builder
286 .AppendAnnotations({
287 "OpMemberDecorate %flat_d 1 RelaxedPrecision",
288 })
289 .AppendTypesConstantsGlobals({
290 // clang-format off
291 "%int = OpTypeInt 32 1",
292 "%float = OpTypeFloat 32",
293 "%flat = OpTypeStruct %int %float",
294 "%_pf_flat = OpTypePointer Function %flat",
295 // decorated flat struct
296 "%flat_d = OpTypeStruct %int %float",
297 "%_pf_flat_d = OpTypePointer Function %flat_d",
298 "%int_1 = OpConstant %int 1",
299 "%float_1 = OpConstant %float 1",
300 "%flat_1 = OpConstantComposite %flat %int_1 %float_1",
301 "%flat_d_1 = OpConstantComposite %flat_d %int_1 %float_1",
302 // clang-format on
303 })
304 .AppendInMain({
305 "%flat_var = OpVariable %_pf_flat Function",
306 "OpStore %flat_var %flat_1",
307 "%flat_d_var = OpVariable %_pf_flat_d Function",
308 "OpStore %flat_d_var %flat_d_1",
309 })
310 .AppendNames({
311 "OpName %flat_1 \"flat_1_dup\"",
312 "OpName %flat_d_1 \"flat_d_1_dup\"",
313 });
314
315 Check(expected_builder, test_builder);
316 }
317
318 struct UnifyConstantTestCase {
319 // preserved constants.
320 std::vector<std::string> preserved_consts;
321 // expected uses of the preserved constants.
322 std::vector<std::string> use_preserved_consts;
323 // duplicated constants of the preserved constants.
324 std::vector<std::string> duplicate_consts;
325 // uses of the duplicated constants, expected to be updated to use the
326 // preserved constants.
327 std::vector<std::string> use_duplicate_consts;
328 // The updated OpName instructions that originally refer to duplicated
329 // constants.
330 std::vector<std::string> remapped_names;
331 };
332
333 using UnifyFrontEndConstantParamTest = UnifyConstantTest<
334 PassTest<::testing::TestWithParam<UnifyConstantTestCase>>>;
335
TEST_P(UnifyFrontEndConstantParamTest,TestCase)336 TEST_P(UnifyFrontEndConstantParamTest, TestCase) {
337 auto& tc = GetParam();
338 AssemblyBuilder test_builder;
339 AssemblyBuilder expected_builder;
340 test_builder.AppendTypesConstantsGlobals(CommonTypes());
341 expected_builder.AppendTypesConstantsGlobals(CommonTypes());
342
343 test_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
344 .AppendTypesConstantsGlobals(tc.duplicate_consts)
345 .AppendInMain(tc.use_duplicate_consts);
346
347 // Duplicated constants are killed in the expected output, and the debug
348 // instructions attached to those duplicated instructions will be migrated to
349 // the corresponding preserved constants.
350 expected_builder.AppendTypesConstantsGlobals(tc.preserved_consts)
351 .AppendInMain(tc.use_preserved_consts)
352 .AppendNames(tc.remapped_names);
353
354 Check(expected_builder, test_builder);
355 }
356
357 INSTANTIATE_TEST_SUITE_P(
358 Case, UnifyFrontEndConstantParamTest,
359 ::
360 testing::
361 ValuesIn(
362 std::
363 vector<UnifyConstantTestCase>(
364 {
365 // clang-format off
366 // basic tests for scalar constants
367 {
368 // preserved constants
369 {
370 "%bool_true = OpConstantTrue %bool",
371 "%signed_1 = OpConstant %int 1",
372 "%signed_minus_1 = OpConstant %int64 -1",
373 "%unsigned_max = OpConstant %uint64 18446744073709551615",
374 "%float_1 = OpConstant %float 1",
375 "%double_1 = OpConstant %double 1",
376 },
377 // use preserved constants in main
378 {
379 "%bool_var = OpVariable %_pf_bool Function",
380 "OpStore %bool_var %bool_true",
381 "%int_var = OpVariable %_pf_int Function",
382 "OpStore %int_var %signed_1",
383 "%int64_var = OpVariable %_pf_int64 Function",
384 "OpStore %int64_var %signed_minus_1",
385 "%uint64_var = OpVariable %_pf_uint64 Function",
386 "OpStore %uint64_var %unsigned_max",
387 "%float_var = OpVariable %_pf_float Function",
388 "OpStore %float_var %float_1",
389 "%double_var = OpVariable %_pf_double Function",
390 "OpStore %double_var %double_1",
391 },
392 // duplicated constants
393 {
394 "%bool_true_duplicate = OpConstantTrue %bool",
395 "%signed_1_duplicate = OpConstant %int 1",
396 "%signed_minus_1_duplicate = OpConstant %int64 -1",
397 "%unsigned_max_duplicate = OpConstant %uint64 18446744073709551615",
398 "%float_1_duplicate = OpConstant %float 1",
399 "%double_1_duplicate = OpConstant %double 1",
400 },
401 // use duplicated constants in main
402 {
403 "%bool_var = OpVariable %_pf_bool Function",
404 "OpStore %bool_var %bool_true_duplicate",
405 "%int_var = OpVariable %_pf_int Function",
406 "OpStore %int_var %signed_1_duplicate",
407 "%int64_var = OpVariable %_pf_int64 Function",
408 "OpStore %int64_var %signed_minus_1_duplicate",
409 "%uint64_var = OpVariable %_pf_uint64 Function",
410 "OpStore %uint64_var %unsigned_max_duplicate",
411 "%float_var = OpVariable %_pf_float Function",
412 "OpStore %float_var %float_1_duplicate",
413 "%double_var = OpVariable %_pf_double Function",
414 "OpStore %double_var %double_1_duplicate",
415 },
416 // remapped names
417 {
418 "OpName %bool_true \"bool_true_duplicate\"",
419 "OpName %signed_1 \"signed_1_duplicate\"",
420 "OpName %signed_minus_1 \"signed_minus_1_duplicate\"",
421 "OpName %unsigned_max \"unsigned_max_duplicate\"",
422 "OpName %float_1 \"float_1_duplicate\"",
423 "OpName %double_1 \"double_1_duplicate\"",
424 },
425 },
426 // NaN in different bit patterns should not be unified, but the ones
427 // using same bit pattern should be unified.
428 {
429 // preserved constants
430 {
431 "%float_nan_1 = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
432 "%float_nan_2 = OpConstant %float 0x1.800002p+128",// !2143289345 7FC00001
433 },
434 // use preserved constants in main
435 {
436 "%float_var = OpVariable %_pf_float Function",
437 "OpStore %float_var %float_nan_1",
438 "OpStore %float_var %float_nan_2",
439 },
440 // duplicated constants
441 {
442 "%float_nan_1_duplicate = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
443 "%float_nan_2_duplicate = OpConstant %float 0x1.800002p+128",// !2143289345, 7FC00001
444 },
445 // use duplicated constants in main
446 {
447 "%float_var = OpVariable %_pf_float Function",
448 "OpStore %float_var %float_nan_1_duplicate",
449 "OpStore %float_var %float_nan_2_duplicate",
450 },
451 // remapped names
452 {
453 "OpName %float_nan_1 \"float_nan_1_duplicate\"",
454 "OpName %float_nan_2 \"float_nan_2_duplicate\"",
455 },
456 },
457 // null values
458 {
459 // preserved constants
460 {
461 "%bool_null = OpConstantNull %bool",
462 "%signed_null = OpConstantNull %int",
463 "%signed_64_null = OpConstantNull %int64",
464 "%float_null = OpConstantNull %float",
465 "%double_null = OpConstantNull %double",
466 // zero-valued constants will not be unified with the equivalent
467 // null constants.
468 "%signed_zero = OpConstant %int 0",
469 },
470 // use preserved constants in main
471 {
472 "%bool_var = OpVariable %_pf_bool Function",
473 "OpStore %bool_var %bool_null",
474 "%int_var = OpVariable %_pf_int Function",
475 "OpStore %int_var %signed_null",
476 "%int64_var = OpVariable %_pf_int64 Function",
477 "OpStore %int64_var %signed_64_null",
478 "%float_var = OpVariable %_pf_float Function",
479 "OpStore %float_var %float_null",
480 "%double_var = OpVariable %_pf_double Function",
481 "OpStore %double_var %double_null",
482 },
483 // duplicated constants
484 {
485 "%bool_null_duplicate = OpConstantNull %bool",
486 "%signed_null_duplicate = OpConstantNull %int",
487 "%signed_64_null_duplicate = OpConstantNull %int64",
488 "%float_null_duplicate = OpConstantNull %float",
489 "%double_null_duplicate = OpConstantNull %double",
490 },
491 // use duplicated constants in main
492 {
493 "%bool_var = OpVariable %_pf_bool Function",
494 "OpStore %bool_var %bool_null_duplicate",
495 "%int_var = OpVariable %_pf_int Function",
496 "OpStore %int_var %signed_null_duplicate",
497 "%int64_var = OpVariable %_pf_int64 Function",
498 "OpStore %int64_var %signed_64_null_duplicate",
499 "%float_var = OpVariable %_pf_float Function",
500 "OpStore %float_var %float_null_duplicate",
501 "%double_var = OpVariable %_pf_double Function",
502 "OpStore %double_var %double_null_duplicate",
503 },
504 // remapped names
505 {
506 "OpName %bool_null \"bool_null_duplicate\"",
507 "OpName %signed_null \"signed_null_duplicate\"",
508 "OpName %signed_64_null \"signed_64_null_duplicate\"",
509 "OpName %float_null \"float_null_duplicate\"",
510 "OpName %double_null \"double_null_duplicate\"",
511 },
512 },
513 // constant sampler
514 {
515 // preserved constants
516 {
517 "%sampler = OpTypeSampler",
518 "%_pf_sampler = OpTypePointer Function %sampler",
519 "%sampler_1 = OpConstantSampler %sampler Repeat 0 Linear",
520 },
521 // use preserved constants in main
522 {
523 "%sampler_var = OpVariable %_pf_sampler Function",
524 "OpStore %sampler_var %sampler_1",
525 },
526 // duplicated constants
527 {
528 "%sampler_1_duplicate = OpConstantSampler %sampler Repeat 0 Linear",
529 },
530 // use duplicated constants in main
531 {
532 "%sampler_var = OpVariable %_pf_sampler Function",
533 "OpStore %sampler_var %sampler_1_duplicate",
534 },
535 // remapped names
536 {
537 "OpName %sampler_1 \"sampler_1_duplicate\"",
538 },
539 },
540 // duplicate vector built from same ids.
541 {
542 // preserved constants
543 {
544 "%signed_1 = OpConstant %int 1",
545 "%signed_2 = OpConstant %int 2",
546 "%signed_3 = OpConstant %int 3",
547 "%signed_4 = OpConstant %int 4",
548 "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
549 },
550 // use preserved constants in main
551 {
552 "%vec_var = OpVariable %_pf_v4int Function",
553 "OpStore %vec_var %vec",
554 },
555 // duplicated constants
556 {
557 "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
558 },
559 // use duplicated constants in main
560 {
561 "%vec_var = OpVariable %_pf_v4int Function",
562 "OpStore %vec_var %vec_duplicate",
563 },
564 // remapped names
565 {
566 "OpName %vec \"vec_duplicate\"",
567 }
568 },
569 // duplicate vector built from duplicated ids.
570 {
571 // preserved constants
572 {
573 "%signed_1 = OpConstant %int 1",
574 "%signed_2 = OpConstant %int 2",
575 "%signed_3 = OpConstant %int 3",
576 "%signed_4 = OpConstant %int 4",
577 "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
578 },
579 // use preserved constants in main
580 {
581 "%vec_var = OpVariable %_pf_v4int Function",
582 "OpStore %vec_var %vec",
583 },
584 // duplicated constants
585 {
586 "%signed_3_duplicate = OpConstant %int 3",
587 "%signed_4_duplicate = OpConstant %int 4",
588 "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3_duplicate %signed_4_duplicate",
589 },
590 // use duplicated constants in main
591 {
592 "%vec_var = OpVariable %_pf_v4int Function",
593 "OpStore %vec_var %vec_duplicate",
594 },
595 // remapped names
596 {
597 "OpName %signed_3 \"signed_3_duplicate\"",
598 "OpName %signed_4 \"signed_4_duplicate\"",
599 "OpName %vec \"vec_duplicate\"",
600 },
601 },
602 // flat struct
603 {
604 // preserved constants
605 {
606 "%bool_true = OpConstantTrue %bool",
607 "%signed_1 = OpConstant %int 1",
608 "%float_1 = OpConstant %float 1",
609 "%double_1 = OpConstant %double 1",
610 "%s = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1 %double_1",
611 },
612 // use preserved constants in main
613 {
614 "%s_var = OpVariable %_pf_flat_struct Function",
615 "OpStore %s_var %s",
616 },
617 // duplicated constants
618 {
619 "%float_1_duplicate = OpConstant %float 1",
620 "%double_1_duplicate = OpConstant %double 1",
621 "%s_duplicate = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1_duplicate %double_1_duplicate",
622 },
623 // use duplicated constants in main
624 {
625 "%s_var = OpVariable %_pf_flat_struct Function",
626 "OpStore %s_var %s_duplicate",
627 },
628 // remapped names
629 {
630 "OpName %float_1 \"float_1_duplicate\"",
631 "OpName %double_1 \"double_1_duplicate\"",
632 "OpName %s \"s_duplicate\"",
633 },
634 },
635 // nested struct
636 {
637 // preserved constants
638 {
639 "%bool_true = OpConstantTrue %bool",
640 "%signed_1 = OpConstant %int 1",
641 "%float_1 = OpConstant %float 1",
642 "%double_1 = OpConstant %double 1",
643 "%inner = OpConstantComposite %inner_struct %bool_true %float_1",
644 "%outer = OpConstantComposite %outer_struct %inner %signed_1 %double_1",
645 },
646 // use preserved constants in main
647 {
648 "%outer_var = OpVariable %_pf_outer_struct Function",
649 "OpStore %outer_var %outer",
650 },
651 // duplicated constants
652 {
653 "%float_1_duplicate = OpConstant %float 1",
654 "%double_1_duplicate = OpConstant %double 1",
655 "%inner_duplicate = OpConstantComposite %inner_struct %bool_true %float_1_duplicate",
656 "%outer_duplicate = OpConstantComposite %outer_struct %inner_duplicate %signed_1 %double_1_duplicate",
657 },
658 // use duplicated constants in main
659 {
660 "%outer_var = OpVariable %_pf_outer_struct Function",
661 "OpStore %outer_var %outer_duplicate",
662 },
663 // remapped names
664 {
665 "OpName %float_1 \"float_1_duplicate\"",
666 "OpName %double_1 \"double_1_duplicate\"",
667 "OpName %inner \"inner_duplicate\"",
668 "OpName %outer \"outer_duplicate\"",
669 },
670 },
671 // composite type null constants. Null constants and zero-valued
672 // constants should not be used to replace each other.
673 {
674 // preserved constants
675 {
676 "%bool_zero = OpConstantFalse %bool",
677 "%float_zero = OpConstant %float 0",
678 "%int_null = OpConstantNull %int",
679 "%double_null = OpConstantNull %double",
680 // inner_struct type null constant.
681 "%null_inner = OpConstantNull %inner_struct",
682 // zero-valued composite constant built from zero-valued constant
683 // component. inner_zero should not be replace by null_inner.
684 "%inner_zero = OpConstantComposite %inner_struct %bool_zero %float_zero",
685 // zero-valued composite contant built from zero-valued constants
686 // and null constants.
687 "%outer_zero = OpConstantComposite %outer_struct %inner_zero %int_null %double_null",
688 // outer_struct type null constant, it should not be replaced by
689 // outer_zero.
690 "%null_outer = OpConstantNull %outer_struct",
691 },
692 // use preserved constants in main
693 {
694 "%inner_var = OpVariable %_pf_inner_struct Function",
695 "OpStore %inner_var %inner_zero",
696 "OpStore %inner_var %null_inner",
697 "%outer_var = OpVariable %_pf_outer_struct Function",
698 "OpStore %outer_var %outer_zero",
699 "OpStore %outer_var %null_outer",
700 },
701 // duplicated constants
702 {
703 "%null_inner_dup = OpConstantNull %inner_struct",
704 "%null_outer_dup = OpConstantNull %outer_struct",
705 "%inner_zero_dup = OpConstantComposite %inner_struct %bool_zero %float_zero",
706 "%outer_zero_dup = OpConstantComposite %outer_struct %inner_zero_dup %int_null %double_null",
707 },
708 // use duplicated constants in main
709 {
710 "%inner_var = OpVariable %_pf_inner_struct Function",
711 "OpStore %inner_var %inner_zero_dup",
712 "OpStore %inner_var %null_inner_dup",
713 "%outer_var = OpVariable %_pf_outer_struct Function",
714 "OpStore %outer_var %outer_zero_dup",
715 "OpStore %outer_var %null_outer_dup",
716 },
717 // remapped names
718 {
719 "OpName %null_inner \"null_inner_dup\"",
720 "OpName %null_outer \"null_outer_dup\"",
721 "OpName %inner_zero \"inner_zero_dup\"",
722 "OpName %outer_zero \"outer_zero_dup\"",
723 },
724 },
725 // Spec Constants with SpecId decoration should be skipped.
726 {
727 // preserved constants
728 {
729 // Assembly builder will add OpDecorate SpecId instruction for the
730 // following spec constant instructions automatically.
731 "%spec_bool_1 = OpSpecConstantTrue %bool",
732 "%spec_bool_2 = OpSpecConstantTrue %bool",
733 "%spec_int_1 = OpSpecConstant %int 1",
734 "%spec_int_2 = OpSpecConstant %int 1",
735 },
736 // use preserved constants in main
737 {
738 "%bool_var = OpVariable %_pf_bool Function",
739 "OpStore %bool_var %spec_bool_1",
740 "OpStore %bool_var %spec_bool_2",
741 "%int_var = OpVariable %_pf_int Function",
742 "OpStore %int_var %spec_int_1",
743 "OpStore %int_var %spec_int_2",
744 },
745 // duplicated constants. No duplicated instruction to remove in this
746 // case.
747 {},
748 // use duplicated constants in main. Same as the above 'use preserved
749 // constants in main' defined above, as no instruction should be
750 // removed in this case.
751 {
752 "%bool_var = OpVariable %_pf_bool Function",
753 "OpStore %bool_var %spec_bool_1",
754 "OpStore %bool_var %spec_bool_2",
755 "%int_var = OpVariable %_pf_int Function",
756 "OpStore %int_var %spec_int_1",
757 "OpStore %int_var %spec_int_2",
758 },
759 // remapped names. No duplicated instruction removed, so this is
760 // empty.
761 {}
762 },
763 // spec constant composite
764 {
765 // preserved constants
766 {
767 "%spec_bool_true = OpSpecConstantTrue %bool",
768 "%spec_signed_1 = OpSpecConstant %int 1",
769 "%float_1 = OpConstant %float 1",
770 "%double_1 = OpConstant %double 1",
771 "%spec_inner = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1",
772 "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %spec_signed_1 %double_1",
773 "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
774 },
775 // use preserved constants in main
776 {
777 "%outer_var = OpVariable %_pf_outer_struct Function",
778 "OpStore %outer_var %spec_outer",
779 "%v2float_var = OpVariable %_pf_v2float Function",
780 "OpStore %v2float_var %spec_vec2",
781 },
782 // duplicated constants
783 {
784 "%float_1_duplicate = OpConstant %float 1",
785 "%double_1_duplicate = OpConstant %double 1",
786 "%spec_inner_duplicate = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1_duplicate",
787 "%spec_outer_duplicate = OpSpecConstantComposite %outer_struct %spec_inner_duplicate %spec_signed_1 %double_1_duplicate",
788 "%spec_vec2_duplicate = OpSpecConstantComposite %v2float %float_1 %float_1_duplicate",
789 },
790 // use duplicated constants in main
791 {
792 "%outer_var = OpVariable %_pf_outer_struct Function",
793 "OpStore %outer_var %spec_outer_duplicate",
794 "%v2float_var = OpVariable %_pf_v2float Function",
795 "OpStore %v2float_var %spec_vec2_duplicate",
796 },
797 // remapped names
798 {
799 "OpName %float_1 \"float_1_duplicate\"",
800 "OpName %double_1 \"double_1_duplicate\"",
801 "OpName %spec_inner \"spec_inner_duplicate\"",
802 "OpName %spec_outer \"spec_outer_duplicate\"",
803 "OpName %spec_vec2 \"spec_vec2_duplicate\"",
804 },
805 },
806 // spec constant op with int scalar
807 {
808 // preserved constants
809 {
810 "%spec_signed_1 = OpSpecConstant %int 1",
811 "%spec_signed_2 = OpSpecConstant %int 2",
812 "%spec_signed_add = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
813 },
814 // use preserved constants in main
815 {
816 "%int_var = OpVariable %_pf_int Function",
817 "OpStore %int_var %spec_signed_add",
818 },
819 // duplicated constants
820 {
821 "%spec_signed_add_duplicate = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
822 },
823 // use duplicated contants in main
824 {
825 "%int_var = OpVariable %_pf_int Function",
826 "OpStore %int_var %spec_signed_add_duplicate",
827 },
828 // remapped names
829 {
830 "OpName %spec_signed_add \"spec_signed_add_duplicate\"",
831 },
832 },
833 // spec constant op composite extract
834 {
835 // preserved constants
836 {
837 "%float_1 = OpConstant %float 1",
838 "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
839 "%spec_extract = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
840 },
841 // use preserved constants in main
842 {
843 "%float_var = OpVariable %_pf_float Function",
844 "OpStore %float_var %spec_extract",
845 },
846 // duplicated constants
847 {
848 "%spec_extract_duplicate = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
849 },
850 // use duplicated constants in main
851 {
852 "%float_var = OpVariable %_pf_float Function",
853 "OpStore %float_var %spec_extract_duplicate",
854 },
855 // remapped names
856 {
857 "OpName %spec_extract \"spec_extract_duplicate\"",
858 },
859 },
860 // spec constant op vector shuffle
861 {
862 // preserved constants
863 {
864 "%float_1 = OpConstant %float 1",
865 "%float_2 = OpConstant %float 2",
866 "%spec_vec2_1 = OpSpecConstantComposite %v2float %float_1 %float_1",
867 "%spec_vec2_2 = OpSpecConstantComposite %v2float %float_2 %float_2",
868 "%spec_vector_shuffle = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
869 },
870 // use preserved constants in main
871 {
872 "%v2float_var = OpVariable %_pf_v2float Function",
873 "OpStore %v2float_var %spec_vector_shuffle",
874 },
875 // duplicated constants
876 {
877 "%spec_vector_shuffle_duplicate = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
878 },
879 // use duplicated constants in main
880 {
881 "%v2float_var = OpVariable %_pf_v2float Function",
882 "OpStore %v2float_var %spec_vector_shuffle_duplicate",
883 },
884 // remapped names
885 {
886 "OpName %spec_vector_shuffle \"spec_vector_shuffle_duplicate\"",
887 },
888 },
889 // long dependency chain
890 {
891 // preserved constants
892 {
893 "%array_size = OpConstant %int 4",
894 "%type_arr_int_4 = OpTypeArray %int %array_size",
895 "%signed_0 = OpConstant %int 100",
896 "%signed_1 = OpConstant %int 1",
897 "%signed_2 = OpSpecConstantOp %int IAdd %signed_0 %signed_1",
898 "%signed_3 = OpSpecConstantOp %int ISub %signed_0 %signed_2",
899 "%signed_4 = OpSpecConstantOp %int IAdd %signed_0 %signed_3",
900 "%signed_5 = OpSpecConstantOp %int ISub %signed_0 %signed_4",
901 "%signed_6 = OpSpecConstantOp %int IAdd %signed_0 %signed_5",
902 "%signed_7 = OpSpecConstantOp %int ISub %signed_0 %signed_6",
903 "%signed_8 = OpSpecConstantOp %int IAdd %signed_0 %signed_7",
904 "%signed_9 = OpSpecConstantOp %int ISub %signed_0 %signed_8",
905 "%signed_10 = OpSpecConstantOp %int IAdd %signed_0 %signed_9",
906 "%signed_11 = OpSpecConstantOp %int ISub %signed_0 %signed_10",
907 "%signed_12 = OpSpecConstantOp %int IAdd %signed_0 %signed_11",
908 "%signed_13 = OpSpecConstantOp %int ISub %signed_0 %signed_12",
909 "%signed_14 = OpSpecConstantOp %int IAdd %signed_0 %signed_13",
910 "%signed_15 = OpSpecConstantOp %int ISub %signed_0 %signed_14",
911 "%signed_16 = OpSpecConstantOp %int ISub %signed_0 %signed_15",
912 "%signed_17 = OpSpecConstantOp %int IAdd %signed_0 %signed_16",
913 "%signed_18 = OpSpecConstantOp %int ISub %signed_0 %signed_17",
914 "%signed_19 = OpSpecConstantOp %int IAdd %signed_0 %signed_18",
915 "%signed_20 = OpSpecConstantOp %int ISub %signed_0 %signed_19",
916 "%signed_vec_a = OpSpecConstantComposite %v2int %signed_18 %signed_19",
917 "%signed_vec_b = OpSpecConstantOp %v2int IMul %signed_vec_a %signed_vec_a",
918 "%signed_21 = OpSpecConstantOp %int CompositeExtract %signed_vec_b 0",
919 "%signed_array = OpConstantComposite %type_arr_int_4 %signed_20 %signed_20 %signed_21 %signed_21",
920 "%signed_22 = OpSpecConstantOp %int CompositeExtract %signed_array 0",
921 },
922 // use preserved constants in main
923 {
924 "%int_var = OpVariable %_pf_int Function",
925 "OpStore %int_var %signed_22",
926 },
927 // duplicated constants
928 {
929 "%signed_0_dup = OpConstant %int 100",
930 "%signed_1_dup = OpConstant %int 1",
931 "%signed_2_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_1_dup",
932 "%signed_3_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_2_dup",
933 "%signed_4_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_3_dup",
934 "%signed_5_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_4_dup",
935 "%signed_6_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_5_dup",
936 "%signed_7_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_6_dup",
937 "%signed_8_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_7_dup",
938 "%signed_9_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_8_dup",
939 "%signed_10_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_9_dup",
940 "%signed_11_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_10_dup",
941 "%signed_12_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_11_dup",
942 "%signed_13_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_12_dup",
943 "%signed_14_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_13_dup",
944 "%signed_15_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_14_dup",
945 "%signed_16_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_15_dup",
946 "%signed_17_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_16_dup",
947 "%signed_18_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_17_dup",
948 "%signed_19_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_18_dup",
949 "%signed_20_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_19_dup",
950 "%signed_vec_a_dup = OpSpecConstantComposite %v2int %signed_18_dup %signed_19_dup",
951 "%signed_vec_b_dup = OpSpecConstantOp %v2int IMul %signed_vec_a_dup %signed_vec_a_dup",
952 "%signed_21_dup = OpSpecConstantOp %int CompositeExtract %signed_vec_b_dup 0",
953 "%signed_array_dup = OpConstantComposite %type_arr_int_4 %signed_20_dup %signed_20_dup %signed_21_dup %signed_21_dup",
954 "%signed_22_dup = OpSpecConstantOp %int CompositeExtract %signed_array_dup 0",
955 },
956 // use duplicated constants in main
957 {
958 "%int_var = OpVariable %_pf_int Function",
959 "OpStore %int_var %signed_22_dup",
960 },
961 // remapped names
962 {
963 "OpName %signed_0 \"signed_0_dup\"",
964 "OpName %signed_1 \"signed_1_dup\"",
965 "OpName %signed_2 \"signed_2_dup\"",
966 "OpName %signed_3 \"signed_3_dup\"",
967 "OpName %signed_4 \"signed_4_dup\"",
968 "OpName %signed_5 \"signed_5_dup\"",
969 "OpName %signed_6 \"signed_6_dup\"",
970 "OpName %signed_7 \"signed_7_dup\"",
971 "OpName %signed_8 \"signed_8_dup\"",
972 "OpName %signed_9 \"signed_9_dup\"",
973 "OpName %signed_10 \"signed_10_dup\"",
974 "OpName %signed_11 \"signed_11_dup\"",
975 "OpName %signed_12 \"signed_12_dup\"",
976 "OpName %signed_13 \"signed_13_dup\"",
977 "OpName %signed_14 \"signed_14_dup\"",
978 "OpName %signed_15 \"signed_15_dup\"",
979 "OpName %signed_16 \"signed_16_dup\"",
980 "OpName %signed_17 \"signed_17_dup\"",
981 "OpName %signed_18 \"signed_18_dup\"",
982 "OpName %signed_19 \"signed_19_dup\"",
983 "OpName %signed_20 \"signed_20_dup\"",
984 "OpName %signed_vec_a \"signed_vec_a_dup\"",
985 "OpName %signed_vec_b \"signed_vec_b_dup\"",
986 "OpName %signed_21 \"signed_21_dup\"",
987 "OpName %signed_array \"signed_array_dup\"",
988 "OpName %signed_22 \"signed_22_dup\"",
989 },
990 },
991 // clang-format on
992 })));
993
994 } // namespace
995 } // namespace opt
996 } // namespace spvtools
997