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 #include <vector>
     17 
     18 #include "gmock/gmock.h"
     19 #include "test/opt/assembly_builder.h"
     20 #include "test/opt/pass_fixture.h"
     21 #include "test/opt/pass_utils.h"
     22 
     23 namespace spvtools {
     24 namespace opt {
     25 namespace {
     26 
     27 using ::testing::HasSubstr;
     28 using EliminateDeadFunctionsBasicTest = PassTest<::testing::Test>;
     29 
     30 TEST_F(EliminateDeadFunctionsBasicTest, BasicDeleteDeadFunction) {
     31   // The function Dead should be removed because it is never called.
     32   const std::vector<const char*> common_code = {
     33       // clang-format off
     34                "OpCapability Shader",
     35                "OpMemoryModel Logical GLSL450",
     36                "OpEntryPoint Fragment %main \"main\"",
     37                "OpName %main \"main\"",
     38                "OpName %Live \"Live\"",
     39        "%void = OpTypeVoid",
     40           "%7 = OpTypeFunction %void",
     41        "%main = OpFunction %void None %7",
     42          "%15 = OpLabel",
     43          "%16 = OpFunctionCall %void %Live",
     44          "%17 = OpFunctionCall %void %Live",
     45                "OpReturn",
     46                "OpFunctionEnd",
     47   "%Live = OpFunction %void None %7",
     48          "%20 = OpLabel",
     49                "OpReturn",
     50                "OpFunctionEnd"
     51       // clang-format on
     52   };
     53 
     54   const std::vector<const char*> dead_function = {
     55       // clang-format off
     56       "%Dead = OpFunction %void None %7",
     57          "%19 = OpLabel",
     58                "OpReturn",
     59                "OpFunctionEnd",
     60       // clang-format on
     61   };
     62 
     63   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
     64   SinglePassRunAndCheck<EliminateDeadFunctionsPass>(
     65       JoinAllInsts(Concat(common_code, dead_function)),
     66       JoinAllInsts(common_code), /* skip_nop = */ true);
     67 }
     68 
     69 TEST_F(EliminateDeadFunctionsBasicTest, BasicKeepLiveFunction) {
     70   // Everything is reachable from an entry point, so no functions should be
     71   // deleted.
     72   const std::vector<const char*> text = {
     73       // clang-format off
     74                "OpCapability Shader",
     75                "OpMemoryModel Logical GLSL450",
     76                "OpEntryPoint Fragment %main \"main\"",
     77                "OpName %main \"main\"",
     78                "OpName %Live1 \"Live1\"",
     79                "OpName %Live2 \"Live2\"",
     80        "%void = OpTypeVoid",
     81           "%7 = OpTypeFunction %void",
     82        "%main = OpFunction %void None %7",
     83          "%15 = OpLabel",
     84          "%16 = OpFunctionCall %void %Live2",
     85          "%17 = OpFunctionCall %void %Live1",
     86                "OpReturn",
     87                "OpFunctionEnd",
     88       "%Live1 = OpFunction %void None %7",
     89          "%19 = OpLabel",
     90                "OpReturn",
     91                "OpFunctionEnd",
     92       "%Live2 = OpFunction %void None %7",
     93          "%20 = OpLabel",
     94                "OpReturn",
     95                "OpFunctionEnd"
     96       // clang-format on
     97   };
     98 
     99   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    100   std::string assembly = JoinAllInsts(text);
    101   auto result = SinglePassRunAndDisassemble<EliminateDeadFunctionsPass>(
    102       assembly, /* skip_nop = */ true, /* do_validation = */ false);
    103   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    104   EXPECT_EQ(assembly, std::get<0>(result));
    105 }
    106 
    107 TEST_F(EliminateDeadFunctionsBasicTest, BasicKeepExportFunctions) {
    108   // All functions are reachable.  In particular, ExportedFunc and Constant are
    109   // reachable because ExportedFunc is exported.  Nothing should be removed.
    110   const std::vector<const char*> text = {
    111       // clang-format off
    112                "OpCapability Shader",
    113                "OpCapability Linkage",
    114                "OpMemoryModel Logical GLSL450",
    115                "OpEntryPoint Fragment %main \"main\"",
    116                "OpName %main \"main\"",
    117                "OpName %ExportedFunc \"ExportedFunc\"",
    118                "OpName %Live \"Live\"",
    119                "OpDecorate %ExportedFunc LinkageAttributes \"ExportedFunc\" Export",
    120        "%void = OpTypeVoid",
    121           "%7 = OpTypeFunction %void",
    122        "%main = OpFunction %void None %7",
    123          "%15 = OpLabel",
    124                "OpReturn",
    125                "OpFunctionEnd",
    126 "%ExportedFunc = OpFunction %void None %7",
    127          "%19 = OpLabel",
    128          "%16 = OpFunctionCall %void %Live",
    129                "OpReturn",
    130                "OpFunctionEnd",
    131   "%Live = OpFunction %void None %7",
    132          "%20 = OpLabel",
    133                "OpReturn",
    134                "OpFunctionEnd"
    135       // clang-format on
    136   };
    137 
    138   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    139   std::string assembly = JoinAllInsts(text);
    140   auto result = SinglePassRunAndDisassemble<EliminateDeadFunctionsPass>(
    141       assembly, /* skip_nop = */ true, /* do_validation = */ false);
    142   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    143   EXPECT_EQ(assembly, std::get<0>(result));
    144 }
    145 
    146 TEST_F(EliminateDeadFunctionsBasicTest, BasicRemoveDecorationsAndNames) {
    147   // We want to remove the names and decorations associated with results that
    148   // are removed.  This test will check for that.
    149   const std::string text = R"(
    150                OpCapability Shader
    151                OpMemoryModel Logical GLSL450
    152                OpEntryPoint Vertex %main "main"
    153                OpName %main "main"
    154                OpName %Dead "Dead"
    155                OpName %x "x"
    156                OpName %y "y"
    157                OpName %z "z"
    158                OpDecorate %x RelaxedPrecision
    159                OpDecorate %y RelaxedPrecision
    160                OpDecorate %z RelaxedPrecision
    161                OpDecorate %6 RelaxedPrecision
    162                OpDecorate %7 RelaxedPrecision
    163                OpDecorate %8 RelaxedPrecision
    164        %void = OpTypeVoid
    165          %10 = OpTypeFunction %void
    166       %float = OpTypeFloat 32
    167 %_ptr_Function_float = OpTypePointer Function %float
    168     %float_1 = OpConstant %float 1
    169        %main = OpFunction %void None %10
    170          %14 = OpLabel
    171                OpReturn
    172                OpFunctionEnd
    173        %Dead = OpFunction %void None %10
    174          %15 = OpLabel
    175           %x = OpVariable %_ptr_Function_float Function
    176           %y = OpVariable %_ptr_Function_float Function
    177           %z = OpVariable %_ptr_Function_float Function
    178                OpStore %x %float_1
    179                OpStore %y %float_1
    180           %6 = OpLoad %float %x
    181           %7 = OpLoad %float %y
    182           %8 = OpFAdd %float %6 %7
    183                OpStore %z %8
    184                OpReturn
    185                OpFunctionEnd)";
    186 
    187   const std::string expected_output = R"(OpCapability Shader
    188 OpMemoryModel Logical GLSL450
    189 OpEntryPoint Vertex %main "main"
    190 OpName %main "main"
    191 %void = OpTypeVoid
    192 %10 = OpTypeFunction %void
    193 %float = OpTypeFloat 32
    194 %_ptr_Function_float = OpTypePointer Function %float
    195 %float_1 = OpConstant %float 1
    196 %main = OpFunction %void None %10
    197 %14 = OpLabel
    198 OpReturn
    199 OpFunctionEnd
    200 )";
    201 
    202   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    203   SinglePassRunAndCheck<EliminateDeadFunctionsPass>(text, expected_output,
    204                                                     /* skip_nop = */ true);
    205 }
    206 
    207 }  // namespace
    208 }  // namespace opt
    209 }  // namespace spvtools
    210