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