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