1617a3babSopenharmony_ci// 2617a3babSopenharmony_ci// Copyright (C) 2014-2016 LunarG, Inc. 3617a3babSopenharmony_ci// Copyright (C) 2018-2020 Google, Inc. 4617a3babSopenharmony_ci// 5617a3babSopenharmony_ci// All rights reserved. 6617a3babSopenharmony_ci// 7617a3babSopenharmony_ci// Redistribution and use in source and binary forms, with or without 8617a3babSopenharmony_ci// modification, are permitted provided that the following conditions 9617a3babSopenharmony_ci// are met: 10617a3babSopenharmony_ci// 11617a3babSopenharmony_ci// Redistributions of source code must retain the above copyright 12617a3babSopenharmony_ci// notice, this list of conditions and the following disclaimer. 13617a3babSopenharmony_ci// 14617a3babSopenharmony_ci// Redistributions in binary form must reproduce the above 15617a3babSopenharmony_ci// copyright notice, this list of conditions and the following 16617a3babSopenharmony_ci// disclaimer in the documentation and/or other materials provided 17617a3babSopenharmony_ci// with the distribution. 18617a3babSopenharmony_ci// 19617a3babSopenharmony_ci// Neither the name of 3Dlabs Inc. Ltd. nor the names of its 20617a3babSopenharmony_ci// contributors may be used to endorse or promote products derived 21617a3babSopenharmony_ci// from this software without specific prior written permission. 22617a3babSopenharmony_ci// 23617a3babSopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24617a3babSopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25617a3babSopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26617a3babSopenharmony_ci// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27617a3babSopenharmony_ci// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28617a3babSopenharmony_ci// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29617a3babSopenharmony_ci// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30617a3babSopenharmony_ci// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31617a3babSopenharmony_ci// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32617a3babSopenharmony_ci// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 33617a3babSopenharmony_ci// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34617a3babSopenharmony_ci// POSSIBILITY OF SUCH DAMAGE. 35617a3babSopenharmony_ci 36617a3babSopenharmony_ci// 37617a3babSopenharmony_ci// Call into SPIRV-Tools to disassemble, validate, and optimize. 38617a3babSopenharmony_ci// 39617a3babSopenharmony_ci 40617a3babSopenharmony_ci#if ENABLE_OPT 41617a3babSopenharmony_ci 42617a3babSopenharmony_ci#include <cstdio> 43617a3babSopenharmony_ci#include <iostream> 44617a3babSopenharmony_ci 45617a3babSopenharmony_ci#include "SpvTools.h" 46617a3babSopenharmony_ci#include "spirv-tools/optimizer.hpp" 47617a3babSopenharmony_ci 48617a3babSopenharmony_cinamespace glslang { 49617a3babSopenharmony_ci 50617a3babSopenharmony_ci// Translate glslang's view of target versioning to what SPIRV-Tools uses. 51617a3babSopenharmony_cispv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger) 52617a3babSopenharmony_ci{ 53617a3babSopenharmony_ci switch (spvVersion.vulkan) { 54617a3babSopenharmony_ci case glslang::EShTargetVulkan_1_0: 55617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_0; 56617a3babSopenharmony_ci case glslang::EShTargetVulkan_1_1: 57617a3babSopenharmony_ci switch (spvVersion.spv) { 58617a3babSopenharmony_ci case EShTargetSpv_1_0: 59617a3babSopenharmony_ci case EShTargetSpv_1_1: 60617a3babSopenharmony_ci case EShTargetSpv_1_2: 61617a3babSopenharmony_ci case EShTargetSpv_1_3: 62617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_1; 63617a3babSopenharmony_ci case EShTargetSpv_1_4: 64617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_1_SPIRV_1_4; 65617a3babSopenharmony_ci default: 66617a3babSopenharmony_ci logger->missingFunctionality("Target version for SPIRV-Tools validator"); 67617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_1; 68617a3babSopenharmony_ci } 69617a3babSopenharmony_ci case glslang::EShTargetVulkan_1_2: 70617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_2; 71617a3babSopenharmony_ci case glslang::EShTargetVulkan_1_3: 72617a3babSopenharmony_ci return spv_target_env::SPV_ENV_VULKAN_1_3; 73617a3babSopenharmony_ci default: 74617a3babSopenharmony_ci break; 75617a3babSopenharmony_ci } 76617a3babSopenharmony_ci 77617a3babSopenharmony_ci if (spvVersion.openGl > 0) 78617a3babSopenharmony_ci return spv_target_env::SPV_ENV_OPENGL_4_5; 79617a3babSopenharmony_ci 80617a3babSopenharmony_ci logger->missingFunctionality("Target version for SPIRV-Tools validator"); 81617a3babSopenharmony_ci return spv_target_env::SPV_ENV_UNIVERSAL_1_0; 82617a3babSopenharmony_ci} 83617a3babSopenharmony_ci 84617a3babSopenharmony_ci// Callback passed to spvtools::Optimizer::SetMessageConsumer 85617a3babSopenharmony_civoid OptimizerMesssageConsumer(spv_message_level_t level, const char *source, 86617a3babSopenharmony_ci const spv_position_t &position, const char *message) 87617a3babSopenharmony_ci{ 88617a3babSopenharmony_ci auto &out = std::cerr; 89617a3babSopenharmony_ci switch (level) 90617a3babSopenharmony_ci { 91617a3babSopenharmony_ci case SPV_MSG_FATAL: 92617a3babSopenharmony_ci case SPV_MSG_INTERNAL_ERROR: 93617a3babSopenharmony_ci case SPV_MSG_ERROR: 94617a3babSopenharmony_ci out << "error: "; 95617a3babSopenharmony_ci break; 96617a3babSopenharmony_ci case SPV_MSG_WARNING: 97617a3babSopenharmony_ci out << "warning: "; 98617a3babSopenharmony_ci break; 99617a3babSopenharmony_ci case SPV_MSG_INFO: 100617a3babSopenharmony_ci case SPV_MSG_DEBUG: 101617a3babSopenharmony_ci out << "info: "; 102617a3babSopenharmony_ci break; 103617a3babSopenharmony_ci default: 104617a3babSopenharmony_ci break; 105617a3babSopenharmony_ci } 106617a3babSopenharmony_ci if (source) 107617a3babSopenharmony_ci { 108617a3babSopenharmony_ci out << source << ":"; 109617a3babSopenharmony_ci } 110617a3babSopenharmony_ci out << position.line << ":" << position.column << ":" << position.index << ":"; 111617a3babSopenharmony_ci if (message) 112617a3babSopenharmony_ci { 113617a3babSopenharmony_ci out << " " << message; 114617a3babSopenharmony_ci } 115617a3babSopenharmony_ci out << std::endl; 116617a3babSopenharmony_ci} 117617a3babSopenharmony_ci 118617a3babSopenharmony_ci// Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment. 119617a3babSopenharmony_civoid SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv) 120617a3babSopenharmony_ci{ 121617a3babSopenharmony_ci SpirvToolsDisassemble(out, spirv, spv_target_env::SPV_ENV_UNIVERSAL_1_3); 122617a3babSopenharmony_ci} 123617a3babSopenharmony_ci 124617a3babSopenharmony_ci// Use the SPIRV-Tools disassembler to print SPIR-V with a provided SPIR-V environment. 125617a3babSopenharmony_civoid SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv, 126617a3babSopenharmony_ci spv_target_env requested_context) 127617a3babSopenharmony_ci{ 128617a3babSopenharmony_ci // disassemble 129617a3babSopenharmony_ci spv_context context = spvContextCreate(requested_context); 130617a3babSopenharmony_ci spv_text text; 131617a3babSopenharmony_ci spv_diagnostic diagnostic = nullptr; 132617a3babSopenharmony_ci spvBinaryToText(context, spirv.data(), spirv.size(), 133617a3babSopenharmony_ci SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT, 134617a3babSopenharmony_ci &text, &diagnostic); 135617a3babSopenharmony_ci 136617a3babSopenharmony_ci // dump 137617a3babSopenharmony_ci if (diagnostic == nullptr) 138617a3babSopenharmony_ci out << text->str; 139617a3babSopenharmony_ci else 140617a3babSopenharmony_ci spvDiagnosticPrint(diagnostic); 141617a3babSopenharmony_ci 142617a3babSopenharmony_ci // teardown 143617a3babSopenharmony_ci spvDiagnosticDestroy(diagnostic); 144617a3babSopenharmony_ci spvContextDestroy(context); 145617a3babSopenharmony_ci} 146617a3babSopenharmony_ci 147617a3babSopenharmony_ci// Apply the SPIRV-Tools validator to generated SPIR-V. 148617a3babSopenharmony_civoid SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, 149617a3babSopenharmony_ci spv::SpvBuildLogger* logger, bool prelegalization) 150617a3babSopenharmony_ci{ 151617a3babSopenharmony_ci // validate 152617a3babSopenharmony_ci spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); 153617a3babSopenharmony_ci spv_const_binary_t binary = { spirv.data(), spirv.size() }; 154617a3babSopenharmony_ci spv_diagnostic diagnostic = nullptr; 155617a3babSopenharmony_ci spv_validator_options options = spvValidatorOptionsCreate(); 156617a3babSopenharmony_ci spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets()); 157617a3babSopenharmony_ci spvValidatorOptionsSetBeforeHlslLegalization(options, prelegalization); 158617a3babSopenharmony_ci spvValidatorOptionsSetScalarBlockLayout(options, intermediate.usingScalarBlockLayout()); 159617a3babSopenharmony_ci spvValidatorOptionsSetWorkgroupScalarBlockLayout(options, intermediate.usingScalarBlockLayout()); 160617a3babSopenharmony_ci spvValidateWithOptions(context, options, &binary, &diagnostic); 161617a3babSopenharmony_ci 162617a3babSopenharmony_ci // report 163617a3babSopenharmony_ci if (diagnostic != nullptr) { 164617a3babSopenharmony_ci logger->error("SPIRV-Tools Validation Errors"); 165617a3babSopenharmony_ci logger->error(diagnostic->error); 166617a3babSopenharmony_ci } 167617a3babSopenharmony_ci 168617a3babSopenharmony_ci // tear down 169617a3babSopenharmony_ci spvValidatorOptionsDestroy(options); 170617a3babSopenharmony_ci spvDiagnosticDestroy(diagnostic); 171617a3babSopenharmony_ci spvContextDestroy(context); 172617a3babSopenharmony_ci} 173617a3babSopenharmony_ci 174617a3babSopenharmony_ci// Apply the SPIRV-Tools optimizer to generated SPIR-V. HLSL SPIR-V is legalized in the process. 175617a3babSopenharmony_civoid SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, 176617a3babSopenharmony_ci spv::SpvBuildLogger* logger, const SpvOptions* options) 177617a3babSopenharmony_ci{ 178617a3babSopenharmony_ci spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger); 179617a3babSopenharmony_ci 180617a3babSopenharmony_ci spvtools::Optimizer optimizer(target_env); 181617a3babSopenharmony_ci optimizer.SetMessageConsumer(OptimizerMesssageConsumer); 182617a3babSopenharmony_ci 183617a3babSopenharmony_ci // If debug (specifically source line info) is being generated, propagate 184617a3babSopenharmony_ci // line information into all SPIR-V instructions. This avoids loss of 185617a3babSopenharmony_ci // information when instructions are deleted or moved. Later, remove 186617a3babSopenharmony_ci // redundant information to minimize final SPRIR-V size. 187617a3babSopenharmony_ci if (options->stripDebugInfo) { 188617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass()); 189617a3babSopenharmony_ci } 190617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateWrapOpKillPass()); 191617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); 192617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateMergeReturnPass()); 193617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass()); 194617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass()); 195617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateScalarReplacementPass()); 196617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass()); 197617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass()); 198617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass()); 199617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateSimplificationPass()); 200617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); 201617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); 202617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); 203617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); 204617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass()); 205617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateBlockMergePass()); 206617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass()); 207617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateIfConversionPass()); 208617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateSimplificationPass()); 209617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); 210617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateVectorDCEPass()); 211617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass()); 212617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass()); 213617a3babSopenharmony_ci if (options->optimizeSize) { 214617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass()); 215617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass()); 216617a3babSopenharmony_ci } 217617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); 218617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateCFGCleanupPass()); 219617a3babSopenharmony_ci 220617a3babSopenharmony_ci spvtools::OptimizerOptions spvOptOptions; 221617a3babSopenharmony_ci optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); 222617a3babSopenharmony_ci spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on 223617a3babSopenharmony_ci optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); 224617a3babSopenharmony_ci} 225617a3babSopenharmony_ci 226617a3babSopenharmony_cibool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv, 227617a3babSopenharmony_ci std::unordered_set<uint32_t>* live_locs, 228617a3babSopenharmony_ci std::unordered_set<uint32_t>* live_builtins, 229617a3babSopenharmony_ci spv::SpvBuildLogger*) 230617a3babSopenharmony_ci{ 231617a3babSopenharmony_ci spvtools::Optimizer optimizer(target_env); 232617a3babSopenharmony_ci optimizer.SetMessageConsumer(OptimizerMesssageConsumer); 233617a3babSopenharmony_ci 234617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins)); 235617a3babSopenharmony_ci 236617a3babSopenharmony_ci spvtools::OptimizerOptions spvOptOptions; 237617a3babSopenharmony_ci optimizer.SetTargetEnv(target_env); 238617a3babSopenharmony_ci spvOptOptions.set_run_validator(false); 239617a3babSopenharmony_ci return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); 240617a3babSopenharmony_ci} 241617a3babSopenharmony_ci 242617a3babSopenharmony_civoid SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector<unsigned int>& spirv, 243617a3babSopenharmony_ci std::unordered_set<uint32_t>* live_locs, 244617a3babSopenharmony_ci std::unordered_set<uint32_t>* live_builtins, 245617a3babSopenharmony_ci spv::SpvBuildLogger*) 246617a3babSopenharmony_ci{ 247617a3babSopenharmony_ci spvtools::Optimizer optimizer(target_env); 248617a3babSopenharmony_ci optimizer.SetMessageConsumer(OptimizerMesssageConsumer); 249617a3babSopenharmony_ci 250617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins)); 251617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true)); 252617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass()); 253617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true)); 254617a3babSopenharmony_ci 255617a3babSopenharmony_ci spvtools::OptimizerOptions spvOptOptions; 256617a3babSopenharmony_ci optimizer.SetTargetEnv(target_env); 257617a3babSopenharmony_ci spvOptOptions.set_run_validator(false); 258617a3babSopenharmony_ci optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); 259617a3babSopenharmony_ci} 260617a3babSopenharmony_ci 261617a3babSopenharmony_civoid SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector<unsigned int>& spirv, 262617a3babSopenharmony_ci spv::SpvBuildLogger*) 263617a3babSopenharmony_ci{ 264617a3babSopenharmony_ci spvtools::Optimizer optimizer(target_env); 265617a3babSopenharmony_ci optimizer.SetMessageConsumer(OptimizerMesssageConsumer); 266617a3babSopenharmony_ci 267617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass()); 268617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); 269617a3babSopenharmony_ci 270617a3babSopenharmony_ci spvtools::OptimizerOptions spvOptOptions; 271617a3babSopenharmony_ci optimizer.SetTargetEnv(target_env); 272617a3babSopenharmony_ci spvOptOptions.set_run_validator(false); 273617a3babSopenharmony_ci optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); 274617a3babSopenharmony_ci} 275617a3babSopenharmony_ci 276617a3babSopenharmony_ci// Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by 277617a3babSopenharmony_ci// SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if 278617a3babSopenharmony_ci// optimization is disabled. 279617a3babSopenharmony_civoid SpirvToolsStripDebugInfo(const glslang::TIntermediate& intermediate, 280617a3babSopenharmony_ci std::vector<unsigned int>& spirv, spv::SpvBuildLogger* logger) 281617a3babSopenharmony_ci{ 282617a3babSopenharmony_ci spv_target_env target_env = MapToSpirvToolsEnv(intermediate.getSpv(), logger); 283617a3babSopenharmony_ci 284617a3babSopenharmony_ci spvtools::Optimizer optimizer(target_env); 285617a3babSopenharmony_ci optimizer.SetMessageConsumer(OptimizerMesssageConsumer); 286617a3babSopenharmony_ci 287617a3babSopenharmony_ci optimizer.RegisterPass(spvtools::CreateStripDebugInfoPass()); 288617a3babSopenharmony_ci 289617a3babSopenharmony_ci spvtools::OptimizerOptions spvOptOptions; 290617a3babSopenharmony_ci optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); 291617a3babSopenharmony_ci spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on 292617a3babSopenharmony_ci optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); 293617a3babSopenharmony_ci} 294617a3babSopenharmony_ci 295617a3babSopenharmony_ci}; // end namespace glslang 296617a3babSopenharmony_ci 297617a3babSopenharmony_ci#endif 298