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 <memory>
     16 #include <string>
     17 #include <vector>
     18 
     19 #include "gmock/gmock.h"
     20 #include "spirv-tools/libspirv.hpp"
     21 #include "spirv-tools/optimizer.hpp"
     22 #include "test/opt/pass_fixture.h"
     23 #include "test/opt/pass_utils.h"
     24 
     25 namespace spvtools {
     26 namespace opt {
     27 namespace {
     28 
     29 using CompactIdsTest = PassTest<::testing::Test>;
     30 
     31 TEST_F(CompactIdsTest, PassOff) {
     32   const std::string before =
     33       R"(OpCapability Addresses
     34 OpCapability Kernel
     35 OpCapability GenericPointer
     36 OpCapability Linkage
     37 OpMemoryModel Physical32 OpenCL
     38 %99 = OpTypeInt 32 0
     39 %10 = OpTypeVector %99 2
     40 %20 = OpConstant %99 2
     41 %30 = OpTypeArray %99 %20
     42 )";
     43 
     44   const std::string after = before;
     45 
     46   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
     47   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
     48   SinglePassRunAndCheck<NullPass>(before, after, false, false);
     49 }
     50 
     51 TEST_F(CompactIdsTest, PassOn) {
     52   const std::string before =
     53       R"(OpCapability Addresses
     54 OpCapability Kernel
     55 OpCapability GenericPointer
     56 OpCapability Linkage
     57 OpMemoryModel Physical32 OpenCL
     58 OpEntryPoint Kernel %3 "simple_kernel"
     59 %99 = OpTypeInt 32 0
     60 %10 = OpTypeVector %99 2
     61 %20 = OpConstant %99 2
     62 %30 = OpTypeArray %99 %20
     63 %40 = OpTypeVoid
     64 %50 = OpTypeFunction %40
     65  %3 = OpFunction %40 None %50
     66 %70 = OpLabel
     67 OpReturn
     68 OpFunctionEnd
     69 )";
     70 
     71   const std::string after =
     72       R"(OpCapability Addresses
     73 OpCapability Kernel
     74 OpCapability GenericPointer
     75 OpCapability Linkage
     76 OpMemoryModel Physical32 OpenCL
     77 OpEntryPoint Kernel %1 "simple_kernel"
     78 %2 = OpTypeInt 32 0
     79 %3 = OpTypeVector %2 2
     80 %4 = OpConstant %2 2
     81 %5 = OpTypeArray %2 %4
     82 %6 = OpTypeVoid
     83 %7 = OpTypeFunction %6
     84 %1 = OpFunction %6 None %7
     85 %8 = OpLabel
     86 OpReturn
     87 OpFunctionEnd
     88 )";
     89 
     90   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
     91   SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
     92   SinglePassRunAndCheck<CompactIdsPass>(before, after, false, false);
     93 }
     94 
     95 TEST(CompactIds, InstructionResultIsUpdated) {
     96   // For https://github.com/KhronosGroup/SPIRV-Tools/issues/827
     97   // In that bug, the compact Ids pass was directly updating the result Id
     98   // word for an OpFunction instruction, but not updating the cached
     99   // result_id_ in that Instruction object.
    100   //
    101   // This test is a bit cheesy.  We don't expose internal interfaces enough
    102   // to see the inconsistency.  So reproduce the original scenario, with
    103   // compact ids followed by a pass that trips up on the inconsistency.
    104 
    105   const std::string input(R"(OpCapability Shader
    106 OpMemoryModel Logical Simple
    107 OpEntryPoint GLCompute %100 "main"
    108 %200 = OpTypeVoid
    109 %300 = OpTypeFunction %200
    110 %100 = OpFunction %200 None %300
    111 %400 = OpLabel
    112 OpReturn
    113 OpFunctionEnd
    114 )");
    115 
    116   std::vector<uint32_t> binary;
    117   const spv_target_env env = SPV_ENV_UNIVERSAL_1_0;
    118   spvtools::SpirvTools tools(env);
    119   auto assembled = tools.Assemble(
    120       input, &binary, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    121   EXPECT_TRUE(assembled);
    122 
    123   spvtools::Optimizer optimizer(env);
    124   optimizer.RegisterPass(CreateCompactIdsPass());
    125   // The exhaustive inliner will use the result_id
    126   optimizer.RegisterPass(CreateInlineExhaustivePass());
    127 
    128   // This should not crash!
    129   optimizer.Run(binary.data(), binary.size(), &binary);
    130 
    131   std::string disassembly;
    132   tools.Disassemble(binary, &disassembly, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
    133 
    134   const std::string expected(R"(OpCapability Shader
    135 OpMemoryModel Logical Simple
    136 OpEntryPoint GLCompute %1 "main"
    137 %2 = OpTypeVoid
    138 %3 = OpTypeFunction %2
    139 %1 = OpFunction %2 None %3
    140 %4 = OpLabel
    141 OpReturn
    142 OpFunctionEnd
    143 )");
    144 
    145   EXPECT_THAT(disassembly, ::testing::Eq(expected));
    146 }
    147 
    148 TEST(CompactIds, HeaderIsUpdated) {
    149   const std::string input(R"(OpCapability Shader
    150 OpMemoryModel Logical Simple
    151 OpEntryPoint GLCompute %100 "main"
    152 %200 = OpTypeVoid
    153 %300 = OpTypeFunction %200
    154 %100 = OpFunction %200 None %300
    155 %400 = OpLabel
    156 OpReturn
    157 OpFunctionEnd
    158 )");
    159 
    160   std::vector<uint32_t> binary;
    161   const spv_target_env env = SPV_ENV_UNIVERSAL_1_0;
    162   spvtools::SpirvTools tools(env);
    163   auto assembled = tools.Assemble(
    164       input, &binary, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    165   EXPECT_TRUE(assembled);
    166 
    167   spvtools::Optimizer optimizer(env);
    168   optimizer.RegisterPass(CreateCompactIdsPass());
    169   // The exhaustive inliner will use the result_id
    170   optimizer.RegisterPass(CreateInlineExhaustivePass());
    171 
    172   // This should not crash!
    173   optimizer.Run(binary.data(), binary.size(), &binary);
    174 
    175   std::string disassembly;
    176   tools.Disassemble(binary, &disassembly, SPV_BINARY_TO_TEXT_OPTION_NONE);
    177 
    178   const std::string expected(R"(; SPIR-V
    179 ; Version: 1.0
    180 ; Generator: Khronos SPIR-V Tools Assembler; 0
    181 ; Bound: 5
    182 ; Schema: 0
    183 OpCapability Shader
    184 OpMemoryModel Logical Simple
    185 OpEntryPoint GLCompute %1 "main"
    186 %2 = OpTypeVoid
    187 %3 = OpTypeFunction %2
    188 %1 = OpFunction %2 None %3
    189 %4 = OpLabel
    190 OpReturn
    191 OpFunctionEnd
    192 )");
    193 
    194   EXPECT_THAT(disassembly, ::testing::Eq(expected));
    195 }
    196 
    197 // Test context consistency check after invalidating
    198 // CFG and others by compact IDs Pass.
    199 // Uses a GLSL shader with named labels for variety
    200 TEST(CompactIds, ConsistentCheck) {
    201   const std::string input(R"(OpCapability Shader
    202 OpMemoryModel Logical GLSL450
    203 OpEntryPoint Fragment %main "main" %in_var_A %out_var_SV_TARGET
    204 OpExecutionMode %main OriginUpperLeft
    205 OpSource HLSL 600
    206 OpName %main "main"
    207 OpName %in_var_A "in.var.A"
    208 OpName %out_var_SV_TARGET "out.var.SV_TARGET"
    209 OpDecorate %in_var_A Location 0
    210 OpDecorate %out_var_SV_TARGET Location 0
    211 %void = OpTypeVoid
    212 %3 = OpTypeFunction %void
    213 %float = OpTypeFloat 32
    214 %v4float = OpTypeVector %float 4
    215 %_ptr_Input_v4float = OpTypePointer Input %v4float
    216 %_ptr_Output_v4float = OpTypePointer Output %v4float
    217 %in_var_A = OpVariable %_ptr_Input_v4float Input
    218 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
    219 %main = OpFunction %void None %3
    220 %5 = OpLabel
    221 %12 = OpLoad %v4float %in_var_A
    222 %23 = OpVectorShuffle %v4float %12 %12 0 0 0 1
    223 OpStore %out_var_SV_TARGET %23
    224 OpReturn
    225 OpFunctionEnd
    226 )");
    227 
    228   spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
    229   std::unique_ptr<IRContext> context =
    230       BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input,
    231                   SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    232   ASSERT_NE(context, nullptr);
    233 
    234   CompactIdsPass compact_id_pass;
    235   context->BuildInvalidAnalyses(compact_id_pass.GetPreservedAnalyses());
    236   const auto status = compact_id_pass.Run(context.get());
    237   ASSERT_NE(status, Pass::Status::Failure);
    238   EXPECT_TRUE(context->IsConsistent());
    239 
    240   // Test output just in case
    241   std::vector<uint32_t> binary;
    242   context->module()->ToBinary(&binary, false);
    243   std::string disassembly;
    244   tools.Disassemble(binary, &disassembly,
    245                     SpirvTools::kDefaultDisassembleOption);
    246 
    247   const std::string expected(R"(OpCapability Shader
    248 OpMemoryModel Logical GLSL450
    249 OpEntryPoint Fragment %main "main" %in_var_A %out_var_SV_TARGET
    250 OpExecutionMode %main OriginUpperLeft
    251 OpSource HLSL 600
    252 OpName %main "main"
    253 OpName %in_var_A "in.var.A"
    254 OpName %out_var_SV_TARGET "out.var.SV_TARGET"
    255 OpDecorate %in_var_A Location 0
    256 OpDecorate %out_var_SV_TARGET Location 0
    257 %void = OpTypeVoid
    258 %5 = OpTypeFunction %void
    259 %float = OpTypeFloat 32
    260 %v4float = OpTypeVector %float 4
    261 %_ptr_Input_v4float = OpTypePointer Input %v4float
    262 %_ptr_Output_v4float = OpTypePointer Output %v4float
    263 %in_var_A = OpVariable %_ptr_Input_v4float Input
    264 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
    265 %main = OpFunction %void None %5
    266 %10 = OpLabel
    267 %11 = OpLoad %v4float %in_var_A
    268 %12 = OpVectorShuffle %v4float %11 %11 0 0 0 1
    269 OpStore %out_var_SV_TARGET %12
    270 OpReturn
    271 OpFunctionEnd
    272 )");
    273 
    274   EXPECT_THAT(disassembly, ::testing::Eq(expected));
    275 }
    276 
    277 }  // namespace
    278 }  // namespace opt
    279 }  // namespace spvtools
    280