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_block_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(RemoveBlockReductionPassTest, BasicCheck) {
26fd4e5da5Sopenharmony_ci  std::string shader = R"(
27fd4e5da5Sopenharmony_ci               OpCapability Shader
28fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
29fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
30fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
31fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
32fd4e5da5Sopenharmony_ci               OpSource ESSL 310
33fd4e5da5Sopenharmony_ci               OpName %4 "main"
34fd4e5da5Sopenharmony_ci               OpName %8 "x"
35fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
36fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
37fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
38fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
39fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
40fd4e5da5Sopenharmony_ci         %10 = OpConstant %6 2
41fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 3
42fd4e5da5Sopenharmony_ci         %12 = OpConstant %6 4
43fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
44fd4e5da5Sopenharmony_ci          %5 = OpLabel
45fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
46fd4e5da5Sopenharmony_ci               OpBranch %14
47fd4e5da5Sopenharmony_ci         %13 = OpLabel ; unreachable
48fd4e5da5Sopenharmony_ci               OpStore %8 %9
49fd4e5da5Sopenharmony_ci               OpBranch %14
50fd4e5da5Sopenharmony_ci         %14 = OpLabel
51fd4e5da5Sopenharmony_ci               OpStore %8 %10
52fd4e5da5Sopenharmony_ci               OpBranch %16
53fd4e5da5Sopenharmony_ci         %15 = OpLabel ; unreachable
54fd4e5da5Sopenharmony_ci               OpStore %8 %11
55fd4e5da5Sopenharmony_ci               OpBranch %16
56fd4e5da5Sopenharmony_ci         %16 = OpLabel
57fd4e5da5Sopenharmony_ci               OpStore %8 %12
58fd4e5da5Sopenharmony_ci               OpBranch %17
59fd4e5da5Sopenharmony_ci         %17 = OpLabel
60fd4e5da5Sopenharmony_ci               OpReturn
61fd4e5da5Sopenharmony_ci               OpFunctionEnd
62fd4e5da5Sopenharmony_ci  )";
63fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
64fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
65fd4e5da5Sopenharmony_ci  const auto context =
66fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
67fd4e5da5Sopenharmony_ci  const auto ops =
68fd4e5da5Sopenharmony_ci      RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
69fd4e5da5Sopenharmony_ci          context.get(), 0);
70fd4e5da5Sopenharmony_ci  ASSERT_EQ(2, ops.size());
71fd4e5da5Sopenharmony_ci
72fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
73fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
74fd4e5da5Sopenharmony_ci
75fd4e5da5Sopenharmony_ci  std::string after_op_0 = R"(
76fd4e5da5Sopenharmony_ci               OpCapability Shader
77fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
78fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
79fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
80fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
81fd4e5da5Sopenharmony_ci               OpSource ESSL 310
82fd4e5da5Sopenharmony_ci               OpName %4 "main"
83fd4e5da5Sopenharmony_ci               OpName %8 "x"
84fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
85fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
86fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
87fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
88fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
89fd4e5da5Sopenharmony_ci         %10 = OpConstant %6 2
90fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 3
91fd4e5da5Sopenharmony_ci         %12 = OpConstant %6 4
92fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
93fd4e5da5Sopenharmony_ci          %5 = OpLabel
94fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
95fd4e5da5Sopenharmony_ci               OpBranch %14
96fd4e5da5Sopenharmony_ci         %14 = OpLabel
97fd4e5da5Sopenharmony_ci               OpStore %8 %10
98fd4e5da5Sopenharmony_ci               OpBranch %16
99fd4e5da5Sopenharmony_ci         %15 = OpLabel
100fd4e5da5Sopenharmony_ci               OpStore %8 %11
101fd4e5da5Sopenharmony_ci               OpBranch %16
102fd4e5da5Sopenharmony_ci         %16 = OpLabel
103fd4e5da5Sopenharmony_ci               OpStore %8 %12
104fd4e5da5Sopenharmony_ci               OpBranch %17
105fd4e5da5Sopenharmony_ci         %17 = OpLabel
106fd4e5da5Sopenharmony_ci               OpReturn
107fd4e5da5Sopenharmony_ci               OpFunctionEnd
108fd4e5da5Sopenharmony_ci  )";
109fd4e5da5Sopenharmony_ci
110fd4e5da5Sopenharmony_ci  CheckEqual(env, after_op_0, context.get());
111fd4e5da5Sopenharmony_ci
112fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[1]->PreconditionHolds());
113fd4e5da5Sopenharmony_ci  ops[1]->TryToApply();
114fd4e5da5Sopenharmony_ci
115fd4e5da5Sopenharmony_ci  std::string after_op_1 = R"(
116fd4e5da5Sopenharmony_ci               OpCapability Shader
117fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
118fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
119fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
120fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
121fd4e5da5Sopenharmony_ci               OpSource ESSL 310
122fd4e5da5Sopenharmony_ci               OpName %4 "main"
123fd4e5da5Sopenharmony_ci               OpName %8 "x"
124fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
125fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
126fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
127fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
128fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 1
129fd4e5da5Sopenharmony_ci         %10 = OpConstant %6 2
130fd4e5da5Sopenharmony_ci         %11 = OpConstant %6 3
131fd4e5da5Sopenharmony_ci         %12 = OpConstant %6 4
132fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
133fd4e5da5Sopenharmony_ci          %5 = OpLabel
134fd4e5da5Sopenharmony_ci          %8 = OpVariable %7 Function
135fd4e5da5Sopenharmony_ci               OpBranch %14
136fd4e5da5Sopenharmony_ci         %14 = OpLabel
137fd4e5da5Sopenharmony_ci               OpStore %8 %10
138fd4e5da5Sopenharmony_ci               OpBranch %16
139fd4e5da5Sopenharmony_ci         %16 = OpLabel
140fd4e5da5Sopenharmony_ci               OpStore %8 %12
141fd4e5da5Sopenharmony_ci               OpBranch %17
142fd4e5da5Sopenharmony_ci         %17 = OpLabel
143fd4e5da5Sopenharmony_ci               OpReturn
144fd4e5da5Sopenharmony_ci               OpFunctionEnd
145fd4e5da5Sopenharmony_ci  )";
146fd4e5da5Sopenharmony_ci
147fd4e5da5Sopenharmony_ci  CheckEqual(env, after_op_1, context.get());
148fd4e5da5Sopenharmony_ci}
149fd4e5da5Sopenharmony_ci
150fd4e5da5Sopenharmony_ciTEST(RemoveBlockReductionPassTest, UnreachableContinueAndMerge) {
151fd4e5da5Sopenharmony_ci  // Loop with unreachable merge and continue target. There should be no
152fd4e5da5Sopenharmony_ci  // opportunities.
153fd4e5da5Sopenharmony_ci
154fd4e5da5Sopenharmony_ci  std::string shader = R"(
155fd4e5da5Sopenharmony_ci               OpCapability Shader
156fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
157fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
158fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
159fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
160fd4e5da5Sopenharmony_ci               OpSource ESSL 310
161fd4e5da5Sopenharmony_ci               OpName %4 "main"
162fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
163fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
164fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
165fd4e5da5Sopenharmony_ci          %5 = OpLabel
166fd4e5da5Sopenharmony_ci               OpBranch %13
167fd4e5da5Sopenharmony_ci         %13 = OpLabel
168fd4e5da5Sopenharmony_ci               OpLoopMerge %16 %15 None
169fd4e5da5Sopenharmony_ci               OpBranch %14
170fd4e5da5Sopenharmony_ci         %14 = OpLabel
171fd4e5da5Sopenharmony_ci               OpReturn
172fd4e5da5Sopenharmony_ci         %15 = OpLabel
173fd4e5da5Sopenharmony_ci               OpBranch %13
174fd4e5da5Sopenharmony_ci         %16 = OpLabel
175fd4e5da5Sopenharmony_ci               OpReturn
176fd4e5da5Sopenharmony_ci               OpFunctionEnd
177fd4e5da5Sopenharmony_ci  )";
178fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
179fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
180fd4e5da5Sopenharmony_ci  const auto context =
181fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
182fd4e5da5Sopenharmony_ci  const auto ops =
183fd4e5da5Sopenharmony_ci      RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
184fd4e5da5Sopenharmony_ci          context.get(), 0);
185fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
186fd4e5da5Sopenharmony_ci}
187fd4e5da5Sopenharmony_ci
188fd4e5da5Sopenharmony_ciTEST(RemoveBlockReductionPassTest, OneBlock) {
189fd4e5da5Sopenharmony_ci  // Function with just one block. There should be no opportunities.
190fd4e5da5Sopenharmony_ci
191fd4e5da5Sopenharmony_ci  std::string shader = R"(
192fd4e5da5Sopenharmony_ci               OpCapability Shader
193fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
194fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
195fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
196fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
197fd4e5da5Sopenharmony_ci               OpSource ESSL 310
198fd4e5da5Sopenharmony_ci               OpName %4 "main"
199fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
200fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
201fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
202fd4e5da5Sopenharmony_ci          %5 = OpLabel
203fd4e5da5Sopenharmony_ci               OpReturn
204fd4e5da5Sopenharmony_ci               OpFunctionEnd
205fd4e5da5Sopenharmony_ci  )";
206fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
207fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
208fd4e5da5Sopenharmony_ci  const auto context =
209fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
210fd4e5da5Sopenharmony_ci  const auto ops =
211fd4e5da5Sopenharmony_ci      RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
212fd4e5da5Sopenharmony_ci          context.get(), 0);
213fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
214fd4e5da5Sopenharmony_ci}
215fd4e5da5Sopenharmony_ci
216fd4e5da5Sopenharmony_ciTEST(RemoveBlockReductionPassTest, UnreachableBlocksWithOutsideIdUses) {
217fd4e5da5Sopenharmony_ci  // A function with two unreachable blocks A -> B. A defines ID %9 and B uses
218fd4e5da5Sopenharmony_ci  // %9. There are no references to A, but removing A would be invalid because
219fd4e5da5Sopenharmony_ci  // of B's use of %9, so there should be no opportunities.
220fd4e5da5Sopenharmony_ci
221fd4e5da5Sopenharmony_ci  std::string shader = R"(
222fd4e5da5Sopenharmony_ci               OpCapability Shader
223fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
224fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
225fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
226fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
227fd4e5da5Sopenharmony_ci               OpSource ESSL 310
228fd4e5da5Sopenharmony_ci               OpName %2 "main"
229fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
230fd4e5da5Sopenharmony_ci          %4 = OpTypeInt 32 1
231fd4e5da5Sopenharmony_ci          %5 = OpTypeFunction %3
232fd4e5da5Sopenharmony_ci          %6 = OpConstant %4 1
233fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %5
234fd4e5da5Sopenharmony_ci          %7 = OpLabel
235fd4e5da5Sopenharmony_ci               OpReturn
236fd4e5da5Sopenharmony_ci          %8 = OpLabel          ; A
237fd4e5da5Sopenharmony_ci          %9 = OpUndef %4
238fd4e5da5Sopenharmony_ci               OpBranch %10
239fd4e5da5Sopenharmony_ci         %10 = OpLabel          ; B
240fd4e5da5Sopenharmony_ci         %11 = OpIAdd %4 %6 %9  ; uses %9 from A, so A cannot be removed
241fd4e5da5Sopenharmony_ci               OpReturn
242fd4e5da5Sopenharmony_ci               OpFunctionEnd
243fd4e5da5Sopenharmony_ci  )";
244fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
245fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
246fd4e5da5Sopenharmony_ci  const auto context =
247fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
248fd4e5da5Sopenharmony_ci  const auto ops =
249fd4e5da5Sopenharmony_ci      RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
250fd4e5da5Sopenharmony_ci          context.get(), 0);
251fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
252fd4e5da5Sopenharmony_ci}
253fd4e5da5Sopenharmony_ci
254fd4e5da5Sopenharmony_ciTEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) {
255fd4e5da5Sopenharmony_ci  // Similar to the above test.
256fd4e5da5Sopenharmony_ci
257fd4e5da5Sopenharmony_ci  // A function with two unreachable blocks A -> B. Both blocks create and use
258fd4e5da5Sopenharmony_ci  // IDs, but the uses are contained within each block, so A should be removed.
259fd4e5da5Sopenharmony_ci
260fd4e5da5Sopenharmony_ci  std::string shader = R"(
261fd4e5da5Sopenharmony_ci               OpCapability Shader
262fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
263fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
264fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
265fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
266fd4e5da5Sopenharmony_ci               OpSource ESSL 310
267fd4e5da5Sopenharmony_ci               OpName %2 "main"
268fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
269fd4e5da5Sopenharmony_ci          %4 = OpTypeInt 32 1
270fd4e5da5Sopenharmony_ci          %5 = OpTypeFunction %3
271fd4e5da5Sopenharmony_ci          %6 = OpConstant %4 1
272fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %5
273fd4e5da5Sopenharmony_ci          %7 = OpLabel
274fd4e5da5Sopenharmony_ci               OpReturn
275fd4e5da5Sopenharmony_ci          %8 = OpLabel                     ; A
276fd4e5da5Sopenharmony_ci          %9 = OpUndef %4                  ; define %9
277fd4e5da5Sopenharmony_ci         %10 = OpIAdd %4 %6 %9             ; use %9
278fd4e5da5Sopenharmony_ci               OpBranch %11
279fd4e5da5Sopenharmony_ci         %11 = OpLabel                     ; B
280fd4e5da5Sopenharmony_ci         %12 = OpUndef %4                  ; define %12
281fd4e5da5Sopenharmony_ci         %13 = OpIAdd %4 %6 %12            ; use %12
282fd4e5da5Sopenharmony_ci               OpReturn
283fd4e5da5Sopenharmony_ci               OpFunctionEnd
284fd4e5da5Sopenharmony_ci  )";
285fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
286fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
287fd4e5da5Sopenharmony_ci  const auto context =
288fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
289fd4e5da5Sopenharmony_ci  auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
290fd4e5da5Sopenharmony_ci      context.get(), 0);
291fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
292fd4e5da5Sopenharmony_ci
293fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
294fd4e5da5Sopenharmony_ci
295fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
296fd4e5da5Sopenharmony_ci
297fd4e5da5Sopenharmony_ci  // Same as above, but block A is removed.
298fd4e5da5Sopenharmony_ci  std::string after_op_0 = R"(
299fd4e5da5Sopenharmony_ci               OpCapability Shader
300fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
301fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
302fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
303fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
304fd4e5da5Sopenharmony_ci               OpSource ESSL 310
305fd4e5da5Sopenharmony_ci               OpName %2 "main"
306fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
307fd4e5da5Sopenharmony_ci          %4 = OpTypeInt 32 1
308fd4e5da5Sopenharmony_ci          %5 = OpTypeFunction %3
309fd4e5da5Sopenharmony_ci          %6 = OpConstant %4 1
310fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %5
311fd4e5da5Sopenharmony_ci          %7 = OpLabel
312fd4e5da5Sopenharmony_ci               OpReturn
313fd4e5da5Sopenharmony_ci         %11 = OpLabel
314fd4e5da5Sopenharmony_ci         %12 = OpUndef %4
315fd4e5da5Sopenharmony_ci         %13 = OpIAdd %4 %6 %12
316fd4e5da5Sopenharmony_ci               OpReturn
317fd4e5da5Sopenharmony_ci               OpFunctionEnd
318fd4e5da5Sopenharmony_ci  )";
319fd4e5da5Sopenharmony_ci
320fd4e5da5Sopenharmony_ci  CheckEqual(env, after_op_0, context.get());
321fd4e5da5Sopenharmony_ci
322fd4e5da5Sopenharmony_ci  // Find opportunities again. There are no reference to B. B should now be
323fd4e5da5Sopenharmony_ci  // removed.
324fd4e5da5Sopenharmony_ci
325fd4e5da5Sopenharmony_ci  ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
326fd4e5da5Sopenharmony_ci      context.get(), 0);
327fd4e5da5Sopenharmony_ci
328fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
329fd4e5da5Sopenharmony_ci
330fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
331fd4e5da5Sopenharmony_ci
332fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
333fd4e5da5Sopenharmony_ci
334fd4e5da5Sopenharmony_ci  // Same as above, but block B is removed.
335fd4e5da5Sopenharmony_ci  std::string after_op_0_again = R"(
336fd4e5da5Sopenharmony_ci               OpCapability Shader
337fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
338fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
339fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
340fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
341fd4e5da5Sopenharmony_ci               OpSource ESSL 310
342fd4e5da5Sopenharmony_ci               OpName %2 "main"
343fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
344fd4e5da5Sopenharmony_ci          %4 = OpTypeInt 32 1
345fd4e5da5Sopenharmony_ci          %5 = OpTypeFunction %3
346fd4e5da5Sopenharmony_ci          %6 = OpConstant %4 1
347fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %5
348fd4e5da5Sopenharmony_ci          %7 = OpLabel
349fd4e5da5Sopenharmony_ci               OpReturn
350fd4e5da5Sopenharmony_ci               OpFunctionEnd
351fd4e5da5Sopenharmony_ci  )";
352fd4e5da5Sopenharmony_ci
353fd4e5da5Sopenharmony_ci  CheckEqual(env, after_op_0_again, context.get());
354fd4e5da5Sopenharmony_ci}
355fd4e5da5Sopenharmony_ci
356fd4e5da5Sopenharmony_ci}  // namespace
357fd4e5da5Sopenharmony_ci}  // namespace reduce
358fd4e5da5Sopenharmony_ci}  // namespace spvtools
359