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_CASE_P(Case, UnifyFrontEndConstantParamTest,
358 ::testing::ValuesIn(std::vector<UnifyConstantTestCase>({
359 // clang-format off
360 // basic tests for scalar constants
361 {
362 // preserved constants
363 {
364 "%bool_true = OpConstantTrue %bool",
365 "%signed_1 = OpConstant %int 1",
366 "%signed_minus_1 = OpConstant %int64 -1",
367 "%unsigned_max = OpConstant %uint64 18446744073709551615",
368 "%float_1 = OpConstant %float 1",
369 "%double_1 = OpConstant %double 1",
370 },
371 // use preserved constants in main
372 {
373 "%bool_var = OpVariable %_pf_bool Function",
374 "OpStore %bool_var %bool_true",
375 "%int_var = OpVariable %_pf_int Function",
376 "OpStore %int_var %signed_1",
377 "%int64_var = OpVariable %_pf_int64 Function",
378 "OpStore %int64_var %signed_minus_1",
379 "%uint64_var = OpVariable %_pf_uint64 Function",
380 "OpStore %uint64_var %unsigned_max",
381 "%float_var = OpVariable %_pf_float Function",
382 "OpStore %float_var %float_1",
383 "%double_var = OpVariable %_pf_double Function",
384 "OpStore %double_var %double_1",
385 },
386 // duplicated constants
387 {
388 "%bool_true_duplicate = OpConstantTrue %bool",
389 "%signed_1_duplicate = OpConstant %int 1",
390 "%signed_minus_1_duplicate = OpConstant %int64 -1",
391 "%unsigned_max_duplicate = OpConstant %uint64 18446744073709551615",
392 "%float_1_duplicate = OpConstant %float 1",
393 "%double_1_duplicate = OpConstant %double 1",
394 },
395 // use duplicated constants in main
396 {
397 "%bool_var = OpVariable %_pf_bool Function",
398 "OpStore %bool_var %bool_true_duplicate",
399 "%int_var = OpVariable %_pf_int Function",
400 "OpStore %int_var %signed_1_duplicate",
401 "%int64_var = OpVariable %_pf_int64 Function",
402 "OpStore %int64_var %signed_minus_1_duplicate",
403 "%uint64_var = OpVariable %_pf_uint64 Function",
404 "OpStore %uint64_var %unsigned_max_duplicate",
405 "%float_var = OpVariable %_pf_float Function",
406 "OpStore %float_var %float_1_duplicate",
407 "%double_var = OpVariable %_pf_double Function",
408 "OpStore %double_var %double_1_duplicate",
409 },
410 // remapped names
411 {
412 "OpName %bool_true \"bool_true_duplicate\"",
413 "OpName %signed_1 \"signed_1_duplicate\"",
414 "OpName %signed_minus_1 \"signed_minus_1_duplicate\"",
415 "OpName %unsigned_max \"unsigned_max_duplicate\"",
416 "OpName %float_1 \"float_1_duplicate\"",
417 "OpName %double_1 \"double_1_duplicate\"",
418 },
419 },
420 // NaN in different bit patterns should not be unified, but the ones
421 // using same bit pattern should be unified.
422 {
423 // preserved constants
424 {
425 "%float_nan_1 = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
426 "%float_nan_2 = OpConstant %float 0x1.800002p+128",// !2143289345 7FC00001
427 },
428 // use preserved constants in main
429 {
430 "%float_var = OpVariable %_pf_float Function",
431 "OpStore %float_var %float_nan_1",
432 "OpStore %float_var %float_nan_2",
433 },
434 // duplicated constants
435 {
436 "%float_nan_1_duplicate = OpConstant %float 0x1.8p+128", // !2143289344, 7FC00000
437 "%float_nan_2_duplicate = OpConstant %float 0x1.800002p+128",// !2143289345, 7FC00001
438 },
439 // use duplicated constants in main
440 {
441 "%float_var = OpVariable %_pf_float Function",
442 "OpStore %float_var %float_nan_1_duplicate",
443 "OpStore %float_var %float_nan_2_duplicate",
444 },
445 // remapped names
446 {
447 "OpName %float_nan_1 \"float_nan_1_duplicate\"",
448 "OpName %float_nan_2 \"float_nan_2_duplicate\"",
449 },
450 },
451 // null values
452 {
453 // preserved constants
454 {
455 "%bool_null = OpConstantNull %bool",
456 "%signed_null = OpConstantNull %int",
457 "%signed_64_null = OpConstantNull %int64",
458 "%float_null = OpConstantNull %float",
459 "%double_null = OpConstantNull %double",
460 // zero-valued constants will not be unified with the equivalent
461 // null constants.
462 "%signed_zero = OpConstant %int 0",
463 },
464 // use preserved constants in main
465 {
466 "%bool_var = OpVariable %_pf_bool Function",
467 "OpStore %bool_var %bool_null",
468 "%int_var = OpVariable %_pf_int Function",
469 "OpStore %int_var %signed_null",
470 "%int64_var = OpVariable %_pf_int64 Function",
471 "OpStore %int64_var %signed_64_null",
472 "%float_var = OpVariable %_pf_float Function",
473 "OpStore %float_var %float_null",
474 "%double_var = OpVariable %_pf_double Function",
475 "OpStore %double_var %double_null",
476 },
477 // duplicated constants
478 {
479 "%bool_null_duplicate = OpConstantNull %bool",
480 "%signed_null_duplicate = OpConstantNull %int",
481 "%signed_64_null_duplicate = OpConstantNull %int64",
482 "%float_null_duplicate = OpConstantNull %float",
483 "%double_null_duplicate = OpConstantNull %double",
484 },
485 // use duplicated constants in main
486 {
487 "%bool_var = OpVariable %_pf_bool Function",
488 "OpStore %bool_var %bool_null_duplicate",
489 "%int_var = OpVariable %_pf_int Function",
490 "OpStore %int_var %signed_null_duplicate",
491 "%int64_var = OpVariable %_pf_int64 Function",
492 "OpStore %int64_var %signed_64_null_duplicate",
493 "%float_var = OpVariable %_pf_float Function",
494 "OpStore %float_var %float_null_duplicate",
495 "%double_var = OpVariable %_pf_double Function",
496 "OpStore %double_var %double_null_duplicate",
497 },
498 // remapped names
499 {
500 "OpName %bool_null \"bool_null_duplicate\"",
501 "OpName %signed_null \"signed_null_duplicate\"",
502 "OpName %signed_64_null \"signed_64_null_duplicate\"",
503 "OpName %float_null \"float_null_duplicate\"",
504 "OpName %double_null \"double_null_duplicate\"",
505 },
506 },
507 // constant sampler
508 {
509 // preserved constants
510 {
511 "%sampler = OpTypeSampler",
512 "%_pf_sampler = OpTypePointer Function %sampler",
513 "%sampler_1 = OpConstantSampler %sampler Repeat 0 Linear",
514 },
515 // use preserved constants in main
516 {
517 "%sampler_var = OpVariable %_pf_sampler Function",
518 "OpStore %sampler_var %sampler_1",
519 },
520 // duplicated constants
521 {
522 "%sampler_1_duplicate = OpConstantSampler %sampler Repeat 0 Linear",
523 },
524 // use duplicated constants in main
525 {
526 "%sampler_var = OpVariable %_pf_sampler Function",
527 "OpStore %sampler_var %sampler_1_duplicate",
528 },
529 // remapped names
530 {
531 "OpName %sampler_1 \"sampler_1_duplicate\"",
532 },
533 },
534 // duplicate vector built from same ids.
535 {
536 // preserved constants
537 {
538 "%signed_1 = OpConstant %int 1",
539 "%signed_2 = OpConstant %int 2",
540 "%signed_3 = OpConstant %int 3",
541 "%signed_4 = OpConstant %int 4",
542 "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
543 },
544 // use preserved constants in main
545 {
546 "%vec_var = OpVariable %_pf_v4int Function",
547 "OpStore %vec_var %vec",
548 },
549 // duplicated constants
550 {
551 "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
552 },
553 // use duplicated constants in main
554 {
555 "%vec_var = OpVariable %_pf_v4int Function",
556 "OpStore %vec_var %vec_duplicate",
557 },
558 // remapped names
559 {
560 "OpName %vec \"vec_duplicate\"",
561 }
562 },
563 // duplicate vector built from duplicated ids.
564 {
565 // preserved constants
566 {
567 "%signed_1 = OpConstant %int 1",
568 "%signed_2 = OpConstant %int 2",
569 "%signed_3 = OpConstant %int 3",
570 "%signed_4 = OpConstant %int 4",
571 "%vec = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3 %signed_4",
572 },
573 // use preserved constants in main
574 {
575 "%vec_var = OpVariable %_pf_v4int Function",
576 "OpStore %vec_var %vec",
577 },
578 // duplicated constants
579 {
580 "%signed_3_duplicate = OpConstant %int 3",
581 "%signed_4_duplicate = OpConstant %int 4",
582 "%vec_duplicate = OpConstantComposite %v4int %signed_1 %signed_2 %signed_3_duplicate %signed_4_duplicate",
583 },
584 // use duplicated constants in main
585 {
586 "%vec_var = OpVariable %_pf_v4int Function",
587 "OpStore %vec_var %vec_duplicate",
588 },
589 // remapped names
590 {
591 "OpName %signed_3 \"signed_3_duplicate\"",
592 "OpName %signed_4 \"signed_4_duplicate\"",
593 "OpName %vec \"vec_duplicate\"",
594 },
595 },
596 // flat struct
597 {
598 // preserved constants
599 {
600 "%bool_true = OpConstantTrue %bool",
601 "%signed_1 = OpConstant %int 1",
602 "%float_1 = OpConstant %float 1",
603 "%double_1 = OpConstant %double 1",
604 "%s = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1 %double_1",
605 },
606 // use preserved constants in main
607 {
608 "%s_var = OpVariable %_pf_flat_struct Function",
609 "OpStore %s_var %s",
610 },
611 // duplicated constants
612 {
613 "%float_1_duplicate = OpConstant %float 1",
614 "%double_1_duplicate = OpConstant %double 1",
615 "%s_duplicate = OpConstantComposite %flat_struct %bool_true %signed_1 %float_1_duplicate %double_1_duplicate",
616 },
617 // use duplicated constants in main
618 {
619 "%s_var = OpVariable %_pf_flat_struct Function",
620 "OpStore %s_var %s_duplicate",
621 },
622 // remapped names
623 {
624 "OpName %float_1 \"float_1_duplicate\"",
625 "OpName %double_1 \"double_1_duplicate\"",
626 "OpName %s \"s_duplicate\"",
627 },
628 },
629 // nested struct
630 {
631 // preserved constants
632 {
633 "%bool_true = OpConstantTrue %bool",
634 "%signed_1 = OpConstant %int 1",
635 "%float_1 = OpConstant %float 1",
636 "%double_1 = OpConstant %double 1",
637 "%inner = OpConstantComposite %inner_struct %bool_true %float_1",
638 "%outer = OpConstantComposite %outer_struct %inner %signed_1 %double_1",
639 },
640 // use preserved constants in main
641 {
642 "%outer_var = OpVariable %_pf_outer_struct Function",
643 "OpStore %outer_var %outer",
644 },
645 // duplicated constants
646 {
647 "%float_1_duplicate = OpConstant %float 1",
648 "%double_1_duplicate = OpConstant %double 1",
649 "%inner_duplicate = OpConstantComposite %inner_struct %bool_true %float_1_duplicate",
650 "%outer_duplicate = OpConstantComposite %outer_struct %inner_duplicate %signed_1 %double_1_duplicate",
651 },
652 // use duplicated constants in main
653 {
654 "%outer_var = OpVariable %_pf_outer_struct Function",
655 "OpStore %outer_var %outer_duplicate",
656 },
657 // remapped names
658 {
659 "OpName %float_1 \"float_1_duplicate\"",
660 "OpName %double_1 \"double_1_duplicate\"",
661 "OpName %inner \"inner_duplicate\"",
662 "OpName %outer \"outer_duplicate\"",
663 },
664 },
665 // composite type null constants. Null constants and zero-valued
666 // constants should not be used to replace each other.
667 {
668 // preserved constants
669 {
670 "%bool_zero = OpConstantFalse %bool",
671 "%float_zero = OpConstant %float 0",
672 "%int_null = OpConstantNull %int",
673 "%double_null = OpConstantNull %double",
674 // inner_struct type null constant.
675 "%null_inner = OpConstantNull %inner_struct",
676 // zero-valued composite constant built from zero-valued constant
677 // component. inner_zero should not be replace by null_inner.
678 "%inner_zero = OpConstantComposite %inner_struct %bool_zero %float_zero",
679 // zero-valued composite contant built from zero-valued constants
680 // and null constants.
681 "%outer_zero = OpConstantComposite %outer_struct %inner_zero %int_null %double_null",
682 // outer_struct type null constant, it should not be replaced by
683 // outer_zero.
684 "%null_outer = OpConstantNull %outer_struct",
685 },
686 // use preserved constants in main
687 {
688 "%inner_var = OpVariable %_pf_inner_struct Function",
689 "OpStore %inner_var %inner_zero",
690 "OpStore %inner_var %null_inner",
691 "%outer_var = OpVariable %_pf_outer_struct Function",
692 "OpStore %outer_var %outer_zero",
693 "OpStore %outer_var %null_outer",
694 },
695 // duplicated constants
696 {
697 "%null_inner_dup = OpConstantNull %inner_struct",
698 "%null_outer_dup = OpConstantNull %outer_struct",
699 "%inner_zero_dup = OpConstantComposite %inner_struct %bool_zero %float_zero",
700 "%outer_zero_dup = OpConstantComposite %outer_struct %inner_zero_dup %int_null %double_null",
701 },
702 // use duplicated constants in main
703 {
704 "%inner_var = OpVariable %_pf_inner_struct Function",
705 "OpStore %inner_var %inner_zero_dup",
706 "OpStore %inner_var %null_inner_dup",
707 "%outer_var = OpVariable %_pf_outer_struct Function",
708 "OpStore %outer_var %outer_zero_dup",
709 "OpStore %outer_var %null_outer_dup",
710 },
711 // remapped names
712 {
713 "OpName %null_inner \"null_inner_dup\"",
714 "OpName %null_outer \"null_outer_dup\"",
715 "OpName %inner_zero \"inner_zero_dup\"",
716 "OpName %outer_zero \"outer_zero_dup\"",
717 },
718 },
719 // Spec Constants with SpecId decoration should be skipped.
720 {
721 // preserved constants
722 {
723 // Assembly builder will add OpDecorate SpecId instruction for the
724 // following spec constant instructions automatically.
725 "%spec_bool_1 = OpSpecConstantTrue %bool",
726 "%spec_bool_2 = OpSpecConstantTrue %bool",
727 "%spec_int_1 = OpSpecConstant %int 1",
728 "%spec_int_2 = OpSpecConstant %int 1",
729 },
730 // use preserved constants in main
731 {
732 "%bool_var = OpVariable %_pf_bool Function",
733 "OpStore %bool_var %spec_bool_1",
734 "OpStore %bool_var %spec_bool_2",
735 "%int_var = OpVariable %_pf_int Function",
736 "OpStore %int_var %spec_int_1",
737 "OpStore %int_var %spec_int_2",
738 },
739 // duplicated constants. No duplicated instruction to remove in this
740 // case.
741 {},
742 // use duplicated constants in main. Same as the above 'use preserved
743 // constants in main' defined above, as no instruction should be
744 // removed in this case.
745 {
746 "%bool_var = OpVariable %_pf_bool Function",
747 "OpStore %bool_var %spec_bool_1",
748 "OpStore %bool_var %spec_bool_2",
749 "%int_var = OpVariable %_pf_int Function",
750 "OpStore %int_var %spec_int_1",
751 "OpStore %int_var %spec_int_2",
752 },
753 // remapped names. No duplicated instruction removed, so this is
754 // empty.
755 {}
756 },
757 // spec constant composite
758 {
759 // preserved constants
760 {
761 "%spec_bool_true = OpSpecConstantTrue %bool",
762 "%spec_signed_1 = OpSpecConstant %int 1",
763 "%float_1 = OpConstant %float 1",
764 "%double_1 = OpConstant %double 1",
765 "%spec_inner = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1",
766 "%spec_outer = OpSpecConstantComposite %outer_struct %spec_inner %spec_signed_1 %double_1",
767 "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
768 },
769 // use preserved constants in main
770 {
771 "%outer_var = OpVariable %_pf_outer_struct Function",
772 "OpStore %outer_var %spec_outer",
773 "%v2float_var = OpVariable %_pf_v2float Function",
774 "OpStore %v2float_var %spec_vec2",
775 },
776 // duplicated constants
777 {
778 "%float_1_duplicate = OpConstant %float 1",
779 "%double_1_duplicate = OpConstant %double 1",
780 "%spec_inner_duplicate = OpSpecConstantComposite %inner_struct %spec_bool_true %float_1_duplicate",
781 "%spec_outer_duplicate = OpSpecConstantComposite %outer_struct %spec_inner_duplicate %spec_signed_1 %double_1_duplicate",
782 "%spec_vec2_duplicate = OpSpecConstantComposite %v2float %float_1 %float_1_duplicate",
783 },
784 // use duplicated constants in main
785 {
786 "%outer_var = OpVariable %_pf_outer_struct Function",
787 "OpStore %outer_var %spec_outer_duplicate",
788 "%v2float_var = OpVariable %_pf_v2float Function",
789 "OpStore %v2float_var %spec_vec2_duplicate",
790 },
791 // remapped names
792 {
793 "OpName %float_1 \"float_1_duplicate\"",
794 "OpName %double_1 \"double_1_duplicate\"",
795 "OpName %spec_inner \"spec_inner_duplicate\"",
796 "OpName %spec_outer \"spec_outer_duplicate\"",
797 "OpName %spec_vec2 \"spec_vec2_duplicate\"",
798 },
799 },
800 // spec constant op with int scalar
801 {
802 // preserved constants
803 {
804 "%spec_signed_1 = OpSpecConstant %int 1",
805 "%spec_signed_2 = OpSpecConstant %int 2",
806 "%spec_signed_add = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
807 },
808 // use preserved constants in main
809 {
810 "%int_var = OpVariable %_pf_int Function",
811 "OpStore %int_var %spec_signed_add",
812 },
813 // duplicated constants
814 {
815 "%spec_signed_add_duplicate = OpSpecConstantOp %int IAdd %spec_signed_1 %spec_signed_2",
816 },
817 // use duplicated contants in main
818 {
819 "%int_var = OpVariable %_pf_int Function",
820 "OpStore %int_var %spec_signed_add_duplicate",
821 },
822 // remapped names
823 {
824 "OpName %spec_signed_add \"spec_signed_add_duplicate\"",
825 },
826 },
827 // spec constant op composite extract
828 {
829 // preserved constants
830 {
831 "%float_1 = OpConstant %float 1",
832 "%spec_vec2 = OpSpecConstantComposite %v2float %float_1 %float_1",
833 "%spec_extract = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
834 },
835 // use preserved constants in main
836 {
837 "%float_var = OpVariable %_pf_float Function",
838 "OpStore %float_var %spec_extract",
839 },
840 // duplicated constants
841 {
842 "%spec_extract_duplicate = OpSpecConstantOp %float CompositeExtract %spec_vec2 1",
843 },
844 // use duplicated constants in main
845 {
846 "%float_var = OpVariable %_pf_float Function",
847 "OpStore %float_var %spec_extract_duplicate",
848 },
849 // remapped names
850 {
851 "OpName %spec_extract \"spec_extract_duplicate\"",
852 },
853 },
854 // spec constant op vector shuffle
855 {
856 // preserved constants
857 {
858 "%float_1 = OpConstant %float 1",
859 "%float_2 = OpConstant %float 2",
860 "%spec_vec2_1 = OpSpecConstantComposite %v2float %float_1 %float_1",
861 "%spec_vec2_2 = OpSpecConstantComposite %v2float %float_2 %float_2",
862 "%spec_vector_shuffle = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
863 },
864 // use preserved constants in main
865 {
866 "%v2float_var = OpVariable %_pf_v2float Function",
867 "OpStore %v2float_var %spec_vector_shuffle",
868 },
869 // duplicated constants
870 {
871 "%spec_vector_shuffle_duplicate = OpSpecConstantOp %v2float VectorShuffle %spec_vec2_1 %spec_vec2_2 1 2",
872 },
873 // use duplicated constants in main
874 {
875 "%v2float_var = OpVariable %_pf_v2float Function",
876 "OpStore %v2float_var %spec_vector_shuffle_duplicate",
877 },
878 // remapped names
879 {
880 "OpName %spec_vector_shuffle \"spec_vector_shuffle_duplicate\"",
881 },
882 },
883 // long dependency chain
884 {
885 // preserved constants
886 {
887 "%array_size = OpConstant %int 4",
888 "%type_arr_int_4 = OpTypeArray %int %array_size",
889 "%signed_0 = OpConstant %int 100",
890 "%signed_1 = OpConstant %int 1",
891 "%signed_2 = OpSpecConstantOp %int IAdd %signed_0 %signed_1",
892 "%signed_3 = OpSpecConstantOp %int ISub %signed_0 %signed_2",
893 "%signed_4 = OpSpecConstantOp %int IAdd %signed_0 %signed_3",
894 "%signed_5 = OpSpecConstantOp %int ISub %signed_0 %signed_4",
895 "%signed_6 = OpSpecConstantOp %int IAdd %signed_0 %signed_5",
896 "%signed_7 = OpSpecConstantOp %int ISub %signed_0 %signed_6",
897 "%signed_8 = OpSpecConstantOp %int IAdd %signed_0 %signed_7",
898 "%signed_9 = OpSpecConstantOp %int ISub %signed_0 %signed_8",
899 "%signed_10 = OpSpecConstantOp %int IAdd %signed_0 %signed_9",
900 "%signed_11 = OpSpecConstantOp %int ISub %signed_0 %signed_10",
901 "%signed_12 = OpSpecConstantOp %int IAdd %signed_0 %signed_11",
902 "%signed_13 = OpSpecConstantOp %int ISub %signed_0 %signed_12",
903 "%signed_14 = OpSpecConstantOp %int IAdd %signed_0 %signed_13",
904 "%signed_15 = OpSpecConstantOp %int ISub %signed_0 %signed_14",
905 "%signed_16 = OpSpecConstantOp %int ISub %signed_0 %signed_15",
906 "%signed_17 = OpSpecConstantOp %int IAdd %signed_0 %signed_16",
907 "%signed_18 = OpSpecConstantOp %int ISub %signed_0 %signed_17",
908 "%signed_19 = OpSpecConstantOp %int IAdd %signed_0 %signed_18",
909 "%signed_20 = OpSpecConstantOp %int ISub %signed_0 %signed_19",
910 "%signed_vec_a = OpSpecConstantComposite %v2int %signed_18 %signed_19",
911 "%signed_vec_b = OpSpecConstantOp %v2int IMul %signed_vec_a %signed_vec_a",
912 "%signed_21 = OpSpecConstantOp %int CompositeExtract %signed_vec_b 0",
913 "%signed_array = OpConstantComposite %type_arr_int_4 %signed_20 %signed_20 %signed_21 %signed_21",
914 "%signed_22 = OpSpecConstantOp %int CompositeExtract %signed_array 0",
915 },
916 // use preserved constants in main
917 {
918 "%int_var = OpVariable %_pf_int Function",
919 "OpStore %int_var %signed_22",
920 },
921 // duplicated constants
922 {
923 "%signed_0_dup = OpConstant %int 100",
924 "%signed_1_dup = OpConstant %int 1",
925 "%signed_2_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_1_dup",
926 "%signed_3_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_2_dup",
927 "%signed_4_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_3_dup",
928 "%signed_5_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_4_dup",
929 "%signed_6_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_5_dup",
930 "%signed_7_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_6_dup",
931 "%signed_8_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_7_dup",
932 "%signed_9_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_8_dup",
933 "%signed_10_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_9_dup",
934 "%signed_11_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_10_dup",
935 "%signed_12_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_11_dup",
936 "%signed_13_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_12_dup",
937 "%signed_14_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_13_dup",
938 "%signed_15_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_14_dup",
939 "%signed_16_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_15_dup",
940 "%signed_17_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_16_dup",
941 "%signed_18_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_17_dup",
942 "%signed_19_dup = OpSpecConstantOp %int IAdd %signed_0_dup %signed_18_dup",
943 "%signed_20_dup = OpSpecConstantOp %int ISub %signed_0_dup %signed_19_dup",
944 "%signed_vec_a_dup = OpSpecConstantComposite %v2int %signed_18_dup %signed_19_dup",
945 "%signed_vec_b_dup = OpSpecConstantOp %v2int IMul %signed_vec_a_dup %signed_vec_a_dup",
946 "%signed_21_dup = OpSpecConstantOp %int CompositeExtract %signed_vec_b_dup 0",
947 "%signed_array_dup = OpConstantComposite %type_arr_int_4 %signed_20_dup %signed_20_dup %signed_21_dup %signed_21_dup",
948 "%signed_22_dup = OpSpecConstantOp %int CompositeExtract %signed_array_dup 0",
949 },
950 // use duplicated constants in main
951 {
952 "%int_var = OpVariable %_pf_int Function",
953 "OpStore %int_var %signed_22_dup",
954 },
955 // remapped names
956 {
957 "OpName %signed_0 \"signed_0_dup\"",
958 "OpName %signed_1 \"signed_1_dup\"",
959 "OpName %signed_2 \"signed_2_dup\"",
960 "OpName %signed_3 \"signed_3_dup\"",
961 "OpName %signed_4 \"signed_4_dup\"",
962 "OpName %signed_5 \"signed_5_dup\"",
963 "OpName %signed_6 \"signed_6_dup\"",
964 "OpName %signed_7 \"signed_7_dup\"",
965 "OpName %signed_8 \"signed_8_dup\"",
966 "OpName %signed_9 \"signed_9_dup\"",
967 "OpName %signed_10 \"signed_10_dup\"",
968 "OpName %signed_11 \"signed_11_dup\"",
969 "OpName %signed_12 \"signed_12_dup\"",
970 "OpName %signed_13 \"signed_13_dup\"",
971 "OpName %signed_14 \"signed_14_dup\"",
972 "OpName %signed_15 \"signed_15_dup\"",
973 "OpName %signed_16 \"signed_16_dup\"",
974 "OpName %signed_17 \"signed_17_dup\"",
975 "OpName %signed_18 \"signed_18_dup\"",
976 "OpName %signed_19 \"signed_19_dup\"",
977 "OpName %signed_20 \"signed_20_dup\"",
978 "OpName %signed_vec_a \"signed_vec_a_dup\"",
979 "OpName %signed_vec_b \"signed_vec_b_dup\"",
980 "OpName %signed_21 \"signed_21_dup\"",
981 "OpName %signed_array \"signed_array_dup\"",
982 "OpName %signed_22 \"signed_22_dup\"",
983 },
984 },
985 // clang-format on
986 })));
987
988 } // namespace
989 } // namespace opt
990 } // namespace spvtools
991