• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 generate a preheader when one is not present
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     if (i == 5) {
40       break;
41     }
42   }
43   for (int i = 0; i < 10; i++) {
44     hoist = a + b;
45   }
46 }
47 */
TEST_F(PassClassTest,HoistWithoutPreheader)48 TEST_F(PassClassTest, HoistWithoutPreheader) {
49   const std::string text = R"(OpCapability Shader
50 %1 = OpExtInstImport "GLSL.std.450"
51 OpMemoryModel Logical GLSL450
52 OpEntryPoint Fragment %main "main"
53 OpExecutionMode %main OriginUpperLeft
54 OpSource GLSL 440
55 OpName %main "main"
56 %void = OpTypeVoid
57 %4 = OpTypeFunction %void
58 %int = OpTypeInt 32 1
59 %_ptr_Function_int = OpTypePointer Function %int
60 %int_1 = OpConstant %int 1
61 %int_2 = OpConstant %int 2
62 %int_0 = OpConstant %int 0
63 %int_10 = OpConstant %int 10
64 %bool = OpTypeBool
65 %int_5 = OpConstant %int 5
66 %main = OpFunction %void None %4
67 %13 = OpLabel
68 OpBranch %14
69 %14 = OpLabel
70 %15 = OpPhi %int %int_0 %13 %16 %17
71 ; CHECK: OpLoopMerge [[preheader:%\w+]]
72 OpLoopMerge %25 %17 None
73 OpBranch %19
74 %19 = OpLabel
75 %20 = OpSLessThan %bool %15 %int_10
76 OpBranchConditional %20 %21 %25
77 %21 = OpLabel
78 %22 = OpIEqual %bool %15 %int_5
79 OpSelectionMerge %23 None
80 OpBranchConditional %22 %24 %23
81 %24 = OpLabel
82 OpBranch %25
83 %23 = OpLabel
84 OpBranch %17
85 %17 = OpLabel
86 %16 = OpIAdd %int %15 %int_1
87 OpBranch %14
88 ; Check that we hoisted the code to the preheader
89 ; CHECK: [[preheader]] = OpLabel
90 ; CHECK-NEXT: OpPhi
91 ; CHECK-NEXT: OpPhi
92 ; CHECK-NEXT: OpIAdd
93 ; CHECK-NEXT: OpBranch [[header:%\w+]]
94 ; CHECK: [[header]] = OpLabel
95 ; CHECK-NEXT: OpPhi
96 ; CHECK-NEXT: OpPhi
97 ; CHECK: OpLoopMerge
98 %25 = OpLabel
99 %26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
100 %29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
101 OpLoopMerge %31 %28 None
102 OpBranch %32
103 %32 = OpLabel
104 %33 = OpSLessThan %bool %29 %int_10
105 OpBranchConditional %33 %34 %31
106 %34 = OpLabel
107 %27 = OpIAdd %int %int_1 %int_2
108 OpBranch %28
109 %28 = OpLabel
110 %30 = OpIAdd %int %29 %int_1
111 OpBranch %25
112 %31 = OpLabel
113 OpReturn
114 OpFunctionEnd
115 )";
116 
117   SinglePassRunAndMatch<LICMPass>(text, false);
118 }
119 
TEST_F(PassClassTest,HoistWithoutPreheaderAtIdBound)120 TEST_F(PassClassTest, HoistWithoutPreheaderAtIdBound) {
121   const std::string text = R"(OpCapability Shader
122 %1 = OpExtInstImport "GLSL.std.450"
123 OpMemoryModel Logical GLSL450
124 OpEntryPoint Fragment %main "main"
125 OpExecutionMode %main OriginUpperLeft
126 OpSource GLSL 440
127 OpName %main "main"
128 %void = OpTypeVoid
129 %4 = OpTypeFunction %void
130 %int = OpTypeInt 32 1
131 %_ptr_Function_int = OpTypePointer Function %int
132 %int_1 = OpConstant %int 1
133 %int_2 = OpConstant %int 2
134 %int_0 = OpConstant %int 0
135 %int_10 = OpConstant %int 10
136 %bool = OpTypeBool
137 %int_5 = OpConstant %int 5
138 %main = OpFunction %void None %4
139 %13 = OpLabel
140 OpBranch %14
141 %14 = OpLabel
142 %15 = OpPhi %int %int_0 %13 %16 %17
143 OpLoopMerge %25 %17 None
144 OpBranch %19
145 %19 = OpLabel
146 %20 = OpSLessThan %bool %15 %int_10
147 OpBranchConditional %20 %21 %25
148 %21 = OpLabel
149 %22 = OpIEqual %bool %15 %int_5
150 OpSelectionMerge %23 None
151 OpBranchConditional %22 %24 %23
152 %24 = OpLabel
153 OpBranch %25
154 %23 = OpLabel
155 OpBranch %17
156 %17 = OpLabel
157 %16 = OpIAdd %int %15 %int_1
158 OpBranch %14
159 %25 = OpLabel
160 %26 = OpPhi %int %int_0 %24 %int_0 %19 %27 %28
161 %29 = OpPhi %int %int_0 %24 %int_0 %19 %30 %28
162 OpLoopMerge %31 %28 None
163 OpBranch %32
164 %32 = OpLabel
165 %33 = OpSLessThan %bool %29 %int_10
166 OpBranchConditional %33 %34 %31
167 %34 = OpLabel
168 %27 = OpIAdd %int %int_1 %int_2
169 OpBranch %28
170 %28 = OpLabel
171 %30 = OpIAdd %int %29 %int_1
172 OpBranch %25
173 %31 = OpLabel
174 OpReturn
175 OpFunctionEnd
176 )";
177 
178   std::unique_ptr<IRContext> context =
179       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
180                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
181   uint32_t current_bound = context->module()->id_bound();
182   context->set_max_id_bound(current_bound);
183 
184   auto pass = MakeUnique<LICMPass>();
185   auto result = pass->Run(context.get());
186   EXPECT_EQ(result, Pass::Status::Failure);
187 
188   std::vector<uint32_t> binary;
189   context->module()->ToBinary(&binary, false);
190   std::string optimized_asm;
191   SpirvTools tools_(SPV_ENV_UNIVERSAL_1_1);
192   tools_.Disassemble(binary, &optimized_asm);
193   std::cout << optimized_asm << std::endl;
194 }
195 }  // namespace
196 }  // namespace opt
197 }  // namespace spvtools
198