1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google Inc. 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 <memory> 16fd4e5da5Sopenharmony_ci#include <string> 17fd4e5da5Sopenharmony_ci#include <unordered_set> 18fd4e5da5Sopenharmony_ci#include <vector> 19fd4e5da5Sopenharmony_ci 20fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 21fd4e5da5Sopenharmony_ci#include "source/opt/iterator.h" 22fd4e5da5Sopenharmony_ci#include "source/opt/loop_descriptor.h" 23fd4e5da5Sopenharmony_ci#include "source/opt/pass.h" 24fd4e5da5Sopenharmony_ci#include "source/opt/tree_iterator.h" 25fd4e5da5Sopenharmony_ci#include "test/opt/assembly_builder.h" 26fd4e5da5Sopenharmony_ci#include "test/opt/function_utils.h" 27fd4e5da5Sopenharmony_ci#include "test/opt/pass_fixture.h" 28fd4e5da5Sopenharmony_ci#include "test/opt/pass_utils.h" 29fd4e5da5Sopenharmony_ci 30fd4e5da5Sopenharmony_cinamespace spvtools { 31fd4e5da5Sopenharmony_cinamespace opt { 32fd4e5da5Sopenharmony_cinamespace { 33fd4e5da5Sopenharmony_ci 34fd4e5da5Sopenharmony_ciusing ::testing::UnorderedElementsAre; 35fd4e5da5Sopenharmony_ci 36fd4e5da5Sopenharmony_cibool Validate(const std::vector<uint32_t>& bin) { 37fd4e5da5Sopenharmony_ci spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2; 38fd4e5da5Sopenharmony_ci spv_context spvContext = spvContextCreate(target_env); 39fd4e5da5Sopenharmony_ci spv_diagnostic diagnostic = nullptr; 40fd4e5da5Sopenharmony_ci spv_const_binary_t binary = {bin.data(), bin.size()}; 41fd4e5da5Sopenharmony_ci spv_result_t error = spvValidate(spvContext, &binary, &diagnostic); 42fd4e5da5Sopenharmony_ci if (error != 0) spvDiagnosticPrint(diagnostic); 43fd4e5da5Sopenharmony_ci spvDiagnosticDestroy(diagnostic); 44fd4e5da5Sopenharmony_ci spvContextDestroy(spvContext); 45fd4e5da5Sopenharmony_ci return error == 0; 46fd4e5da5Sopenharmony_ci} 47fd4e5da5Sopenharmony_ci 48fd4e5da5Sopenharmony_ciusing PassClassTest = PassTest<::testing::Test>; 49fd4e5da5Sopenharmony_ci 50fd4e5da5Sopenharmony_ci/* 51fd4e5da5Sopenharmony_ciGenerated from the following GLSL 52fd4e5da5Sopenharmony_ci#version 330 core 53fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c; 54fd4e5da5Sopenharmony_civoid main() { 55fd4e5da5Sopenharmony_ci int i = 0; 56fd4e5da5Sopenharmony_ci for (; i < 10; ++i) { 57fd4e5da5Sopenharmony_ci int j = 0; 58fd4e5da5Sopenharmony_ci int k = 0; 59fd4e5da5Sopenharmony_ci for (; j < 11; ++j) {} 60fd4e5da5Sopenharmony_ci for (; k < 12; ++k) {} 61fd4e5da5Sopenharmony_ci } 62fd4e5da5Sopenharmony_ci} 63fd4e5da5Sopenharmony_ci*/ 64fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, BasicVisitFromEntryPoint) { 65fd4e5da5Sopenharmony_ci const std::string text = R"( 66fd4e5da5Sopenharmony_ci OpCapability Shader 67fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 68fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 69fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "main" %3 70fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 71fd4e5da5Sopenharmony_ci OpSource GLSL 330 72fd4e5da5Sopenharmony_ci OpName %2 "main" 73fd4e5da5Sopenharmony_ci OpName %4 "i" 74fd4e5da5Sopenharmony_ci OpName %5 "j" 75fd4e5da5Sopenharmony_ci OpName %6 "k" 76fd4e5da5Sopenharmony_ci OpName %3 "c" 77fd4e5da5Sopenharmony_ci OpDecorate %3 Location 0 78fd4e5da5Sopenharmony_ci %7 = OpTypeVoid 79fd4e5da5Sopenharmony_ci %8 = OpTypeFunction %7 80fd4e5da5Sopenharmony_ci %9 = OpTypeInt 32 1 81fd4e5da5Sopenharmony_ci %10 = OpTypePointer Function %9 82fd4e5da5Sopenharmony_ci %11 = OpConstant %9 0 83fd4e5da5Sopenharmony_ci %12 = OpConstant %9 10 84fd4e5da5Sopenharmony_ci %13 = OpTypeBool 85fd4e5da5Sopenharmony_ci %14 = OpConstant %9 11 86fd4e5da5Sopenharmony_ci %15 = OpConstant %9 1 87fd4e5da5Sopenharmony_ci %16 = OpConstant %9 12 88fd4e5da5Sopenharmony_ci %17 = OpTypeFloat 32 89fd4e5da5Sopenharmony_ci %18 = OpTypeVector %17 4 90fd4e5da5Sopenharmony_ci %19 = OpTypePointer Output %18 91fd4e5da5Sopenharmony_ci %3 = OpVariable %19 Output 92fd4e5da5Sopenharmony_ci %2 = OpFunction %7 None %8 93fd4e5da5Sopenharmony_ci %20 = OpLabel 94fd4e5da5Sopenharmony_ci %4 = OpVariable %10 Function 95fd4e5da5Sopenharmony_ci %5 = OpVariable %10 Function 96fd4e5da5Sopenharmony_ci %6 = OpVariable %10 Function 97fd4e5da5Sopenharmony_ci OpStore %4 %11 98fd4e5da5Sopenharmony_ci OpBranch %21 99fd4e5da5Sopenharmony_ci %21 = OpLabel 100fd4e5da5Sopenharmony_ci OpLoopMerge %22 %23 None 101fd4e5da5Sopenharmony_ci OpBranch %24 102fd4e5da5Sopenharmony_ci %24 = OpLabel 103fd4e5da5Sopenharmony_ci %25 = OpLoad %9 %4 104fd4e5da5Sopenharmony_ci %26 = OpSLessThan %13 %25 %12 105fd4e5da5Sopenharmony_ci OpBranchConditional %26 %27 %22 106fd4e5da5Sopenharmony_ci %27 = OpLabel 107fd4e5da5Sopenharmony_ci OpStore %5 %11 108fd4e5da5Sopenharmony_ci OpStore %6 %11 109fd4e5da5Sopenharmony_ci OpBranch %28 110fd4e5da5Sopenharmony_ci %28 = OpLabel 111fd4e5da5Sopenharmony_ci OpLoopMerge %29 %30 None 112fd4e5da5Sopenharmony_ci OpBranch %31 113fd4e5da5Sopenharmony_ci %31 = OpLabel 114fd4e5da5Sopenharmony_ci %32 = OpLoad %9 %5 115fd4e5da5Sopenharmony_ci %33 = OpSLessThan %13 %32 %14 116fd4e5da5Sopenharmony_ci OpBranchConditional %33 %34 %29 117fd4e5da5Sopenharmony_ci %34 = OpLabel 118fd4e5da5Sopenharmony_ci OpBranch %30 119fd4e5da5Sopenharmony_ci %30 = OpLabel 120fd4e5da5Sopenharmony_ci %35 = OpLoad %9 %5 121fd4e5da5Sopenharmony_ci %36 = OpIAdd %9 %35 %15 122fd4e5da5Sopenharmony_ci OpStore %5 %36 123fd4e5da5Sopenharmony_ci OpBranch %28 124fd4e5da5Sopenharmony_ci %29 = OpLabel 125fd4e5da5Sopenharmony_ci OpBranch %37 126fd4e5da5Sopenharmony_ci %37 = OpLabel 127fd4e5da5Sopenharmony_ci OpLoopMerge %38 %39 None 128fd4e5da5Sopenharmony_ci OpBranch %40 129fd4e5da5Sopenharmony_ci %40 = OpLabel 130fd4e5da5Sopenharmony_ci %41 = OpLoad %9 %6 131fd4e5da5Sopenharmony_ci %42 = OpSLessThan %13 %41 %16 132fd4e5da5Sopenharmony_ci OpBranchConditional %42 %43 %38 133fd4e5da5Sopenharmony_ci %43 = OpLabel 134fd4e5da5Sopenharmony_ci OpBranch %39 135fd4e5da5Sopenharmony_ci %39 = OpLabel 136fd4e5da5Sopenharmony_ci %44 = OpLoad %9 %6 137fd4e5da5Sopenharmony_ci %45 = OpIAdd %9 %44 %15 138fd4e5da5Sopenharmony_ci OpStore %6 %45 139fd4e5da5Sopenharmony_ci OpBranch %37 140fd4e5da5Sopenharmony_ci %38 = OpLabel 141fd4e5da5Sopenharmony_ci OpBranch %23 142fd4e5da5Sopenharmony_ci %23 = OpLabel 143fd4e5da5Sopenharmony_ci %46 = OpLoad %9 %4 144fd4e5da5Sopenharmony_ci %47 = OpIAdd %9 %46 %15 145fd4e5da5Sopenharmony_ci OpStore %4 %47 146fd4e5da5Sopenharmony_ci OpBranch %21 147fd4e5da5Sopenharmony_ci %22 = OpLabel 148fd4e5da5Sopenharmony_ci OpReturn 149fd4e5da5Sopenharmony_ci OpFunctionEnd 150fd4e5da5Sopenharmony_ci )"; 151fd4e5da5Sopenharmony_ci // clang-format on 152fd4e5da5Sopenharmony_ci std::unique_ptr<IRContext> context = 153fd4e5da5Sopenharmony_ci BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 154fd4e5da5Sopenharmony_ci SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 155fd4e5da5Sopenharmony_ci Module* module = context->module(); 156fd4e5da5Sopenharmony_ci EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 157fd4e5da5Sopenharmony_ci << text << std::endl; 158fd4e5da5Sopenharmony_ci const Function* f = spvtest::GetFunction(module, 2); 159fd4e5da5Sopenharmony_ci LoopDescriptor& ld = *context->GetLoopDescriptor(f); 160fd4e5da5Sopenharmony_ci 161fd4e5da5Sopenharmony_ci EXPECT_EQ(ld.NumLoops(), 3u); 162fd4e5da5Sopenharmony_ci 163fd4e5da5Sopenharmony_ci // Invalid basic block id. 164fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[0u], nullptr); 165fd4e5da5Sopenharmony_ci // Not a loop header. 166fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[20], nullptr); 167fd4e5da5Sopenharmony_ci 168fd4e5da5Sopenharmony_ci Loop& parent_loop = *ld[21]; 169fd4e5da5Sopenharmony_ci EXPECT_TRUE(parent_loop.HasNestedLoops()); 170fd4e5da5Sopenharmony_ci EXPECT_FALSE(parent_loop.IsNested()); 171fd4e5da5Sopenharmony_ci EXPECT_EQ(parent_loop.GetDepth(), 1u); 172fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(parent_loop.begin(), parent_loop.end()), 2u); 173fd4e5da5Sopenharmony_ci EXPECT_EQ(parent_loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 21)); 174fd4e5da5Sopenharmony_ci EXPECT_EQ(parent_loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 23)); 175fd4e5da5Sopenharmony_ci EXPECT_EQ(parent_loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 22)); 176fd4e5da5Sopenharmony_ci 177fd4e5da5Sopenharmony_ci Loop& child_loop_1 = *ld[28]; 178fd4e5da5Sopenharmony_ci EXPECT_FALSE(child_loop_1.HasNestedLoops()); 179fd4e5da5Sopenharmony_ci EXPECT_TRUE(child_loop_1.IsNested()); 180fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_1.GetDepth(), 2u); 181fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(child_loop_1.begin(), child_loop_1.end()), 0u); 182fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_1.GetHeaderBlock(), spvtest::GetBasicBlock(f, 28)); 183fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_1.GetLatchBlock(), spvtest::GetBasicBlock(f, 30)); 184fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_1.GetMergeBlock(), spvtest::GetBasicBlock(f, 29)); 185fd4e5da5Sopenharmony_ci 186fd4e5da5Sopenharmony_ci Loop& child_loop_2 = *ld[37]; 187fd4e5da5Sopenharmony_ci EXPECT_FALSE(child_loop_2.HasNestedLoops()); 188fd4e5da5Sopenharmony_ci EXPECT_TRUE(child_loop_2.IsNested()); 189fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_2.GetDepth(), 2u); 190fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(child_loop_2.begin(), child_loop_2.end()), 0u); 191fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_2.GetHeaderBlock(), spvtest::GetBasicBlock(f, 37)); 192fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_2.GetLatchBlock(), spvtest::GetBasicBlock(f, 39)); 193fd4e5da5Sopenharmony_ci EXPECT_EQ(child_loop_2.GetMergeBlock(), spvtest::GetBasicBlock(f, 38)); 194fd4e5da5Sopenharmony_ci} 195fd4e5da5Sopenharmony_ci 196fd4e5da5Sopenharmony_cistatic void CheckLoopBlocks(Loop* loop, 197fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t>* expected_ids) { 198fd4e5da5Sopenharmony_ci SCOPED_TRACE("Check loop " + std::to_string(loop->GetHeaderBlock()->id())); 199fd4e5da5Sopenharmony_ci for (uint32_t bb_id : loop->GetBlocks()) { 200fd4e5da5Sopenharmony_ci EXPECT_EQ(expected_ids->count(bb_id), 1u); 201fd4e5da5Sopenharmony_ci expected_ids->erase(bb_id); 202fd4e5da5Sopenharmony_ci } 203fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock())); 204fd4e5da5Sopenharmony_ci EXPECT_EQ(expected_ids->size(), 0u); 205fd4e5da5Sopenharmony_ci} 206fd4e5da5Sopenharmony_ci 207fd4e5da5Sopenharmony_ci/* 208fd4e5da5Sopenharmony_ciGenerated from the following GLSL 209fd4e5da5Sopenharmony_ci#version 330 core 210fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c; 211fd4e5da5Sopenharmony_civoid main() { 212fd4e5da5Sopenharmony_ci int i = 0; 213fd4e5da5Sopenharmony_ci for (; i < 10; ++i) { 214fd4e5da5Sopenharmony_ci for (int j = 0; j < 11; ++j) { 215fd4e5da5Sopenharmony_ci if (j < 5) { 216fd4e5da5Sopenharmony_ci for (int k = 0; k < 12; ++k) {} 217fd4e5da5Sopenharmony_ci } 218fd4e5da5Sopenharmony_ci else {} 219fd4e5da5Sopenharmony_ci for (int k = 0; k < 12; ++k) {} 220fd4e5da5Sopenharmony_ci } 221fd4e5da5Sopenharmony_ci } 222fd4e5da5Sopenharmony_ci}*/ 223fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, TripleNestedLoop) { 224fd4e5da5Sopenharmony_ci const std::string text = R"( 225fd4e5da5Sopenharmony_ci OpCapability Shader 226fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 227fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 228fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "main" %3 229fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 230fd4e5da5Sopenharmony_ci OpSource GLSL 330 231fd4e5da5Sopenharmony_ci OpName %2 "main" 232fd4e5da5Sopenharmony_ci OpName %4 "i" 233fd4e5da5Sopenharmony_ci OpName %5 "j" 234fd4e5da5Sopenharmony_ci OpName %6 "k" 235fd4e5da5Sopenharmony_ci OpName %7 "k" 236fd4e5da5Sopenharmony_ci OpName %3 "c" 237fd4e5da5Sopenharmony_ci OpDecorate %3 Location 0 238fd4e5da5Sopenharmony_ci %8 = OpTypeVoid 239fd4e5da5Sopenharmony_ci %9 = OpTypeFunction %8 240fd4e5da5Sopenharmony_ci %10 = OpTypeInt 32 1 241fd4e5da5Sopenharmony_ci %11 = OpTypePointer Function %10 242fd4e5da5Sopenharmony_ci %12 = OpConstant %10 0 243fd4e5da5Sopenharmony_ci %13 = OpConstant %10 10 244fd4e5da5Sopenharmony_ci %14 = OpTypeBool 245fd4e5da5Sopenharmony_ci %15 = OpConstant %10 11 246fd4e5da5Sopenharmony_ci %16 = OpConstant %10 5 247fd4e5da5Sopenharmony_ci %17 = OpConstant %10 12 248fd4e5da5Sopenharmony_ci %18 = OpConstant %10 1 249fd4e5da5Sopenharmony_ci %19 = OpTypeFloat 32 250fd4e5da5Sopenharmony_ci %20 = OpTypeVector %19 4 251fd4e5da5Sopenharmony_ci %21 = OpTypePointer Output %20 252fd4e5da5Sopenharmony_ci %3 = OpVariable %21 Output 253fd4e5da5Sopenharmony_ci %2 = OpFunction %8 None %9 254fd4e5da5Sopenharmony_ci %22 = OpLabel 255fd4e5da5Sopenharmony_ci %4 = OpVariable %11 Function 256fd4e5da5Sopenharmony_ci %5 = OpVariable %11 Function 257fd4e5da5Sopenharmony_ci %6 = OpVariable %11 Function 258fd4e5da5Sopenharmony_ci %7 = OpVariable %11 Function 259fd4e5da5Sopenharmony_ci OpStore %4 %12 260fd4e5da5Sopenharmony_ci OpBranch %23 261fd4e5da5Sopenharmony_ci %23 = OpLabel 262fd4e5da5Sopenharmony_ci OpLoopMerge %24 %25 None 263fd4e5da5Sopenharmony_ci OpBranch %26 264fd4e5da5Sopenharmony_ci %26 = OpLabel 265fd4e5da5Sopenharmony_ci %27 = OpLoad %10 %4 266fd4e5da5Sopenharmony_ci %28 = OpSLessThan %14 %27 %13 267fd4e5da5Sopenharmony_ci OpBranchConditional %28 %29 %24 268fd4e5da5Sopenharmony_ci %29 = OpLabel 269fd4e5da5Sopenharmony_ci OpStore %5 %12 270fd4e5da5Sopenharmony_ci OpBranch %30 271fd4e5da5Sopenharmony_ci %30 = OpLabel 272fd4e5da5Sopenharmony_ci OpLoopMerge %31 %32 None 273fd4e5da5Sopenharmony_ci OpBranch %33 274fd4e5da5Sopenharmony_ci %33 = OpLabel 275fd4e5da5Sopenharmony_ci %34 = OpLoad %10 %5 276fd4e5da5Sopenharmony_ci %35 = OpSLessThan %14 %34 %15 277fd4e5da5Sopenharmony_ci OpBranchConditional %35 %36 %31 278fd4e5da5Sopenharmony_ci %36 = OpLabel 279fd4e5da5Sopenharmony_ci %37 = OpLoad %10 %5 280fd4e5da5Sopenharmony_ci %38 = OpSLessThan %14 %37 %16 281fd4e5da5Sopenharmony_ci OpSelectionMerge %39 None 282fd4e5da5Sopenharmony_ci OpBranchConditional %38 %40 %39 283fd4e5da5Sopenharmony_ci %40 = OpLabel 284fd4e5da5Sopenharmony_ci OpStore %6 %12 285fd4e5da5Sopenharmony_ci OpBranch %41 286fd4e5da5Sopenharmony_ci %41 = OpLabel 287fd4e5da5Sopenharmony_ci OpLoopMerge %42 %43 None 288fd4e5da5Sopenharmony_ci OpBranch %44 289fd4e5da5Sopenharmony_ci %44 = OpLabel 290fd4e5da5Sopenharmony_ci %45 = OpLoad %10 %6 291fd4e5da5Sopenharmony_ci %46 = OpSLessThan %14 %45 %17 292fd4e5da5Sopenharmony_ci OpBranchConditional %46 %47 %42 293fd4e5da5Sopenharmony_ci %47 = OpLabel 294fd4e5da5Sopenharmony_ci OpBranch %43 295fd4e5da5Sopenharmony_ci %43 = OpLabel 296fd4e5da5Sopenharmony_ci %48 = OpLoad %10 %6 297fd4e5da5Sopenharmony_ci %49 = OpIAdd %10 %48 %18 298fd4e5da5Sopenharmony_ci OpStore %6 %49 299fd4e5da5Sopenharmony_ci OpBranch %41 300fd4e5da5Sopenharmony_ci %42 = OpLabel 301fd4e5da5Sopenharmony_ci OpBranch %39 302fd4e5da5Sopenharmony_ci %39 = OpLabel 303fd4e5da5Sopenharmony_ci OpStore %7 %12 304fd4e5da5Sopenharmony_ci OpBranch %50 305fd4e5da5Sopenharmony_ci %50 = OpLabel 306fd4e5da5Sopenharmony_ci OpLoopMerge %51 %52 None 307fd4e5da5Sopenharmony_ci OpBranch %53 308fd4e5da5Sopenharmony_ci %53 = OpLabel 309fd4e5da5Sopenharmony_ci %54 = OpLoad %10 %7 310fd4e5da5Sopenharmony_ci %55 = OpSLessThan %14 %54 %17 311fd4e5da5Sopenharmony_ci OpBranchConditional %55 %56 %51 312fd4e5da5Sopenharmony_ci %56 = OpLabel 313fd4e5da5Sopenharmony_ci OpBranch %52 314fd4e5da5Sopenharmony_ci %52 = OpLabel 315fd4e5da5Sopenharmony_ci %57 = OpLoad %10 %7 316fd4e5da5Sopenharmony_ci %58 = OpIAdd %10 %57 %18 317fd4e5da5Sopenharmony_ci OpStore %7 %58 318fd4e5da5Sopenharmony_ci OpBranch %50 319fd4e5da5Sopenharmony_ci %51 = OpLabel 320fd4e5da5Sopenharmony_ci OpBranch %32 321fd4e5da5Sopenharmony_ci %32 = OpLabel 322fd4e5da5Sopenharmony_ci %59 = OpLoad %10 %5 323fd4e5da5Sopenharmony_ci %60 = OpIAdd %10 %59 %18 324fd4e5da5Sopenharmony_ci OpStore %5 %60 325fd4e5da5Sopenharmony_ci OpBranch %30 326fd4e5da5Sopenharmony_ci %31 = OpLabel 327fd4e5da5Sopenharmony_ci OpBranch %25 328fd4e5da5Sopenharmony_ci %25 = OpLabel 329fd4e5da5Sopenharmony_ci %61 = OpLoad %10 %4 330fd4e5da5Sopenharmony_ci %62 = OpIAdd %10 %61 %18 331fd4e5da5Sopenharmony_ci OpStore %4 %62 332fd4e5da5Sopenharmony_ci OpBranch %23 333fd4e5da5Sopenharmony_ci %24 = OpLabel 334fd4e5da5Sopenharmony_ci OpReturn 335fd4e5da5Sopenharmony_ci OpFunctionEnd 336fd4e5da5Sopenharmony_ci )"; 337fd4e5da5Sopenharmony_ci // clang-format on 338fd4e5da5Sopenharmony_ci std::unique_ptr<IRContext> context = 339fd4e5da5Sopenharmony_ci BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 340fd4e5da5Sopenharmony_ci SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 341fd4e5da5Sopenharmony_ci Module* module = context->module(); 342fd4e5da5Sopenharmony_ci EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 343fd4e5da5Sopenharmony_ci << text << std::endl; 344fd4e5da5Sopenharmony_ci const Function* f = spvtest::GetFunction(module, 2); 345fd4e5da5Sopenharmony_ci LoopDescriptor& ld = *context->GetLoopDescriptor(f); 346fd4e5da5Sopenharmony_ci 347fd4e5da5Sopenharmony_ci EXPECT_EQ(ld.NumLoops(), 4u); 348fd4e5da5Sopenharmony_ci 349fd4e5da5Sopenharmony_ci // Invalid basic block id. 350fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[0u], nullptr); 351fd4e5da5Sopenharmony_ci // Not in a loop. 352fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[22], nullptr); 353fd4e5da5Sopenharmony_ci 354fd4e5da5Sopenharmony_ci // Check that we can map basic block to the correct loop. 355fd4e5da5Sopenharmony_ci // The following block ids do not belong to a loop. 356fd4e5da5Sopenharmony_ci for (uint32_t bb_id : {22, 24}) EXPECT_EQ(ld[bb_id], nullptr); 357fd4e5da5Sopenharmony_ci 358fd4e5da5Sopenharmony_ci { 359fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> basic_block_in_loop = { 360fd4e5da5Sopenharmony_ci {23, 26, 29, 30, 33, 36, 40, 41, 44, 47, 43, 361fd4e5da5Sopenharmony_ci 42, 39, 50, 53, 56, 52, 51, 32, 31, 25}}; 362fd4e5da5Sopenharmony_ci Loop* loop = ld[23]; 363fd4e5da5Sopenharmony_ci CheckLoopBlocks(loop, &basic_block_in_loop); 364fd4e5da5Sopenharmony_ci 365fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop->HasNestedLoops()); 366fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsNested()); 367fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetDepth(), 1u); 368fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(loop->begin(), loop->end()), 1u); 369fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 22)); 370fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 23)); 371fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 25)); 372fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 24)); 373fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock())); 374fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock())); 375fd4e5da5Sopenharmony_ci } 376fd4e5da5Sopenharmony_ci 377fd4e5da5Sopenharmony_ci { 378fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> basic_block_in_loop = { 379fd4e5da5Sopenharmony_ci {30, 33, 36, 40, 41, 44, 47, 43, 42, 39, 50, 53, 56, 52, 51, 32}}; 380fd4e5da5Sopenharmony_ci Loop* loop = ld[30]; 381fd4e5da5Sopenharmony_ci CheckLoopBlocks(loop, &basic_block_in_loop); 382fd4e5da5Sopenharmony_ci 383fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop->HasNestedLoops()); 384fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop->IsNested()); 385fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetDepth(), 2u); 386fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(loop->begin(), loop->end()), 2u); 387fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 29)); 388fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 30)); 389fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 32)); 390fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 31)); 391fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock())); 392fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock())); 393fd4e5da5Sopenharmony_ci } 394fd4e5da5Sopenharmony_ci 395fd4e5da5Sopenharmony_ci { 396fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> basic_block_in_loop = {{41, 44, 47, 43}}; 397fd4e5da5Sopenharmony_ci Loop* loop = ld[41]; 398fd4e5da5Sopenharmony_ci CheckLoopBlocks(loop, &basic_block_in_loop); 399fd4e5da5Sopenharmony_ci 400fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->HasNestedLoops()); 401fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop->IsNested()); 402fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetDepth(), 3u); 403fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u); 404fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 40)); 405fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 41)); 406fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 43)); 407fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 42)); 408fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock())); 409fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock())); 410fd4e5da5Sopenharmony_ci } 411fd4e5da5Sopenharmony_ci 412fd4e5da5Sopenharmony_ci { 413fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> basic_block_in_loop = {{50, 53, 56, 52}}; 414fd4e5da5Sopenharmony_ci Loop* loop = ld[50]; 415fd4e5da5Sopenharmony_ci CheckLoopBlocks(loop, &basic_block_in_loop); 416fd4e5da5Sopenharmony_ci 417fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->HasNestedLoops()); 418fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop->IsNested()); 419fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetDepth(), 3u); 420fd4e5da5Sopenharmony_ci EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u); 421fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 39)); 422fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 50)); 423fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 52)); 424fd4e5da5Sopenharmony_ci EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 51)); 425fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock())); 426fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock())); 427fd4e5da5Sopenharmony_ci } 428fd4e5da5Sopenharmony_ci 429fd4e5da5Sopenharmony_ci // Make sure LoopDescriptor gives us the inner most loop when we query for 430fd4e5da5Sopenharmony_ci // loops. 431fd4e5da5Sopenharmony_ci for (const BasicBlock& bb : *f) { 432fd4e5da5Sopenharmony_ci if (Loop* loop = ld[&bb]) { 433fd4e5da5Sopenharmony_ci for (Loop& sub_loop : 434fd4e5da5Sopenharmony_ci make_range(++TreeDFIterator<Loop>(loop), TreeDFIterator<Loop>())) { 435fd4e5da5Sopenharmony_ci EXPECT_FALSE(sub_loop.IsInsideLoop(bb.id())); 436fd4e5da5Sopenharmony_ci } 437fd4e5da5Sopenharmony_ci } 438fd4e5da5Sopenharmony_ci } 439fd4e5da5Sopenharmony_ci} 440fd4e5da5Sopenharmony_ci 441fd4e5da5Sopenharmony_ci/* 442fd4e5da5Sopenharmony_ciGenerated from the following GLSL 443fd4e5da5Sopenharmony_ci#version 330 core 444fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c; 445fd4e5da5Sopenharmony_civoid main() { 446fd4e5da5Sopenharmony_ci for (int i = 0; i < 10; ++i) { 447fd4e5da5Sopenharmony_ci for (int j = 0; j < 11; ++j) { 448fd4e5da5Sopenharmony_ci for (int k = 0; k < 11; ++k) {} 449fd4e5da5Sopenharmony_ci } 450fd4e5da5Sopenharmony_ci for (int k = 0; k < 12; ++k) {} 451fd4e5da5Sopenharmony_ci } 452fd4e5da5Sopenharmony_ci} 453fd4e5da5Sopenharmony_ci*/ 454fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, LoopParentTest) { 455fd4e5da5Sopenharmony_ci const std::string text = R"( 456fd4e5da5Sopenharmony_ci OpCapability Shader 457fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 458fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 459fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "main" %3 460fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 461fd4e5da5Sopenharmony_ci OpSource GLSL 330 462fd4e5da5Sopenharmony_ci OpName %2 "main" 463fd4e5da5Sopenharmony_ci OpName %4 "i" 464fd4e5da5Sopenharmony_ci OpName %5 "j" 465fd4e5da5Sopenharmony_ci OpName %6 "k" 466fd4e5da5Sopenharmony_ci OpName %7 "k" 467fd4e5da5Sopenharmony_ci OpName %3 "c" 468fd4e5da5Sopenharmony_ci OpDecorate %3 Location 0 469fd4e5da5Sopenharmony_ci %8 = OpTypeVoid 470fd4e5da5Sopenharmony_ci %9 = OpTypeFunction %8 471fd4e5da5Sopenharmony_ci %10 = OpTypeInt 32 1 472fd4e5da5Sopenharmony_ci %11 = OpTypePointer Function %10 473fd4e5da5Sopenharmony_ci %12 = OpConstant %10 0 474fd4e5da5Sopenharmony_ci %13 = OpConstant %10 10 475fd4e5da5Sopenharmony_ci %14 = OpTypeBool 476fd4e5da5Sopenharmony_ci %15 = OpConstant %10 11 477fd4e5da5Sopenharmony_ci %16 = OpConstant %10 1 478fd4e5da5Sopenharmony_ci %17 = OpConstant %10 12 479fd4e5da5Sopenharmony_ci %18 = OpTypeFloat 32 480fd4e5da5Sopenharmony_ci %19 = OpTypeVector %18 4 481fd4e5da5Sopenharmony_ci %20 = OpTypePointer Output %19 482fd4e5da5Sopenharmony_ci %3 = OpVariable %20 Output 483fd4e5da5Sopenharmony_ci %2 = OpFunction %8 None %9 484fd4e5da5Sopenharmony_ci %21 = OpLabel 485fd4e5da5Sopenharmony_ci %4 = OpVariable %11 Function 486fd4e5da5Sopenharmony_ci %5 = OpVariable %11 Function 487fd4e5da5Sopenharmony_ci %6 = OpVariable %11 Function 488fd4e5da5Sopenharmony_ci %7 = OpVariable %11 Function 489fd4e5da5Sopenharmony_ci OpStore %4 %12 490fd4e5da5Sopenharmony_ci OpBranch %22 491fd4e5da5Sopenharmony_ci %22 = OpLabel 492fd4e5da5Sopenharmony_ci OpLoopMerge %23 %24 None 493fd4e5da5Sopenharmony_ci OpBranch %25 494fd4e5da5Sopenharmony_ci %25 = OpLabel 495fd4e5da5Sopenharmony_ci %26 = OpLoad %10 %4 496fd4e5da5Sopenharmony_ci %27 = OpSLessThan %14 %26 %13 497fd4e5da5Sopenharmony_ci OpBranchConditional %27 %28 %23 498fd4e5da5Sopenharmony_ci %28 = OpLabel 499fd4e5da5Sopenharmony_ci OpStore %5 %12 500fd4e5da5Sopenharmony_ci OpBranch %29 501fd4e5da5Sopenharmony_ci %29 = OpLabel 502fd4e5da5Sopenharmony_ci OpLoopMerge %30 %31 None 503fd4e5da5Sopenharmony_ci OpBranch %32 504fd4e5da5Sopenharmony_ci %32 = OpLabel 505fd4e5da5Sopenharmony_ci %33 = OpLoad %10 %5 506fd4e5da5Sopenharmony_ci %34 = OpSLessThan %14 %33 %15 507fd4e5da5Sopenharmony_ci OpBranchConditional %34 %35 %30 508fd4e5da5Sopenharmony_ci %35 = OpLabel 509fd4e5da5Sopenharmony_ci OpStore %6 %12 510fd4e5da5Sopenharmony_ci OpBranch %36 511fd4e5da5Sopenharmony_ci %36 = OpLabel 512fd4e5da5Sopenharmony_ci OpLoopMerge %37 %38 None 513fd4e5da5Sopenharmony_ci OpBranch %39 514fd4e5da5Sopenharmony_ci %39 = OpLabel 515fd4e5da5Sopenharmony_ci %40 = OpLoad %10 %6 516fd4e5da5Sopenharmony_ci %41 = OpSLessThan %14 %40 %15 517fd4e5da5Sopenharmony_ci OpBranchConditional %41 %42 %37 518fd4e5da5Sopenharmony_ci %42 = OpLabel 519fd4e5da5Sopenharmony_ci OpBranch %38 520fd4e5da5Sopenharmony_ci %38 = OpLabel 521fd4e5da5Sopenharmony_ci %43 = OpLoad %10 %6 522fd4e5da5Sopenharmony_ci %44 = OpIAdd %10 %43 %16 523fd4e5da5Sopenharmony_ci OpStore %6 %44 524fd4e5da5Sopenharmony_ci OpBranch %36 525fd4e5da5Sopenharmony_ci %37 = OpLabel 526fd4e5da5Sopenharmony_ci OpBranch %31 527fd4e5da5Sopenharmony_ci %31 = OpLabel 528fd4e5da5Sopenharmony_ci %45 = OpLoad %10 %5 529fd4e5da5Sopenharmony_ci %46 = OpIAdd %10 %45 %16 530fd4e5da5Sopenharmony_ci OpStore %5 %46 531fd4e5da5Sopenharmony_ci OpBranch %29 532fd4e5da5Sopenharmony_ci %30 = OpLabel 533fd4e5da5Sopenharmony_ci OpStore %7 %12 534fd4e5da5Sopenharmony_ci OpBranch %47 535fd4e5da5Sopenharmony_ci %47 = OpLabel 536fd4e5da5Sopenharmony_ci OpLoopMerge %48 %49 None 537fd4e5da5Sopenharmony_ci OpBranch %50 538fd4e5da5Sopenharmony_ci %50 = OpLabel 539fd4e5da5Sopenharmony_ci %51 = OpLoad %10 %7 540fd4e5da5Sopenharmony_ci %52 = OpSLessThan %14 %51 %17 541fd4e5da5Sopenharmony_ci OpBranchConditional %52 %53 %48 542fd4e5da5Sopenharmony_ci %53 = OpLabel 543fd4e5da5Sopenharmony_ci OpBranch %49 544fd4e5da5Sopenharmony_ci %49 = OpLabel 545fd4e5da5Sopenharmony_ci %54 = OpLoad %10 %7 546fd4e5da5Sopenharmony_ci %55 = OpIAdd %10 %54 %16 547fd4e5da5Sopenharmony_ci OpStore %7 %55 548fd4e5da5Sopenharmony_ci OpBranch %47 549fd4e5da5Sopenharmony_ci %48 = OpLabel 550fd4e5da5Sopenharmony_ci OpBranch %24 551fd4e5da5Sopenharmony_ci %24 = OpLabel 552fd4e5da5Sopenharmony_ci %56 = OpLoad %10 %4 553fd4e5da5Sopenharmony_ci %57 = OpIAdd %10 %56 %16 554fd4e5da5Sopenharmony_ci OpStore %4 %57 555fd4e5da5Sopenharmony_ci OpBranch %22 556fd4e5da5Sopenharmony_ci %23 = OpLabel 557fd4e5da5Sopenharmony_ci OpReturn 558fd4e5da5Sopenharmony_ci OpFunctionEnd 559fd4e5da5Sopenharmony_ci )"; 560fd4e5da5Sopenharmony_ci // clang-format on 561fd4e5da5Sopenharmony_ci std::unique_ptr<IRContext> context = 562fd4e5da5Sopenharmony_ci BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 563fd4e5da5Sopenharmony_ci SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 564fd4e5da5Sopenharmony_ci Module* module = context->module(); 565fd4e5da5Sopenharmony_ci EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 566fd4e5da5Sopenharmony_ci << text << std::endl; 567fd4e5da5Sopenharmony_ci const Function* f = spvtest::GetFunction(module, 2); 568fd4e5da5Sopenharmony_ci LoopDescriptor& ld = *context->GetLoopDescriptor(f); 569fd4e5da5Sopenharmony_ci 570fd4e5da5Sopenharmony_ci EXPECT_EQ(ld.NumLoops(), 4u); 571fd4e5da5Sopenharmony_ci 572fd4e5da5Sopenharmony_ci { 573fd4e5da5Sopenharmony_ci Loop& loop = *ld[22]; 574fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.HasNestedLoops()); 575fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop.IsNested()); 576fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetDepth(), 1u); 577fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetParent(), nullptr); 578fd4e5da5Sopenharmony_ci } 579fd4e5da5Sopenharmony_ci 580fd4e5da5Sopenharmony_ci { 581fd4e5da5Sopenharmony_ci Loop& loop = *ld[29]; 582fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.HasNestedLoops()); 583fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.IsNested()); 584fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetDepth(), 2u); 585fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetParent(), ld[22]); 586fd4e5da5Sopenharmony_ci } 587fd4e5da5Sopenharmony_ci 588fd4e5da5Sopenharmony_ci { 589fd4e5da5Sopenharmony_ci Loop& loop = *ld[36]; 590fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop.HasNestedLoops()); 591fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.IsNested()); 592fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetDepth(), 3u); 593fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetParent(), ld[29]); 594fd4e5da5Sopenharmony_ci } 595fd4e5da5Sopenharmony_ci 596fd4e5da5Sopenharmony_ci { 597fd4e5da5Sopenharmony_ci Loop& loop = *ld[47]; 598fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop.HasNestedLoops()); 599fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.IsNested()); 600fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetDepth(), 2u); 601fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetParent(), ld[22]); 602fd4e5da5Sopenharmony_ci } 603fd4e5da5Sopenharmony_ci} 604fd4e5da5Sopenharmony_ci 605fd4e5da5Sopenharmony_ci/* 606fd4e5da5Sopenharmony_ciGenerated from the following GLSL + --eliminate-local-multi-store 607fd4e5da5Sopenharmony_ciThe preheader of loop %33 and %41 were removed as well. 608fd4e5da5Sopenharmony_ci 609fd4e5da5Sopenharmony_ci#version 330 core 610fd4e5da5Sopenharmony_civoid main() { 611fd4e5da5Sopenharmony_ci int a = 0; 612fd4e5da5Sopenharmony_ci for (int i = 0; i < 10; ++i) { 613fd4e5da5Sopenharmony_ci if (i == 0) { 614fd4e5da5Sopenharmony_ci a = 1; 615fd4e5da5Sopenharmony_ci } else { 616fd4e5da5Sopenharmony_ci a = 2; 617fd4e5da5Sopenharmony_ci } 618fd4e5da5Sopenharmony_ci for (int j = 0; j < 11; ++j) { 619fd4e5da5Sopenharmony_ci a++; 620fd4e5da5Sopenharmony_ci } 621fd4e5da5Sopenharmony_ci } 622fd4e5da5Sopenharmony_ci for (int k = 0; k < 12; ++k) {} 623fd4e5da5Sopenharmony_ci} 624fd4e5da5Sopenharmony_ci*/ 625fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, CreatePreheaderTest) { 626fd4e5da5Sopenharmony_ci const std::string text = R"( 627fd4e5da5Sopenharmony_ci OpCapability Shader 628fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 629fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 630fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "main" 631fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 632fd4e5da5Sopenharmony_ci OpSource GLSL 330 633fd4e5da5Sopenharmony_ci OpName %2 "main" 634fd4e5da5Sopenharmony_ci %3 = OpTypeVoid 635fd4e5da5Sopenharmony_ci %4 = OpTypeFunction %3 636fd4e5da5Sopenharmony_ci %5 = OpTypeInt 32 1 637fd4e5da5Sopenharmony_ci %6 = OpTypePointer Function %5 638fd4e5da5Sopenharmony_ci %7 = OpConstant %5 0 639fd4e5da5Sopenharmony_ci %8 = OpConstant %5 10 640fd4e5da5Sopenharmony_ci %9 = OpTypeBool 641fd4e5da5Sopenharmony_ci %10 = OpConstant %5 1 642fd4e5da5Sopenharmony_ci %11 = OpConstant %5 2 643fd4e5da5Sopenharmony_ci %12 = OpConstant %5 11 644fd4e5da5Sopenharmony_ci %13 = OpConstant %5 12 645fd4e5da5Sopenharmony_ci %14 = OpUndef %5 646fd4e5da5Sopenharmony_ci %2 = OpFunction %3 None %4 647fd4e5da5Sopenharmony_ci %15 = OpLabel 648fd4e5da5Sopenharmony_ci OpBranch %16 649fd4e5da5Sopenharmony_ci %16 = OpLabel 650fd4e5da5Sopenharmony_ci %17 = OpPhi %5 %7 %15 %18 %19 651fd4e5da5Sopenharmony_ci %20 = OpPhi %5 %7 %15 %21 %19 652fd4e5da5Sopenharmony_ci %22 = OpPhi %5 %14 %15 %23 %19 653fd4e5da5Sopenharmony_ci OpLoopMerge %41 %19 None 654fd4e5da5Sopenharmony_ci OpBranch %25 655fd4e5da5Sopenharmony_ci %25 = OpLabel 656fd4e5da5Sopenharmony_ci %26 = OpSLessThan %9 %20 %8 657fd4e5da5Sopenharmony_ci OpBranchConditional %26 %27 %41 658fd4e5da5Sopenharmony_ci %27 = OpLabel 659fd4e5da5Sopenharmony_ci %28 = OpIEqual %9 %20 %7 660fd4e5da5Sopenharmony_ci OpSelectionMerge %33 None 661fd4e5da5Sopenharmony_ci OpBranchConditional %28 %30 %31 662fd4e5da5Sopenharmony_ci %30 = OpLabel 663fd4e5da5Sopenharmony_ci OpBranch %33 664fd4e5da5Sopenharmony_ci %31 = OpLabel 665fd4e5da5Sopenharmony_ci OpBranch %33 666fd4e5da5Sopenharmony_ci %33 = OpLabel 667fd4e5da5Sopenharmony_ci %18 = OpPhi %5 %10 %30 %11 %31 %34 %35 668fd4e5da5Sopenharmony_ci %23 = OpPhi %5 %7 %30 %7 %31 %36 %35 669fd4e5da5Sopenharmony_ci OpLoopMerge %37 %35 None 670fd4e5da5Sopenharmony_ci OpBranch %38 671fd4e5da5Sopenharmony_ci %38 = OpLabel 672fd4e5da5Sopenharmony_ci %39 = OpSLessThan %9 %23 %12 673fd4e5da5Sopenharmony_ci OpBranchConditional %39 %40 %37 674fd4e5da5Sopenharmony_ci %40 = OpLabel 675fd4e5da5Sopenharmony_ci %34 = OpIAdd %5 %18 %10 676fd4e5da5Sopenharmony_ci OpBranch %35 677fd4e5da5Sopenharmony_ci %35 = OpLabel 678fd4e5da5Sopenharmony_ci %36 = OpIAdd %5 %23 %10 679fd4e5da5Sopenharmony_ci OpBranch %33 680fd4e5da5Sopenharmony_ci %37 = OpLabel 681fd4e5da5Sopenharmony_ci OpBranch %19 682fd4e5da5Sopenharmony_ci %19 = OpLabel 683fd4e5da5Sopenharmony_ci %21 = OpIAdd %5 %20 %10 684fd4e5da5Sopenharmony_ci OpBranch %16 685fd4e5da5Sopenharmony_ci %41 = OpLabel 686fd4e5da5Sopenharmony_ci %42 = OpPhi %5 %7 %25 %43 %44 687fd4e5da5Sopenharmony_ci OpLoopMerge %45 %44 None 688fd4e5da5Sopenharmony_ci OpBranch %46 689fd4e5da5Sopenharmony_ci %46 = OpLabel 690fd4e5da5Sopenharmony_ci %47 = OpSLessThan %9 %42 %13 691fd4e5da5Sopenharmony_ci OpBranchConditional %47 %48 %45 692fd4e5da5Sopenharmony_ci %48 = OpLabel 693fd4e5da5Sopenharmony_ci OpBranch %44 694fd4e5da5Sopenharmony_ci %44 = OpLabel 695fd4e5da5Sopenharmony_ci %43 = OpIAdd %5 %42 %10 696fd4e5da5Sopenharmony_ci OpBranch %41 697fd4e5da5Sopenharmony_ci %45 = OpLabel 698fd4e5da5Sopenharmony_ci OpReturn 699fd4e5da5Sopenharmony_ci OpFunctionEnd 700fd4e5da5Sopenharmony_ci )"; 701fd4e5da5Sopenharmony_ci // clang-format on 702fd4e5da5Sopenharmony_ci std::unique_ptr<IRContext> context = 703fd4e5da5Sopenharmony_ci BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 704fd4e5da5Sopenharmony_ci SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 705fd4e5da5Sopenharmony_ci Module* module = context->module(); 706fd4e5da5Sopenharmony_ci EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 707fd4e5da5Sopenharmony_ci << text << std::endl; 708fd4e5da5Sopenharmony_ci const Function* f = spvtest::GetFunction(module, 2); 709fd4e5da5Sopenharmony_ci LoopDescriptor& ld = *context->GetLoopDescriptor(f); 710fd4e5da5Sopenharmony_ci // No invalidation of the cfg should occur during this test. 711fd4e5da5Sopenharmony_ci CFG* cfg = context->cfg(); 712fd4e5da5Sopenharmony_ci 713fd4e5da5Sopenharmony_ci EXPECT_EQ(ld.NumLoops(), 3u); 714fd4e5da5Sopenharmony_ci 715fd4e5da5Sopenharmony_ci { 716fd4e5da5Sopenharmony_ci Loop& loop = *ld[16]; 717fd4e5da5Sopenharmony_ci EXPECT_TRUE(loop.HasNestedLoops()); 718fd4e5da5Sopenharmony_ci EXPECT_FALSE(loop.IsNested()); 719fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetDepth(), 1u); 720fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetParent(), nullptr); 721fd4e5da5Sopenharmony_ci } 722fd4e5da5Sopenharmony_ci 723fd4e5da5Sopenharmony_ci { 724fd4e5da5Sopenharmony_ci Loop& loop = *ld[33]; 725fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr); 726fd4e5da5Sopenharmony_ci EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr); 727fd4e5da5Sopenharmony_ci // Make sure the loop descriptor was properly updated. 728fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[loop.GetPreHeaderBlock()], ld[16]); 729fd4e5da5Sopenharmony_ci { 730fd4e5da5Sopenharmony_ci const std::vector<uint32_t>& preds = 731fd4e5da5Sopenharmony_ci cfg->preds(loop.GetPreHeaderBlock()->id()); 732fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end()); 733fd4e5da5Sopenharmony_ci EXPECT_EQ(pred_set.size(), 2u); 734fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(30)); 735fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(31)); 736fd4e5da5Sopenharmony_ci // Check the phi instructions. 737fd4e5da5Sopenharmony_ci loop.GetPreHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) { 738fd4e5da5Sopenharmony_ci for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) { 739fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i))); 740fd4e5da5Sopenharmony_ci } 741fd4e5da5Sopenharmony_ci }); 742fd4e5da5Sopenharmony_ci } 743fd4e5da5Sopenharmony_ci { 744fd4e5da5Sopenharmony_ci const std::vector<uint32_t>& preds = 745fd4e5da5Sopenharmony_ci cfg->preds(loop.GetHeaderBlock()->id()); 746fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end()); 747fd4e5da5Sopenharmony_ci EXPECT_EQ(pred_set.size(), 2u); 748fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id())); 749fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(35)); 750fd4e5da5Sopenharmony_ci // Check the phi instructions. 751fd4e5da5Sopenharmony_ci loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) { 752fd4e5da5Sopenharmony_ci for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) { 753fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i))); 754fd4e5da5Sopenharmony_ci } 755fd4e5da5Sopenharmony_ci }); 756fd4e5da5Sopenharmony_ci } 757fd4e5da5Sopenharmony_ci } 758fd4e5da5Sopenharmony_ci 759fd4e5da5Sopenharmony_ci { 760fd4e5da5Sopenharmony_ci Loop& loop = *ld[41]; 761fd4e5da5Sopenharmony_ci EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr); 762fd4e5da5Sopenharmony_ci EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr); 763fd4e5da5Sopenharmony_ci EXPECT_EQ(ld[loop.GetPreHeaderBlock()], nullptr); 764fd4e5da5Sopenharmony_ci EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id()).size(), 1u); 765fd4e5da5Sopenharmony_ci EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id())[0], 25u); 766fd4e5da5Sopenharmony_ci // Check the phi instructions. 767fd4e5da5Sopenharmony_ci loop.GetPreHeaderBlock()->ForEachPhiInst([](Instruction* phi) { 768fd4e5da5Sopenharmony_ci EXPECT_EQ(phi->NumInOperands(), 2u); 769fd4e5da5Sopenharmony_ci EXPECT_EQ(phi->GetSingleWordInOperand(1), 25u); 770fd4e5da5Sopenharmony_ci }); 771fd4e5da5Sopenharmony_ci { 772fd4e5da5Sopenharmony_ci const std::vector<uint32_t>& preds = 773fd4e5da5Sopenharmony_ci cfg->preds(loop.GetHeaderBlock()->id()); 774fd4e5da5Sopenharmony_ci std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end()); 775fd4e5da5Sopenharmony_ci EXPECT_EQ(pred_set.size(), 2u); 776fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id())); 777fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(44)); 778fd4e5da5Sopenharmony_ci // Check the phi instructions. 779fd4e5da5Sopenharmony_ci loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) { 780fd4e5da5Sopenharmony_ci for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) { 781fd4e5da5Sopenharmony_ci EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i))); 782fd4e5da5Sopenharmony_ci } 783fd4e5da5Sopenharmony_ci }); 784fd4e5da5Sopenharmony_ci } 785fd4e5da5Sopenharmony_ci } 786fd4e5da5Sopenharmony_ci 787fd4e5da5Sopenharmony_ci // Make sure pre-header insertion leaves the module valid. 788fd4e5da5Sopenharmony_ci std::vector<uint32_t> bin; 789fd4e5da5Sopenharmony_ci context->module()->ToBinary(&bin, true); 790fd4e5da5Sopenharmony_ci EXPECT_TRUE(Validate(bin)); 791fd4e5da5Sopenharmony_ci} 792fd4e5da5Sopenharmony_ci 793fd4e5da5Sopenharmony_ci} // namespace 794fd4e5da5Sopenharmony_ci} // namespace opt 795fd4e5da5Sopenharmony_ci} // namespace spvtools 796