1 // Copyright (c) 2017 Google Inc.
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include <gmock/gmock.h>
21 #include "../assembly_builder.h"
22 #include "../function_utils.h"
23 #include "../pass_fixture.h"
24 #include "../pass_utils.h"
25 #include "opt/loop_descriptor.h"
30 using namespace spvtools;
31 using ::testing::UnorderedElementsAre;
33 using PassClassTest = PassTest<::testing::Test>;
36 Generated from the following GLSL
38 layout(location = 0) out vec4 c;
45 TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
46 const std::string text = R"(
48 %1 = OpExtInstImport "GLSL.std.450"
49 OpMemoryModel Logical GLSL450
50 OpEntryPoint Fragment %2 "main" %3
51 OpExecutionMode %2 OriginUpperLeft
56 OpDecorate %3 Location 0
58 %7 = OpTypeFunction %6
60 %9 = OpTypePointer Function %8
62 %11 = OpConstant %8 10
66 %15 = OpTypeVector %14 4
67 %16 = OpTypePointer Output %15
68 %3 = OpVariable %16 Output
69 %2 = OpFunction %6 None %7
71 %5 = OpVariable %9 Function
75 OpLoopMerge %19 %20 None
79 %23 = OpSLessThan %12 %22 %11
80 OpBranchConditional %23 %24 %19
85 %26 = OpIAdd %8 %25 %13
93 std::unique_ptr<ir::IRContext> context =
94 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
95 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
96 ir::Module* module = context->module();
97 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
99 const ir::Function* f = spvtest::GetFunction(module, 2);
100 ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
102 EXPECT_EQ(ld.NumLoops(), 1u);
104 ir::Loop& loop = ld.GetLoopByIndex(0);
105 EXPECT_EQ(loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 18));
106 EXPECT_EQ(loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 20));
107 EXPECT_EQ(loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 19));
109 EXPECT_FALSE(loop.HasNestedLoops());
110 EXPECT_FALSE(loop.IsNested());
111 EXPECT_EQ(loop.GetDepth(), 1u);
115 Generated from the following GLSL:
117 layout(location = 0) out vec4 c;
119 for(int i = 0; i < 10; ++i) {}
120 for(int i = 0; i < 10; ++i) {}
123 But it was "hacked" to make the first loop merge block the second loop header.
125 TEST_F(PassClassTest, LoopWithNoPreHeader) {
126 const std::string text = R"(
128 %1 = OpExtInstImport "GLSL.std.450"
129 OpMemoryModel Logical GLSL450
130 OpEntryPoint Fragment %2 "main" %3
131 OpExecutionMode %2 OriginUpperLeft
137 OpDecorate %3 Location 0
139 %7 = OpTypeFunction %6
141 %9 = OpTypePointer Function %8
142 %10 = OpConstant %8 0
143 %11 = OpConstant %8 10
145 %13 = OpConstant %8 1
147 %15 = OpTypeVector %14 4
148 %16 = OpTypePointer Output %15
149 %3 = OpVariable %16 Output
150 %2 = OpFunction %6 None %7
152 %4 = OpVariable %9 Function
153 %5 = OpVariable %9 Function
158 OpLoopMerge %27 %20 None
162 %23 = OpSLessThan %12 %22 %11
163 OpBranchConditional %23 %24 %27
168 %26 = OpIAdd %8 %25 %13
172 OpLoopMerge %28 %29 None
176 %32 = OpSLessThan %12 %31 %11
177 OpBranchConditional %32 %33 %28
182 %35 = OpIAdd %8 %34 %13
190 std::unique_ptr<ir::IRContext> context =
191 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
192 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
193 ir::Module* module = context->module();
194 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
195 << text << std::endl;
196 const ir::Function* f = spvtest::GetFunction(module, 2);
197 ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
199 EXPECT_EQ(ld.NumLoops(), 2u);
201 ir::Loop* loop = ld[27];
202 EXPECT_EQ(loop->GetPreHeaderBlock(), nullptr);
203 EXPECT_NE(loop->GetOrCreatePreHeaderBlock(context.get()), nullptr);