1fd4e5da5Sopenharmony_ci// Copyright (c) 2019 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_load.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
18fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h"
19fd4e5da5Sopenharmony_ci#include "source/fuzz/instruction_descriptor.h"
20fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h"
21fd4e5da5Sopenharmony_ci
22fd4e5da5Sopenharmony_cinamespace spvtools {
23fd4e5da5Sopenharmony_cinamespace fuzz {
24fd4e5da5Sopenharmony_cinamespace {
25fd4e5da5Sopenharmony_ci
26fd4e5da5Sopenharmony_ciTEST(TransformationLoadTest, BasicTest) {
27fd4e5da5Sopenharmony_ci  std::string shader = R"(
28fd4e5da5Sopenharmony_ci               OpCapability Shader
29fd4e5da5Sopenharmony_ci               OpCapability VariablePointers
30fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
31fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
32fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
33fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
34fd4e5da5Sopenharmony_ci               OpSource ESSL 310
35fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
36fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
37fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
38fd4e5da5Sopenharmony_ci          %7 = OpTypeFloat 32
39fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %6 %7
40fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
41fd4e5da5Sopenharmony_ci         %10 = OpTypeFunction %6 %9
42fd4e5da5Sopenharmony_ci         %14 = OpConstant %6 0
43fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %6
44fd4e5da5Sopenharmony_ci         %51 = OpTypePointer Private %6
45fd4e5da5Sopenharmony_ci         %21 = OpConstant %6 2
46fd4e5da5Sopenharmony_ci         %23 = OpConstant %6 1
47fd4e5da5Sopenharmony_ci         %24 = OpConstant %7 1
48fd4e5da5Sopenharmony_ci         %25 = OpTypePointer Function %7
49fd4e5da5Sopenharmony_ci         %50 = OpTypePointer Private %7
50fd4e5da5Sopenharmony_ci         %34 = OpTypeBool
51fd4e5da5Sopenharmony_ci         %35 = OpConstantFalse %34
52fd4e5da5Sopenharmony_ci         %60 = OpConstantNull %50
53fd4e5da5Sopenharmony_ci         %52 = OpVariable %50 Private
54fd4e5da5Sopenharmony_ci         %53 = OpVariable %51 Private
55fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
56fd4e5da5Sopenharmony_ci          %5 = OpLabel
57fd4e5da5Sopenharmony_ci         %20 = OpVariable %9 Function
58fd4e5da5Sopenharmony_ci         %27 = OpVariable %9 Function ; irrelevant
59fd4e5da5Sopenharmony_ci         %22 = OpAccessChain %15 %20 %14
60fd4e5da5Sopenharmony_ci         %44 = OpCopyObject %9 %20
61fd4e5da5Sopenharmony_ci         %26 = OpAccessChain %25 %20 %23
62fd4e5da5Sopenharmony_ci         %29 = OpFunctionCall %6 %12 %27
63fd4e5da5Sopenharmony_ci         %30 = OpAccessChain %15 %20 %14
64fd4e5da5Sopenharmony_ci         %45 = OpCopyObject %15 %30
65fd4e5da5Sopenharmony_ci         %33 = OpAccessChain %15 %20 %14
66fd4e5da5Sopenharmony_ci               OpSelectionMerge %37 None
67fd4e5da5Sopenharmony_ci               OpBranchConditional %35 %36 %37
68fd4e5da5Sopenharmony_ci         %36 = OpLabel
69fd4e5da5Sopenharmony_ci         %38 = OpAccessChain %15 %20 %14
70fd4e5da5Sopenharmony_ci         %40 = OpAccessChain %15 %20 %14
71fd4e5da5Sopenharmony_ci         %43 = OpAccessChain %15 %20 %14
72fd4e5da5Sopenharmony_ci               OpBranch %37
73fd4e5da5Sopenharmony_ci         %37 = OpLabel
74fd4e5da5Sopenharmony_ci               OpReturn
75fd4e5da5Sopenharmony_ci               OpFunctionEnd
76fd4e5da5Sopenharmony_ci         %12 = OpFunction %6 None %10
77fd4e5da5Sopenharmony_ci         %11 = OpFunctionParameter %9 ; irrelevant
78fd4e5da5Sopenharmony_ci         %13 = OpLabel
79fd4e5da5Sopenharmony_ci         %46 = OpCopyObject %9 %11 ; irrelevant
80fd4e5da5Sopenharmony_ci         %16 = OpAccessChain %15 %11 %14 ; irrelevant
81fd4e5da5Sopenharmony_ci               OpReturnValue %21
82fd4e5da5Sopenharmony_ci               OpFunctionEnd
83fd4e5da5Sopenharmony_ci  )";
84fd4e5da5Sopenharmony_ci
85fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
86fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
87fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
88fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
89fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
90fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
91fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
92fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
93fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
94fd4e5da5Sopenharmony_ci      27);
95fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
96fd4e5da5Sopenharmony_ci      11);
97fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
98fd4e5da5Sopenharmony_ci      46);
99fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
100fd4e5da5Sopenharmony_ci      16);
101fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
102fd4e5da5Sopenharmony_ci      52);
103fd4e5da5Sopenharmony_ci
104fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(36);
105fd4e5da5Sopenharmony_ci
106fd4e5da5Sopenharmony_ci  // Variables with pointee types:
107fd4e5da5Sopenharmony_ci  //  52 - ptr_to(7)
108fd4e5da5Sopenharmony_ci  //  53 - ptr_to(6)
109fd4e5da5Sopenharmony_ci  //  20 - ptr_to(8)
110fd4e5da5Sopenharmony_ci  //  27 - ptr_to(8) - irrelevant
111fd4e5da5Sopenharmony_ci
112fd4e5da5Sopenharmony_ci  // Access chains with pointee type:
113fd4e5da5Sopenharmony_ci  //  22 - ptr_to(6)
114fd4e5da5Sopenharmony_ci  //  26 - ptr_to(6)
115fd4e5da5Sopenharmony_ci  //  30 - ptr_to(6)
116fd4e5da5Sopenharmony_ci  //  33 - ptr_to(6)
117fd4e5da5Sopenharmony_ci  //  38 - ptr_to(6)
118fd4e5da5Sopenharmony_ci  //  40 - ptr_to(6)
119fd4e5da5Sopenharmony_ci  //  43 - ptr_to(6)
120fd4e5da5Sopenharmony_ci  //  16 - ptr_to(6) - irrelevant
121fd4e5da5Sopenharmony_ci
122fd4e5da5Sopenharmony_ci  // Copied object with pointee type:
123fd4e5da5Sopenharmony_ci  //  44 - ptr_to(8)
124fd4e5da5Sopenharmony_ci  //  45 - ptr_to(6)
125fd4e5da5Sopenharmony_ci  //  46 - ptr_to(8) - irrelevant
126fd4e5da5Sopenharmony_ci
127fd4e5da5Sopenharmony_ci  // Function parameters with pointee type:
128fd4e5da5Sopenharmony_ci  //  11 - ptr_to(8) - irrelevant
129fd4e5da5Sopenharmony_ci
130fd4e5da5Sopenharmony_ci  // Pointers that cannot be used:
131fd4e5da5Sopenharmony_ci  //  60 - null
132fd4e5da5Sopenharmony_ci
133fd4e5da5Sopenharmony_ci  // Bad: id is not fresh
134fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
135fd4e5da5Sopenharmony_ci                   33, 33, false, 0, 0,
136fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
137fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
138fd4e5da5Sopenharmony_ci  // Bad: attempt to load from 11 from outside its function
139fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
140fd4e5da5Sopenharmony_ci                   100, 11, false, 0, 0,
141fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
142fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
143fd4e5da5Sopenharmony_ci
144fd4e5da5Sopenharmony_ci  // Bad: pointer is not available
145fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
146fd4e5da5Sopenharmony_ci                   100, 33, false, 0, 0,
147fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(45, spv::Op::OpCopyObject, 0))
148fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
149fd4e5da5Sopenharmony_ci
150fd4e5da5Sopenharmony_ci  // Bad: attempt to insert before OpVariable
151fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
152fd4e5da5Sopenharmony_ci      TransformationLoad(100, 27, false, 0, 0,
153fd4e5da5Sopenharmony_ci                         MakeInstructionDescriptor(27, spv::Op::OpVariable, 0))
154fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
155fd4e5da5Sopenharmony_ci
156fd4e5da5Sopenharmony_ci  // Bad: pointer id does not exist
157fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
158fd4e5da5Sopenharmony_ci                   100, 1000, false, 0, 0,
159fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
160fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
161fd4e5da5Sopenharmony_ci
162fd4e5da5Sopenharmony_ci  // Bad: pointer id exists but does not have a type
163fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
164fd4e5da5Sopenharmony_ci                   100, 5, false, 0, 0,
165fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
166fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
167fd4e5da5Sopenharmony_ci
168fd4e5da5Sopenharmony_ci  // Bad: pointer id exists and has a type, but is not a pointer
169fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
170fd4e5da5Sopenharmony_ci                   100, 24, false, 0, 0,
171fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
172fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
173fd4e5da5Sopenharmony_ci
174fd4e5da5Sopenharmony_ci  // Bad: attempt to load from null pointer
175fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
176fd4e5da5Sopenharmony_ci                   100, 60, false, 0, 0,
177fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0))
178fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
179fd4e5da5Sopenharmony_ci
180fd4e5da5Sopenharmony_ci  // Bad: %40 is not available at the program point
181fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
182fd4e5da5Sopenharmony_ci      TransformationLoad(100, 40, false, 0, 0,
183fd4e5da5Sopenharmony_ci                         MakeInstructionDescriptor(37, spv::Op::OpReturn, 0))
184fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
185fd4e5da5Sopenharmony_ci
186fd4e5da5Sopenharmony_ci  // Bad: The described instruction does not exist
187fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
188fd4e5da5Sopenharmony_ci      TransformationLoad(100, 33, false, 0, 0,
189fd4e5da5Sopenharmony_ci                         MakeInstructionDescriptor(1000, spv::Op::OpReturn, 0))
190fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
191fd4e5da5Sopenharmony_ci
192fd4e5da5Sopenharmony_ci  {
193fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
194fd4e5da5Sopenharmony_ci        100, 33, false, 0, 0,
195fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(38, spv::Op::OpAccessChain, 0));
196fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
197fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
198fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
199fd4e5da5Sopenharmony_ci                          &transformation_context);
200fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
201fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
202fd4e5da5Sopenharmony_ci  }
203fd4e5da5Sopenharmony_ci
204fd4e5da5Sopenharmony_ci  {
205fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
206fd4e5da5Sopenharmony_ci        101, 46, false, 0, 0,
207fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(16, spv::Op::OpReturnValue, 0));
208fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
209fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
210fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
211fd4e5da5Sopenharmony_ci                          &transformation_context);
212fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
213fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
214fd4e5da5Sopenharmony_ci  }
215fd4e5da5Sopenharmony_ci
216fd4e5da5Sopenharmony_ci  {
217fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
218fd4e5da5Sopenharmony_ci        102, 16, false, 0, 0,
219fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(16, spv::Op::OpReturnValue, 0));
220fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
221fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
222fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
223fd4e5da5Sopenharmony_ci                          &transformation_context);
224fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
225fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
226fd4e5da5Sopenharmony_ci  }
227fd4e5da5Sopenharmony_ci
228fd4e5da5Sopenharmony_ci  {
229fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
230fd4e5da5Sopenharmony_ci        103, 40, false, 0, 0,
231fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(43, spv::Op::OpAccessChain, 0));
232fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
233fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
234fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
235fd4e5da5Sopenharmony_ci                          &transformation_context);
236fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
237fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
238fd4e5da5Sopenharmony_ci  }
239fd4e5da5Sopenharmony_ci
240fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
241fd4e5da5Sopenharmony_ci               OpCapability Shader
242fd4e5da5Sopenharmony_ci               OpCapability VariablePointers
243fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
244fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
245fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
246fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
247fd4e5da5Sopenharmony_ci               OpSource ESSL 310
248fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
249fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
250fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
251fd4e5da5Sopenharmony_ci          %7 = OpTypeFloat 32
252fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %6 %7
253fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
254fd4e5da5Sopenharmony_ci         %10 = OpTypeFunction %6 %9
255fd4e5da5Sopenharmony_ci         %14 = OpConstant %6 0
256fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %6
257fd4e5da5Sopenharmony_ci         %51 = OpTypePointer Private %6
258fd4e5da5Sopenharmony_ci         %21 = OpConstant %6 2
259fd4e5da5Sopenharmony_ci         %23 = OpConstant %6 1
260fd4e5da5Sopenharmony_ci         %24 = OpConstant %7 1
261fd4e5da5Sopenharmony_ci         %25 = OpTypePointer Function %7
262fd4e5da5Sopenharmony_ci         %50 = OpTypePointer Private %7
263fd4e5da5Sopenharmony_ci         %34 = OpTypeBool
264fd4e5da5Sopenharmony_ci         %35 = OpConstantFalse %34
265fd4e5da5Sopenharmony_ci         %60 = OpConstantNull %50
266fd4e5da5Sopenharmony_ci         %52 = OpVariable %50 Private
267fd4e5da5Sopenharmony_ci         %53 = OpVariable %51 Private
268fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
269fd4e5da5Sopenharmony_ci          %5 = OpLabel
270fd4e5da5Sopenharmony_ci         %20 = OpVariable %9 Function
271fd4e5da5Sopenharmony_ci         %27 = OpVariable %9 Function ; irrelevant
272fd4e5da5Sopenharmony_ci         %22 = OpAccessChain %15 %20 %14
273fd4e5da5Sopenharmony_ci         %44 = OpCopyObject %9 %20
274fd4e5da5Sopenharmony_ci         %26 = OpAccessChain %25 %20 %23
275fd4e5da5Sopenharmony_ci         %29 = OpFunctionCall %6 %12 %27
276fd4e5da5Sopenharmony_ci         %30 = OpAccessChain %15 %20 %14
277fd4e5da5Sopenharmony_ci         %45 = OpCopyObject %15 %30
278fd4e5da5Sopenharmony_ci         %33 = OpAccessChain %15 %20 %14
279fd4e5da5Sopenharmony_ci               OpSelectionMerge %37 None
280fd4e5da5Sopenharmony_ci               OpBranchConditional %35 %36 %37
281fd4e5da5Sopenharmony_ci         %36 = OpLabel
282fd4e5da5Sopenharmony_ci        %100 = OpLoad %6 %33
283fd4e5da5Sopenharmony_ci         %38 = OpAccessChain %15 %20 %14
284fd4e5da5Sopenharmony_ci         %40 = OpAccessChain %15 %20 %14
285fd4e5da5Sopenharmony_ci        %103 = OpLoad %6 %40
286fd4e5da5Sopenharmony_ci         %43 = OpAccessChain %15 %20 %14
287fd4e5da5Sopenharmony_ci               OpBranch %37
288fd4e5da5Sopenharmony_ci         %37 = OpLabel
289fd4e5da5Sopenharmony_ci               OpReturn
290fd4e5da5Sopenharmony_ci               OpFunctionEnd
291fd4e5da5Sopenharmony_ci         %12 = OpFunction %6 None %10
292fd4e5da5Sopenharmony_ci         %11 = OpFunctionParameter %9 ; irrelevant
293fd4e5da5Sopenharmony_ci         %13 = OpLabel
294fd4e5da5Sopenharmony_ci         %46 = OpCopyObject %9 %11 ; irrelevant
295fd4e5da5Sopenharmony_ci         %16 = OpAccessChain %15 %11 %14 ; irrelevant
296fd4e5da5Sopenharmony_ci        %101 = OpLoad %8 %46
297fd4e5da5Sopenharmony_ci        %102 = OpLoad %6 %16
298fd4e5da5Sopenharmony_ci               OpReturnValue %21
299fd4e5da5Sopenharmony_ci               OpFunctionEnd
300fd4e5da5Sopenharmony_ci  )";
301fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
302fd4e5da5Sopenharmony_ci}
303fd4e5da5Sopenharmony_ci
304fd4e5da5Sopenharmony_ciTEST(TransformationLoadTest, AtomicLoadTestCase) {
305fd4e5da5Sopenharmony_ci  const std::string shader = R"(
306fd4e5da5Sopenharmony_ci               OpCapability Shader
307fd4e5da5Sopenharmony_ci               OpCapability Int8
308fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
309fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
310fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
311fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
312fd4e5da5Sopenharmony_ci               OpSource ESSL 320
313fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
314fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
315fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
316fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 8 1
317fd4e5da5Sopenharmony_ci          %9 = OpTypeInt 32 0
318fd4e5da5Sopenharmony_ci         %26 = OpTypeFloat 32
319fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %6
320fd4e5da5Sopenharmony_ci         %10 = OpTypePointer StorageBuffer %8
321fd4e5da5Sopenharmony_ci         %11 = OpVariable %10 StorageBuffer
322fd4e5da5Sopenharmony_ci         %19 = OpConstant %26 0
323fd4e5da5Sopenharmony_ci         %18 = OpConstant %9 1
324fd4e5da5Sopenharmony_ci         %12 = OpConstant %6 0
325fd4e5da5Sopenharmony_ci         %13 = OpTypePointer StorageBuffer %6
326fd4e5da5Sopenharmony_ci         %15 = OpConstant %6 4
327fd4e5da5Sopenharmony_ci         %16 = OpConstant %6 7
328fd4e5da5Sopenharmony_ci         %17 = OpConstant %7 4
329fd4e5da5Sopenharmony_ci         %20 = OpConstant %9 64
330fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
331fd4e5da5Sopenharmony_ci          %5 = OpLabel
332fd4e5da5Sopenharmony_ci         %14 = OpAccessChain %13 %11 %12
333fd4e5da5Sopenharmony_ci         %24 = OpAccessChain %13 %11 %12
334fd4e5da5Sopenharmony_ci               OpReturn
335fd4e5da5Sopenharmony_ci               OpFunctionEnd
336fd4e5da5Sopenharmony_ci  )";
337fd4e5da5Sopenharmony_ci
338fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
339fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
340fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
341fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
342fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
343fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
344fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
345fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
346fd4e5da5Sopenharmony_ci
347fd4e5da5Sopenharmony_ci  // Bad: id is not fresh.
348fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
349fd4e5da5Sopenharmony_ci                   14, 14, true, 15, 20,
350fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
351fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
352fd4e5da5Sopenharmony_ci
353fd4e5da5Sopenharmony_ci  // Bad: id 100 of memory scope instruction does not exist.
354fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
355fd4e5da5Sopenharmony_ci                   21, 14, true, 100, 20,
356fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
357fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
358fd4e5da5Sopenharmony_ci  // Bad: id 100 of memory semantics instruction does not exist.
359fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
360fd4e5da5Sopenharmony_ci                   21, 14, true, 15, 100,
361fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
362fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
363fd4e5da5Sopenharmony_ci  // Bad: memory scope should be |OpConstant| opcode.
364fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
365fd4e5da5Sopenharmony_ci                   21, 14, true, 5, 20,
366fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
367fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
368fd4e5da5Sopenharmony_ci  // Bad: memory semantics should be |OpConstant| opcode.
369fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
370fd4e5da5Sopenharmony_ci                   21, 14, true, 15, 5,
371fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
372fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
373fd4e5da5Sopenharmony_ci
374fd4e5da5Sopenharmony_ci  // Bad: The memory scope instruction must have an Integer operand.
375fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
376fd4e5da5Sopenharmony_ci                   21, 14, true, 15, 19,
377fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
378fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
379fd4e5da5Sopenharmony_ci  // Bad: The memory memory semantics instruction must have an Integer operand.
380fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
381fd4e5da5Sopenharmony_ci                   21, 14, true, 19, 20,
382fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
383fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
384fd4e5da5Sopenharmony_ci
385fd4e5da5Sopenharmony_ci  // Bad: Integer size of the memory scope must be equal to 32 bits.
386fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
387fd4e5da5Sopenharmony_ci                   21, 14, true, 17, 20,
388fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
389fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
390fd4e5da5Sopenharmony_ci
391fd4e5da5Sopenharmony_ci  // Bad: Integer size of memory semantics must be equal to 32 bits.
392fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
393fd4e5da5Sopenharmony_ci                   21, 14, true, 15, 17,
394fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
395fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
396fd4e5da5Sopenharmony_ci
397fd4e5da5Sopenharmony_ci  // Bad: memory scope value must be 4 (spv::Scope::Invocation).
398fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
399fd4e5da5Sopenharmony_ci                   21, 14, true, 16, 20,
400fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
401fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
402fd4e5da5Sopenharmony_ci
403fd4e5da5Sopenharmony_ci  // Bad: memory semantics value must be either:
404fd4e5da5Sopenharmony_ci  // 64 (SpvMemorySemanticsUniformMemoryMask)
405fd4e5da5Sopenharmony_ci  // 256 (SpvMemorySemanticsWorkgroupMemoryMask)
406fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
407fd4e5da5Sopenharmony_ci                   21, 14, true, 15, 16,
408fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0))
409fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
410fd4e5da5Sopenharmony_ci
411fd4e5da5Sopenharmony_ci  // Bad: The described instruction does not exist
412fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
413fd4e5da5Sopenharmony_ci                   21, 14, false, 15, 20,
414fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(150, spv::Op::OpAccessChain, 0))
415fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
416fd4e5da5Sopenharmony_ci
417fd4e5da5Sopenharmony_ci  // Successful transformations.
418fd4e5da5Sopenharmony_ci  {
419fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
420fd4e5da5Sopenharmony_ci        21, 14, true, 15, 20,
421fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(24, spv::Op::OpAccessChain, 0));
422fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
423fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
424fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
425fd4e5da5Sopenharmony_ci                          &transformation_context);
426fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
427fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
428fd4e5da5Sopenharmony_ci  }
429fd4e5da5Sopenharmony_ci
430fd4e5da5Sopenharmony_ci  const std::string after_transformation = R"(
431fd4e5da5Sopenharmony_ci               OpCapability Shader
432fd4e5da5Sopenharmony_ci               OpCapability Int8
433fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
434fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
435fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
436fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
437fd4e5da5Sopenharmony_ci               OpSource ESSL 320
438fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
439fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
440fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
441fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 8 1
442fd4e5da5Sopenharmony_ci          %9 = OpTypeInt 32 0
443fd4e5da5Sopenharmony_ci         %26 = OpTypeFloat 32
444fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %6
445fd4e5da5Sopenharmony_ci         %10 = OpTypePointer StorageBuffer %8
446fd4e5da5Sopenharmony_ci         %11 = OpVariable %10 StorageBuffer
447fd4e5da5Sopenharmony_ci         %19 = OpConstant %26 0
448fd4e5da5Sopenharmony_ci         %18 = OpConstant %9 1
449fd4e5da5Sopenharmony_ci         %12 = OpConstant %6 0
450fd4e5da5Sopenharmony_ci         %13 = OpTypePointer StorageBuffer %6
451fd4e5da5Sopenharmony_ci         %15 = OpConstant %6 4
452fd4e5da5Sopenharmony_ci         %16 = OpConstant %6 7
453fd4e5da5Sopenharmony_ci         %17 = OpConstant %7 4
454fd4e5da5Sopenharmony_ci         %20 = OpConstant %9 64
455fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
456fd4e5da5Sopenharmony_ci          %5 = OpLabel
457fd4e5da5Sopenharmony_ci         %14 = OpAccessChain %13 %11 %12
458fd4e5da5Sopenharmony_ci         %21 = OpAtomicLoad %6 %14 %15 %20
459fd4e5da5Sopenharmony_ci         %24 = OpAccessChain %13 %11 %12
460fd4e5da5Sopenharmony_ci               OpReturn
461fd4e5da5Sopenharmony_ci               OpFunctionEnd
462fd4e5da5Sopenharmony_ci  )";
463fd4e5da5Sopenharmony_ci
464fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
465fd4e5da5Sopenharmony_ci}
466fd4e5da5Sopenharmony_ci
467fd4e5da5Sopenharmony_ciTEST(TransformationLoadTest, AtomicLoadTestCaseForWorkgroupMemory) {
468fd4e5da5Sopenharmony_ci  std::string shader = R"(
469fd4e5da5Sopenharmony_ci               OpCapability Shader
470fd4e5da5Sopenharmony_ci               OpCapability Int8
471fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
472fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
473fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
474fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
475fd4e5da5Sopenharmony_ci               OpSource ESSL 310
476fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
477fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
478fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
479fd4e5da5Sopenharmony_ci          %26 = OpTypeFloat 32
480fd4e5da5Sopenharmony_ci          %27 = OpTypeInt 8 1
481fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 32 0 ; 0 means unsigned
482fd4e5da5Sopenharmony_ci          %8 = OpConstant %7 0
483fd4e5da5Sopenharmony_ci         %17 = OpConstant %27 4
484fd4e5da5Sopenharmony_ci         %19 = OpConstant %26 0
485fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %6
486fd4e5da5Sopenharmony_ci         %13 = OpTypeStruct %6
487fd4e5da5Sopenharmony_ci         %12 = OpTypePointer Workgroup %13
488fd4e5da5Sopenharmony_ci         %11 = OpVariable %12 Workgroup
489fd4e5da5Sopenharmony_ci         %14 = OpConstant %6 0
490fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %6
491fd4e5da5Sopenharmony_ci         %51 = OpTypePointer Private %6
492fd4e5da5Sopenharmony_ci         %21 = OpConstant %6 4
493fd4e5da5Sopenharmony_ci         %23 = OpConstant %6 256
494fd4e5da5Sopenharmony_ci         %25 = OpTypePointer Function %7
495fd4e5da5Sopenharmony_ci         %50 = OpTypePointer Workgroup %6
496fd4e5da5Sopenharmony_ci         %34 = OpTypeBool
497fd4e5da5Sopenharmony_ci         %35 = OpConstantFalse %34
498fd4e5da5Sopenharmony_ci         %53 = OpVariable %51 Private
499fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
500fd4e5da5Sopenharmony_ci          %5 = OpLabel
501fd4e5da5Sopenharmony_ci               OpSelectionMerge %37 None
502fd4e5da5Sopenharmony_ci               OpBranchConditional %35 %36 %37
503fd4e5da5Sopenharmony_ci         %36 = OpLabel
504fd4e5da5Sopenharmony_ci         %38 = OpAccessChain %50 %11 %14
505fd4e5da5Sopenharmony_ci         %40 = OpAccessChain %50 %11 %14
506fd4e5da5Sopenharmony_ci               OpBranch %37
507fd4e5da5Sopenharmony_ci         %37 = OpLabel
508fd4e5da5Sopenharmony_ci               OpReturn
509fd4e5da5Sopenharmony_ci               OpFunctionEnd
510fd4e5da5Sopenharmony_ci  )";
511fd4e5da5Sopenharmony_ci
512fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
513fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
514fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
515fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
516fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
517fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
518fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
519fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
520fd4e5da5Sopenharmony_ci
521fd4e5da5Sopenharmony_ci  // Bad: Can't insert OpAccessChain before the id 23 of memory scope.
522fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
523fd4e5da5Sopenharmony_ci                   60, 38, true, 21, 23,
524fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(23, spv::Op::OpAccessChain, 0))
525fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
526fd4e5da5Sopenharmony_ci
527fd4e5da5Sopenharmony_ci  // Bad: Can't insert OpAccessChain before the id 23 of memory semantics.
528fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationLoad(
529fd4e5da5Sopenharmony_ci                   60, 38, true, 21, 23,
530fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0))
531fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
532fd4e5da5Sopenharmony_ci
533fd4e5da5Sopenharmony_ci  // Successful transformations.
534fd4e5da5Sopenharmony_ci  {
535fd4e5da5Sopenharmony_ci    TransformationLoad transformation(
536fd4e5da5Sopenharmony_ci        60, 38, true, 21, 23,
537fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(40, spv::Op::OpAccessChain, 0));
538fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
539fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
540fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
541fd4e5da5Sopenharmony_ci                          &transformation_context);
542fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
543fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
544fd4e5da5Sopenharmony_ci  }
545fd4e5da5Sopenharmony_ci
546fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
547fd4e5da5Sopenharmony_ci               OpCapability Shader
548fd4e5da5Sopenharmony_ci               OpCapability Int8
549fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
550fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
551fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
552fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
553fd4e5da5Sopenharmony_ci               OpSource ESSL 310
554fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
555fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
556fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
557fd4e5da5Sopenharmony_ci          %26 = OpTypeFloat 32
558fd4e5da5Sopenharmony_ci          %27 = OpTypeInt 8 1
559fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 32 0 ; 0 means unsigned
560fd4e5da5Sopenharmony_ci          %8 = OpConstant %7 0
561fd4e5da5Sopenharmony_ci         %17 = OpConstant %27 4
562fd4e5da5Sopenharmony_ci         %19 = OpConstant %26 0
563fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %6
564fd4e5da5Sopenharmony_ci         %13 = OpTypeStruct %6
565fd4e5da5Sopenharmony_ci         %12 = OpTypePointer Workgroup %13
566fd4e5da5Sopenharmony_ci         %11 = OpVariable %12 Workgroup
567fd4e5da5Sopenharmony_ci         %14 = OpConstant %6 0
568fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %6
569fd4e5da5Sopenharmony_ci         %51 = OpTypePointer Private %6
570fd4e5da5Sopenharmony_ci         %21 = OpConstant %6 4
571fd4e5da5Sopenharmony_ci         %23 = OpConstant %6 256
572fd4e5da5Sopenharmony_ci         %25 = OpTypePointer Function %7
573fd4e5da5Sopenharmony_ci         %50 = OpTypePointer Workgroup %6
574fd4e5da5Sopenharmony_ci         %34 = OpTypeBool
575fd4e5da5Sopenharmony_ci         %35 = OpConstantFalse %34
576fd4e5da5Sopenharmony_ci         %53 = OpVariable %51 Private
577fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
578fd4e5da5Sopenharmony_ci          %5 = OpLabel
579fd4e5da5Sopenharmony_ci               OpSelectionMerge %37 None
580fd4e5da5Sopenharmony_ci               OpBranchConditional %35 %36 %37
581fd4e5da5Sopenharmony_ci         %36 = OpLabel
582fd4e5da5Sopenharmony_ci         %38 = OpAccessChain %50 %11 %14
583fd4e5da5Sopenharmony_ci         %60 = OpAtomicLoad %6 %38 %21 %23
584fd4e5da5Sopenharmony_ci         %40 = OpAccessChain %50 %11 %14
585fd4e5da5Sopenharmony_ci               OpBranch %37
586fd4e5da5Sopenharmony_ci         %37 = OpLabel
587fd4e5da5Sopenharmony_ci               OpReturn
588fd4e5da5Sopenharmony_ci               OpFunctionEnd
589fd4e5da5Sopenharmony_ci  )";
590fd4e5da5Sopenharmony_ci
591fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
592fd4e5da5Sopenharmony_ci}
593fd4e5da5Sopenharmony_ci
594fd4e5da5Sopenharmony_ci}  // namespace
595fd4e5da5Sopenharmony_ci}  // namespace fuzz
596fd4e5da5Sopenharmony_ci}  // namespace spvtools
597