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_access_chain.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(TransformationAccessChainTest, 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" %48 %54
33fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
34fd4e5da5Sopenharmony_ci               OpSource ESSL 310
35fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
36fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
37fd4e5da5Sopenharmony_ci          %6 = OpTypeFloat 32
38fd4e5da5Sopenharmony_ci          %7 = OpTypeVector %6 2
39fd4e5da5Sopenharmony_ci         %50 = OpTypeMatrix %7 2
40fd4e5da5Sopenharmony_ci         %70 = OpTypePointer Function %7
41fd4e5da5Sopenharmony_ci         %71 = OpTypePointer Function %50
42fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %7 %6
43fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
44fd4e5da5Sopenharmony_ci         %10 = OpTypeInt 32 1
45fd4e5da5Sopenharmony_ci         %11 = OpTypePointer Function %10
46fd4e5da5Sopenharmony_ci         %12 = OpTypeFunction %10 %9 %11
47fd4e5da5Sopenharmony_ci         %17 = OpConstant %10 0
48fd4e5da5Sopenharmony_ci         %18 = OpTypeInt 32 0
49fd4e5da5Sopenharmony_ci         %19 = OpConstant %18 0
50fd4e5da5Sopenharmony_ci         %20 = OpTypePointer Function %6
51fd4e5da5Sopenharmony_ci         %99 = OpTypePointer Private %6
52fd4e5da5Sopenharmony_ci         %29 = OpConstant %6 0
53fd4e5da5Sopenharmony_ci         %30 = OpConstant %6 1
54fd4e5da5Sopenharmony_ci         %31 = OpConstantComposite %7 %29 %30
55fd4e5da5Sopenharmony_ci         %32 = OpConstant %6 2
56fd4e5da5Sopenharmony_ci         %33 = OpConstantComposite %8 %31 %32
57fd4e5da5Sopenharmony_ci         %35 = OpConstant %10 10
58fd4e5da5Sopenharmony_ci         %51 = OpConstant %18 10
59fd4e5da5Sopenharmony_ci         %80 = OpConstant %18 0
60fd4e5da5Sopenharmony_ci         %81 = OpConstant %10 1
61fd4e5da5Sopenharmony_ci         %82 = OpConstant %18 2
62fd4e5da5Sopenharmony_ci         %83 = OpConstant %10 3
63fd4e5da5Sopenharmony_ci         %84 = OpConstant %18 4
64fd4e5da5Sopenharmony_ci         %85 = OpConstant %10 5
65fd4e5da5Sopenharmony_ci         %52 = OpTypeArray %50 %51
66fd4e5da5Sopenharmony_ci         %53 = OpTypePointer Private %52
67fd4e5da5Sopenharmony_ci         %46 = OpConstantNull %9
68fd4e5da5Sopenharmony_ci         %47 = OpTypePointer Private %8
69fd4e5da5Sopenharmony_ci         %48 = OpVariable %47 Private
70fd4e5da5Sopenharmony_ci         %54 = OpVariable %53 Private
71fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
72fd4e5da5Sopenharmony_ci          %5 = OpLabel
73fd4e5da5Sopenharmony_ci         %28 = OpVariable %9 Function
74fd4e5da5Sopenharmony_ci         %34 = OpVariable %11 Function
75fd4e5da5Sopenharmony_ci         %36 = OpVariable %9 Function
76fd4e5da5Sopenharmony_ci         %38 = OpVariable %11 Function
77fd4e5da5Sopenharmony_ci         %44 = OpCopyObject %9 %36
78fd4e5da5Sopenharmony_ci               OpStore %28 %33
79fd4e5da5Sopenharmony_ci               OpStore %34 %35
80fd4e5da5Sopenharmony_ci         %37 = OpLoad %8 %28
81fd4e5da5Sopenharmony_ci               OpStore %36 %37
82fd4e5da5Sopenharmony_ci         %39 = OpLoad %10 %34
83fd4e5da5Sopenharmony_ci               OpStore %38 %39
84fd4e5da5Sopenharmony_ci         %40 = OpFunctionCall %10 %15 %36 %38
85fd4e5da5Sopenharmony_ci         %41 = OpLoad %10 %34
86fd4e5da5Sopenharmony_ci         %42 = OpIAdd %10 %41 %40
87fd4e5da5Sopenharmony_ci               OpStore %34 %42
88fd4e5da5Sopenharmony_ci               OpReturn
89fd4e5da5Sopenharmony_ci               OpFunctionEnd
90fd4e5da5Sopenharmony_ci         %15 = OpFunction %10 None %12
91fd4e5da5Sopenharmony_ci         %13 = OpFunctionParameter %9
92fd4e5da5Sopenharmony_ci         %14 = OpFunctionParameter %11
93fd4e5da5Sopenharmony_ci         %16 = OpLabel
94fd4e5da5Sopenharmony_ci         %21 = OpAccessChain %20 %13 %17 %19
95fd4e5da5Sopenharmony_ci         %43 = OpCopyObject %9 %13
96fd4e5da5Sopenharmony_ci         %22 = OpLoad %6 %21
97fd4e5da5Sopenharmony_ci         %23 = OpConvertFToS %10 %22
98fd4e5da5Sopenharmony_ci         %24 = OpLoad %10 %14
99fd4e5da5Sopenharmony_ci         %25 = OpIAdd %10 %23 %24
100fd4e5da5Sopenharmony_ci               OpReturnValue %25
101fd4e5da5Sopenharmony_ci               OpFunctionEnd
102fd4e5da5Sopenharmony_ci  )";
103fd4e5da5Sopenharmony_ci
104fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
105fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
106fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
107fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
108fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
109fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_ci  // Types:
112fd4e5da5Sopenharmony_ci  // Ptr | Pointee | Storage class | GLSL for pointee    | Ids of this type
113fd4e5da5Sopenharmony_ci  // ----+---------+---------------+---------------------+------------------
114fd4e5da5Sopenharmony_ci  //  9  |    8    | Function      | struct(vec2, float) | 28, 36, 44, 13, 43
115fd4e5da5Sopenharmony_ci  // 11  |   10    | Function      | int                 | 34, 38, 14
116fd4e5da5Sopenharmony_ci  // 20  |    6    | Function      | float               | -
117fd4e5da5Sopenharmony_ci  // 99  |    6    | Private       | float               | -
118fd4e5da5Sopenharmony_ci  // 53  |   52    | Private       | mat2x2[10]          | 54
119fd4e5da5Sopenharmony_ci  // 47  |    8    | Private       | struct(vec2, float) | 48
120fd4e5da5Sopenharmony_ci  // 70  |    7    | Function      | vec2                | -
121fd4e5da5Sopenharmony_ci  // 71  |   59    | Function      | mat2x2              | -
122fd4e5da5Sopenharmony_ci
123fd4e5da5Sopenharmony_ci  // Indices 0-5 are in ids 80-85
124fd4e5da5Sopenharmony_ci
125fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
126fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
127fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
128fd4e5da5Sopenharmony_ci      54);
129fd4e5da5Sopenharmony_ci
130fd4e5da5Sopenharmony_ci  // Check the case where the index type is not a 32-bit integer.
131fd4e5da5Sopenharmony_ci  TransformationAccessChain invalid_index_example1(
132fd4e5da5Sopenharmony_ci      101, 28, {29}, MakeInstructionDescriptor(42, spv::Op::OpReturn, 0));
133fd4e5da5Sopenharmony_ci
134fd4e5da5Sopenharmony_ci  // Since the index  is not a 32-bit integer type but a 32-bit float type,
135fd4e5da5Sopenharmony_ci  // ValidIndexComposite should return false and thus the transformation is not
136fd4e5da5Sopenharmony_ci  // applicable.
137fd4e5da5Sopenharmony_ci  ASSERT_FALSE(invalid_index_example1.IsApplicable(context.get(),
138fd4e5da5Sopenharmony_ci                                                   transformation_context));
139fd4e5da5Sopenharmony_ci
140fd4e5da5Sopenharmony_ci  // Bad: id is not fresh
141fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
142fd4e5da5Sopenharmony_ci      TransformationAccessChain(
143fd4e5da5Sopenharmony_ci          43, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
144fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
145fd4e5da5Sopenharmony_ci
146fd4e5da5Sopenharmony_ci  // Bad: pointer id does not exist
147fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
148fd4e5da5Sopenharmony_ci      TransformationAccessChain(
149fd4e5da5Sopenharmony_ci          100, 1000, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
150fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
151fd4e5da5Sopenharmony_ci
152fd4e5da5Sopenharmony_ci  // Bad: pointer id is not a type
153fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
154fd4e5da5Sopenharmony_ci      TransformationAccessChain(
155fd4e5da5Sopenharmony_ci          100, 5, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
156fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
157fd4e5da5Sopenharmony_ci
158fd4e5da5Sopenharmony_ci  // Bad: pointer id is not a pointer
159fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
160fd4e5da5Sopenharmony_ci      TransformationAccessChain(
161fd4e5da5Sopenharmony_ci          100, 23, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
162fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
163fd4e5da5Sopenharmony_ci
164fd4e5da5Sopenharmony_ci  // Bad: index id does not exist
165fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
166fd4e5da5Sopenharmony_ci      TransformationAccessChain(
167fd4e5da5Sopenharmony_ci          100, 43, {1000}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
168fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
169fd4e5da5Sopenharmony_ci
170fd4e5da5Sopenharmony_ci  // Bad: index id is not a constant and the pointer refers to a struct
171fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
172fd4e5da5Sopenharmony_ci      TransformationAccessChain(
173fd4e5da5Sopenharmony_ci          100, 43, {24}, MakeInstructionDescriptor(25, spv::Op::OpIAdd, 0))
174fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
175fd4e5da5Sopenharmony_ci
176fd4e5da5Sopenharmony_ci  // Bad: too many indices
177fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
178fd4e5da5Sopenharmony_ci                   100, 43, {80, 80, 80},
179fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
180fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
181fd4e5da5Sopenharmony_ci
182fd4e5da5Sopenharmony_ci  // Bad: index id is out of bounds when accessing a struct
183fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
184fd4e5da5Sopenharmony_ci      TransformationAccessChain(
185fd4e5da5Sopenharmony_ci          100, 43, {83, 80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
186fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
187fd4e5da5Sopenharmony_ci
188fd4e5da5Sopenharmony_ci  // Bad: attempt to insert before variable
189fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
190fd4e5da5Sopenharmony_ci      TransformationAccessChain(
191fd4e5da5Sopenharmony_ci          100, 34, {}, MakeInstructionDescriptor(36, spv::Op::OpVariable, 0))
192fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
193fd4e5da5Sopenharmony_ci
194fd4e5da5Sopenharmony_ci  // Bad: OpTypeBool must be present in the module to clamp an index
195fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
196fd4e5da5Sopenharmony_ci      TransformationAccessChain(
197fd4e5da5Sopenharmony_ci          100, 36, {80, 81}, MakeInstructionDescriptor(37, spv::Op::OpStore, 0))
198fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
199fd4e5da5Sopenharmony_ci
200fd4e5da5Sopenharmony_ci  // Bad: pointer not available
201fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
202fd4e5da5Sopenharmony_ci                   100, 43, {80},
203fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0))
204fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
205fd4e5da5Sopenharmony_ci
206fd4e5da5Sopenharmony_ci  // Bad: instruction descriptor does not identify anything
207fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
208fd4e5da5Sopenharmony_ci      TransformationAccessChain(
209fd4e5da5Sopenharmony_ci          100, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 100))
210fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
211fd4e5da5Sopenharmony_ci
212fd4e5da5Sopenharmony_ci#ifndef NDEBUG
213fd4e5da5Sopenharmony_ci  // Bad: pointer is null
214fd4e5da5Sopenharmony_ci  ASSERT_DEATH(
215fd4e5da5Sopenharmony_ci      TransformationAccessChain(
216fd4e5da5Sopenharmony_ci          100, 46, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
217fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context),
218fd4e5da5Sopenharmony_ci      "Access chains should not be created from null/undefined pointers");
219fd4e5da5Sopenharmony_ci#endif
220fd4e5da5Sopenharmony_ci
221fd4e5da5Sopenharmony_ci  // Bad: pointer to result type does not exist
222fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
223fd4e5da5Sopenharmony_ci      TransformationAccessChain(
224fd4e5da5Sopenharmony_ci          100, 52, {0}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0))
225fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
226fd4e5da5Sopenharmony_ci
227fd4e5da5Sopenharmony_ci  {
228fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
229fd4e5da5Sopenharmony_ci        100, 43, {80}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
230fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
231fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
232fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
233fd4e5da5Sopenharmony_ci                          &transformation_context);
234fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
235fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
236fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
237fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
238fd4e5da5Sopenharmony_ci  }
239fd4e5da5Sopenharmony_ci
240fd4e5da5Sopenharmony_ci  {
241fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
242fd4e5da5Sopenharmony_ci        101, 28, {81}, MakeInstructionDescriptor(42, spv::Op::OpReturn, 0));
243fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
244fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
245fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
246fd4e5da5Sopenharmony_ci                          &transformation_context);
247fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
248fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
249fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
250fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
251fd4e5da5Sopenharmony_ci  }
252fd4e5da5Sopenharmony_ci
253fd4e5da5Sopenharmony_ci  {
254fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
255fd4e5da5Sopenharmony_ci        102, 44, {}, MakeInstructionDescriptor(44, spv::Op::OpStore, 0));
256fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
257fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
258fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
259fd4e5da5Sopenharmony_ci                          &transformation_context);
260fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
261fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
262fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
263fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
264fd4e5da5Sopenharmony_ci  }
265fd4e5da5Sopenharmony_ci
266fd4e5da5Sopenharmony_ci  {
267fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
268fd4e5da5Sopenharmony_ci        103, 13, {80},
269fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(21, spv::Op::OpAccessChain, 0));
270fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
271fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
272fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
273fd4e5da5Sopenharmony_ci                          &transformation_context);
274fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
275fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
276fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
277fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
278fd4e5da5Sopenharmony_ci  }
279fd4e5da5Sopenharmony_ci
280fd4e5da5Sopenharmony_ci  {
281fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
282fd4e5da5Sopenharmony_ci        104, 34, {}, MakeInstructionDescriptor(44, spv::Op::OpStore, 1));
283fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
284fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
285fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
286fd4e5da5Sopenharmony_ci                          &transformation_context);
287fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
288fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
289fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
290fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
291fd4e5da5Sopenharmony_ci  }
292fd4e5da5Sopenharmony_ci
293fd4e5da5Sopenharmony_ci  {
294fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
295fd4e5da5Sopenharmony_ci        105, 38, {}, MakeInstructionDescriptor(40, spv::Op::OpFunctionCall, 0));
296fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
297fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
298fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
299fd4e5da5Sopenharmony_ci                          &transformation_context);
300fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
301fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
302fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
303fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(106));
304fd4e5da5Sopenharmony_ci  }
305fd4e5da5Sopenharmony_ci
306fd4e5da5Sopenharmony_ci  {
307fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
308fd4e5da5Sopenharmony_ci        106, 14, {}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
309fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
310fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
311fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
312fd4e5da5Sopenharmony_ci                          &transformation_context);
313fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
314fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
315fd4e5da5Sopenharmony_ci    ASSERT_FALSE(
316fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(107));
317fd4e5da5Sopenharmony_ci  }
318fd4e5da5Sopenharmony_ci  {
319fd4e5da5Sopenharmony_ci    // Check the case where the access chain's base pointer has the irrelevant
320fd4e5da5Sopenharmony_ci    // pointee fact; the resulting access chain should inherit this fact.
321fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
322fd4e5da5Sopenharmony_ci        107, 54, {}, MakeInstructionDescriptor(24, spv::Op::OpLoad, 0));
323fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
324fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
325fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
326fd4e5da5Sopenharmony_ci                          &transformation_context);
327fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
328fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
329fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
330fd4e5da5Sopenharmony_ci        transformation_context.GetFactManager()->PointeeValueIsIrrelevant(54));
331fd4e5da5Sopenharmony_ci  }
332fd4e5da5Sopenharmony_ci
333fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
334fd4e5da5Sopenharmony_ci               OpCapability Shader
335fd4e5da5Sopenharmony_ci               OpCapability VariablePointers
336fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
337fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
338fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main" %48 %54
339fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
340fd4e5da5Sopenharmony_ci               OpSource ESSL 310
341fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
342fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
343fd4e5da5Sopenharmony_ci          %6 = OpTypeFloat 32
344fd4e5da5Sopenharmony_ci          %7 = OpTypeVector %6 2
345fd4e5da5Sopenharmony_ci         %50 = OpTypeMatrix %7 2
346fd4e5da5Sopenharmony_ci         %70 = OpTypePointer Function %7
347fd4e5da5Sopenharmony_ci         %71 = OpTypePointer Function %50
348fd4e5da5Sopenharmony_ci          %8 = OpTypeStruct %7 %6
349fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
350fd4e5da5Sopenharmony_ci         %10 = OpTypeInt 32 1
351fd4e5da5Sopenharmony_ci         %11 = OpTypePointer Function %10
352fd4e5da5Sopenharmony_ci         %12 = OpTypeFunction %10 %9 %11
353fd4e5da5Sopenharmony_ci         %17 = OpConstant %10 0
354fd4e5da5Sopenharmony_ci         %18 = OpTypeInt 32 0
355fd4e5da5Sopenharmony_ci         %19 = OpConstant %18 0
356fd4e5da5Sopenharmony_ci         %20 = OpTypePointer Function %6
357fd4e5da5Sopenharmony_ci         %99 = OpTypePointer Private %6
358fd4e5da5Sopenharmony_ci         %29 = OpConstant %6 0
359fd4e5da5Sopenharmony_ci         %30 = OpConstant %6 1
360fd4e5da5Sopenharmony_ci         %31 = OpConstantComposite %7 %29 %30
361fd4e5da5Sopenharmony_ci         %32 = OpConstant %6 2
362fd4e5da5Sopenharmony_ci         %33 = OpConstantComposite %8 %31 %32
363fd4e5da5Sopenharmony_ci         %35 = OpConstant %10 10
364fd4e5da5Sopenharmony_ci         %51 = OpConstant %18 10
365fd4e5da5Sopenharmony_ci         %80 = OpConstant %18 0
366fd4e5da5Sopenharmony_ci         %81 = OpConstant %10 1
367fd4e5da5Sopenharmony_ci         %82 = OpConstant %18 2
368fd4e5da5Sopenharmony_ci         %83 = OpConstant %10 3
369fd4e5da5Sopenharmony_ci         %84 = OpConstant %18 4
370fd4e5da5Sopenharmony_ci         %85 = OpConstant %10 5
371fd4e5da5Sopenharmony_ci         %52 = OpTypeArray %50 %51
372fd4e5da5Sopenharmony_ci         %53 = OpTypePointer Private %52
373fd4e5da5Sopenharmony_ci         %46 = OpConstantNull %9
374fd4e5da5Sopenharmony_ci         %47 = OpTypePointer Private %8
375fd4e5da5Sopenharmony_ci         %48 = OpVariable %47 Private
376fd4e5da5Sopenharmony_ci         %54 = OpVariable %53 Private
377fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
378fd4e5da5Sopenharmony_ci          %5 = OpLabel
379fd4e5da5Sopenharmony_ci         %28 = OpVariable %9 Function
380fd4e5da5Sopenharmony_ci         %34 = OpVariable %11 Function
381fd4e5da5Sopenharmony_ci         %36 = OpVariable %9 Function
382fd4e5da5Sopenharmony_ci         %38 = OpVariable %11 Function
383fd4e5da5Sopenharmony_ci         %44 = OpCopyObject %9 %36
384fd4e5da5Sopenharmony_ci        %102 = OpAccessChain %9 %44
385fd4e5da5Sopenharmony_ci               OpStore %28 %33
386fd4e5da5Sopenharmony_ci        %104 = OpAccessChain %11 %34
387fd4e5da5Sopenharmony_ci               OpStore %34 %35
388fd4e5da5Sopenharmony_ci         %37 = OpLoad %8 %28
389fd4e5da5Sopenharmony_ci               OpStore %36 %37
390fd4e5da5Sopenharmony_ci         %39 = OpLoad %10 %34
391fd4e5da5Sopenharmony_ci               OpStore %38 %39
392fd4e5da5Sopenharmony_ci        %105 = OpAccessChain %11 %38
393fd4e5da5Sopenharmony_ci         %40 = OpFunctionCall %10 %15 %36 %38
394fd4e5da5Sopenharmony_ci         %41 = OpLoad %10 %34
395fd4e5da5Sopenharmony_ci         %42 = OpIAdd %10 %41 %40
396fd4e5da5Sopenharmony_ci               OpStore %34 %42
397fd4e5da5Sopenharmony_ci        %101 = OpAccessChain %20 %28 %81
398fd4e5da5Sopenharmony_ci               OpReturn
399fd4e5da5Sopenharmony_ci               OpFunctionEnd
400fd4e5da5Sopenharmony_ci         %15 = OpFunction %10 None %12
401fd4e5da5Sopenharmony_ci         %13 = OpFunctionParameter %9
402fd4e5da5Sopenharmony_ci         %14 = OpFunctionParameter %11
403fd4e5da5Sopenharmony_ci         %16 = OpLabel
404fd4e5da5Sopenharmony_ci        %103 = OpAccessChain %70 %13 %80
405fd4e5da5Sopenharmony_ci         %21 = OpAccessChain %20 %13 %17 %19
406fd4e5da5Sopenharmony_ci         %43 = OpCopyObject %9 %13
407fd4e5da5Sopenharmony_ci         %22 = OpLoad %6 %21
408fd4e5da5Sopenharmony_ci         %23 = OpConvertFToS %10 %22
409fd4e5da5Sopenharmony_ci        %100 = OpAccessChain %70 %43 %80
410fd4e5da5Sopenharmony_ci        %106 = OpAccessChain %11 %14
411fd4e5da5Sopenharmony_ci        %107 = OpAccessChain %53 %54
412fd4e5da5Sopenharmony_ci         %24 = OpLoad %10 %14
413fd4e5da5Sopenharmony_ci         %25 = OpIAdd %10 %23 %24
414fd4e5da5Sopenharmony_ci               OpReturnValue %25
415fd4e5da5Sopenharmony_ci               OpFunctionEnd
416fd4e5da5Sopenharmony_ci  )";
417fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
418fd4e5da5Sopenharmony_ci}
419fd4e5da5Sopenharmony_ci
420fd4e5da5Sopenharmony_ciTEST(TransformationAccessChainTest, StructIndexMustBeConstant) {
421fd4e5da5Sopenharmony_ci  std::string shader = R"(
422fd4e5da5Sopenharmony_ci               OpCapability Shader
423fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
424fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
425fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
426fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
427fd4e5da5Sopenharmony_ci               OpSource ESSL 320
428fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
429fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
430fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
431fd4e5da5Sopenharmony_ci         %20 = OpUndef %6
432fd4e5da5Sopenharmony_ci          %7 = OpTypeStruct %6 %6
433fd4e5da5Sopenharmony_ci          %8 = OpTypePointer Function %7
434fd4e5da5Sopenharmony_ci         %10 = OpConstant %6 0
435fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 2
436fd4e5da5Sopenharmony_ci         %12 = OpTypePointer Function %6
437fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
438fd4e5da5Sopenharmony_ci          %5 = OpLabel
439fd4e5da5Sopenharmony_ci          %9 = OpVariable %8 Function
440fd4e5da5Sopenharmony_ci               OpReturn
441fd4e5da5Sopenharmony_ci               OpFunctionEnd
442fd4e5da5Sopenharmony_ci  )";
443fd4e5da5Sopenharmony_ci
444fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
445fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
446fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
447fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
448fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
449fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
450fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
451fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
452fd4e5da5Sopenharmony_ci  // Bad: %9 is a pointer to a struct, but %20 is not a constant.
453fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
454fd4e5da5Sopenharmony_ci      TransformationAccessChain(
455fd4e5da5Sopenharmony_ci          100, 9, {20}, MakeInstructionDescriptor(9, spv::Op::OpReturn, 0))
456fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
457fd4e5da5Sopenharmony_ci}
458fd4e5da5Sopenharmony_ci
459fd4e5da5Sopenharmony_ciTEST(TransformationAccessChainTest, IsomorphicStructs) {
460fd4e5da5Sopenharmony_ci  std::string shader = R"(
461fd4e5da5Sopenharmony_ci               OpCapability Shader
462fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
463fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
464fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main" %11 %12
465fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
466fd4e5da5Sopenharmony_ci               OpSource ESSL 310
467fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
468fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
469fd4e5da5Sopenharmony_ci          %6 = OpTypeFloat 32
470fd4e5da5Sopenharmony_ci          %7 = OpTypeStruct %6
471fd4e5da5Sopenharmony_ci          %8 = OpTypePointer Private %7
472fd4e5da5Sopenharmony_ci          %9 = OpTypeStruct %6
473fd4e5da5Sopenharmony_ci         %10 = OpTypePointer Private %9
474fd4e5da5Sopenharmony_ci         %11 = OpVariable %8 Private
475fd4e5da5Sopenharmony_ci         %12 = OpVariable %10 Private
476fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
477fd4e5da5Sopenharmony_ci          %5 = OpLabel
478fd4e5da5Sopenharmony_ci               OpReturn
479fd4e5da5Sopenharmony_ci               OpFunctionEnd
480fd4e5da5Sopenharmony_ci  )";
481fd4e5da5Sopenharmony_ci
482fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
483fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
484fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
485fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
486fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
487fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
488fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
489fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
490fd4e5da5Sopenharmony_ci  {
491fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
492fd4e5da5Sopenharmony_ci        100, 11, {}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0));
493fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
494fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
495fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
496fd4e5da5Sopenharmony_ci                          &transformation_context);
497fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
498fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
499fd4e5da5Sopenharmony_ci  }
500fd4e5da5Sopenharmony_ci  {
501fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
502fd4e5da5Sopenharmony_ci        101, 12, {}, MakeInstructionDescriptor(5, spv::Op::OpReturn, 0));
503fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
504fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
505fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
506fd4e5da5Sopenharmony_ci                          &transformation_context);
507fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
508fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
509fd4e5da5Sopenharmony_ci  }
510fd4e5da5Sopenharmony_ci
511fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
512fd4e5da5Sopenharmony_ci               OpCapability Shader
513fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
514fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
515fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main" %11 %12
516fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
517fd4e5da5Sopenharmony_ci               OpSource ESSL 310
518fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
519fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
520fd4e5da5Sopenharmony_ci          %6 = OpTypeFloat 32
521fd4e5da5Sopenharmony_ci          %7 = OpTypeStruct %6
522fd4e5da5Sopenharmony_ci          %8 = OpTypePointer Private %7
523fd4e5da5Sopenharmony_ci          %9 = OpTypeStruct %6
524fd4e5da5Sopenharmony_ci         %10 = OpTypePointer Private %9
525fd4e5da5Sopenharmony_ci         %11 = OpVariable %8 Private
526fd4e5da5Sopenharmony_ci         %12 = OpVariable %10 Private
527fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
528fd4e5da5Sopenharmony_ci          %5 = OpLabel
529fd4e5da5Sopenharmony_ci        %100 = OpAccessChain %8 %11
530fd4e5da5Sopenharmony_ci        %101 = OpAccessChain %10 %12
531fd4e5da5Sopenharmony_ci               OpReturn
532fd4e5da5Sopenharmony_ci               OpFunctionEnd
533fd4e5da5Sopenharmony_ci  )";
534fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
535fd4e5da5Sopenharmony_ci}
536fd4e5da5Sopenharmony_ci
537fd4e5da5Sopenharmony_ciTEST(TransformationAccessChainTest, ClampingVariables) {
538fd4e5da5Sopenharmony_ci  std::string shader = R"(
539fd4e5da5Sopenharmony_ci               OpCapability Shader
540fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
541fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
542fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
543fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
544fd4e5da5Sopenharmony_ci               OpSource ESSL 310
545fd4e5da5Sopenharmony_ci          %4 = OpTypeVoid
546fd4e5da5Sopenharmony_ci          %5 = OpTypeBool
547fd4e5da5Sopenharmony_ci          %6 = OpTypeFunction %4
548fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 32 1
549fd4e5da5Sopenharmony_ci          %8 = OpTypeVector %7 4
550fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
551fd4e5da5Sopenharmony_ci         %10 = OpConstant %7 0
552fd4e5da5Sopenharmony_ci         %11 = OpConstant %7 1
553fd4e5da5Sopenharmony_ci         %12 = OpConstant %7 3
554fd4e5da5Sopenharmony_ci         %13 = OpConstant %7 2
555fd4e5da5Sopenharmony_ci         %14 = OpConstantComposite %8 %10 %11 %12 %13
556fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %7
557fd4e5da5Sopenharmony_ci         %16 = OpTypeInt 32 0
558fd4e5da5Sopenharmony_ci         %17 = OpConstant %16 1
559fd4e5da5Sopenharmony_ci         %18 = OpConstant %16 3
560fd4e5da5Sopenharmony_ci         %19 = OpTypeStruct %8
561fd4e5da5Sopenharmony_ci         %20 = OpTypePointer Function %19
562fd4e5da5Sopenharmony_ci         %21 = OpConstant %7 9
563fd4e5da5Sopenharmony_ci         %22 = OpConstant %16 10
564fd4e5da5Sopenharmony_ci         %23 = OpTypeArray %19 %22
565fd4e5da5Sopenharmony_ci         %24 = OpTypePointer Function %23
566fd4e5da5Sopenharmony_ci         %25 = OpTypeFloat 32
567fd4e5da5Sopenharmony_ci         %26 = OpTypeVector %25 4
568fd4e5da5Sopenharmony_ci         %27 = OpTypePointer Output %26
569fd4e5da5Sopenharmony_ci          %3 = OpVariable %27 Output
570fd4e5da5Sopenharmony_ci          %2 = OpFunction %4 None %6
571fd4e5da5Sopenharmony_ci         %28 = OpLabel
572fd4e5da5Sopenharmony_ci         %29 = OpVariable %9 Function
573fd4e5da5Sopenharmony_ci         %30 = OpVariable %15 Function
574fd4e5da5Sopenharmony_ci         %31 = OpVariable %15 Function
575fd4e5da5Sopenharmony_ci         %32 = OpVariable %20 Function
576fd4e5da5Sopenharmony_ci         %33 = OpVariable %15 Function
577fd4e5da5Sopenharmony_ci         %34 = OpVariable %24 Function
578fd4e5da5Sopenharmony_ci               OpStore %29 %14
579fd4e5da5Sopenharmony_ci               OpStore %30 %10
580fd4e5da5Sopenharmony_ci         %36 = OpLoad %7 %30
581fd4e5da5Sopenharmony_ci         %38 = OpLoad %8 %29
582fd4e5da5Sopenharmony_ci         %39 = OpCompositeConstruct %19 %38
583fd4e5da5Sopenharmony_ci         %40 = OpLoad %7 %30
584fd4e5da5Sopenharmony_ci         %42 = OpLoad %8 %29
585fd4e5da5Sopenharmony_ci         %43 = OpCompositeConstruct %19 %42
586fd4e5da5Sopenharmony_ci         %45 = OpLoad %7 %30
587fd4e5da5Sopenharmony_ci         %46 = OpLoad %7 %33
588fd4e5da5Sopenharmony_ci               OpReturn
589fd4e5da5Sopenharmony_ci               OpFunctionEnd
590fd4e5da5Sopenharmony_ci  )";
591fd4e5da5Sopenharmony_ci
592fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
593fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
594fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
595fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
596fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
597fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
598fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
599fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
600fd4e5da5Sopenharmony_ci  // Bad: no ids given for clamping
601fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
602fd4e5da5Sopenharmony_ci      TransformationAccessChain(
603fd4e5da5Sopenharmony_ci          100, 29, {17}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0))
604fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
605fd4e5da5Sopenharmony_ci
606fd4e5da5Sopenharmony_ci  // Bad: an id given for clamping is not fresh
607fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
608fd4e5da5Sopenharmony_ci                   100, 29, {17},
609fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
610fd4e5da5Sopenharmony_ci                   {{46, 201}})
611fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
612fd4e5da5Sopenharmony_ci
613fd4e5da5Sopenharmony_ci  // Bad: an id given for clamping is not fresh
614fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
615fd4e5da5Sopenharmony_ci                   100, 29, {17},
616fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
617fd4e5da5Sopenharmony_ci                   {{200, 46}})
618fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
619fd4e5da5Sopenharmony_ci
620fd4e5da5Sopenharmony_ci  // Bad: an id given for clamping is the same as the id for the access chain
621fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
622fd4e5da5Sopenharmony_ci                   100, 29, {17},
623fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
624fd4e5da5Sopenharmony_ci                   {{100, 201}})
625fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
626fd4e5da5Sopenharmony_ci
627fd4e5da5Sopenharmony_ci  // Bad: the fresh ids given are not distinct
628fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
629fd4e5da5Sopenharmony_ci                   100, 29, {17},
630fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
631fd4e5da5Sopenharmony_ci                   {{200, 200}})
632fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
633fd4e5da5Sopenharmony_ci
634fd4e5da5Sopenharmony_ci  // Bad: not enough ids given for clamping (2 pairs needed)
635fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
636fd4e5da5Sopenharmony_ci                   104, 34, {45, 10, 46},
637fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
638fd4e5da5Sopenharmony_ci                   {{208, 209}, {209, 211}})
639fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
640fd4e5da5Sopenharmony_ci
641fd4e5da5Sopenharmony_ci  // Bad: the fresh ids given are not distinct
642fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationAccessChain(
643fd4e5da5Sopenharmony_ci                   104, 34, {45, 10, 46},
644fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
645fd4e5da5Sopenharmony_ci                   {{208, 209}, {209, 211}})
646fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
647fd4e5da5Sopenharmony_ci
648fd4e5da5Sopenharmony_ci  {
649fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
650fd4e5da5Sopenharmony_ci        100, 29, {17}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0),
651fd4e5da5Sopenharmony_ci        {{200, 201}});
652fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
653fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
654fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
655fd4e5da5Sopenharmony_ci                          &transformation_context);
656fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
657fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
658fd4e5da5Sopenharmony_ci  }
659fd4e5da5Sopenharmony_ci
660fd4e5da5Sopenharmony_ci  {
661fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
662fd4e5da5Sopenharmony_ci        101, 29, {36}, MakeInstructionDescriptor(38, spv::Op::OpLoad, 0),
663fd4e5da5Sopenharmony_ci        {{202, 203}});
664fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
665fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
666fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
667fd4e5da5Sopenharmony_ci                          &transformation_context);
668fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
669fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
670fd4e5da5Sopenharmony_ci  }
671fd4e5da5Sopenharmony_ci
672fd4e5da5Sopenharmony_ci  {
673fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
674fd4e5da5Sopenharmony_ci        102, 32, {10, 40}, MakeInstructionDescriptor(42, spv::Op::OpLoad, 0),
675fd4e5da5Sopenharmony_ci        {{204, 205}});
676fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
677fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
678fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
679fd4e5da5Sopenharmony_ci                          &transformation_context);
680fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
681fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
682fd4e5da5Sopenharmony_ci  }
683fd4e5da5Sopenharmony_ci
684fd4e5da5Sopenharmony_ci  {
685fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
686fd4e5da5Sopenharmony_ci        103, 34, {11}, MakeInstructionDescriptor(45, spv::Op::OpLoad, 0),
687fd4e5da5Sopenharmony_ci        {{206, 207}});
688fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
689fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
690fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
691fd4e5da5Sopenharmony_ci                          &transformation_context);
692fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
693fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
694fd4e5da5Sopenharmony_ci  }
695fd4e5da5Sopenharmony_ci
696fd4e5da5Sopenharmony_ci  {
697fd4e5da5Sopenharmony_ci    TransformationAccessChain transformation(
698fd4e5da5Sopenharmony_ci        104, 34, {45, 10, 46},
699fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(46, spv::Op::OpReturn, 0),
700fd4e5da5Sopenharmony_ci        {{208, 209}, {210, 211}});
701fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
702fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
703fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
704fd4e5da5Sopenharmony_ci                          &transformation_context);
705fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
706fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
707fd4e5da5Sopenharmony_ci  }
708fd4e5da5Sopenharmony_ci
709fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
710fd4e5da5Sopenharmony_ci               OpCapability Shader
711fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
712fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
713fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
714fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
715fd4e5da5Sopenharmony_ci               OpSource ESSL 310
716fd4e5da5Sopenharmony_ci          %4 = OpTypeVoid
717fd4e5da5Sopenharmony_ci          %5 = OpTypeBool
718fd4e5da5Sopenharmony_ci          %6 = OpTypeFunction %4
719fd4e5da5Sopenharmony_ci          %7 = OpTypeInt 32 1
720fd4e5da5Sopenharmony_ci          %8 = OpTypeVector %7 4
721fd4e5da5Sopenharmony_ci          %9 = OpTypePointer Function %8
722fd4e5da5Sopenharmony_ci         %10 = OpConstant %7 0
723fd4e5da5Sopenharmony_ci         %11 = OpConstant %7 1
724fd4e5da5Sopenharmony_ci         %12 = OpConstant %7 3
725fd4e5da5Sopenharmony_ci         %13 = OpConstant %7 2
726fd4e5da5Sopenharmony_ci         %14 = OpConstantComposite %8 %10 %11 %12 %13
727fd4e5da5Sopenharmony_ci         %15 = OpTypePointer Function %7
728fd4e5da5Sopenharmony_ci         %16 = OpTypeInt 32 0
729fd4e5da5Sopenharmony_ci         %17 = OpConstant %16 1
730fd4e5da5Sopenharmony_ci         %18 = OpConstant %16 3
731fd4e5da5Sopenharmony_ci         %19 = OpTypeStruct %8
732fd4e5da5Sopenharmony_ci         %20 = OpTypePointer Function %19
733fd4e5da5Sopenharmony_ci         %21 = OpConstant %7 9
734fd4e5da5Sopenharmony_ci         %22 = OpConstant %16 10
735fd4e5da5Sopenharmony_ci         %23 = OpTypeArray %19 %22
736fd4e5da5Sopenharmony_ci         %24 = OpTypePointer Function %23
737fd4e5da5Sopenharmony_ci         %25 = OpTypeFloat 32
738fd4e5da5Sopenharmony_ci         %26 = OpTypeVector %25 4
739fd4e5da5Sopenharmony_ci         %27 = OpTypePointer Output %26
740fd4e5da5Sopenharmony_ci          %3 = OpVariable %27 Output
741fd4e5da5Sopenharmony_ci          %2 = OpFunction %4 None %6
742fd4e5da5Sopenharmony_ci         %28 = OpLabel
743fd4e5da5Sopenharmony_ci         %29 = OpVariable %9 Function
744fd4e5da5Sopenharmony_ci         %30 = OpVariable %15 Function
745fd4e5da5Sopenharmony_ci         %31 = OpVariable %15 Function
746fd4e5da5Sopenharmony_ci         %32 = OpVariable %20 Function
747fd4e5da5Sopenharmony_ci         %33 = OpVariable %15 Function
748fd4e5da5Sopenharmony_ci         %34 = OpVariable %24 Function
749fd4e5da5Sopenharmony_ci               OpStore %29 %14
750fd4e5da5Sopenharmony_ci               OpStore %30 %10
751fd4e5da5Sopenharmony_ci        %200 = OpULessThanEqual %5 %17 %18
752fd4e5da5Sopenharmony_ci        %201 = OpSelect %16 %200 %17 %18
753fd4e5da5Sopenharmony_ci        %100 = OpAccessChain %15 %29 %201
754fd4e5da5Sopenharmony_ci         %36 = OpLoad %7 %30
755fd4e5da5Sopenharmony_ci        %202 = OpULessThanEqual %5 %36 %12
756fd4e5da5Sopenharmony_ci        %203 = OpSelect %7 %202 %36 %12
757fd4e5da5Sopenharmony_ci        %101 = OpAccessChain %15 %29 %203
758fd4e5da5Sopenharmony_ci         %38 = OpLoad %8 %29
759fd4e5da5Sopenharmony_ci         %39 = OpCompositeConstruct %19 %38
760fd4e5da5Sopenharmony_ci         %40 = OpLoad %7 %30
761fd4e5da5Sopenharmony_ci        %204 = OpULessThanEqual %5 %40 %12
762fd4e5da5Sopenharmony_ci        %205 = OpSelect %7 %204 %40 %12
763fd4e5da5Sopenharmony_ci        %102 = OpAccessChain %15 %32 %10 %205
764fd4e5da5Sopenharmony_ci         %42 = OpLoad %8 %29
765fd4e5da5Sopenharmony_ci         %43 = OpCompositeConstruct %19 %42
766fd4e5da5Sopenharmony_ci        %206 = OpULessThanEqual %5 %11 %21
767fd4e5da5Sopenharmony_ci        %207 = OpSelect %7 %206 %11 %21
768fd4e5da5Sopenharmony_ci        %103 = OpAccessChain %20 %34 %207
769fd4e5da5Sopenharmony_ci         %45 = OpLoad %7 %30
770fd4e5da5Sopenharmony_ci         %46 = OpLoad %7 %33
771fd4e5da5Sopenharmony_ci        %208 = OpULessThanEqual %5 %45 %21
772fd4e5da5Sopenharmony_ci        %209 = OpSelect %7 %208 %45 %21
773fd4e5da5Sopenharmony_ci        %210 = OpULessThanEqual %5 %46 %12
774fd4e5da5Sopenharmony_ci        %211 = OpSelect %7 %210 %46 %12
775fd4e5da5Sopenharmony_ci        %104 = OpAccessChain %15 %34 %209 %10 %211
776fd4e5da5Sopenharmony_ci               OpReturn
777fd4e5da5Sopenharmony_ci               OpFunctionEnd
778fd4e5da5Sopenharmony_ci  )";
779fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
780fd4e5da5Sopenharmony_ci}
781fd4e5da5Sopenharmony_ci
782fd4e5da5Sopenharmony_ci}  // namespace
783fd4e5da5Sopenharmony_ci}  // namespace fuzz
784fd4e5da5Sopenharmony_ci}  // namespace spvtools
785