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