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/build_module.h" 19 #include "source/opt/value_number_table.h" 20 #include "test/opt/assembly_builder.h" 21 #include "test/opt/pass_fixture.h" 22 #include "test/opt/pass_utils.h" 23 24 namespace spvtools { 25 namespace opt { 26 namespace { 27 28 using ::testing::HasSubstr; 29 using ::testing::MatchesRegex; 30 using LocalRedundancyEliminationTest = PassTest<::testing::Test>; 31 32 // Remove an instruction when it was already computed. 33 TEST_F(LocalRedundancyEliminationTest, RemoveRedundantAdd) { 34 const std::string text = R"( 35 OpCapability Shader 36 %1 = OpExtInstImport "GLSL.std.450" 37 OpMemoryModel Logical GLSL450 38 OpEntryPoint Fragment %2 "main" 39 OpExecutionMode %2 OriginUpperLeft 40 OpSource GLSL 430 41 %3 = OpTypeVoid 42 %4 = OpTypeFunction %3 43 %5 = OpTypeFloat 32 44 %6 = OpTypePointer Function %5 45 %2 = OpFunction %3 None %4 46 %7 = OpLabel 47 %8 = OpVariable %6 Function 48 %9 = OpLoad %5 %8 49 %10 = OpFAdd %5 %9 %9 50 ; CHECK: OpFAdd 51 ; CHECK-NOT: OpFAdd 52 %11 = OpFAdd %5 %9 %9 53 OpReturn 54 OpFunctionEnd 55 )"; 56 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false); 57 } 58 59 // Make sure we keep instruction that are different, but look similar. 60 TEST_F(LocalRedundancyEliminationTest, KeepDifferentAdd) { 61 const std::string text = R"( 62 OpCapability Shader 63 %1 = OpExtInstImport "GLSL.std.450" 64 OpMemoryModel Logical GLSL450 65 OpEntryPoint Fragment %2 "main" 66 OpExecutionMode %2 OriginUpperLeft 67 OpSource GLSL 430 68 %3 = OpTypeVoid 69 %4 = OpTypeFunction %3 70 %5 = OpTypeFloat 32 71 %6 = OpTypePointer Function %5 72 %2 = OpFunction %3 None %4 73 %7 = OpLabel 74 %8 = OpVariable %6 Function 75 %9 = OpLoad %5 %8 76 %10 = OpFAdd %5 %9 %9 77 ; CHECK: OpFAdd 78 OpStore %8 %10 79 %11 = OpLoad %5 %8 80 ; CHECK: %11 = OpLoad 81 %12 = OpFAdd %5 %11 %11 82 ; CHECK: OpFAdd [[:%\w+]] %11 %11 83 OpReturn 84 OpFunctionEnd 85 )"; 86 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 87 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false); 88 } 89 90 // This test is check that the values are being propagated properly, and that 91 // we are able to identify sequences of instruction that are not needed. 92 TEST_F(LocalRedundancyEliminationTest, RemoveMultipleInstructions) { 93 const std::string text = R"( 94 OpCapability Shader 95 %1 = OpExtInstImport "GLSL.std.450" 96 OpMemoryModel Logical GLSL450 97 OpEntryPoint Fragment %2 "main" 98 OpExecutionMode %2 OriginUpperLeft 99 OpSource GLSL 430 100 %3 = OpTypeVoid 101 %4 = OpTypeFunction %3 102 %5 = OpTypeFloat 32 103 %6 = OpTypePointer Uniform %5 104 %8 = OpVariable %6 Uniform 105 %2 = OpFunction %3 None %4 106 %7 = OpLabel 107 ; CHECK: [[r1:%\w+]] = OpLoad 108 %9 = OpLoad %5 %8 109 ; CHECK-NEXT: [[r2:%\w+]] = OpFAdd [[:%\w+]] [[r1]] [[r1]] 110 %10 = OpFAdd %5 %9 %9 111 ; CHECK-NEXT: [[r3:%\w+]] = OpFMul [[:%\w+]] [[r2]] [[r1]] 112 %11 = OpFMul %5 %10 %9 113 ; CHECK-NOT: OpLoad 114 %12 = OpLoad %5 %8 115 ; CHECK-NOT: OpFAdd [[:\w+]] %12 %12 116 %13 = OpFAdd %5 %12 %12 117 ; CHECK-NOT: OpFMul 118 %14 = OpFMul %5 %13 %12 119 ; CHECK-NEXT: [[:%\w+]] = OpFAdd [[:%\w+]] [[r3]] [[r3]] 120 %15 = OpFAdd %5 %14 %11 121 OpReturn 122 OpFunctionEnd 123 )"; 124 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 125 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false); 126 } 127 128 // Redundant instructions in different blocks should be kept. 129 TEST_F(LocalRedundancyEliminationTest, KeepInstructionsInDifferentBlocks) { 130 const std::string text = R"( 131 OpCapability Shader 132 %1 = OpExtInstImport "GLSL.std.450" 133 OpMemoryModel Logical GLSL450 134 OpEntryPoint Fragment %2 "main" 135 OpExecutionMode %2 OriginUpperLeft 136 OpSource GLSL 430 137 %3 = OpTypeVoid 138 %4 = OpTypeFunction %3 139 %5 = OpTypeFloat 32 140 %6 = OpTypePointer Function %5 141 %2 = OpFunction %3 None %4 142 %bb1 = OpLabel 143 %8 = OpVariable %6 Function 144 %9 = OpLoad %5 %8 145 %10 = OpFAdd %5 %9 %9 146 ; CHECK: OpFAdd 147 OpBranch %bb2 148 %bb2 = OpLabel 149 ; CHECK: OpFAdd 150 %11 = OpFAdd %5 %9 %9 151 OpReturn 152 OpFunctionEnd 153 )"; 154 SinglePassRunAndMatch<LocalRedundancyEliminationPass>(text, false); 155 } 156 157 } // namespace 158 } // namespace opt 159 } // namespace spvtools 160