Loop invariant code motion initial implementation
[platform/upstream/SPIRV-Tools.git] / test / opt / loop_optimizations / loop_descriptions.cpp
1 // Copyright (c) 2017 Google Inc.
2 //
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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include <gmock/gmock.h>
16
17 #include <memory>
18 #include <string>
19 #include <vector>
20
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"
26 #include "opt/pass.h"
27
28 namespace {
29
30 using namespace spvtools;
31 using ::testing::UnorderedElementsAre;
32
33 using PassClassTest = PassTest<::testing::Test>;
34
35 /*
36 Generated from the following GLSL
37 #version 330 core
38 layout(location = 0) out vec4 c;
39 void main() {
40   int i = 0;
41   for(; i < 10; ++i) {
42   }
43 }
44 */
45 TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
46   const std::string text = R"(
47                 OpCapability Shader
48           %1 = OpExtInstImport "GLSL.std.450"
49                OpMemoryModel Logical GLSL450
50                OpEntryPoint Fragment %2 "main" %3
51                OpExecutionMode %2 OriginUpperLeft
52                OpSource GLSL 330
53                OpName %2 "main"
54                OpName %5 "i"
55                OpName %3 "c"
56                OpDecorate %3 Location 0
57           %6 = OpTypeVoid
58           %7 = OpTypeFunction %6
59           %8 = OpTypeInt 32 1
60           %9 = OpTypePointer Function %8
61          %10 = OpConstant %8 0
62          %11 = OpConstant %8 10
63          %12 = OpTypeBool
64          %13 = OpConstant %8 1
65          %14 = OpTypeFloat 32
66          %15 = OpTypeVector %14 4
67          %16 = OpTypePointer Output %15
68           %3 = OpVariable %16 Output
69           %2 = OpFunction %6 None %7
70          %17 = OpLabel
71           %5 = OpVariable %9 Function
72                OpStore %5 %10
73                OpBranch %18
74          %18 = OpLabel
75                OpLoopMerge %19 %20 None
76                OpBranch %21
77          %21 = OpLabel
78          %22 = OpLoad %8 %5
79          %23 = OpSLessThan %12 %22 %11
80                OpBranchConditional %23 %24 %19
81          %24 = OpLabel
82                OpBranch %20
83          %20 = OpLabel
84          %25 = OpLoad %8 %5
85          %26 = OpIAdd %8 %25 %13
86                OpStore %5 %26
87                OpBranch %18
88          %19 = OpLabel
89                OpReturn
90                OpFunctionEnd
91   )";
92   // clang-format on
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"
98                              << text << std::endl;
99   const ir::Function* f = spvtest::GetFunction(module, 2);
100   ir::LoopDescriptor& ld = *context->GetLoopDescriptor(f);
101
102   EXPECT_EQ(ld.NumLoops(), 1u);
103
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));
108
109   EXPECT_FALSE(loop.HasNestedLoops());
110   EXPECT_FALSE(loop.IsNested());
111   EXPECT_EQ(loop.GetDepth(), 1u);
112 }
113
114 /*
115 Generated from the following GLSL:
116 #version 330 core
117 layout(location = 0) out vec4 c;
118 void main() {
119   for(int i = 0; i < 10; ++i) {}
120   for(int i = 0; i < 10; ++i) {}
121 }
122
123 But it was "hacked" to make the first loop merge block the second loop header.
124 */
125 TEST_F(PassClassTest, LoopWithNoPreHeader) {
126   const std::string text = R"(
127                OpCapability Shader
128           %1 = OpExtInstImport "GLSL.std.450"
129                OpMemoryModel Logical GLSL450
130                OpEntryPoint Fragment %2 "main" %3
131                OpExecutionMode %2 OriginUpperLeft
132                OpSource GLSL 330
133                OpName %2 "main"
134                OpName %4 "i"
135                OpName %5 "i"
136                OpName %3 "c"
137                OpDecorate %3 Location 0
138           %6 = OpTypeVoid
139           %7 = OpTypeFunction %6
140           %8 = OpTypeInt 32 1
141           %9 = OpTypePointer Function %8
142          %10 = OpConstant %8 0
143          %11 = OpConstant %8 10
144          %12 = OpTypeBool
145          %13 = OpConstant %8 1
146          %14 = OpTypeFloat 32
147          %15 = OpTypeVector %14 4
148          %16 = OpTypePointer Output %15
149           %3 = OpVariable %16 Output
150           %2 = OpFunction %6 None %7
151          %17 = OpLabel
152           %4 = OpVariable %9 Function
153           %5 = OpVariable %9 Function
154                OpStore %4 %10
155                OpStore %5 %10
156                OpBranch %18
157          %18 = OpLabel
158                OpLoopMerge %27 %20 None
159                OpBranch %21
160          %21 = OpLabel
161          %22 = OpLoad %8 %4
162          %23 = OpSLessThan %12 %22 %11
163                OpBranchConditional %23 %24 %27
164          %24 = OpLabel
165                OpBranch %20
166          %20 = OpLabel
167          %25 = OpLoad %8 %4
168          %26 = OpIAdd %8 %25 %13
169                OpStore %4 %26
170                OpBranch %18
171          %27 = OpLabel
172                OpLoopMerge %28 %29 None
173                OpBranch %30
174          %30 = OpLabel
175          %31 = OpLoad %8 %5
176          %32 = OpSLessThan %12 %31 %11
177                OpBranchConditional %32 %33 %28
178          %33 = OpLabel
179                OpBranch %29
180          %29 = OpLabel
181          %34 = OpLoad %8 %5
182          %35 = OpIAdd %8 %34 %13
183                OpStore %5 %35
184                OpBranch %27
185          %28 = OpLabel
186                OpReturn
187                OpFunctionEnd
188   )";
189   // clang-format on
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);
198
199   EXPECT_EQ(ld.NumLoops(), 2u);
200
201   ir::Loop* loop = ld[27];
202   EXPECT_EQ(loop->GetPreHeaderBlock(), nullptr);
203   EXPECT_NE(loop->GetOrCreatePreHeaderBlock(), nullptr);
204 }
205
206 }  // namespace