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 move invariants through multiple loops
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 = 2;
36   int b = 1;
37   int hoist = 0;
38   for (int i = 0; i < 10; i++) {
39     for (int j = 0; j < 10; j++) {
40       // hoist 'hoist = a - b' out of both loops
41       hoist = a - b;
42     }
43   }
44 }
45 */
TEST_F(PassClassTest, NestedDoubleHoist)46 TEST_F(PassClassTest, NestedDoubleHoist) {
47   const std::string before_hoist = R"(OpCapability Shader
48 %1 = OpExtInstImport "GLSL.std.450"
49 OpMemoryModel Logical GLSL450
50 OpEntryPoint Fragment %main "main"
51 OpExecutionMode %main OriginUpperLeft
52 OpSource GLSL 440
53 OpName %main "main"
54 %void = OpTypeVoid
55 %4 = OpTypeFunction %void
56 %int = OpTypeInt 32 1
57 %_ptr_Function_int = OpTypePointer Function %int
58 %int_2 = OpConstant %int 2
59 %int_1 = OpConstant %int 1
60 %int_0 = OpConstant %int 0
61 %int_10 = OpConstant %int 10
62 %bool = OpTypeBool
63 %12 = OpUndef %int
64 %main = OpFunction %void None %4
65 %13 = OpLabel
66 OpBranch %14
67 %14 = OpLabel
68 %15 = OpPhi %int %int_0 %13 %16 %17
69 %18 = OpPhi %int %int_0 %13 %19 %17
70 %20 = OpPhi %int %12 %13 %21 %17
71 OpLoopMerge %22 %17 None
72 OpBranch %23
73 %23 = OpLabel
74 %24 = OpSLessThan %bool %18 %int_10
75 OpBranchConditional %24 %25 %22
76 %25 = OpLabel
77 OpBranch %26
78 %26 = OpLabel
79 %16 = OpPhi %int %15 %25 %27 %28
80 %21 = OpPhi %int %int_0 %25 %29 %28
81 OpLoopMerge %30 %28 None
82 OpBranch %31
83 %31 = OpLabel
84 %32 = OpSLessThan %bool %21 %int_10
85 OpBranchConditional %32 %33 %30
86 %33 = OpLabel
87 %27 = OpISub %int %int_2 %int_1
88 OpBranch %28
89 %28 = OpLabel
90 %29 = OpIAdd %int %21 %int_1
91 OpBranch %26
92 %30 = OpLabel
93 OpBranch %17
94 %17 = OpLabel
95 %19 = OpIAdd %int %18 %int_1
96 OpBranch %14
97 %22 = OpLabel
98 OpReturn
99 OpFunctionEnd
100 )";
101 
102   const std::string after_hoist = R"(OpCapability Shader
103 %1 = OpExtInstImport "GLSL.std.450"
104 OpMemoryModel Logical GLSL450
105 OpEntryPoint Fragment %main "main"
106 OpExecutionMode %main OriginUpperLeft
107 OpSource GLSL 440
108 OpName %main "main"
109 %void = OpTypeVoid
110 %4 = OpTypeFunction %void
111 %int = OpTypeInt 32 1
112 %_ptr_Function_int = OpTypePointer Function %int
113 %int_2 = OpConstant %int 2
114 %int_1 = OpConstant %int 1
115 %int_0 = OpConstant %int 0
116 %int_10 = OpConstant %int 10
117 %bool = OpTypeBool
118 %12 = OpUndef %int
119 %main = OpFunction %void None %4
120 %13 = OpLabel
121 %27 = OpISub %int %int_2 %int_1
122 OpBranch %14
123 %14 = OpLabel
124 %15 = OpPhi %int %int_0 %13 %16 %17
125 %18 = OpPhi %int %int_0 %13 %19 %17
126 %20 = OpPhi %int %12 %13 %21 %17
127 OpLoopMerge %22 %17 None
128 OpBranch %23
129 %23 = OpLabel
130 %24 = OpSLessThan %bool %18 %int_10
131 OpBranchConditional %24 %25 %22
132 %25 = OpLabel
133 OpBranch %26
134 %26 = OpLabel
135 %16 = OpPhi %int %15 %25 %27 %28
136 %21 = OpPhi %int %int_0 %25 %29 %28
137 OpLoopMerge %30 %28 None
138 OpBranch %31
139 %31 = OpLabel
140 %32 = OpSLessThan %bool %21 %int_10
141 OpBranchConditional %32 %33 %30
142 %33 = OpLabel
143 OpBranch %28
144 %28 = OpLabel
145 %29 = OpIAdd %int %21 %int_1
146 OpBranch %26
147 %30 = OpLabel
148 OpBranch %17
149 %17 = OpLabel
150 %19 = OpIAdd %int %18 %int_1
151 OpBranch %14
152 %22 = OpLabel
153 OpReturn
154 OpFunctionEnd
155 )";
156 
157   SinglePassRunAndCheck<LICMPass>(before_hoist, after_hoist, true);
158 }
159 
160 }  // namespace
161 }  // namespace opt
162 }  // namespace spvtools
163