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 <string>
16 
17 #include "gmock/gmock.h"
18 #include "source/opt/value_number_table.h"
19 #include "test/opt/pass_fixture.h"
20 #include "test/opt/pass_utils.h"
21 
22 namespace spvtools {
23 namespace opt {
24 namespace {
25 
26 using ::testing::HasSubstr;
27 using ::testing::MatchesRegex;
28 using LocalRedundancyEliminationTest = PassTest<::testing::Test>;
29 
30 // Remove an instruction when it was already computed.
TEST_F(LocalRedundancyEliminationTest, RemoveRedundantAdd)31 TEST_F(LocalRedundancyEliminationTest, RemoveRedundantAdd) {
32   const std::string text = R"(
33                OpCapability Shader
34           %1 = OpExtInstImport "GLSL.std.450"
35                OpMemoryModel Logical GLSL450
36                OpEntryPoint Fragment %2 "main"
37                OpExecutionMode %2 OriginUpperLeft
38                OpSource GLSL 430
39           %3 = OpTypeVoid
40           %4 = OpTypeFunction %3
41           %5 = OpTypeFloat 32
42           %6 = OpTypePointer Function %5
43           %2 = OpFunction %3 None %4
44           %7 = OpLabel
45           %8 = OpVariable %6 Function
46           %9 = OpLoad %5 %8
47          %10 = OpFAdd %5 %9 %9
48 ; CHECK: OpFAdd
49 ; CHECK-NOT: OpFAdd
50          %11 = OpFAdd %5 %9 %9
51                OpReturn
52                OpFunctionEnd
53   )";
54   SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
55 }
56 
57 // Make sure we keep instruction that are different, but look similar.
TEST_F(LocalRedundancyEliminationTest, KeepDifferentAdd)58 TEST_F(LocalRedundancyEliminationTest, KeepDifferentAdd) {
59   const std::string text = R"(
60                OpCapability Shader
61           %1 = OpExtInstImport "GLSL.std.450"
62                OpMemoryModel Logical GLSL450
63                OpEntryPoint Fragment %2 "main"
64                OpExecutionMode %2 OriginUpperLeft
65                OpSource GLSL 430
66           %3 = OpTypeVoid
67           %4 = OpTypeFunction %3
68           %5 = OpTypeFloat 32
69           %6 = OpTypePointer Function %5
70           %2 = OpFunction %3 None %4
71           %7 = OpLabel
72           %8 = OpVariable %6 Function
73           %9 = OpLoad %5 %8
74          %10 = OpFAdd %5 %9 %9
75 ; CHECK: OpFAdd
76                OpStore %8 %10
77          %11 = OpLoad %5 %8
78 ; CHECK: %11 = OpLoad
79          %12 = OpFAdd %5 %11 %11
80 ; CHECK: OpFAdd [[:%\w+]] %11 %11
81                OpReturn
82                OpFunctionEnd
83   )";
84   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
85   SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
86 }
87 
88 // This test is check that the values are being propagated properly, and that
89 // we are able to identify sequences of instruction that are not needed.
TEST_F(LocalRedundancyEliminationTest, RemoveMultipleInstructions)90 TEST_F(LocalRedundancyEliminationTest, RemoveMultipleInstructions) {
91   const std::string text = R"(
92                OpCapability Shader
93           %1 = OpExtInstImport "GLSL.std.450"
94                OpMemoryModel Logical GLSL450
95                OpEntryPoint Fragment %2 "main"
96                OpExecutionMode %2 OriginUpperLeft
97                OpSource GLSL 430
98           %3 = OpTypeVoid
99           %4 = OpTypeFunction %3
100           %5 = OpTypeFloat 32
101           %6 = OpTypePointer Uniform %5
102           %8 = OpVariable %6 Uniform
103           %2 = OpFunction %3 None %4
104           %7 = OpLabel
105 ; CHECK: [[r1:%\w+]] = OpLoad
106           %9 = OpLoad %5 %8
107 ; CHECK-NEXT: [[r2:%\w+]] = OpFAdd [[:%\w+]] [[r1]] [[r1]]
108          %10 = OpFAdd %5 %9 %9
109 ; CHECK-NEXT: [[r3:%\w+]] = OpFMul [[:%\w+]] [[r2]] [[r1]]
110          %11 = OpFMul %5 %10 %9
111 ; CHECK-NOT: OpLoad
112          %12 = OpLoad %5 %8
113 ; CHECK-NOT: OpFAdd [[:\w+]] %12 %12
114          %13 = OpFAdd %5 %12 %12
115 ; CHECK-NOT: OpFMul
116          %14 = OpFMul %5 %13 %12
117 ; CHECK-NEXT: [[:%\w+]] = OpFAdd [[:%\w+]] [[r3]] [[r3]]
118          %15 = OpFAdd %5 %14 %11
119                OpReturn
120                OpFunctionEnd
121   )";
122   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
123   SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
124 }
125 
126 // Redundant instructions in different blocks should be kept.
TEST_F(LocalRedundancyEliminationTest, KeepInstructionsInDifferentBlocks)127 TEST_F(LocalRedundancyEliminationTest, KeepInstructionsInDifferentBlocks) {
128   const std::string text = R"(
129                OpCapability Shader
130           %1 = OpExtInstImport "GLSL.std.450"
131                OpMemoryModel Logical GLSL450
132                OpEntryPoint Fragment %2 "main"
133                OpExecutionMode %2 OriginUpperLeft
134                OpSource GLSL 430
135           %3 = OpTypeVoid
136           %4 = OpTypeFunction %3
137           %5 = OpTypeFloat 32
138           %6 = OpTypePointer Function %5
139           %2 = OpFunction %3 None %4
140         %bb1 = OpLabel
141           %8 = OpVariable %6 Function
142           %9 = OpLoad %5 %8
143          %10 = OpFAdd %5 %9 %9
144 ; CHECK: OpFAdd
145                OpBranch %bb2
146         %bb2 = OpLabel
147 ; CHECK: OpFAdd
148          %11 = OpFAdd %5 %9 %9
149                OpReturn
150                OpFunctionEnd
151   )";
152   SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false);
153 }
154 
TEST_F(LocalRedundancyEliminationTest, StorageBufferIdentification)155 TEST_F(LocalRedundancyEliminationTest, StorageBufferIdentification) {
156   const std::string text = R"(
157 ; CHECK: [[gep:%\w+]] = OpAccessChain
158 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[gep]]
159 ; CHECK: [[add:%\w+]] = OpIAdd {{%\w+}} [[ld]]
160 ; CHECK: OpStore [[gep]] [[add]]
161 ; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[gep]]
162 ; CHECK: [[add:%\w+]] = OpIAdd {{%\w+}} [[ld]]
163 ; CHECK: OpStore [[gep]] [[add]]
164 
165 OpCapability Shader
166 OpCapability Linkage
167 OpMemoryModel Logical GLSL450
168 OpDecorate %block BufferBlock
169 OpMemberDecorate %block 0 Offset 0
170 %void = OpTypeVoid
171 %int = OpTypeInt 32 0
172 %int_0 = OpConstant %int 0
173 %int_1 = OpConstant %int 1
174 %block = OpTypeStruct %int
175 %array = OpTypeArray %block %int_1
176 %ptr_ssbo_array = OpTypePointer Uniform %array
177 %ptr_ssbo_int = OpTypePointer Uniform %int
178 %var = OpVariable %ptr_ssbo_array Uniform
179 %void_fn = OpTypeFunction %void
180 %fn = OpFunction %void None %void_fn
181 %entry = OpLabel
182 %gep1 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
183 %ld1 = OpLoad %int %gep1
184 %add1 = OpIAdd %int %ld1 %int_1
185 %gep2 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
186 OpStore %gep2 %add1
187 %gep3 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
188 %ld3 = OpLoad %int %gep3
189 %add3 = OpIAdd %int %ld3 %int_1
190 %gep4 = OpAccessChain %ptr_ssbo_int %var %int_0 %int_0
191 OpStore %gep4 %add3
192 OpReturn
193 OpFunctionEnd
194 )";
195 
196   SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, true);
197 }
198 
199 }  // namespace
200 }  // namespace opt
201 }  // namespace spvtools
202