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