1fd4e5da5Sopenharmony_ci// Copyright (c) 2020 Google LLC
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/fuzz/transformation_composite_insert.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
18fd4e5da5Sopenharmony_ci#include "source/fuzz/data_descriptor.h"
19fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h"
20fd4e5da5Sopenharmony_ci#include "source/fuzz/instruction_descriptor.h"
21fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h"
22fd4e5da5Sopenharmony_ci
23fd4e5da5Sopenharmony_cinamespace spvtools {
24fd4e5da5Sopenharmony_cinamespace fuzz {
25fd4e5da5Sopenharmony_cinamespace {
26fd4e5da5Sopenharmony_ci
27fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, NotApplicableScenarios) {
28fd4e5da5Sopenharmony_ci  // This test handles cases where IsApplicable() returns false.
29fd4e5da5Sopenharmony_ci
30fd4e5da5Sopenharmony_ci  std::string shader = R"(
31fd4e5da5Sopenharmony_ci               OpCapability Shader
32fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
33fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
34fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
35fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
36fd4e5da5Sopenharmony_ci               OpSource ESSL 310
37fd4e5da5Sopenharmony_ci               OpName %4 "main"
38fd4e5da5Sopenharmony_ci               OpName %8 "i1"
39fd4e5da5Sopenharmony_ci               OpName %10 "i2"
40fd4e5da5Sopenharmony_ci               OpName %12 "base"
41fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
42fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
43fd4e5da5Sopenharmony_ci               OpName %14 "b"
44fd4e5da5Sopenharmony_ci               OpName %18 "level_1"
45fd4e5da5Sopenharmony_ci               OpMemberName %18 0 "b1"
46fd4e5da5Sopenharmony_ci               OpMemberName %18 1 "b2"
47fd4e5da5Sopenharmony_ci               OpName %20 "l1"
48fd4e5da5Sopenharmony_ci               OpName %24 "level_2"
49fd4e5da5Sopenharmony_ci               OpMemberName %24 0 "c1"
50fd4e5da5Sopenharmony_ci               OpMemberName %24 1 "c2"
51fd4e5da5Sopenharmony_ci               OpName %26 "l2"
52fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
53fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
54fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
55fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
56fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
57fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
58fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
59fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
60fd4e5da5Sopenharmony_ci         %18 = OpTypeStruct %12 %12
61fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Function %18
62fd4e5da5Sopenharmony_ci         %24 = OpTypeStruct %18 %18
63fd4e5da5Sopenharmony_ci         %25 = OpTypePointer Function %24
64fd4e5da5Sopenharmony_ci         %30 = OpTypeBool
65fd4e5da5Sopenharmony_ci         %31 = OpConstantTrue %30
66fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
67fd4e5da5Sopenharmony_ci          %5 = OpLabel
68fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
69fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
70fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
71fd4e5da5Sopenharmony_ci         %20 = OpVariable %19 Function
72fd4e5da5Sopenharmony_ci         %26 = OpVariable %25 Function
73fd4e5da5Sopenharmony_ci               OpStore %8 %9
74fd4e5da5Sopenharmony_ci               OpStore %10 %11
75fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
76fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
77fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
78fd4e5da5Sopenharmony_ci               OpStore %14 %17
79fd4e5da5Sopenharmony_ci         %21 = OpLoad %12 %14
80fd4e5da5Sopenharmony_ci         %22 = OpLoad %12 %14
81fd4e5da5Sopenharmony_ci         %23 = OpCompositeConstruct %18 %21 %22
82fd4e5da5Sopenharmony_ci               OpStore %20 %23
83fd4e5da5Sopenharmony_ci         %27 = OpLoad %18 %20
84fd4e5da5Sopenharmony_ci         %28 = OpLoad %18 %20
85fd4e5da5Sopenharmony_ci         %29 = OpCompositeConstruct %24 %27 %28
86fd4e5da5Sopenharmony_ci               OpStore %26 %29
87fd4e5da5Sopenharmony_ci               OpSelectionMerge %33 None
88fd4e5da5Sopenharmony_ci               OpBranchConditional %31 %32 %33
89fd4e5da5Sopenharmony_ci         %32 = OpLabel
90fd4e5da5Sopenharmony_ci               OpBranch %33
91fd4e5da5Sopenharmony_ci         %33 = OpLabel
92fd4e5da5Sopenharmony_ci               OpReturn
93fd4e5da5Sopenharmony_ci               OpFunctionEnd
94fd4e5da5Sopenharmony_ci    )";
95fd4e5da5Sopenharmony_ci
96fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
97fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
98fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
99fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
100fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
101fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
102fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
103fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
104fd4e5da5Sopenharmony_ci  // Bad: |fresh_id| is not fresh.
105fd4e5da5Sopenharmony_ci  auto transformation_bad_1 = TransformationCompositeInsert(
106fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 20, 29, 11,
107fd4e5da5Sopenharmony_ci      {1, 0, 0});
108fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
109fd4e5da5Sopenharmony_ci      transformation_bad_1.IsApplicable(context.get(), transformation_context));
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_ci  // Bad: |composite_id| does not refer to a existing instruction.
112fd4e5da5Sopenharmony_ci  auto transformation_bad_2 = TransformationCompositeInsert(
113fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 40, 11,
114fd4e5da5Sopenharmony_ci      {1, 0, 0});
115fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
116fd4e5da5Sopenharmony_ci      transformation_bad_2.IsApplicable(context.get(), transformation_context));
117fd4e5da5Sopenharmony_ci
118fd4e5da5Sopenharmony_ci  // Bad: |composite_id| does not refer to a composite value.
119fd4e5da5Sopenharmony_ci  auto transformation_bad_3 = TransformationCompositeInsert(
120fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 9, 11, {1, 0, 0});
121fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
122fd4e5da5Sopenharmony_ci      transformation_bad_3.IsApplicable(context.get(), transformation_context));
123fd4e5da5Sopenharmony_ci
124fd4e5da5Sopenharmony_ci  // Bad: |object_id| does not refer to a defined instruction.
125fd4e5da5Sopenharmony_ci  auto transformation_bad_4 = TransformationCompositeInsert(
126fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 29, 40,
127fd4e5da5Sopenharmony_ci      {1, 0, 0});
128fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
129fd4e5da5Sopenharmony_ci      transformation_bad_4.IsApplicable(context.get(), transformation_context));
130fd4e5da5Sopenharmony_ci
131fd4e5da5Sopenharmony_ci  // Bad: |object_id| cannot refer to a pointer.
132fd4e5da5Sopenharmony_ci  auto transformation_bad_5 = TransformationCompositeInsert(
133fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 29, 8, {1, 0, 0});
134fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
135fd4e5da5Sopenharmony_ci      transformation_bad_5.IsApplicable(context.get(), transformation_context));
136fd4e5da5Sopenharmony_ci
137fd4e5da5Sopenharmony_ci  // Bad: |index| is not a correct index.
138fd4e5da5Sopenharmony_ci  auto transformation_bad_6 = TransformationCompositeInsert(
139fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 29, 11,
140fd4e5da5Sopenharmony_ci      {2, 0, 0});
141fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
142fd4e5da5Sopenharmony_ci      transformation_bad_6.IsApplicable(context.get(), transformation_context));
143fd4e5da5Sopenharmony_ci
144fd4e5da5Sopenharmony_ci  // Bad: Type id of the object to be inserted and the type id of the
145fd4e5da5Sopenharmony_ci  // component at |index| are not the same.
146fd4e5da5Sopenharmony_ci  auto transformation_bad_7 = TransformationCompositeInsert(
147fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 29, 11, {1, 0});
148fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
149fd4e5da5Sopenharmony_ci      transformation_bad_7.IsApplicable(context.get(), transformation_context));
150fd4e5da5Sopenharmony_ci
151fd4e5da5Sopenharmony_ci  // Bad: |instruction_to_insert_before| does not refer to a defined
152fd4e5da5Sopenharmony_ci  // instruction.
153fd4e5da5Sopenharmony_ci  auto transformation_bad_8 = TransformationCompositeInsert(
154fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpIMul, 0), 50, 29, 11, {1, 0, 0});
155fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
156fd4e5da5Sopenharmony_ci      transformation_bad_8.IsApplicable(context.get(), transformation_context));
157fd4e5da5Sopenharmony_ci
158fd4e5da5Sopenharmony_ci  // Bad: OpCompositeInsert cannot be inserted before OpBranchConditional with
159fd4e5da5Sopenharmony_ci  // OpSelectionMerge above it.
160fd4e5da5Sopenharmony_ci  auto transformation_bad_9 = TransformationCompositeInsert(
161fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpBranchConditional, 0), 50, 29,
162fd4e5da5Sopenharmony_ci      11, {1, 0, 0});
163fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
164fd4e5da5Sopenharmony_ci      transformation_bad_9.IsApplicable(context.get(), transformation_context));
165fd4e5da5Sopenharmony_ci
166fd4e5da5Sopenharmony_ci  // Bad: |composite_id| does not have a type_id.
167fd4e5da5Sopenharmony_ci  auto transformation_bad_10 = TransformationCompositeInsert(
168fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(29, spv::Op::OpStore, 0), 50, 1, 11, {1, 0, 0});
169fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_bad_10.IsApplicable(context.get(),
170fd4e5da5Sopenharmony_ci                                                  transformation_context));
171fd4e5da5Sopenharmony_ci}
172fd4e5da5Sopenharmony_ci
173fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, EmptyCompositeScenarios) {
174fd4e5da5Sopenharmony_ci  // This test handles cases where either the composite is empty or the
175fd4e5da5Sopenharmony_ci  // composite contains an empty composite.
176fd4e5da5Sopenharmony_ci
177fd4e5da5Sopenharmony_ci  std::string shader = R"(
178fd4e5da5Sopenharmony_ci               OpCapability Shader
179fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
180fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
181fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
182fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
183fd4e5da5Sopenharmony_ci               OpSource ESSL 310
184fd4e5da5Sopenharmony_ci               OpName %4 "main"
185fd4e5da5Sopenharmony_ci               OpName %8 "i1"
186fd4e5da5Sopenharmony_ci               OpName %10 "i2"
187fd4e5da5Sopenharmony_ci               OpName %12 "base"
188fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
189fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
190fd4e5da5Sopenharmony_ci               OpName %14 "b"
191fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
192fd4e5da5Sopenharmony_ci         %60 = OpTypeStruct
193fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
194fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
195fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
196fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
197fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
198fd4e5da5Sopenharmony_ci         %61 = OpConstantComposite %60
199fd4e5da5Sopenharmony_ci         %62 = OpConstantComposite %60
200fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
201fd4e5da5Sopenharmony_ci         %63 = OpTypeStruct %6 %60
202fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
203fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
204fd4e5da5Sopenharmony_ci          %5 = OpLabel
205fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
206fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
207fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
208fd4e5da5Sopenharmony_ci               OpStore %8 %9
209fd4e5da5Sopenharmony_ci               OpStore %10 %11
210fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
211fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
212fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
213fd4e5da5Sopenharmony_ci         %64 = OpCompositeConstruct %63 %15 %61
214fd4e5da5Sopenharmony_ci               OpStore %14 %17
215fd4e5da5Sopenharmony_ci               OpReturn
216fd4e5da5Sopenharmony_ci               OpFunctionEnd
217fd4e5da5Sopenharmony_ci    )";
218fd4e5da5Sopenharmony_ci
219fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
220fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
221fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
222fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
223fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
224fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
225fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
226fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
227fd4e5da5Sopenharmony_ci  // Bad: The composite with |composite_id| cannot be empty.
228fd4e5da5Sopenharmony_ci  auto transformation_bad_1 = TransformationCompositeInsert(
229fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(64, spv::Op::OpStore, 0), 50, 61, 62, {1});
230fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
231fd4e5da5Sopenharmony_ci      transformation_bad_1.IsApplicable(context.get(), transformation_context));
232fd4e5da5Sopenharmony_ci
233fd4e5da5Sopenharmony_ci  // Good: It is possible to insert into a composite an element which is an
234fd4e5da5Sopenharmony_ci  // empty composite.
235fd4e5da5Sopenharmony_ci  auto transformation_good_1 = TransformationCompositeInsert(
236fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(64, spv::Op::OpStore, 0), 50, 64, 62, {1});
237fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
238fd4e5da5Sopenharmony_ci                                                 transformation_context));
239fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
240fd4e5da5Sopenharmony_ci                        &transformation_context);
241fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
242fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
243fd4e5da5Sopenharmony_ci
244fd4e5da5Sopenharmony_ci  std::string after_transformations = R"(
245fd4e5da5Sopenharmony_ci               OpCapability Shader
246fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
247fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
248fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
249fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
250fd4e5da5Sopenharmony_ci               OpSource ESSL 310
251fd4e5da5Sopenharmony_ci               OpName %4 "main"
252fd4e5da5Sopenharmony_ci               OpName %8 "i1"
253fd4e5da5Sopenharmony_ci               OpName %10 "i2"
254fd4e5da5Sopenharmony_ci               OpName %12 "base"
255fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
256fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
257fd4e5da5Sopenharmony_ci               OpName %14 "b"
258fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
259fd4e5da5Sopenharmony_ci         %60 = OpTypeStruct
260fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
261fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
262fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
263fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
264fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
265fd4e5da5Sopenharmony_ci         %61 = OpConstantComposite %60
266fd4e5da5Sopenharmony_ci         %62 = OpConstantComposite %60
267fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
268fd4e5da5Sopenharmony_ci         %63 = OpTypeStruct %6 %60
269fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
270fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
271fd4e5da5Sopenharmony_ci          %5 = OpLabel
272fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
273fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
274fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
275fd4e5da5Sopenharmony_ci               OpStore %8 %9
276fd4e5da5Sopenharmony_ci               OpStore %10 %11
277fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
278fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
279fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
280fd4e5da5Sopenharmony_ci         %64 = OpCompositeConstruct %63 %15 %61
281fd4e5da5Sopenharmony_ci         %50 = OpCompositeInsert %63 %62 %64 1
282fd4e5da5Sopenharmony_ci               OpStore %14 %17
283fd4e5da5Sopenharmony_ci               OpReturn
284fd4e5da5Sopenharmony_ci               OpFunctionEnd
285fd4e5da5Sopenharmony_ci  )";
286fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
287fd4e5da5Sopenharmony_ci}
288fd4e5da5Sopenharmony_ci
289fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, IrrelevantCompositeNoSynonyms) {
290fd4e5da5Sopenharmony_ci  // This test handles cases where either |composite| is irrelevant.
291fd4e5da5Sopenharmony_ci  // The transformation shouldn't create any synonyms.
292fd4e5da5Sopenharmony_ci  // The member composite has a different number of elements than the parent
293fd4e5da5Sopenharmony_ci  // composite.
294fd4e5da5Sopenharmony_ci
295fd4e5da5Sopenharmony_ci  std::string shader = R"(
296fd4e5da5Sopenharmony_ci               OpCapability Shader
297fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
298fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
299fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
300fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
301fd4e5da5Sopenharmony_ci               OpSource ESSL 310
302fd4e5da5Sopenharmony_ci               OpName %4 "main"
303fd4e5da5Sopenharmony_ci               OpName %8 "i1"
304fd4e5da5Sopenharmony_ci               OpName %10 "i2"
305fd4e5da5Sopenharmony_ci               OpName %12 "base"
306fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
307fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
308fd4e5da5Sopenharmony_ci               OpName %14 "b"
309fd4e5da5Sopenharmony_ci               OpName %18 "level_1"
310fd4e5da5Sopenharmony_ci               OpMemberName %18 0 "b1"
311fd4e5da5Sopenharmony_ci               OpMemberName %18 1 "b2"
312fd4e5da5Sopenharmony_ci               OpMemberName %18 2 "b3"
313fd4e5da5Sopenharmony_ci               OpName %20 "l1"
314fd4e5da5Sopenharmony_ci               OpName %25 "level_2"
315fd4e5da5Sopenharmony_ci               OpMemberName %25 0 "c1"
316fd4e5da5Sopenharmony_ci               OpMemberName %25 1 "c2"
317fd4e5da5Sopenharmony_ci               OpName %27 "l2"
318fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
319fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
320fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
321fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
322fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
323fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
324fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
325fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
326fd4e5da5Sopenharmony_ci         %18 = OpTypeStruct %12 %12 %12
327fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Function %18
328fd4e5da5Sopenharmony_ci         %25 = OpTypeStruct %18 %18
329fd4e5da5Sopenharmony_ci         %26 = OpTypePointer Function %25
330fd4e5da5Sopenharmony_ci         %31 = OpTypeBool
331fd4e5da5Sopenharmony_ci         %32 = OpConstantTrue %31
332fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
333fd4e5da5Sopenharmony_ci          %5 = OpLabel
334fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
335fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
336fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
337fd4e5da5Sopenharmony_ci         %20 = OpVariable %19 Function
338fd4e5da5Sopenharmony_ci         %27 = OpVariable %26 Function
339fd4e5da5Sopenharmony_ci               OpStore %8 %9
340fd4e5da5Sopenharmony_ci               OpStore %10 %11
341fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
342fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
343fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
344fd4e5da5Sopenharmony_ci               OpStore %14 %17
345fd4e5da5Sopenharmony_ci         %21 = OpLoad %12 %14
346fd4e5da5Sopenharmony_ci         %22 = OpLoad %12 %14
347fd4e5da5Sopenharmony_ci         %23 = OpLoad %12 %14
348fd4e5da5Sopenharmony_ci         %24 = OpCompositeConstruct %18 %21 %22 %23
349fd4e5da5Sopenharmony_ci               OpStore %20 %24
350fd4e5da5Sopenharmony_ci         %28 = OpLoad %18 %20
351fd4e5da5Sopenharmony_ci         %29 = OpLoad %18 %20
352fd4e5da5Sopenharmony_ci         %30 = OpCompositeConstruct %25 %28 %29
353fd4e5da5Sopenharmony_ci               OpStore %27 %30
354fd4e5da5Sopenharmony_ci               OpSelectionMerge %34 None
355fd4e5da5Sopenharmony_ci               OpBranchConditional %32 %33 %34
356fd4e5da5Sopenharmony_ci         %33 = OpLabel
357fd4e5da5Sopenharmony_ci               OpBranch %34
358fd4e5da5Sopenharmony_ci         %34 = OpLabel
359fd4e5da5Sopenharmony_ci               OpReturn
360fd4e5da5Sopenharmony_ci               OpFunctionEnd
361fd4e5da5Sopenharmony_ci    )";
362fd4e5da5Sopenharmony_ci
363fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
364fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
365fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
366fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
367fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
368fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
369fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
370fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
371fd4e5da5Sopenharmony_ci  // Add fact that the composite is irrelevant.
372fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(30);
373fd4e5da5Sopenharmony_ci
374fd4e5da5Sopenharmony_ci  auto transformation_good_1 = TransformationCompositeInsert(
375fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(30, spv::Op::OpStore, 0), 50, 30, 11,
376fd4e5da5Sopenharmony_ci      {1, 0, 0});
377fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
378fd4e5da5Sopenharmony_ci                                                 transformation_context));
379fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
380fd4e5da5Sopenharmony_ci                        &transformation_context);
381fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
382fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
383fd4e5da5Sopenharmony_ci
384fd4e5da5Sopenharmony_ci  // No synonyms that involve the original object - %30 - should have been
385fd4e5da5Sopenharmony_ci  // added.
386fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
387fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {0}), MakeDataDescriptor(50, {0})));
388fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
389fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 1}), MakeDataDescriptor(50, {1, 1})));
390fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
391fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 2}), MakeDataDescriptor(50, {1, 2})));
392fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
393fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 0, 1}), MakeDataDescriptor(50, {1, 0, 1})));
394fd4e5da5Sopenharmony_ci  // We *should* have a synonym between %11 and the component of %50 into which
395fd4e5da5Sopenharmony_ci  // it has been inserted.
396fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
397fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {1, 0, 0}), MakeDataDescriptor(11, {})));
398fd4e5da5Sopenharmony_ci}
399fd4e5da5Sopenharmony_ci
400fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, IrrelevantObjectNoSynonyms) {
401fd4e5da5Sopenharmony_ci  std::string shader = R"(
402fd4e5da5Sopenharmony_ci               OpCapability Shader
403fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
404fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
405fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
406fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
407fd4e5da5Sopenharmony_ci               OpSource ESSL 310
408fd4e5da5Sopenharmony_ci               OpName %4 "main"
409fd4e5da5Sopenharmony_ci               OpName %8 "i1"
410fd4e5da5Sopenharmony_ci               OpName %10 "i2"
411fd4e5da5Sopenharmony_ci               OpName %12 "base"
412fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
413fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
414fd4e5da5Sopenharmony_ci               OpName %14 "b"
415fd4e5da5Sopenharmony_ci               OpName %18 "level_1"
416fd4e5da5Sopenharmony_ci               OpMemberName %18 0 "b1"
417fd4e5da5Sopenharmony_ci               OpMemberName %18 1 "b2"
418fd4e5da5Sopenharmony_ci               OpMemberName %18 2 "b3"
419fd4e5da5Sopenharmony_ci               OpName %20 "l1"
420fd4e5da5Sopenharmony_ci               OpName %25 "level_2"
421fd4e5da5Sopenharmony_ci               OpMemberName %25 0 "c1"
422fd4e5da5Sopenharmony_ci               OpMemberName %25 1 "c2"
423fd4e5da5Sopenharmony_ci               OpName %27 "l2"
424fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
425fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
426fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
427fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
428fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
429fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
430fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
431fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
432fd4e5da5Sopenharmony_ci         %18 = OpTypeStruct %12 %12 %12
433fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Function %18
434fd4e5da5Sopenharmony_ci         %25 = OpTypeStruct %18 %18
435fd4e5da5Sopenharmony_ci         %26 = OpTypePointer Function %25
436fd4e5da5Sopenharmony_ci         %31 = OpTypeBool
437fd4e5da5Sopenharmony_ci         %32 = OpConstantTrue %31
438fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
439fd4e5da5Sopenharmony_ci          %5 = OpLabel
440fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
441fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
442fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
443fd4e5da5Sopenharmony_ci         %20 = OpVariable %19 Function
444fd4e5da5Sopenharmony_ci         %27 = OpVariable %26 Function
445fd4e5da5Sopenharmony_ci               OpStore %8 %9
446fd4e5da5Sopenharmony_ci               OpStore %10 %11
447fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
448fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
449fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
450fd4e5da5Sopenharmony_ci               OpStore %14 %17
451fd4e5da5Sopenharmony_ci         %21 = OpLoad %12 %14
452fd4e5da5Sopenharmony_ci         %22 = OpLoad %12 %14
453fd4e5da5Sopenharmony_ci         %23 = OpLoad %12 %14
454fd4e5da5Sopenharmony_ci         %24 = OpCompositeConstruct %18 %21 %22 %23
455fd4e5da5Sopenharmony_ci               OpStore %20 %24
456fd4e5da5Sopenharmony_ci         %28 = OpLoad %18 %20
457fd4e5da5Sopenharmony_ci         %29 = OpLoad %18 %20
458fd4e5da5Sopenharmony_ci         %30 = OpCompositeConstruct %25 %28 %29
459fd4e5da5Sopenharmony_ci               OpStore %27 %30
460fd4e5da5Sopenharmony_ci               OpSelectionMerge %34 None
461fd4e5da5Sopenharmony_ci               OpBranchConditional %32 %33 %34
462fd4e5da5Sopenharmony_ci         %33 = OpLabel
463fd4e5da5Sopenharmony_ci               OpBranch %34
464fd4e5da5Sopenharmony_ci         %34 = OpLabel
465fd4e5da5Sopenharmony_ci               OpReturn
466fd4e5da5Sopenharmony_ci               OpFunctionEnd
467fd4e5da5Sopenharmony_ci    )";
468fd4e5da5Sopenharmony_ci
469fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
470fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
471fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
472fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
473fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
474fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
475fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
476fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
477fd4e5da5Sopenharmony_ci  // Add fact that the object is irrelevant.
478fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(11);
479fd4e5da5Sopenharmony_ci
480fd4e5da5Sopenharmony_ci  auto transformation_good_1 = TransformationCompositeInsert(
481fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(30, spv::Op::OpStore, 0), 50, 30, 11,
482fd4e5da5Sopenharmony_ci      {1, 0, 0});
483fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
484fd4e5da5Sopenharmony_ci                                                 transformation_context));
485fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
486fd4e5da5Sopenharmony_ci                        &transformation_context);
487fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
488fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
489fd4e5da5Sopenharmony_ci
490fd4e5da5Sopenharmony_ci  // Since %30 and %50 are not irrelevant, they should be synonymous at all
491fd4e5da5Sopenharmony_ci  // indices unaffected by the insertion.
492fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
493fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {0}), MakeDataDescriptor(50, {0})));
494fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
495fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 1}), MakeDataDescriptor(50, {1, 1})));
496fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
497fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 2}), MakeDataDescriptor(50, {1, 2})));
498fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
499fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 0, 1}), MakeDataDescriptor(50, {1, 0, 1})));
500fd4e5da5Sopenharmony_ci  // Since %11 is irrelevant it should not be synonymous with the component into
501fd4e5da5Sopenharmony_ci  // which it has been inserted.
502fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
503fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {1, 0, 0}), MakeDataDescriptor(11, {})));
504fd4e5da5Sopenharmony_ci}
505fd4e5da5Sopenharmony_ci
506fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, ApplicableCreatedSynonyms) {
507fd4e5da5Sopenharmony_ci  // This test handles cases where neither |composite| nor |object| is
508fd4e5da5Sopenharmony_ci  // irrelevant. The transformation should create synonyms.
509fd4e5da5Sopenharmony_ci  // The member composite has a different number of elements than the parent
510fd4e5da5Sopenharmony_ci  // composite.
511fd4e5da5Sopenharmony_ci
512fd4e5da5Sopenharmony_ci  std::string shader = R"(
513fd4e5da5Sopenharmony_ci               OpCapability Shader
514fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
515fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
516fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
517fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
518fd4e5da5Sopenharmony_ci               OpSource ESSL 310
519fd4e5da5Sopenharmony_ci               OpName %4 "main"
520fd4e5da5Sopenharmony_ci               OpName %8 "i1"
521fd4e5da5Sopenharmony_ci               OpName %10 "i2"
522fd4e5da5Sopenharmony_ci               OpName %12 "base"
523fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
524fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
525fd4e5da5Sopenharmony_ci               OpName %14 "b"
526fd4e5da5Sopenharmony_ci               OpName %18 "level_1"
527fd4e5da5Sopenharmony_ci               OpMemberName %18 0 "b1"
528fd4e5da5Sopenharmony_ci               OpMemberName %18 1 "b2"
529fd4e5da5Sopenharmony_ci               OpMemberName %18 2 "b3"
530fd4e5da5Sopenharmony_ci               OpName %20 "l1"
531fd4e5da5Sopenharmony_ci               OpName %25 "level_2"
532fd4e5da5Sopenharmony_ci               OpMemberName %25 0 "c1"
533fd4e5da5Sopenharmony_ci               OpMemberName %25 1 "c2"
534fd4e5da5Sopenharmony_ci               OpName %27 "l2"
535fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
536fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
537fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
538fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
539fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
540fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
541fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
542fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
543fd4e5da5Sopenharmony_ci         %18 = OpTypeStruct %12 %12 %12
544fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Function %18
545fd4e5da5Sopenharmony_ci         %25 = OpTypeStruct %18 %18
546fd4e5da5Sopenharmony_ci         %26 = OpTypePointer Function %25
547fd4e5da5Sopenharmony_ci         %31 = OpTypeBool
548fd4e5da5Sopenharmony_ci         %32 = OpConstantTrue %31
549fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
550fd4e5da5Sopenharmony_ci          %5 = OpLabel
551fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
552fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
553fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
554fd4e5da5Sopenharmony_ci         %20 = OpVariable %19 Function
555fd4e5da5Sopenharmony_ci         %27 = OpVariable %26 Function
556fd4e5da5Sopenharmony_ci               OpStore %8 %9
557fd4e5da5Sopenharmony_ci               OpStore %10 %11
558fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
559fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
560fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
561fd4e5da5Sopenharmony_ci               OpStore %14 %17
562fd4e5da5Sopenharmony_ci         %21 = OpLoad %12 %14
563fd4e5da5Sopenharmony_ci         %22 = OpLoad %12 %14
564fd4e5da5Sopenharmony_ci         %23 = OpLoad %12 %14
565fd4e5da5Sopenharmony_ci         %24 = OpCompositeConstruct %18 %21 %22 %23
566fd4e5da5Sopenharmony_ci               OpStore %20 %24
567fd4e5da5Sopenharmony_ci         %28 = OpLoad %18 %20
568fd4e5da5Sopenharmony_ci         %29 = OpLoad %18 %20
569fd4e5da5Sopenharmony_ci         %30 = OpCompositeConstruct %25 %28 %29
570fd4e5da5Sopenharmony_ci               OpStore %27 %30
571fd4e5da5Sopenharmony_ci               OpSelectionMerge %34 None
572fd4e5da5Sopenharmony_ci               OpBranchConditional %32 %33 %34
573fd4e5da5Sopenharmony_ci         %33 = OpLabel
574fd4e5da5Sopenharmony_ci               OpBranch %34
575fd4e5da5Sopenharmony_ci         %34 = OpLabel
576fd4e5da5Sopenharmony_ci               OpReturn
577fd4e5da5Sopenharmony_ci               OpFunctionEnd
578fd4e5da5Sopenharmony_ci    )";
579fd4e5da5Sopenharmony_ci
580fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
581fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
582fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
583fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
584fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
585fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
586fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
587fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
588fd4e5da5Sopenharmony_ci  auto transformation_good_1 = TransformationCompositeInsert(
589fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(30, spv::Op::OpStore, 0), 50, 30, 11,
590fd4e5da5Sopenharmony_ci      {1, 0, 0});
591fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_good_1.IsApplicable(context.get(),
592fd4e5da5Sopenharmony_ci                                                 transformation_context));
593fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation_good_1, context.get(),
594fd4e5da5Sopenharmony_ci                        &transformation_context);
595fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
596fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
597fd4e5da5Sopenharmony_ci
598fd4e5da5Sopenharmony_ci  // These synonyms should have been added.
599fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
600fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {0}), MakeDataDescriptor(50, {0})));
601fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
602fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 1}), MakeDataDescriptor(50, {1, 1})));
603fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
604fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 2}), MakeDataDescriptor(50, {1, 2})));
605fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
606fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 0, 1}), MakeDataDescriptor(50, {1, 0, 1})));
607fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
608fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {1, 0, 0}), MakeDataDescriptor(11, {})));
609fd4e5da5Sopenharmony_ci
610fd4e5da5Sopenharmony_ci  // These synonyms should not have been added.
611fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
612fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1}), MakeDataDescriptor(50, {1})));
613fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
614fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 0}), MakeDataDescriptor(50, {1, 0})));
615fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
616fd4e5da5Sopenharmony_ci      MakeDataDescriptor(30, {1, 0, 0}), MakeDataDescriptor(50, {1, 0, 0})));
617fd4e5da5Sopenharmony_ci
618fd4e5da5Sopenharmony_ci  auto transformation_good_2 = TransformationCompositeInsert(
619fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(50, spv::Op::OpStore, 0), 51, 50, 11,
620fd4e5da5Sopenharmony_ci      {0, 1, 1});
621fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_good_2.IsApplicable(context.get(),
622fd4e5da5Sopenharmony_ci                                                 transformation_context));
623fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation_good_2, context.get(),
624fd4e5da5Sopenharmony_ci                        &transformation_context);
625fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
626fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
627fd4e5da5Sopenharmony_ci
628fd4e5da5Sopenharmony_ci  // These synonyms should have been added.
629fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
630fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {1}), MakeDataDescriptor(51, {1})));
631fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
632fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0, 0}), MakeDataDescriptor(51, {0, 0})));
633fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
634fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0, 2}), MakeDataDescriptor(51, {0, 2})));
635fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
636fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0, 1, 0}), MakeDataDescriptor(51, {0, 1, 0})));
637fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
638fd4e5da5Sopenharmony_ci      MakeDataDescriptor(51, {0, 1, 1}), MakeDataDescriptor(11, {})));
639fd4e5da5Sopenharmony_ci
640fd4e5da5Sopenharmony_ci  // These synonyms should not have been added.
641fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
642fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0}), MakeDataDescriptor(51, {0})));
643fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
644fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0, 1}), MakeDataDescriptor(51, {0, 1})));
645fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
646fd4e5da5Sopenharmony_ci      MakeDataDescriptor(50, {0, 1, 1}), MakeDataDescriptor(51, {0, 1, 1})));
647fd4e5da5Sopenharmony_ci
648fd4e5da5Sopenharmony_ci  std::string after_transformations = R"(
649fd4e5da5Sopenharmony_ci               OpCapability Shader
650fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
651fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
652fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
653fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
654fd4e5da5Sopenharmony_ci               OpSource ESSL 310
655fd4e5da5Sopenharmony_ci               OpName %4 "main"
656fd4e5da5Sopenharmony_ci               OpName %8 "i1"
657fd4e5da5Sopenharmony_ci               OpName %10 "i2"
658fd4e5da5Sopenharmony_ci               OpName %12 "base"
659fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
660fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
661fd4e5da5Sopenharmony_ci               OpName %14 "b"
662fd4e5da5Sopenharmony_ci               OpName %18 "level_1"
663fd4e5da5Sopenharmony_ci               OpMemberName %18 0 "b1"
664fd4e5da5Sopenharmony_ci               OpMemberName %18 1 "b2"
665fd4e5da5Sopenharmony_ci               OpMemberName %18 2 "b3"
666fd4e5da5Sopenharmony_ci               OpName %20 "l1"
667fd4e5da5Sopenharmony_ci               OpName %25 "level_2"
668fd4e5da5Sopenharmony_ci               OpMemberName %25 0 "c1"
669fd4e5da5Sopenharmony_ci               OpMemberName %25 1 "c2"
670fd4e5da5Sopenharmony_ci               OpName %27 "l2"
671fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
672fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
673fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
674fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
675fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
676fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
677fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
678fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
679fd4e5da5Sopenharmony_ci         %18 = OpTypeStruct %12 %12 %12
680fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Function %18
681fd4e5da5Sopenharmony_ci         %25 = OpTypeStruct %18 %18
682fd4e5da5Sopenharmony_ci         %26 = OpTypePointer Function %25
683fd4e5da5Sopenharmony_ci         %31 = OpTypeBool
684fd4e5da5Sopenharmony_ci         %32 = OpConstantTrue %31
685fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
686fd4e5da5Sopenharmony_ci          %5 = OpLabel
687fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
688fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
689fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
690fd4e5da5Sopenharmony_ci         %20 = OpVariable %19 Function
691fd4e5da5Sopenharmony_ci         %27 = OpVariable %26 Function
692fd4e5da5Sopenharmony_ci               OpStore %8 %9
693fd4e5da5Sopenharmony_ci               OpStore %10 %11
694fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
695fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
696fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
697fd4e5da5Sopenharmony_ci               OpStore %14 %17
698fd4e5da5Sopenharmony_ci         %21 = OpLoad %12 %14
699fd4e5da5Sopenharmony_ci         %22 = OpLoad %12 %14
700fd4e5da5Sopenharmony_ci         %23 = OpLoad %12 %14
701fd4e5da5Sopenharmony_ci         %24 = OpCompositeConstruct %18 %21 %22 %23
702fd4e5da5Sopenharmony_ci               OpStore %20 %24
703fd4e5da5Sopenharmony_ci         %28 = OpLoad %18 %20
704fd4e5da5Sopenharmony_ci         %29 = OpLoad %18 %20
705fd4e5da5Sopenharmony_ci         %30 = OpCompositeConstruct %25 %28 %29
706fd4e5da5Sopenharmony_ci         %50 = OpCompositeInsert %25 %11 %30 1 0 0
707fd4e5da5Sopenharmony_ci         %51 = OpCompositeInsert %25 %11 %50 0 1 1
708fd4e5da5Sopenharmony_ci               OpStore %27 %30
709fd4e5da5Sopenharmony_ci               OpSelectionMerge %34 None
710fd4e5da5Sopenharmony_ci               OpBranchConditional %32 %33 %34
711fd4e5da5Sopenharmony_ci         %33 = OpLabel
712fd4e5da5Sopenharmony_ci               OpBranch %34
713fd4e5da5Sopenharmony_ci         %34 = OpLabel
714fd4e5da5Sopenharmony_ci               OpReturn
715fd4e5da5Sopenharmony_ci               OpFunctionEnd
716fd4e5da5Sopenharmony_ci    )";
717fd4e5da5Sopenharmony_ci
718fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformations, context.get()));
719fd4e5da5Sopenharmony_ci}
720fd4e5da5Sopenharmony_ci
721fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, IdNotAvailableScenarios) {
722fd4e5da5Sopenharmony_ci  // This test handles cases where either the composite or the object is not
723fd4e5da5Sopenharmony_ci  // available before the |instruction_to_insert_before|.
724fd4e5da5Sopenharmony_ci
725fd4e5da5Sopenharmony_ci  std::string shader = R"(
726fd4e5da5Sopenharmony_ci               OpCapability Shader
727fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
728fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
729fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
730fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
731fd4e5da5Sopenharmony_ci               OpSource ESSL 310
732fd4e5da5Sopenharmony_ci               OpName %4 "main"
733fd4e5da5Sopenharmony_ci               OpName %8 "i1"
734fd4e5da5Sopenharmony_ci               OpName %10 "i2"
735fd4e5da5Sopenharmony_ci               OpName %12 "base"
736fd4e5da5Sopenharmony_ci               OpMemberName %12 0 "a1"
737fd4e5da5Sopenharmony_ci               OpMemberName %12 1 "a2"
738fd4e5da5Sopenharmony_ci               OpName %14 "b1"
739fd4e5da5Sopenharmony_ci               OpName %18 "b2"
740fd4e5da5Sopenharmony_ci               OpName %22 "lvl1"
741fd4e5da5Sopenharmony_ci               OpMemberName %22 0 "b1"
742fd4e5da5Sopenharmony_ci               OpMemberName %22 1 "b2"
743fd4e5da5Sopenharmony_ci               OpName %24 "l1"
744fd4e5da5Sopenharmony_ci               OpName %28 "i3"
745fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
746fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
747fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
748fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
749fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
750fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
751fd4e5da5Sopenharmony_ci         %12 = OpTypeStruct %6 %6
752fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
753fd4e5da5Sopenharmony_ci         %22 = OpTypeStruct %12 %12
754fd4e5da5Sopenharmony_ci         %23 = OpTypePointer Function %22
755fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
756fd4e5da5Sopenharmony_ci          %5 = OpLabel
757fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
758fd4e5da5Sopenharmony_ci         %10 = OpVariable %7 Function
759fd4e5da5Sopenharmony_ci         %14 = OpVariable %13 Function
760fd4e5da5Sopenharmony_ci         %18 = OpVariable %13 Function
761fd4e5da5Sopenharmony_ci         %24 = OpVariable %23 Function
762fd4e5da5Sopenharmony_ci         %28 = OpVariable %7 Function
763fd4e5da5Sopenharmony_ci               OpStore %8 %9
764fd4e5da5Sopenharmony_ci               OpStore %10 %11
765fd4e5da5Sopenharmony_ci         %15 = OpLoad %6 %8
766fd4e5da5Sopenharmony_ci         %16 = OpLoad %6 %10
767fd4e5da5Sopenharmony_ci         %17 = OpCompositeConstruct %12 %15 %16
768fd4e5da5Sopenharmony_ci               OpStore %14 %17
769fd4e5da5Sopenharmony_ci         %19 = OpLoad %6 %10
770fd4e5da5Sopenharmony_ci         %20 = OpLoad %6 %8
771fd4e5da5Sopenharmony_ci         %21 = OpCompositeConstruct %12 %19 %20
772fd4e5da5Sopenharmony_ci               OpStore %18 %21
773fd4e5da5Sopenharmony_ci         %25 = OpLoad %12 %14
774fd4e5da5Sopenharmony_ci         %26 = OpLoad %12 %18
775fd4e5da5Sopenharmony_ci         %27 = OpCompositeConstruct %22 %25 %26
776fd4e5da5Sopenharmony_ci               OpStore %24 %27
777fd4e5da5Sopenharmony_ci         %29 = OpLoad %6 %8
778fd4e5da5Sopenharmony_ci         %30 = OpLoad %6 %10
779fd4e5da5Sopenharmony_ci         %31 = OpIMul %6 %29 %30
780fd4e5da5Sopenharmony_ci               OpStore %28 %31
781fd4e5da5Sopenharmony_ci         %60 = OpCompositeConstruct %12 %20 %19
782fd4e5da5Sopenharmony_ci         %61 = OpCompositeConstruct %22 %26 %25
783fd4e5da5Sopenharmony_ci               OpReturn
784fd4e5da5Sopenharmony_ci               OpFunctionEnd
785fd4e5da5Sopenharmony_ci    )";
786fd4e5da5Sopenharmony_ci
787fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
788fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
789fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
790fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
791fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
792fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
793fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
794fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
795fd4e5da5Sopenharmony_ci  // Bad: The object with |object_id| is not available at
796fd4e5da5Sopenharmony_ci  // |instruction_to_insert_before|.
797fd4e5da5Sopenharmony_ci  auto transformation_bad_1 = TransformationCompositeInsert(
798fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(31, spv::Op::OpIMul, 0), 50, 27, 60, {1});
799fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
800fd4e5da5Sopenharmony_ci      transformation_bad_1.IsApplicable(context.get(), transformation_context));
801fd4e5da5Sopenharmony_ci
802fd4e5da5Sopenharmony_ci  // Bad: The composite with |composite_id| is not available at
803fd4e5da5Sopenharmony_ci  // |instruction_to_insert_before|.
804fd4e5da5Sopenharmony_ci  auto transformation_bad_2 = TransformationCompositeInsert(
805fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(31, spv::Op::OpIMul, 0), 50, 61, 21, {1});
806fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
807fd4e5da5Sopenharmony_ci      transformation_bad_2.IsApplicable(context.get(), transformation_context));
808fd4e5da5Sopenharmony_ci
809fd4e5da5Sopenharmony_ci  // Bad: The |instruction_to_insert_before| is the composite itself and is
810fd4e5da5Sopenharmony_ci  // available.
811fd4e5da5Sopenharmony_ci  auto transformation_bad_3 = TransformationCompositeInsert(
812fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(61, spv::Op::OpCompositeConstruct, 0), 50, 61,
813fd4e5da5Sopenharmony_ci      21, {1});
814fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
815fd4e5da5Sopenharmony_ci      transformation_bad_3.IsApplicable(context.get(), transformation_context));
816fd4e5da5Sopenharmony_ci
817fd4e5da5Sopenharmony_ci  // Bad: The |instruction_to_insert_before| is the object itself and is not
818fd4e5da5Sopenharmony_ci  // available.
819fd4e5da5Sopenharmony_ci  auto transformation_bad_4 = TransformationCompositeInsert(
820fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(60, spv::Op::OpCompositeConstruct, 0), 50, 27,
821fd4e5da5Sopenharmony_ci      60, {1});
822fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
823fd4e5da5Sopenharmony_ci      transformation_bad_4.IsApplicable(context.get(), transformation_context));
824fd4e5da5Sopenharmony_ci}
825fd4e5da5Sopenharmony_ci
826fd4e5da5Sopenharmony_ciTEST(TransformationCompositeInsertTest, CompositeInsertionWithIrrelevantIds) {
827fd4e5da5Sopenharmony_ci  // This checks that we do *not* get data synonym facts when we do composite
828fd4e5da5Sopenharmony_ci  // insertion using irrelevant ids or in dead blocks.
829fd4e5da5Sopenharmony_ci
830fd4e5da5Sopenharmony_ci  std::string shader = R"(
831fd4e5da5Sopenharmony_ci               OpCapability Shader
832fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
833fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
834fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %12 "main"
835fd4e5da5Sopenharmony_ci               OpExecutionMode %12 OriginUpperLeft
836fd4e5da5Sopenharmony_ci               OpSource ESSL 310
837fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
838fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
839fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
840fd4e5da5Sopenharmony_ci          %7 = OpTypeVector %6 2
841fd4e5da5Sopenharmony_ci          %8 = OpConstant %6 0
842fd4e5da5Sopenharmony_ci          %9 = OpConstantComposite %7 %8 %8
843fd4e5da5Sopenharmony_ci         %10 = OpTypeBool
844fd4e5da5Sopenharmony_ci         %11 = OpConstantFalse %10
845fd4e5da5Sopenharmony_ci         %16 = OpConstant %6 0
846fd4e5da5Sopenharmony_ci         %17 = OpConstant %6 1
847fd4e5da5Sopenharmony_ci         %18 = OpConstantComposite %7 %8 %8
848fd4e5da5Sopenharmony_ci         %12 = OpFunction %2 None %3
849fd4e5da5Sopenharmony_ci         %13 = OpLabel
850fd4e5da5Sopenharmony_ci               OpSelectionMerge %15 None
851fd4e5da5Sopenharmony_ci               OpBranchConditional %11 %14 %15
852fd4e5da5Sopenharmony_ci         %14 = OpLabel
853fd4e5da5Sopenharmony_ci               OpBranch %15
854fd4e5da5Sopenharmony_ci         %15 = OpLabel
855fd4e5da5Sopenharmony_ci               OpReturn
856fd4e5da5Sopenharmony_ci               OpFunctionEnd
857fd4e5da5Sopenharmony_ci  )";
858fd4e5da5Sopenharmony_ci
859fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
860fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
861fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
862fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
863fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
864fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
865fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
866fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
867fd4e5da5Sopenharmony_ci
868fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(14);
869fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(16);
870fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactIdIsIrrelevant(18);
871fd4e5da5Sopenharmony_ci
872fd4e5da5Sopenharmony_ci  // Leads to synonyms - nothing is irrelevant.
873fd4e5da5Sopenharmony_ci  auto transformation1 = TransformationCompositeInsert(
874fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(13, spv::Op::OpSelectionMerge, 0), 100, 9, 17,
875fd4e5da5Sopenharmony_ci      {0});
876fd4e5da5Sopenharmony_ci  ASSERT_TRUE(
877fd4e5da5Sopenharmony_ci      transformation1.IsApplicable(context.get(), transformation_context));
878fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation1, context.get(),
879fd4e5da5Sopenharmony_ci                        &transformation_context);
880fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
881fd4e5da5Sopenharmony_ci      MakeDataDescriptor(100, {0}), MakeDataDescriptor(17, {})));
882fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
883fd4e5da5Sopenharmony_ci      MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {1})));
884fd4e5da5Sopenharmony_ci
885fd4e5da5Sopenharmony_ci  // Because %16 is irrelevant, we don't get a synonym with the component to
886fd4e5da5Sopenharmony_ci  // which it has been inserted (but we do for the other component).
887fd4e5da5Sopenharmony_ci  auto transformation2 = TransformationCompositeInsert(
888fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(13, spv::Op::OpSelectionMerge, 0), 101, 9, 16,
889fd4e5da5Sopenharmony_ci      {0});
890fd4e5da5Sopenharmony_ci  ASSERT_TRUE(
891fd4e5da5Sopenharmony_ci      transformation2.IsApplicable(context.get(), transformation_context));
892fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation2, context.get(),
893fd4e5da5Sopenharmony_ci                        &transformation_context);
894fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
895fd4e5da5Sopenharmony_ci      MakeDataDescriptor(101, {0}), MakeDataDescriptor(16, {})));
896fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
897fd4e5da5Sopenharmony_ci      MakeDataDescriptor(101, {1}), MakeDataDescriptor(9, {1})));
898fd4e5da5Sopenharmony_ci
899fd4e5da5Sopenharmony_ci  // Because %18 is irrelevant we only get a synonym for the component into
900fd4e5da5Sopenharmony_ci  // which insertion has taken place.
901fd4e5da5Sopenharmony_ci  auto transformation3 = TransformationCompositeInsert(
902fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(13, spv::Op::OpSelectionMerge, 0), 102, 18, 17,
903fd4e5da5Sopenharmony_ci      {0});
904fd4e5da5Sopenharmony_ci  ASSERT_TRUE(
905fd4e5da5Sopenharmony_ci      transformation3.IsApplicable(context.get(), transformation_context));
906fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation3, context.get(),
907fd4e5da5Sopenharmony_ci                        &transformation_context);
908fd4e5da5Sopenharmony_ci  ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
909fd4e5da5Sopenharmony_ci      MakeDataDescriptor(102, {0}), MakeDataDescriptor(17, {})));
910fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
911fd4e5da5Sopenharmony_ci      MakeDataDescriptor(102, {1}), MakeDataDescriptor(18, {1})));
912fd4e5da5Sopenharmony_ci
913fd4e5da5Sopenharmony_ci  // Does not lead to synonyms as block %14 is dead.
914fd4e5da5Sopenharmony_ci  auto transformation4 = TransformationCompositeInsert(
915fd4e5da5Sopenharmony_ci      MakeInstructionDescriptor(14, spv::Op::OpBranch, 0), 103, 9, 17, {0});
916fd4e5da5Sopenharmony_ci  ASSERT_TRUE(
917fd4e5da5Sopenharmony_ci      transformation4.IsApplicable(context.get(), transformation_context));
918fd4e5da5Sopenharmony_ci  ApplyAndCheckFreshIds(transformation4, context.get(),
919fd4e5da5Sopenharmony_ci                        &transformation_context);
920fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
921fd4e5da5Sopenharmony_ci      MakeDataDescriptor(103, {0}), MakeDataDescriptor(17, {})));
922fd4e5da5Sopenharmony_ci  ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
923fd4e5da5Sopenharmony_ci      MakeDataDescriptor(103, {1}), MakeDataDescriptor(9, {1})));
924fd4e5da5Sopenharmony_ci
925fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
926fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
927fd4e5da5Sopenharmony_ci}
928fd4e5da5Sopenharmony_ci
929fd4e5da5Sopenharmony_ci}  // namespace
930fd4e5da5Sopenharmony_ci}  // namespace fuzz
931fd4e5da5Sopenharmony_ci}  // namespace spvtools
932