Path: blob/master/thirdparty/glslang/SPIRV/SpvTools.cpp
20957 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"46#include "glslang/MachineIndependent/localintermediate.h"4748namespace glslang {4950// Translate glslang's view of target versioning to what SPIRV-Tools uses.51spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)52{53switch (spvVersion.vulkan) {54case glslang::EShTargetVulkan_1_0:55return spv_target_env::SPV_ENV_VULKAN_1_0;56case glslang::EShTargetVulkan_1_1:57switch (spvVersion.spv) {58case EShTargetSpv_1_0:59case EShTargetSpv_1_1:60case EShTargetSpv_1_2:61case EShTargetSpv_1_3:62return spv_target_env::SPV_ENV_VULKAN_1_1;63case EShTargetSpv_1_4:64return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4;65default:66logger->missingFunctionality("Target version for SPIRV-Tools validator");67return spv_target_env::SPV_ENV_VULKAN_1_1;68}69case glslang::EShTargetVulkan_1_2:70return spv_target_env::SPV_ENV_VULKAN_1_2;71case glslang::EShTargetVulkan_1_3:72return spv_target_env::SPV_ENV_VULKAN_1_3;73case glslang::EShTargetVulkan_1_4:74return spv_target_env::SPV_ENV_VULKAN_1_4;75default:76break;77}7879if (spvVersion.openGl > 0)80return spv_target_env::SPV_ENV_OPENGL_4_5;8182logger->missingFunctionality("Target version for SPIRV-Tools validator");83return spv_target_env::SPV_ENV_UNIVERSAL_1_0;84}8586spv_target_env MapToSpirvToolsEnv(const glslang::TIntermediate& intermediate, spv::SpvBuildLogger* logger)87{88return MapToSpirvToolsEnv(intermediate.getSpv(), logger);89}9091// Callback passed to spvtools::Optimizer::SetMessageConsumer92void OptimizerMesssageConsumer(spv_message_level_t level, const char *source,93const spv_position_t &position, const char *message)94{95auto &out = std::cerr;96switch (level)97{98case SPV_MSG_FATAL:99case SPV_MSG_INTERNAL_ERROR:100case SPV_MSG_ERROR:101out << "error: ";102break;103case SPV_MSG_WARNING:104out << "warning: ";105break;106case SPV_MSG_INFO:107case SPV_MSG_DEBUG:108out << "info: ";109break;110default:111break;112}113if (source)114{115out << source << ":";116}117out << position.line << ":" << position.column << ":" << position.index << ":";118if (message)119{120out << " " << message;121}122out << std::endl;123}124125// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment.126void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)127{128SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3);129}130131// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment.132void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv,133spv_target_env requested_context)134{135// disassemble136spv_context context = spvContextCreate(requested_context);137spv_text text;138spv_diagnostic diagnostic = nullptr;139spvBinaryToText(context, spirv.data(), spirv.size(),140SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,141&text, &diagnostic);142143// dump144if (diagnostic == nullptr)145out << text->str;146else147spvDiagnosticPrint(diagnostic);148149// teardown150spvDiagnosticDestroy(diagnostic);151spvContextDestroy(context);152}153154// Apply the SPIRV-Tools validator to generated SPIR-V.155void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,156spv::SpvBuildLogger* logger, bool prelegalization)157{158// validate159spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));160spv_const_binary_t binary = { spirv.data(), spirv.size() };161spv_diagnostic diagnostic = nullptr;162spv_validator_options options = spvValidatorOptionsCreate();163spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());164spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization);165spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout());166spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout());167spvValidatorOptionsSetAllowOffsetTextureOperand(options, intermediate.usingTextureOffsetNonConst());168spvValidateWithOptions(context, options, &binary, &diagnostic);169170// report171if (diagnostic != nullptr) {172logger->error("SPIRV-Tools Validation Errors");173logger->error(diagnostic->error);174}175176// tear down177spvValidatorOptionsDestroy(options);178spvDiagnosticDestroy(diagnostic);179spvContextDestroy(context);180}181182// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process.183void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,184spv::SpvBuildLogger* logger, const SpvOptions* options)185{186spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);187188spvtools::Optimizer optimizer(target_env);189optimizer.SetMessageConsumer(OptimizerMesssageConsumer);190191// If debug (specifically source line info) is being generated, propagate192// line information into all SPIR-V instructions. This avoids loss of193// information when instructions are deleted or moved. Later, remove194// redundant information to minimize final SPRIR-V size.195if (options->stripDebugInfo) {196optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());197}198optimizer.RegisterPass(spvtools::CreateWrapOpKillPass());199optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());200optimizer.RegisterPass(spvtools::CreateMergeReturnPass());201optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());202optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());203optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());204optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());205optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());206optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());207optimizer.RegisterPass(spvtools::CreateSimplificationPass());208optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());209optimizer.RegisterPass(spvtools::CreateVectorDCEPass());210optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());211optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());212optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());213optimizer.RegisterPass(spvtools::CreateBlockMergePass());214optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());215optimizer.RegisterPass(spvtools::CreateIfConversionPass());216optimizer.RegisterPass(spvtools::CreateSimplificationPass());217optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());218optimizer.RegisterPass(spvtools::CreateVectorDCEPass());219optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());220optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass());221if (options->optimizeSize) {222optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());223optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass());224}225optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());226optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());227228spvtools::OptimizerOptions spvOptOptions;229if (options->optimizerAllowExpandedIDBound)230spvOptOptions.set_max_id_bound(0x3FFFFFFF);231optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));232spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on233optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);234235if (options->optimizerAllowExpandedIDBound) {236if (spirv.size() > 3 && spirv[3] > kDefaultMaxIdBound) {237spvtools::Optimizer optimizer2(target_env);238optimizer2.SetMessageConsumer(OptimizerMesssageConsumer);239optimizer2.RegisterPass(spvtools::CreateCompactIdsPass());240optimizer2.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);241}242}243}244245bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,246std::unordered_set<uint32_t>* live_locs,247std::unordered_set<uint32_t>* live_builtins,248spv::SpvBuildLogger*)249{250spvtools::Optimizer optimizer(target_env);251optimizer.SetMessageConsumer(OptimizerMesssageConsumer);252253optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins));254255spvtools::OptimizerOptions spvOptOptions;256optimizer.SetTargetEnv(target_env);257spvOptOptions.set_run_validator(false);258return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);259}260261void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv,262std::unordered_set<uint32_t>* live_locs,263std::unordered_set<uint32_t>* live_builtins,264spv::SpvBuildLogger*)265{266spvtools::Optimizer optimizer(target_env);267optimizer.SetMessageConsumer(OptimizerMesssageConsumer);268269optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins));270optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));271optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass());272optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true));273274spvtools::OptimizerOptions spvOptOptions;275optimizer.SetTargetEnv(target_env);276spvOptOptions.set_run_validator(false);277optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);278}279280void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv,281spv::SpvBuildLogger*)282{283spvtools::Optimizer optimizer(target_env);284optimizer.SetMessageConsumer(OptimizerMesssageConsumer);285286optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass());287optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());288289spvtools::OptimizerOptions spvOptOptions;290optimizer.SetTargetEnv(target_env);291spvOptOptions.set_run_validator(false);292optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);293}294295// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by296// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if297// optimization is disabled.298void SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate,299std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger)300{301spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger);302303spvtools::Optimizer optimizer(target_env);304optimizer.SetMessageConsumer(OptimizerMesssageConsumer);305306optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass());307308spvtools::OptimizerOptions spvOptOptions;309optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger));310spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on311optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions);312}313314} // end namespace glslang315316#endif317318319