Path: blob/master/thirdparty/glslang/SPIRV/SpvTools.cpp
9903 views
//1// Copyright (C) 2014-2016 LunarG, Inc.2// Copyright (C) 2018-2020 Google, Inc.3//4// All rights reserved.5//6// Redistribution and use in source and binary forms, with or without7// modification, are permitted provided that the following conditions8// are met:9//10// Redistributions of source code must retain the above copyright11// notice, this list of conditions and the following disclaimer.12//13// Redistributions in binary form must reproduce the above14// copyright notice, this list of conditions and the following15// disclaimer in the documentation and/or other materials provided16// with the distribution.17//18// Neither the name of 3Dlabs Inc. Ltd. nor the names of its19// contributors may be used to endorse or promote products derived20// from this software without specific prior written permission.21//22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS25// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE26// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,27// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,28// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;29// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER30// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT31// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN32// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE33// POSSIBILITY OF SUCH DAMAGE.3435//36// Call into SPIRV-Tools to disassemble, validate, and optimize.37//3839#if ENABLE_OPT4041#include <cstdio>42#include <iostream>4344#include "SpvTools.h"45#include "spirv-tools/optimizer.hpp"4647namespace glslang {4849// Translate glslang's view of target versioning to what SPIRV-Tools uses.50spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)51{52switch (spvVersion.vulkan) {53case glslang::EShTargetVulkan_1_0:54return spv_target_env::SPV_ENV_VULKAN_1_0;55case glslang::EShTargetVulkan_1_1:56switch (spvVersion.spv) {57case EShTargetSpv_1_0:58case EShTargetSpv_1_1:59case EShTargetSpv_1_2:60case EShTargetSpv_1_3:61return spv_target_env::SPV_ENV_VULKAN_1_1;62case EShTargetSpv_1_4:63return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4;64default:65logger->missingFunctionality("Target version for SPIRV-Tools validator");66return spv_target_env::SPV_ENV_VULKAN_1_1;67}68case glslang::EShTargetVulkan_1_2:69return spv_target_env::SPV_ENV_VULKAN_1_2;70case glslang::EShTargetVulkan_1_3:71return spv_target_env::SPV_ENV_VULKAN_1_3;72default:73break;74}7576if (spvVersion.openGl > 0)77return spv_target_env::SPV_ENV_OPENGL_4_5;7879logger->missingFunctionality("Target version for SPIRV-Tools validator");80return spv_target_env::SPV_ENV_UNIVERSAL_1_0;81}8283// Callback passed to spvtools::Optimizer::SetMessageConsumer84void OptimizerMesssageConsumer(spv_message_level_t level, const char *source,85const spv_position_t &position, const char *message)86{87auto &out = std::cerr;88switch (level)89{90case SPV_MSG_FATAL:91case SPV_MSG_INTERNAL_ERROR:92case SPV_MSG_ERROR:93out << "error: ";94break;95case SPV_MSG_WARNING:96out << "warning: ";97break;98case SPV_MSG_INFO:99case SPV_MSG_DEBUG:100out << "info: ";101break;102default:103break;104}105if (source)106{107out << source << ":";108}109out << position.line << ":" << position.column << ":" << position.index << ":";110if (message)111{112out << " " << message;113}114out << std::endl;115}116117// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment.118void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)119{120SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3);121}122123// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment.124void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,125spv_target_env requested_context)126{127// disassemble128spv_context context = spvContextCreate(requested_context);129spv_text text;130spv_diagnostic diagnostic = nullptr;131spvBinaryToText(context, spirv.data(), spirv.size(),132SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,133&text, &diagnostic);134135// dump136if (diagnostic == nullptr)137out << text->str;138else139spvDiagnosticPrint(diagnostic);140141// teardown142spvDiagnosticDestroy(diagnostic);143spvContextDestroy(context);144}145146// Apply the SPIRV-Tools validator to generated SPIR-V.147void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,148spv::SpvBuildLogger* logger, bool prelegalization)149{150// validate151spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));152spv_const_binary_t binary = { spirv.data(), spirv.size() };153spv_diagnostic diagnostic = nullptr;154spv_validator_options options = spvValidatorOptionsCreate();155spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());156spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);157spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout());158spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout());159spvValidateWithOptions(context, options, &binary, &diagnostic);160161// report162if (diagnostic != nullptr) {163logger->error("SPIRV-Tools Validation Errors");164logger->error(diagnostic->error);165}166167// tear down168spvValidatorOptionsDestroy(options);169spvDiagnosticDestroy(diagnostic);170spvContextDestroy(context);171}172173// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process.174void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,175spv::SpvBuildLogger* logger, const SpvOptions* options)176{177spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);178179spvtools::Optimizer optimizer(target_env);180optimizer.SetMessageConsumer(OptimizerMesssageConsumer);181182// If debug (specifically source line info) is being generated, propagate183// line information into all SPIR-V instructions. This avoids loss of184// information when instructions are deleted or moved. Later, remove185// redundant information to minimize final SPRIR-V size.186if (options->stripDebugInfo) {187optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());188}189optimizer.RegisterPass(spvtools::CreateWrapOpKillPass());190optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());191optimizer.RegisterPass(spvtools::CreateMergeReturnPass());192optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());193optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());194optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());195optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());196optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());197optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());198optimizer.RegisterPass(spvtools::CreateSimplificationPass());199optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());200optimizer.RegisterPass(spvtools::CreateVectorDCEPass());201optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());202optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());203optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());204optimizer.RegisterPass(spvtools::CreateBlockMergePass());205optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());206optimizer.RegisterPass(spvtools::CreateIfConversionPass());207optimizer.RegisterPass(spvtools::CreateSimplificationPass());208optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());209optimizer.RegisterPass(spvtools::CreateVectorDCEPass());210optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());211optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass());212if (options->optimizeSize) {213optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());214optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass());215}216optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());217optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());218219spvtools::OptimizerOptions spvOptOptions;220optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));221spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on222optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);223}224225bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,226std::unordered_set<uint32_t>* live_locs,227std::unordered_set<uint32_t>* live_builtins,228spv::SpvBuildLogger*)229{230spvtools::Optimizer optimizer(target_env);231optimizer.SetMessageConsumer(OptimizerMesssageConsumer);232233optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins));234235spvtools::OptimizerOptions spvOptOptions;236optimizer.SetTargetEnv(target_env);237spvOptOptions.set_run_validator(false);238return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);239}240241void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,242std::unordered_set<uint32_t>* live_locs,243std::unordered_set<uint32_t>* live_builtins,244spv::SpvBuildLogger*)245{246spvtools::Optimizer optimizer(target_env);247optimizer.SetMessageConsumer(OptimizerMesssageConsumer);248249optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins));250optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));251optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass());252optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));253254spvtools::OptimizerOptions spvOptOptions;255optimizer.SetTargetEnv(target_env);256spvOptOptions.set_run_validator(false);257optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);258}259260void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,261spv::SpvBuildLogger*)262{263spvtools::Optimizer optimizer(target_env);264optimizer.SetMessageConsumer(OptimizerMesssageConsumer);265266optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass());267optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());268269spvtools::OptimizerOptions spvOptOptions;270optimizer.SetTargetEnv(target_env);271spvOptOptions.set_run_validator(false);272optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);273}274275// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by276// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if277// optimization is disabled.278void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,279std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)280{281spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);282283spvtools::Optimizer optimizer(target_env);284optimizer.SetMessageConsumer(OptimizerMesssageConsumer);285286optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());287288spvtools::OptimizerOptions spvOptOptions;289optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));290spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on291optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);292}293294}; // end namespace glslang295296#endif297298299