Home | History | Annotate | Download | only in opt
      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 RedundancyEliminationTest = PassTest<::testing::Test>;
     31 
     32 // Test that it can get a simple case of local redundancy elimination.
     33 // The rest of the test check for extra functionality.
     34 TEST_F(RedundancyEliminationTest, RemoveRedundantLocalAdd) {
     35   const std::string text = R"(
     36                OpCapability Shader
     37           %1 = OpExtInstImport "GLSL.std.450"
     38                OpMemoryModel Logical GLSL450
     39                OpEntryPoint Fragment %2 "main"
     40                OpExecutionMode %2 OriginUpperLeft
     41                OpSource GLSL 430
     42           %3 = OpTypeVoid
     43           %4 = OpTypeFunction %3
     44           %5 = OpTypeFloat 32
     45           %6 = OpTypePointer Function %5
     46           %2 = OpFunction %3 None %4
     47           %7 = OpLabel
     48           %8 = OpVariable %6 Function
     49           %9 = OpLoad %5 %8
     50          %10 = OpFAdd %5 %9 %9
     51 ; CHECK: OpFAdd
     52 ; CHECK-NOT: OpFAdd
     53          %11 = OpFAdd %5 %9 %9
     54                OpReturn
     55                OpFunctionEnd
     56   )";
     57   SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
     58 }
     59 
     60 // Remove a redundant add across basic blocks.
     61 TEST_F(RedundancyEliminationTest, RemoveRedundantAdd) {
     62   const std::string text = R"(
     63                OpCapability Shader
     64           %1 = OpExtInstImport "GLSL.std.450"
     65                OpMemoryModel Logical GLSL450
     66                OpEntryPoint Fragment %2 "main"
     67                OpExecutionMode %2 OriginUpperLeft
     68                OpSource GLSL 430
     69           %3 = OpTypeVoid
     70           %4 = OpTypeFunction %3
     71           %5 = OpTypeFloat 32
     72           %6 = OpTypePointer Function %5
     73           %2 = OpFunction %3 None %4
     74           %7 = OpLabel
     75           %8 = OpVariable %6 Function
     76           %9 = OpLoad %5 %8
     77          %10 = OpFAdd %5 %9 %9
     78                OpBranch %11
     79          %11 = OpLabel
     80 ; CHECK: OpFAdd
     81 ; CHECK-NOT: OpFAdd
     82          %12 = OpFAdd %5 %9 %9
     83                OpReturn
     84                OpFunctionEnd
     85   )";
     86   SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
     87 }
     88 
     89 // Remove a redundant add going through a multiple basic blocks.
     90 TEST_F(RedundancyEliminationTest, RemoveRedundantAddDiamond) {
     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 Function %5
    102           %7 = OpTypeBool
    103           %8 = OpConstantTrue %7
    104           %2 = OpFunction %3 None %4
    105           %9 = OpLabel
    106          %10 = OpVariable %6 Function
    107          %11 = OpLoad %5 %10
    108          %12 = OpFAdd %5 %11 %11
    109 ; CHECK: OpFAdd
    110 ; CHECK-NOT: OpFAdd
    111                OpBranchConditional %8 %13 %14
    112          %13 = OpLabel
    113                OpBranch %15
    114          %14 = OpLabel
    115                OpBranch %15
    116          %15 = OpLabel
    117          %16 = OpFAdd %5 %11 %11
    118                OpReturn
    119                OpFunctionEnd
    120 
    121   )";
    122   SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
    123 }
    124 
    125 // Remove a redundant add in a side node.
    126 TEST_F(RedundancyEliminationTest, RemoveRedundantAddInSideNode) {
    127   const std::string text = R"(
    128                OpCapability Shader
    129           %1 = OpExtInstImport "GLSL.std.450"
    130                OpMemoryModel Logical GLSL450
    131                OpEntryPoint Fragment %2 "main"
    132                OpExecutionMode %2 OriginUpperLeft
    133                OpSource GLSL 430
    134           %3 = OpTypeVoid
    135           %4 = OpTypeFunction %3
    136           %5 = OpTypeFloat 32
    137           %6 = OpTypePointer Function %5
    138           %7 = OpTypeBool
    139           %8 = OpConstantTrue %7
    140           %2 = OpFunction %3 None %4
    141           %9 = OpLabel
    142          %10 = OpVariable %6 Function
    143          %11 = OpLoad %5 %10
    144          %12 = OpFAdd %5 %11 %11
    145 ; CHECK: OpFAdd
    146 ; CHECK-NOT: OpFAdd
    147                OpBranchConditional %8 %13 %14
    148          %13 = OpLabel
    149                OpBranch %15
    150          %14 = OpLabel
    151          %16 = OpFAdd %5 %11 %11
    152                OpBranch %15
    153          %15 = OpLabel
    154                OpReturn
    155                OpFunctionEnd
    156 
    157   )";
    158   SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
    159 }
    160 
    161 // Remove a redundant add whose value is in the result of a phi node.
    162 TEST_F(RedundancyEliminationTest, RemoveRedundantAddWithPhi) {
    163   const std::string text = R"(
    164                OpCapability Shader
    165           %1 = OpExtInstImport "GLSL.std.450"
    166                OpMemoryModel Logical GLSL450
    167                OpEntryPoint Fragment %2 "main"
    168                OpExecutionMode %2 OriginUpperLeft
    169                OpSource GLSL 430
    170           %3 = OpTypeVoid
    171           %4 = OpTypeFunction %3
    172           %5 = OpTypeFloat 32
    173           %6 = OpTypePointer Function %5
    174           %7 = OpTypeBool
    175           %8 = OpConstantTrue %7
    176           %2 = OpFunction %3 None %4
    177           %9 = OpLabel
    178          %10 = OpVariable %6 Function
    179          %11 = OpLoad %5 %10
    180                OpBranchConditional %8 %13 %14
    181          %13 = OpLabel
    182          %add1 = OpFAdd %5 %11 %11
    183 ; CHECK: OpFAdd
    184                OpBranch %15
    185          %14 = OpLabel
    186          %add2 = OpFAdd %5 %11 %11
    187 ; CHECK: OpFAdd
    188                OpBranch %15
    189          %15 = OpLabel
    190 ; CHECK: OpPhi
    191           %phi = OpPhi %5 %add1 %13 %add2 %14
    192 ; CHECK-NOT: OpFAdd
    193          %16 = OpFAdd %5 %11 %11
    194                OpReturn
    195                OpFunctionEnd
    196 
    197   )";
    198   SinglePassRunAndMatch<RedundancyEliminationPass>(text, false);
    199 }
    200 
    201 // Keep the add because it is redundant on some paths, but not all paths.
    202 TEST_F(RedundancyEliminationTest, KeepPartiallyRedundantAdd) {
    203   const std::string text = R"(
    204                OpCapability Shader
    205           %1 = OpExtInstImport "GLSL.std.450"
    206                OpMemoryModel Logical GLSL450
    207                OpEntryPoint Fragment %2 "main"
    208                OpExecutionMode %2 OriginUpperLeft
    209                OpSource GLSL 430
    210           %3 = OpTypeVoid
    211           %4 = OpTypeFunction %3
    212           %5 = OpTypeFloat 32
    213           %6 = OpTypePointer Function %5
    214           %7 = OpTypeBool
    215           %8 = OpConstantTrue %7
    216           %2 = OpFunction %3 None %4
    217           %9 = OpLabel
    218          %10 = OpVariable %6 Function
    219          %11 = OpLoad %5 %10
    220                OpBranchConditional %8 %13 %14
    221          %13 = OpLabel
    222         %add = OpFAdd %5 %11 %11
    223                OpBranch %15
    224          %14 = OpLabel
    225                OpBranch %15
    226          %15 = OpLabel
    227          %16 = OpFAdd %5 %11 %11
    228                OpReturn
    229                OpFunctionEnd
    230 
    231   )";
    232   auto result = SinglePassRunAndDisassemble<RedundancyEliminationPass>(
    233       text, /* skip_nop = */ true, /* do_validation = */ false);
    234   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    235 }
    236 
    237 // Keep the add.  Even if it is redundant on all paths, there is no single id
    238 // whose definition dominates the add and contains the same value.
    239 TEST_F(RedundancyEliminationTest, KeepRedundantAddWithoutPhi) {
    240   const std::string text = R"(
    241                OpCapability Shader
    242           %1 = OpExtInstImport "GLSL.std.450"
    243                OpMemoryModel Logical GLSL450
    244                OpEntryPoint Fragment %2 "main"
    245                OpExecutionMode %2 OriginUpperLeft
    246                OpSource GLSL 430
    247           %3 = OpTypeVoid
    248           %4 = OpTypeFunction %3
    249           %5 = OpTypeFloat 32
    250           %6 = OpTypePointer Function %5
    251           %7 = OpTypeBool
    252           %8 = OpConstantTrue %7
    253           %2 = OpFunction %3 None %4
    254           %9 = OpLabel
    255          %10 = OpVariable %6 Function
    256          %11 = OpLoad %5 %10
    257                OpBranchConditional %8 %13 %14
    258          %13 = OpLabel
    259          %add1 = OpFAdd %5 %11 %11
    260                OpBranch %15
    261          %14 = OpLabel
    262          %add2 = OpFAdd %5 %11 %11
    263                OpBranch %15
    264          %15 = OpLabel
    265          %16 = OpFAdd %5 %11 %11
    266                OpReturn
    267                OpFunctionEnd
    268 
    269   )";
    270   auto result = SinglePassRunAndDisassemble<RedundancyEliminationPass>(
    271       text, /* skip_nop = */ true, /* do_validation = */ false);
    272   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    273 }
    274 
    275 }  // namespace
    276 }  // namespace opt
    277 }  // namespace spvtools
    278