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