1 // Copyright (c) 2018 Google LLC.
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 <string>
16
17 #include "gmock/gmock.h"
18 #include "source/opt/licm_pass.h"
19 #include "test/opt/pass_fixture.h"
20
21 namespace spvtools {
22 namespace opt {
23 namespace {
24
25 using ::testing::UnorderedElementsAre;
26 using PassClassTest = PassTest<::testing::Test>;
27
28 /*
29 Tests that the LICM pass will analyse multiple independent loops in a function
30
31 Generated from the following GLSL fragment shader
32 --eliminate-local-multi-store has also been run on the spv binary
33 #version 440 core
34 void main(){
35 int a = 1;
36 int b = 2;
37 int hoist = 0;
38 for (int i = 0; i < 10; i++) {
39 // invariant
40 hoist = a + b;
41 }
42 for (int i = 0; i < 10; i++) {
43 // invariant
44 hoist = a + b;
45 }
46 int c = 1;
47 int d = 2;
48 int hoist2 = 0;
49 for (int i = 0; i < 10; i++) {
50 // invariant
51 hoist2 = c + d;
52 }
53 }
54 */
TEST_F(PassClassTest,HoistFromIndependentLoops)55 TEST_F(PassClassTest, HoistFromIndependentLoops) {
56 const std::string before_hoist = R"(OpCapability Shader
57 %1 = OpExtInstImport "GLSL.std.450"
58 OpMemoryModel Logical GLSL450
59 OpEntryPoint Fragment %main "main"
60 OpExecutionMode %main OriginUpperLeft
61 OpSource GLSL 440
62 OpName %main "main"
63 %void = OpTypeVoid
64 %4 = OpTypeFunction %void
65 %int = OpTypeInt 32 1
66 %_ptr_Function_int = OpTypePointer Function %int
67 %int_1 = OpConstant %int 1
68 %int_2 = OpConstant %int 2
69 %int_0 = OpConstant %int 0
70 %int_10 = OpConstant %int 10
71 %bool = OpTypeBool
72 %main = OpFunction %void None %4
73 %12 = OpLabel
74 OpBranch %13
75 %13 = OpLabel
76 %14 = OpPhi %int %int_0 %12 %15 %16
77 %17 = OpPhi %int %int_0 %12 %18 %16
78 OpLoopMerge %19 %16 None
79 OpBranch %20
80 %20 = OpLabel
81 %21 = OpSLessThan %bool %17 %int_10
82 OpBranchConditional %21 %22 %19
83 %22 = OpLabel
84 %15 = OpIAdd %int %int_1 %int_2
85 OpBranch %16
86 %16 = OpLabel
87 %18 = OpIAdd %int %17 %int_1
88 OpBranch %13
89 %19 = OpLabel
90 OpBranch %23
91 %23 = OpLabel
92 %24 = OpPhi %int %14 %19 %25 %26
93 %27 = OpPhi %int %int_0 %19 %28 %26
94 OpLoopMerge %29 %26 None
95 OpBranch %30
96 %30 = OpLabel
97 %31 = OpSLessThan %bool %27 %int_10
98 OpBranchConditional %31 %32 %29
99 %32 = OpLabel
100 %25 = OpIAdd %int %int_1 %int_2
101 OpBranch %26
102 %26 = OpLabel
103 %28 = OpIAdd %int %27 %int_1
104 OpBranch %23
105 %29 = OpLabel
106 OpBranch %33
107 %33 = OpLabel
108 %34 = OpPhi %int %int_0 %29 %35 %36
109 %37 = OpPhi %int %int_0 %29 %38 %36
110 OpLoopMerge %39 %36 None
111 OpBranch %40
112 %40 = OpLabel
113 %41 = OpSLessThan %bool %37 %int_10
114 OpBranchConditional %41 %42 %39
115 %42 = OpLabel
116 %35 = OpIAdd %int %int_1 %int_2
117 OpBranch %36
118 %36 = OpLabel
119 %38 = OpIAdd %int %37 %int_1
120 OpBranch %33
121 %39 = OpLabel
122 OpReturn
123 OpFunctionEnd
124 )";
125
126 const std::string after_hoist = R"(OpCapability Shader
127 %1 = OpExtInstImport "GLSL.std.450"
128 OpMemoryModel Logical GLSL450
129 OpEntryPoint Fragment %main "main"
130 OpExecutionMode %main OriginUpperLeft
131 OpSource GLSL 440
132 OpName %main "main"
133 %void = OpTypeVoid
134 %4 = OpTypeFunction %void
135 %int = OpTypeInt 32 1
136 %_ptr_Function_int = OpTypePointer Function %int
137 %int_1 = OpConstant %int 1
138 %int_2 = OpConstant %int 2
139 %int_0 = OpConstant %int 0
140 %int_10 = OpConstant %int 10
141 %bool = OpTypeBool
142 %main = OpFunction %void None %4
143 %12 = OpLabel
144 %15 = OpIAdd %int %int_1 %int_2
145 OpBranch %13
146 %13 = OpLabel
147 %14 = OpPhi %int %int_0 %12 %15 %16
148 %17 = OpPhi %int %int_0 %12 %18 %16
149 OpLoopMerge %19 %16 None
150 OpBranch %20
151 %20 = OpLabel
152 %21 = OpSLessThan %bool %17 %int_10
153 OpBranchConditional %21 %22 %19
154 %22 = OpLabel
155 OpBranch %16
156 %16 = OpLabel
157 %18 = OpIAdd %int %17 %int_1
158 OpBranch %13
159 %19 = OpLabel
160 %25 = OpIAdd %int %int_1 %int_2
161 OpBranch %23
162 %23 = OpLabel
163 %24 = OpPhi %int %14 %19 %25 %26
164 %27 = OpPhi %int %int_0 %19 %28 %26
165 OpLoopMerge %29 %26 None
166 OpBranch %30
167 %30 = OpLabel
168 %31 = OpSLessThan %bool %27 %int_10
169 OpBranchConditional %31 %32 %29
170 %32 = OpLabel
171 OpBranch %26
172 %26 = OpLabel
173 %28 = OpIAdd %int %27 %int_1
174 OpBranch %23
175 %29 = OpLabel
176 %35 = OpIAdd %int %int_1 %int_2
177 OpBranch %33
178 %33 = OpLabel
179 %34 = OpPhi %int %int_0 %29 %35 %36
180 %37 = OpPhi %int %int_0 %29 %38 %36
181 OpLoopMerge %39 %36 None
182 OpBranch %40
183 %40 = OpLabel
184 %41 = OpSLessThan %bool %37 %int_10
185 OpBranchConditional %41 %42 %39
186 %42 = OpLabel
187 OpBranch %36
188 %36 = OpLabel
189 %38 = OpIAdd %int %37 %int_1
190 OpBranch %33
191 %39 = OpLabel
192 OpReturn
193 OpFunctionEnd
194 )";
195
196 SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
197 }
198
199 } // namespace
200 } // namespace opt
201 } // namespace spvtools
202