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/reduce/remove_selection_reduction_opportunity_finder.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h"
18fd4e5da5Sopenharmony_ci#include "source/reduce/reduction_opportunity.h"
19fd4e5da5Sopenharmony_ci#include "test/reduce/reduce_test_util.h"
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_cinamespace spvtools {
22fd4e5da5Sopenharmony_cinamespace reduce {
23fd4e5da5Sopenharmony_cinamespace {
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlock) {
26fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
27fd4e5da5Sopenharmony_ci  // should be removed.
28fd4e5da5Sopenharmony_ci  //
29fd4e5da5Sopenharmony_ci  // header
30fd4e5da5Sopenharmony_ci  // ||
31fd4e5da5Sopenharmony_ci  // block
32fd4e5da5Sopenharmony_ci  // |
33fd4e5da5Sopenharmony_ci  // merge
34fd4e5da5Sopenharmony_ci
35fd4e5da5Sopenharmony_ci  std::string shader = R"(
36fd4e5da5Sopenharmony_ci               OpCapability Shader
37fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
38fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
39fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
40fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
41fd4e5da5Sopenharmony_ci               OpSource ESSL 310
42fd4e5da5Sopenharmony_ci               OpName %2 "main"
43fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
44fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
45fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
46fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
47fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
48fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
49fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
50fd4e5da5Sopenharmony_ci          %9 = OpLabel
51fd4e5da5Sopenharmony_ci               OpSelectionMerge %10 None
52fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %11
53fd4e5da5Sopenharmony_ci         %11 = OpLabel
54fd4e5da5Sopenharmony_ci               OpBranch %10
55fd4e5da5Sopenharmony_ci         %10 = OpLabel
56fd4e5da5Sopenharmony_ci               OpReturn
57fd4e5da5Sopenharmony_ci               OpFunctionEnd
58fd4e5da5Sopenharmony_ci    )";
59fd4e5da5Sopenharmony_ci
60fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
61fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
62fd4e5da5Sopenharmony_ci
63fd4e5da5Sopenharmony_ci  auto ops =
64fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
65fd4e5da5Sopenharmony_ci          context.get(), 0);
66fd4e5da5Sopenharmony_ci
67fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
68fd4e5da5Sopenharmony_ci
69fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
70fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
71fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
72fd4e5da5Sopenharmony_ci
73fd4e5da5Sopenharmony_ci  std::string after = R"(
74fd4e5da5Sopenharmony_ci               OpCapability Shader
75fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
76fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
77fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
78fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
79fd4e5da5Sopenharmony_ci               OpSource ESSL 310
80fd4e5da5Sopenharmony_ci               OpName %2 "main"
81fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
82fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
83fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
84fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
85fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
86fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
87fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
88fd4e5da5Sopenharmony_ci          %9 = OpLabel
89fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %11
90fd4e5da5Sopenharmony_ci         %11 = OpLabel
91fd4e5da5Sopenharmony_ci               OpBranch %10
92fd4e5da5Sopenharmony_ci         %10 = OpLabel
93fd4e5da5Sopenharmony_ci               OpReturn
94fd4e5da5Sopenharmony_ci               OpFunctionEnd
95fd4e5da5Sopenharmony_ci    )";
96fd4e5da5Sopenharmony_ci  CheckEqual(env, after, context.get());
97fd4e5da5Sopenharmony_ci
98fd4e5da5Sopenharmony_ci  ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
99fd4e5da5Sopenharmony_ci      context.get(), 0);
100fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
101fd4e5da5Sopenharmony_ci}
102fd4e5da5Sopenharmony_ci
103fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, OpportunityBecauseSameTargetBlockMerge) {
104fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
105fd4e5da5Sopenharmony_ci  // should be removed.
106fd4e5da5Sopenharmony_ci  //
107fd4e5da5Sopenharmony_ci  // header
108fd4e5da5Sopenharmony_ci  // ||
109fd4e5da5Sopenharmony_ci  // merge
110fd4e5da5Sopenharmony_ci
111fd4e5da5Sopenharmony_ci  std::string shader = R"(
112fd4e5da5Sopenharmony_ci               OpCapability Shader
113fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
114fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
115fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
116fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
117fd4e5da5Sopenharmony_ci               OpSource ESSL 310
118fd4e5da5Sopenharmony_ci               OpName %2 "main"
119fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
120fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
121fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
122fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
123fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
124fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
125fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
126fd4e5da5Sopenharmony_ci          %9 = OpLabel
127fd4e5da5Sopenharmony_ci               OpSelectionMerge %10 None
128fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %10 %10
129fd4e5da5Sopenharmony_ci         %10 = OpLabel
130fd4e5da5Sopenharmony_ci               OpReturn
131fd4e5da5Sopenharmony_ci               OpFunctionEnd
132fd4e5da5Sopenharmony_ci    )";
133fd4e5da5Sopenharmony_ci
134fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
135fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
136fd4e5da5Sopenharmony_ci
137fd4e5da5Sopenharmony_ci  auto ops =
138fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
139fd4e5da5Sopenharmony_ci          context.get(), 0);
140fd4e5da5Sopenharmony_ci
141fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
142fd4e5da5Sopenharmony_ci
143fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
144fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
145fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
146fd4e5da5Sopenharmony_ci
147fd4e5da5Sopenharmony_ci  std::string after = R"(
148fd4e5da5Sopenharmony_ci               OpCapability Shader
149fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
150fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
151fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
152fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
153fd4e5da5Sopenharmony_ci               OpSource ESSL 310
154fd4e5da5Sopenharmony_ci               OpName %2 "main"
155fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
156fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
157fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
158fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
159fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
160fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
161fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
162fd4e5da5Sopenharmony_ci          %9 = OpLabel
163fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %10 %10
164fd4e5da5Sopenharmony_ci         %10 = OpLabel
165fd4e5da5Sopenharmony_ci               OpReturn
166fd4e5da5Sopenharmony_ci               OpFunctionEnd
167fd4e5da5Sopenharmony_ci    )";
168fd4e5da5Sopenharmony_ci  CheckEqual(env, after, context.get());
169fd4e5da5Sopenharmony_ci
170fd4e5da5Sopenharmony_ci  ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
171fd4e5da5Sopenharmony_ci      context.get(), 0);
172fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
173fd4e5da5Sopenharmony_ci}
174fd4e5da5Sopenharmony_ci
175fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocksOneMerge) {
176fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
177fd4e5da5Sopenharmony_ci  // should NOT be removed.
178fd4e5da5Sopenharmony_ci  //
179fd4e5da5Sopenharmony_ci  // header
180fd4e5da5Sopenharmony_ci  // |  |
181fd4e5da5Sopenharmony_ci  // | block
182fd4e5da5Sopenharmony_ci  // |  |
183fd4e5da5Sopenharmony_ci  // merge
184fd4e5da5Sopenharmony_ci
185fd4e5da5Sopenharmony_ci  std::string shader = R"(
186fd4e5da5Sopenharmony_ci               OpCapability Shader
187fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
188fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
189fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
190fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
191fd4e5da5Sopenharmony_ci               OpSource ESSL 310
192fd4e5da5Sopenharmony_ci               OpName %2 "main"
193fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
194fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
195fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
196fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
197fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
198fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
199fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
200fd4e5da5Sopenharmony_ci          %9 = OpLabel
201fd4e5da5Sopenharmony_ci               OpSelectionMerge %10 None
202fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %10 %11
203fd4e5da5Sopenharmony_ci         %11 = OpLabel
204fd4e5da5Sopenharmony_ci               OpBranch %10
205fd4e5da5Sopenharmony_ci         %10 = OpLabel
206fd4e5da5Sopenharmony_ci               OpReturn
207fd4e5da5Sopenharmony_ci               OpFunctionEnd
208fd4e5da5Sopenharmony_ci    )";
209fd4e5da5Sopenharmony_ci
210fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
211fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
212fd4e5da5Sopenharmony_ci
213fd4e5da5Sopenharmony_ci  auto ops =
214fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
215fd4e5da5Sopenharmony_ci          context.get(), 0);
216fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
217fd4e5da5Sopenharmony_ci}
218fd4e5da5Sopenharmony_ci
219fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, NoOpportunityBecauseDifferentTargetBlocks) {
220fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
221fd4e5da5Sopenharmony_ci  // should NOT be removed.
222fd4e5da5Sopenharmony_ci  //
223fd4e5da5Sopenharmony_ci  // header
224fd4e5da5Sopenharmony_ci  // | |
225fd4e5da5Sopenharmony_ci  // b b
226fd4e5da5Sopenharmony_ci  // | |
227fd4e5da5Sopenharmony_ci  // merge
228fd4e5da5Sopenharmony_ci
229fd4e5da5Sopenharmony_ci  std::string shader = R"(
230fd4e5da5Sopenharmony_ci               OpCapability Shader
231fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
232fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
233fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
234fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
235fd4e5da5Sopenharmony_ci               OpSource ESSL 310
236fd4e5da5Sopenharmony_ci               OpName %2 "main"
237fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
238fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
239fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
240fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
241fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
242fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
243fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
244fd4e5da5Sopenharmony_ci          %9 = OpLabel
245fd4e5da5Sopenharmony_ci               OpSelectionMerge %10 None
246fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %12
247fd4e5da5Sopenharmony_ci         %11 = OpLabel
248fd4e5da5Sopenharmony_ci               OpBranch %10
249fd4e5da5Sopenharmony_ci         %12 = OpLabel
250fd4e5da5Sopenharmony_ci               OpBranch %10
251fd4e5da5Sopenharmony_ci         %10 = OpLabel
252fd4e5da5Sopenharmony_ci               OpReturn
253fd4e5da5Sopenharmony_ci               OpFunctionEnd
254fd4e5da5Sopenharmony_ci    )";
255fd4e5da5Sopenharmony_ci
256fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
257fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
258fd4e5da5Sopenharmony_ci
259fd4e5da5Sopenharmony_ci  auto ops =
260fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
261fd4e5da5Sopenharmony_ci          context.get(), 0);
262fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
263fd4e5da5Sopenharmony_ci}
264fd4e5da5Sopenharmony_ci
265fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, NoOpportunityBecauseMergeUsed) {
266fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
267fd4e5da5Sopenharmony_ci  // should NOT be removed.
268fd4e5da5Sopenharmony_ci  //
269fd4e5da5Sopenharmony_ci  // header
270fd4e5da5Sopenharmony_ci  // ||
271fd4e5da5Sopenharmony_ci  // block
272fd4e5da5Sopenharmony_ci  // |  |
273fd4e5da5Sopenharmony_ci  // | block
274fd4e5da5Sopenharmony_ci  // |  |
275fd4e5da5Sopenharmony_ci  // merge
276fd4e5da5Sopenharmony_ci
277fd4e5da5Sopenharmony_ci  std::string shader = R"(
278fd4e5da5Sopenharmony_ci               OpCapability Shader
279fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
280fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
281fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
282fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
283fd4e5da5Sopenharmony_ci               OpSource ESSL 310
284fd4e5da5Sopenharmony_ci               OpName %2 "main"
285fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
286fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
287fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
288fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
289fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
290fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
291fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
292fd4e5da5Sopenharmony_ci          %9 = OpLabel
293fd4e5da5Sopenharmony_ci               OpSelectionMerge %10 None
294fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %12
295fd4e5da5Sopenharmony_ci         %11 = OpLabel
296fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %10 %12
297fd4e5da5Sopenharmony_ci         %12 = OpLabel
298fd4e5da5Sopenharmony_ci               OpBranch %10
299fd4e5da5Sopenharmony_ci         %10 = OpLabel
300fd4e5da5Sopenharmony_ci               OpReturn
301fd4e5da5Sopenharmony_ci               OpFunctionEnd
302fd4e5da5Sopenharmony_ci    )";
303fd4e5da5Sopenharmony_ci
304fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
305fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
306fd4e5da5Sopenharmony_ci
307fd4e5da5Sopenharmony_ci  auto ops =
308fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
309fd4e5da5Sopenharmony_ci          context.get(), 0);
310fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
311fd4e5da5Sopenharmony_ci}
312fd4e5da5Sopenharmony_ci
313fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, OpportunityBecauseLoopMergeUsed) {
314fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
315fd4e5da5Sopenharmony_ci  // should be removed.
316fd4e5da5Sopenharmony_ci  //
317fd4e5da5Sopenharmony_ci  // loop header
318fd4e5da5Sopenharmony_ci  //    |
319fd4e5da5Sopenharmony_ci  //    |
320fd4e5da5Sopenharmony_ci  //   s.header
321fd4e5da5Sopenharmony_ci  //    ||
322fd4e5da5Sopenharmony_ci  //   block
323fd4e5da5Sopenharmony_ci  //    |    |
324fd4e5da5Sopenharmony_ci  //    |     |
325fd4e5da5Sopenharmony_ci  //    |      |    ^ (to loop header)
326fd4e5da5Sopenharmony_ci  //   s.merge |    |
327fd4e5da5Sopenharmony_ci  //    |     /   loop continue target (unreachable)
328fd4e5da5Sopenharmony_ci  // loop merge
329fd4e5da5Sopenharmony_ci  //
330fd4e5da5Sopenharmony_ci  //
331fd4e5da5Sopenharmony_ci  // which becomes:
332fd4e5da5Sopenharmony_ci  //
333fd4e5da5Sopenharmony_ci  // loop header
334fd4e5da5Sopenharmony_ci  //    |
335fd4e5da5Sopenharmony_ci  //    |
336fd4e5da5Sopenharmony_ci  //   block
337fd4e5da5Sopenharmony_ci  //    ||
338fd4e5da5Sopenharmony_ci  //   block
339fd4e5da5Sopenharmony_ci  //    |    |
340fd4e5da5Sopenharmony_ci  //    |     |
341fd4e5da5Sopenharmony_ci  //    |      |    ^ (to loop header)
342fd4e5da5Sopenharmony_ci  //   block   |    |
343fd4e5da5Sopenharmony_ci  //    |     /   loop continue target (unreachable)
344fd4e5da5Sopenharmony_ci  // loop merge
345fd4e5da5Sopenharmony_ci
346fd4e5da5Sopenharmony_ci  std::string shader = R"(
347fd4e5da5Sopenharmony_ci               OpCapability Shader
348fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
349fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
350fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
351fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
352fd4e5da5Sopenharmony_ci               OpSource ESSL 310
353fd4e5da5Sopenharmony_ci               OpName %2 "main"
354fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
355fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
356fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
357fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
358fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
359fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
360fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
361fd4e5da5Sopenharmony_ci          %9 = OpLabel
362fd4e5da5Sopenharmony_ci               OpBranch %10
363fd4e5da5Sopenharmony_ci         %10 = OpLabel
364fd4e5da5Sopenharmony_ci               OpLoopMerge %11 %12 None
365fd4e5da5Sopenharmony_ci               OpBranch %13
366fd4e5da5Sopenharmony_ci         %13 = OpLabel
367fd4e5da5Sopenharmony_ci               OpSelectionMerge %14 None
368fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %15 %15
369fd4e5da5Sopenharmony_ci         %15 = OpLabel
370fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %14 %11
371fd4e5da5Sopenharmony_ci         %14 = OpLabel
372fd4e5da5Sopenharmony_ci               OpBranch %11
373fd4e5da5Sopenharmony_ci         %12 = OpLabel
374fd4e5da5Sopenharmony_ci               OpBranch %10
375fd4e5da5Sopenharmony_ci         %11 = OpLabel
376fd4e5da5Sopenharmony_ci               OpReturn
377fd4e5da5Sopenharmony_ci               OpFunctionEnd
378fd4e5da5Sopenharmony_ci    )";
379fd4e5da5Sopenharmony_ci
380fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
381fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
382fd4e5da5Sopenharmony_ci
383fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
384fd4e5da5Sopenharmony_ci
385fd4e5da5Sopenharmony_ci  auto ops =
386fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
387fd4e5da5Sopenharmony_ci          context.get(), 0);
388fd4e5da5Sopenharmony_ci
389fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
390fd4e5da5Sopenharmony_ci
391fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
392fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
393fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
394fd4e5da5Sopenharmony_ci
395fd4e5da5Sopenharmony_ci  std::string after = R"(
396fd4e5da5Sopenharmony_ci               OpCapability Shader
397fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
398fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
399fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
400fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
401fd4e5da5Sopenharmony_ci               OpSource ESSL 310
402fd4e5da5Sopenharmony_ci               OpName %2 "main"
403fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
404fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
405fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
406fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
407fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
408fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
409fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
410fd4e5da5Sopenharmony_ci          %9 = OpLabel
411fd4e5da5Sopenharmony_ci               OpBranch %10
412fd4e5da5Sopenharmony_ci         %10 = OpLabel
413fd4e5da5Sopenharmony_ci               OpLoopMerge %11 %12 None
414fd4e5da5Sopenharmony_ci               OpBranch %13
415fd4e5da5Sopenharmony_ci         %13 = OpLabel
416fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %15 %15
417fd4e5da5Sopenharmony_ci         %15 = OpLabel
418fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %14 %11
419fd4e5da5Sopenharmony_ci         %14 = OpLabel
420fd4e5da5Sopenharmony_ci               OpBranch %11
421fd4e5da5Sopenharmony_ci         %12 = OpLabel
422fd4e5da5Sopenharmony_ci               OpBranch %10
423fd4e5da5Sopenharmony_ci         %11 = OpLabel
424fd4e5da5Sopenharmony_ci               OpReturn
425fd4e5da5Sopenharmony_ci               OpFunctionEnd
426fd4e5da5Sopenharmony_ci    )";
427fd4e5da5Sopenharmony_ci  CheckEqual(env, after, context.get());
428fd4e5da5Sopenharmony_ci
429fd4e5da5Sopenharmony_ci  ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
430fd4e5da5Sopenharmony_ci      context.get(), 0);
431fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
432fd4e5da5Sopenharmony_ci}
433fd4e5da5Sopenharmony_ci
434fd4e5da5Sopenharmony_ciTEST(RemoveSelectionTest, OpportunityBecauseLoopContinueUsed) {
435fd4e5da5Sopenharmony_ci  // A test with the following structure. The OpSelectionMerge instruction
436fd4e5da5Sopenharmony_ci  // should be removed.
437fd4e5da5Sopenharmony_ci  //
438fd4e5da5Sopenharmony_ci  // loop header
439fd4e5da5Sopenharmony_ci  //    |
440fd4e5da5Sopenharmony_ci  //    |
441fd4e5da5Sopenharmony_ci  //   s.header
442fd4e5da5Sopenharmony_ci  //    ||
443fd4e5da5Sopenharmony_ci  //   block
444fd4e5da5Sopenharmony_ci  //    |    |
445fd4e5da5Sopenharmony_ci  //    |     |
446fd4e5da5Sopenharmony_ci  //    |      |    ^ (to loop header)
447fd4e5da5Sopenharmony_ci  //   s.merge |    |
448fd4e5da5Sopenharmony_ci  //    |     loop continue target
449fd4e5da5Sopenharmony_ci  // loop merge
450fd4e5da5Sopenharmony_ci  //
451fd4e5da5Sopenharmony_ci  //
452fd4e5da5Sopenharmony_ci  // which becomes:
453fd4e5da5Sopenharmony_ci  //
454fd4e5da5Sopenharmony_ci  // loop header
455fd4e5da5Sopenharmony_ci  //    |
456fd4e5da5Sopenharmony_ci  //    |
457fd4e5da5Sopenharmony_ci  //   block
458fd4e5da5Sopenharmony_ci  //    ||
459fd4e5da5Sopenharmony_ci  //   block
460fd4e5da5Sopenharmony_ci  //    |    |
461fd4e5da5Sopenharmony_ci  //    |     |
462fd4e5da5Sopenharmony_ci  //    |      |    ^ (to loop header)
463fd4e5da5Sopenharmony_ci  //   block   |    |
464fd4e5da5Sopenharmony_ci  //    |     loop continue target
465fd4e5da5Sopenharmony_ci  // loop merge
466fd4e5da5Sopenharmony_ci
467fd4e5da5Sopenharmony_ci  std::string shader = R"(
468fd4e5da5Sopenharmony_ci               OpCapability Shader
469fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
470fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
471fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
472fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
473fd4e5da5Sopenharmony_ci               OpSource ESSL 310
474fd4e5da5Sopenharmony_ci               OpName %2 "main"
475fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
476fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
477fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
478fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
479fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
480fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
481fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
482fd4e5da5Sopenharmony_ci          %9 = OpLabel
483fd4e5da5Sopenharmony_ci               OpBranch %10
484fd4e5da5Sopenharmony_ci         %10 = OpLabel
485fd4e5da5Sopenharmony_ci               OpLoopMerge %11 %12 None
486fd4e5da5Sopenharmony_ci               OpBranch %13
487fd4e5da5Sopenharmony_ci         %13 = OpLabel
488fd4e5da5Sopenharmony_ci               OpSelectionMerge %14 None
489fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %15 %15
490fd4e5da5Sopenharmony_ci         %15 = OpLabel
491fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %14 %12
492fd4e5da5Sopenharmony_ci         %14 = OpLabel
493fd4e5da5Sopenharmony_ci               OpBranch %11
494fd4e5da5Sopenharmony_ci         %12 = OpLabel
495fd4e5da5Sopenharmony_ci               OpBranch %10
496fd4e5da5Sopenharmony_ci         %11 = OpLabel
497fd4e5da5Sopenharmony_ci               OpReturn
498fd4e5da5Sopenharmony_ci               OpFunctionEnd
499fd4e5da5Sopenharmony_ci    )";
500fd4e5da5Sopenharmony_ci
501fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
502fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, nullptr, shader, kReduceAssembleOption);
503fd4e5da5Sopenharmony_ci
504fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
505fd4e5da5Sopenharmony_ci
506fd4e5da5Sopenharmony_ci  auto ops =
507fd4e5da5Sopenharmony_ci      RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
508fd4e5da5Sopenharmony_ci          context.get(), 0);
509fd4e5da5Sopenharmony_ci
510fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
511fd4e5da5Sopenharmony_ci
512fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
513fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
514fd4e5da5Sopenharmony_ci  CheckValid(env, context.get());
515fd4e5da5Sopenharmony_ci
516fd4e5da5Sopenharmony_ci  std::string after = R"(
517fd4e5da5Sopenharmony_ci               OpCapability Shader
518fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
519fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
520fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
521fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
522fd4e5da5Sopenharmony_ci               OpSource ESSL 310
523fd4e5da5Sopenharmony_ci               OpName %2 "main"
524fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
525fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
526fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
527fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
528fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
529fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
530fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
531fd4e5da5Sopenharmony_ci          %9 = OpLabel
532fd4e5da5Sopenharmony_ci               OpBranch %10
533fd4e5da5Sopenharmony_ci         %10 = OpLabel
534fd4e5da5Sopenharmony_ci               OpLoopMerge %11 %12 None
535fd4e5da5Sopenharmony_ci               OpBranch %13
536fd4e5da5Sopenharmony_ci         %13 = OpLabel
537fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %15 %15
538fd4e5da5Sopenharmony_ci         %15 = OpLabel
539fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %14 %12
540fd4e5da5Sopenharmony_ci         %14 = OpLabel
541fd4e5da5Sopenharmony_ci               OpBranch %11
542fd4e5da5Sopenharmony_ci         %12 = OpLabel
543fd4e5da5Sopenharmony_ci               OpBranch %10
544fd4e5da5Sopenharmony_ci         %11 = OpLabel
545fd4e5da5Sopenharmony_ci               OpReturn
546fd4e5da5Sopenharmony_ci               OpFunctionEnd
547fd4e5da5Sopenharmony_ci    )";
548fd4e5da5Sopenharmony_ci  CheckEqual(env, after, context.get());
549fd4e5da5Sopenharmony_ci
550fd4e5da5Sopenharmony_ci  ops = RemoveSelectionReductionOpportunityFinder().GetAvailableOpportunities(
551fd4e5da5Sopenharmony_ci      context.get(), 0);
552fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
553fd4e5da5Sopenharmony_ci}
554fd4e5da5Sopenharmony_ci
555fd4e5da5Sopenharmony_ci}  // namespace
556fd4e5da5Sopenharmony_ci}  // namespace reduce
557fd4e5da5Sopenharmony_ci}  // namespace spvtools
558