2 // Copyright (C) 2014-2016 LunarG, Inc.
3 // Copyright (C) 2018 Google, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
11 // Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
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.
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.
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.
37 // Call into SPIRV-Tools to disassemble, validate, and optimize.
46 #include "spirv-tools/optimizer.hpp"
47 #include "spirv-tools/libspirv.h"
51 // Translate glslang's view of target versioning to what SPIRV-Tools uses.
52 spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
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;
61 if (spvVersion.openGl > 0)
62 return spv_target_env::SPV_ENV_OPENGL_4_5;
64 logger->missingFunctionality("Target version for SPIRV-Tools validator");
65 return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
69 // Use the SPIRV-Tools disassembler to print SPIR-V.
70 void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
73 spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
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,
81 if (diagnostic == nullptr)
84 spvDiagnosticPrint(diagnostic);
87 spvDiagnosticDestroy(diagnostic);
88 spvContextDestroy(context);
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)
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);
104 if (diagnostic != nullptr) {
105 logger->error("SPIRV-Tools Validation Errors");
106 logger->error(diagnostic->error);
110 spvValidatorOptionsDestroy(options);
111 spvDiagnosticDestroy(diagnostic);
112 spvContextDestroy(context);
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& intermediate, std::vector<unsigned int>& spirv,
118 spv::SpvBuildLogger* logger, const SpvOptions* options)
120 spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
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;
129 case SPV_MSG_INTERNAL_ERROR:
133 case SPV_MSG_WARNING:
145 out << source << ":";
147 out << position.line << ":" << position.column << ":" << position.index << ":";
150 out << " " << message;
155 optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
156 optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
157 optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
158 optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
159 optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
160 optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
161 optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
162 optimizer.RegisterPass(spvtools::CreateSimplificationPass());
163 optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
164 optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
165 optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
166 optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
167 optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
168 optimizer.RegisterPass(spvtools::CreateBlockMergePass());
169 optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
170 optimizer.RegisterPass(spvtools::CreateIfConversionPass());
171 optimizer.RegisterPass(spvtools::CreateSimplificationPass());
172 optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
173 optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
174 optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
175 if (options->optimizeSize) {
176 optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
177 // TODO(greg-lunarg): Add this when AMD driver issues are resolved
178 // optimizer.RegisterPass(CreateCommonUniformElimPass());
180 optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
181 optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
183 optimizer.Run(spirv.data(), spirv.size(), &spirv, spvtools::ValidatorOptions(), true);
186 }; // end namespace glslang