Home | History | Annotate | Download | only in SPIRV
      1 //
      2 // Copyright (C) 2014-2016 LunarG, Inc.
      3 // Copyright (C) 2018 Google, Inc.
      4 //
      5 // All rights reserved.
      6 //
      7 // Redistribution and use in source and binary forms, with or without
      8 // modification, are permitted provided that the following conditions
      9 // are met:
     10 //
     11 //    Redistributions of source code must retain the above copyright
     12 //    notice, this list of conditions and the following disclaimer.
     13 //
     14 //    Redistributions in binary form must reproduce the above
     15 //    copyright notice, this list of conditions and the following
     16 //    disclaimer in the documentation and/or other materials provided
     17 //    with the distribution.
     18 //
     19 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
     20 //    contributors may be used to endorse or promote products derived
     21 //    from this software without specific prior written permission.
     22 //
     23 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     26 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     27 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     31 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
     33 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     34 // POSSIBILITY OF SUCH DAMAGE.
     35 
     36 //
     37 // Call into SPIRV-Tools to disassemble, validate, and optimize.
     38 //
     39 
     40 #if ENABLE_OPT
     41 
     42 #include <cstdio>
     43 #include <iostream>
     44 
     45 #include "SpvTools.h"
     46 #include "spirv-tools/optimizer.hpp"
     47 #include "spirv-tools/libspirv.h"
     48 
     49 namespace glslang {
     50 
     51 // Translate glslang's view of target versioning to what SPIRV-Tools uses.
     52 spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
     53 {
     54     switch (spvVersion.vulkan) {
     55     case glslang::EShTargetVulkan_1_0: return spv_target_env::SPV_ENV_VULKAN_1_0;
     56     case glslang::EShTargetVulkan_1_1: return spv_target_env::SPV_ENV_VULKAN_1_1;
     57     default:
     58         break;
     59     }
     60 
     61     if (spvVersion.openGl > 0)
     62         return spv_target_env::SPV_ENV_OPENGL_4_5;
     63 
     64     logger->missingFunctionality("Target version for SPIRV-Tools validator");
     65     return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
     66 }
     67 
     68 
     69 // Use the SPIRV-Tools disassembler to print SPIR-V.
     70 void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
     71 {
     72     // disassemble
     73     spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
     74     spv_text text;
     75     spv_diagnostic diagnostic = nullptr;
     76     spvBinaryToText(context, spirv.data(), spirv.size(),
     77         SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
     78         &text, &diagnostic);
     79 
     80     // dump
     81     if (diagnostic == nullptr)
     82         out << text->str;
     83     else
     84         spvDiagnosticPrint(diagnostic);
     85 
     86     // teardown
     87     spvDiagnosticDestroy(diagnostic);
     88     spvContextDestroy(context);
     89 }
     90 
     91 // Apply the SPIRV-Tools validator to generated SPIR-V.
     92 void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
     93                         spv::SpvBuildLogger* logger)
     94 {
     95     // validate
     96     spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
     97     spv_const_binary_t binary = { spirv.data(), spirv.size() };
     98     spv_diagnostic diagnostic = nullptr;
     99     spv_validator_options options = spvValidatorOptionsCreate();
    100     spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
    101     spvValidateWithOptions(context, options, &binary, &diagnostic);
    102 
    103     // report
    104     if (diagnostic != nullptr) {
    105         logger->error("SPIRV-Tools Validation Errors");
    106         logger->error(diagnostic->error);
    107     }
    108 
    109     // tear down
    110     spvValidatorOptionsDestroy(options);
    111     spvDiagnosticDestroy(diagnostic);
    112     spvContextDestroy(context);
    113 }
    114 
    115 // Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
    116 // legalizing HLSL SPIR-V.
    117 void SpirvToolsLegalize(const glslang::TIntermediate&, std::vector<unsigned int>& spirv,
    118                         spv::SpvBuildLogger*, const SpvOptions* options)
    119 {
    120     spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
    121 
    122     spvtools::Optimizer optimizer(target_env);
    123     optimizer.SetMessageConsumer(
    124         [](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
    125             auto &out = std::cerr;
    126             switch (level)
    127             {
    128             case SPV_MSG_FATAL:
    129             case SPV_MSG_INTERNAL_ERROR:
    130             case SPV_MSG_ERROR:
    131                 out << "error: ";
    132                 break;
    133             case SPV_MSG_WARNING:
    134                 out << "warning: ";
    135                 break;
    136             case SPV_MSG_INFO:
    137             case SPV_MSG_DEBUG:
    138                 out << "info: ";
    139                 break;
    140             default:
    141                 break;
    142             }
    143             if (source)
    144             {
    145                 out << source << ":";
    146             }
    147             out << position.line << ":" << position.column << ":" << position.index << ":";
    148             if (message)
    149             {
    150                 out << " " << message;
    151             }
    152             out << std::endl;
    153         });
    154 
    155     // If debug (specifically source line info) is being generated, propagate
    156     // line information into all SPIR-V instructions. This avoids loss of
    157     // information when instructions are deleted or moved. Later, remove
    158     // redundant information to minimize final SPRIR-V size.
    159     if (options->generateDebugInfo) {
    160         optimizer.RegisterPass(spvtools::CreatePropagateLineInfoPass());
    161     }
    162     optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
    163     optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
    164     optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
    165     optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
    166     optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
    167     optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
    168     optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
    169     optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
    170     optimizer.RegisterPass(spvtools::CreateSimplificationPass());
    171     optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
    172     optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
    173     optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
    174     optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
    175     optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
    176     optimizer.RegisterPass(spvtools::CreateBlockMergePass());
    177     optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
    178     optimizer.RegisterPass(spvtools::CreateIfConversionPass());
    179     optimizer.RegisterPass(spvtools::CreateSimplificationPass());
    180     optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
    181     optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
    182     optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
    183     if (options->optimizeSize) {
    184         optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
    185         // TODO(greg-lunarg): Add this when AMD driver issues are resolved
    186         // optimizer.RegisterPass(CreateCommonUniformElimPass());
    187     }
    188     optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
    189     optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
    190     if (options->generateDebugInfo) {
    191         optimizer.RegisterPass(spvtools::CreateRedundantLineInfoElimPass());
    192     }
    193 
    194     optimizer.Run(spirv.data(), spirv.size(), &spirv);
    195 }
    196 
    197 }; // end namespace glslang
    198 
    199 #endif
    200