SPV: Isolate SPIRV-tools glue to its own file.

This commit is contained in:
John Kessenich 2018-08-23 15:17:10 -06:00
parent cc14f2d329
commit 717c80a9de
10 changed files with 279 additions and 174 deletions

View File

@ -5,6 +5,7 @@ set(SOURCES
SpvBuilder.cpp SpvBuilder.cpp
SpvPostProcess.cpp SpvPostProcess.cpp
doc.cpp doc.cpp
SpvTools.cpp
disassemble.cpp) disassemble.cpp)
set(SPVREMAP_SOURCES set(SPVREMAP_SOURCES
@ -23,6 +24,7 @@ set(HEADERS
SpvBuilder.h SpvBuilder.h
spvIR.h spvIR.h
doc.h doc.h
SpvTools.h
disassemble.h) disassemble.h)
set(SPVREMAP_HEADERS set(SPVREMAP_HEADERS

View File

@ -54,15 +54,6 @@ namespace spv {
#endif #endif
} }
#if ENABLE_OPT
#include "spirv-tools/optimizer.hpp"
#include "spirv-tools/libspirv.h"
#endif
#if ENABLE_OPT
using namespace spvtools;
#endif
// Glslang includes // Glslang includes
#include "../glslang/MachineIndependent/localintermediate.h" #include "../glslang/MachineIndependent/localintermediate.h"
#include "../glslang/MachineIndependent/SymbolTable.h" #include "../glslang/MachineIndependent/SymbolTable.h"
@ -7004,122 +6995,6 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsign
GlslangToSpv(intermediate, spirv, &logger, options); GlslangToSpv(intermediate, spirv, &logger, options);
} }
#if ENABLE_OPT
// Translate glslang's view of target versioning to what SPIRV-Tools uses.
spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
{
switch (spvVersion.vulkan) {
case glslang::EShTargetVulkan_1_0: return spv_target_env::SPV_ENV_VULKAN_1_0;
case glslang::EShTargetVulkan_1_1: return spv_target_env::SPV_ENV_VULKAN_1_1;
default:
break;
}
if (spvVersion.openGl > 0)
return spv_target_env::SPV_ENV_OPENGL_4_5;
logger->missingFunctionality("Target version for SPIRV-Tools validator");
return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
}
// Apply the SPIRV-Tools validator to generated SPIR-V.
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger)
{
// validate
spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
spv_const_binary_t binary = { spirv.data(), spirv.size() };
spv_diagnostic diagnostic = nullptr;
spv_validator_options options = spvValidatorOptionsCreate();
spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
spvValidateWithOptions(context, options, &binary, &diagnostic);
// report
if (diagnostic != nullptr) {
logger->error("SPIRV-Tools Validation Errors");
logger->error(diagnostic->error);
}
// tear down
spvValidatorOptionsDestroy(options);
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
// legalizing HLSL SPIR-V.
void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, const SpvOptions* options)
{
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
spvtools::Optimizer optimizer(target_env);
optimizer.SetMessageConsumer(
[](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
auto &out = std::cerr;
switch (level)
{
case SPV_MSG_FATAL:
case SPV_MSG_INTERNAL_ERROR:
case SPV_MSG_ERROR:
out << "error: ";
break;
case SPV_MSG_WARNING:
out << "warning: ";
break;
case SPV_MSG_INFO:
case SPV_MSG_DEBUG:
out << "info: ";
break;
default:
break;
}
if (source)
{
out << source << ":";
}
out << position.line << ":" << position.column << ":" << position.index << ":";
if (message)
{
out << " " << message;
}
out << std::endl;
});
optimizer.RegisterPass(CreateMergeReturnPass());
optimizer.RegisterPass(CreateInlineExhaustivePass());
optimizer.RegisterPass(CreateEliminateDeadFunctionsPass());
optimizer.RegisterPass(CreateScalarReplacementPass());
optimizer.RegisterPass(CreateLocalAccessChainConvertPass());
optimizer.RegisterPass(CreateLocalSingleBlockLoadStoreElimPass());
optimizer.RegisterPass(CreateLocalSingleStoreElimPass());
optimizer.RegisterPass(CreateSimplificationPass());
optimizer.RegisterPass(CreateAggressiveDCEPass());
optimizer.RegisterPass(CreateVectorDCEPass());
optimizer.RegisterPass(CreateDeadInsertElimPass());
optimizer.RegisterPass(CreateAggressiveDCEPass());
optimizer.RegisterPass(CreateDeadBranchElimPass());
optimizer.RegisterPass(CreateBlockMergePass());
optimizer.RegisterPass(CreateLocalMultiStoreElimPass());
optimizer.RegisterPass(CreateIfConversionPass());
optimizer.RegisterPass(CreateSimplificationPass());
optimizer.RegisterPass(CreateAggressiveDCEPass());
optimizer.RegisterPass(CreateVectorDCEPass());
optimizer.RegisterPass(CreateDeadInsertElimPass());
if (options->optimizeSize) {
optimizer.RegisterPass(CreateRedundancyEliminationPass());
// TODO(greg-lunarg): Add this when AMD driver issues are resolved
// optimizer.RegisterPass(CreateCommonUniformElimPass());
}
optimizer.RegisterPass(CreateAggressiveDCEPass());
optimizer.RegisterPass(CreateCFGCleanupPass());
optimizer.Run(spirv.data(), spirv.size(), &spirv);
}
#endif
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, SpvOptions* options) spv::SpvBuildLogger* logger, SpvOptions* options)
{ {
@ -7144,10 +7019,12 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsign
// If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan // If from HLSL, run spirv-opt to "legalize" the SPIR-V for Vulkan
// eg. forward and remove memory writes of opaque types. // eg. forward and remove memory writes of opaque types.
if ((intermediate.getSource() == EShSourceHlsl || options->optimizeSize) && if ((intermediate.getSource() == EShSourceHlsl || options->optimizeSize) && !options->disableOptimizer)
!options->disableOptimizer) {
SpirvToolsLegalize(intermediate, spirv, logger, options); SpirvToolsLegalize(intermediate, spirv, logger, options);
}
if (options->disassemble)
glslang::SpirvToolsDisassemble(std::cout, spirv);
#endif #endif
glslang::GetThreadPoolAllocator().pop(); glslang::GetThreadPoolAllocator().pop();

9
SPIRV/GlslangToSpv.h Normal file → Executable file
View File

@ -38,6 +38,7 @@
#pragma warning(disable : 4464) // relative include path contains '..' #pragma warning(disable : 4464) // relative include path contains '..'
#endif #endif
#include "SpvTools.h"
#include "../glslang/Include/intermediate.h" #include "../glslang/Include/intermediate.h"
#include <string> #include <string>
@ -47,14 +48,6 @@
namespace glslang { namespace glslang {
struct SpvOptions {
SpvOptions() : generateDebugInfo(false), disableOptimizer(true),
optimizeSize(false) { }
bool generateDebugInfo;
bool disableOptimizer;
bool optimizeSize;
};
void GetSpirvVersion(std::string&); void GetSpirvVersion(std::string&);
int GetSpirvGeneratorVersion(); int GetSpirvGeneratorVersion();
void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv, void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,

188
SPIRV/SpvTools.cpp Executable file
View File

@ -0,0 +1,188 @@
//
// Copyright (C) 2014-2016 LunarG, Inc.
// Copyright (C) 2018 Google, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Call into SPIRV-Tools to disassemble, validate, and optimize.
//
#if ENABLE_OPT
#include <cstdio>
#include <iostream>
#include "SpvTools.h"
#include "spirv-tools/optimizer.hpp"
#include "spirv-tools/libspirv.h"
namespace glslang {
// Translate glslang's view of target versioning to what SPIRV-Tools uses.
spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger)
{
switch (spvVersion.vulkan) {
case glslang::EShTargetVulkan_1_0: return spv_target_env::SPV_ENV_VULKAN_1_0;
case glslang::EShTargetVulkan_1_1: return spv_target_env::SPV_ENV_VULKAN_1_1;
default:
break;
}
if (spvVersion.openGl > 0)
return spv_target_env::SPV_ENV_OPENGL_4_5;
logger->missingFunctionality("Target version for SPIRV-Tools validator");
return spv_target_env::SPV_ENV_UNIVERSAL_1_0;
}
// Use the SPIRV-Tools disassembler to print SPIR-V.
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
{
// disassemble
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
spv_text text;
spv_diagnostic diagnostic = nullptr;
spvBinaryToText(context, spirv.data(), spirv.size(),
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
&text, &diagnostic);
// dump
if (diagnostic == nullptr)
out << text->str;
else
spvDiagnosticPrint(diagnostic);
// teardown
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
// Apply the SPIRV-Tools validator to generated SPIR-V.
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger)
{
// validate
spv_context context = spvContextCreate(MapToSpirvToolsEnv(intermediate.getSpv(), logger));
spv_const_binary_t binary = { spirv.data(), spirv.size() };
spv_diagnostic diagnostic = nullptr;
spv_validator_options options = spvValidatorOptionsCreate();
spvValidatorOptionsSetRelaxBlockLayout(options, intermediate.usingHlslOffsets());
spvValidateWithOptions(context, options, &binary, &diagnostic);
// report
if (diagnostic != nullptr) {
logger->error("SPIRV-Tools Validation Errors");
logger->error(diagnostic->error);
}
// tear down
spvValidatorOptionsDestroy(options);
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
// legalizing HLSL SPIR-V.
void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger* logger, const SpvOptions* options)
{
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
spvtools::Optimizer optimizer(target_env);
optimizer.SetMessageConsumer(
[](spv_message_level_t level, const char *source, const spv_position_t &position, const char *message) {
auto &out = std::cerr;
switch (level)
{
case SPV_MSG_FATAL:
case SPV_MSG_INTERNAL_ERROR:
case SPV_MSG_ERROR:
out << "error: ";
break;
case SPV_MSG_WARNING:
out << "warning: ";
break;
case SPV_MSG_INFO:
case SPV_MSG_DEBUG:
out << "info: ";
break;
default:
break;
}
if (source)
{
out << source << ":";
}
out << position.line << ":" << position.column << ":" << position.index << ":";
if (message)
{
out << " " << message;
}
out << std::endl;
});
optimizer.RegisterPass(spvtools::CreateMergeReturnPass());
optimizer.RegisterPass(spvtools::CreateInlineExhaustivePass());
optimizer.RegisterPass(spvtools::CreateEliminateDeadFunctionsPass());
optimizer.RegisterPass(spvtools::CreateScalarReplacementPass());
optimizer.RegisterPass(spvtools::CreateLocalAccessChainConvertPass());
optimizer.RegisterPass(spvtools::CreateLocalSingleBlockLoadStoreElimPass());
optimizer.RegisterPass(spvtools::CreateLocalSingleStoreElimPass());
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
optimizer.RegisterPass(spvtools::CreateDeadBranchElimPass());
optimizer.RegisterPass(spvtools::CreateBlockMergePass());
optimizer.RegisterPass(spvtools::CreateLocalMultiStoreElimPass());
optimizer.RegisterPass(spvtools::CreateIfConversionPass());
optimizer.RegisterPass(spvtools::CreateSimplificationPass());
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
optimizer.RegisterPass(spvtools::CreateVectorDCEPass());
optimizer.RegisterPass(spvtools::CreateDeadInsertElimPass());
if (options->optimizeSize) {
optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass());
// TODO(greg-lunarg): Add this when AMD driver issues are resolved
// optimizer.RegisterPass(CreateCommonUniformElimPass());
}
optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass());
optimizer.RegisterPass(spvtools::CreateCFGCleanupPass());
optimizer.Run(spirv.data(), spirv.size(), &spirv);
}
#endif
}; // end namespace glslang

79
SPIRV/SpvTools.h Executable file
View File

@ -0,0 +1,79 @@
//
// Copyright (C) 2014-2016 LunarG, Inc.
// Copyright (C) 2018 Google, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Call into SPIRV-Tools to disassemble, validate, and optimize.
//
#pragma once
#ifndef GLSLANG_SPV_TOOLS_H
#define GLSLANG_SPV_TOOLS_H
#include <vector>
#include <ostream>
#include "../glslang/MachineIndependent/localintermediate.h"
#include "Logger.h"
namespace glslang {
struct SpvOptions {
SpvOptions() : generateDebugInfo(false), disableOptimizer(true),
optimizeSize(false), disassemble(false) { }
bool generateDebugInfo;
bool disableOptimizer;
bool optimizeSize;
bool disassemble;
};
#if ENABLE_OPT
// Use the SPIRV-Tools disassembler to print SPIR-V.
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv);
// Apply the SPIRV-Tools validator to generated SPIR-V.
void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*);
// Apply the SPIRV-Tools optimizer to generated SPIR-V, for the purpose of
// legalizing HLSL SPIR-V.
void SpirvToolsLegalize(const glslang::TIntermediate& intermediate, std::vector<unsigned int>& spirv,
spv::SpvBuildLogger*, const SpvOptions*);
#endif
}; // end namespace glslang
#endif // GLSLANG_SPV_TOOLS_H

View File

@ -46,6 +46,7 @@
#include "disassemble.h" #include "disassemble.h"
#include "doc.h" #include "doc.h"
#include "SpvTools.h"
namespace spv { namespace spv {
extern "C" { extern "C" {
@ -716,32 +717,4 @@ void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
SpirvStream.processInstructions(); SpirvStream.processInstructions();
} }
#if ENABLE_OPT
#include "spirv-tools/libspirv.h"
// Use the SPIRV-Tools disassembler to print SPIR-V.
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& spirv)
{
// disassemble
spv_context context = spvContextCreate(SPV_ENV_UNIVERSAL_1_3);
spv_text text;
spv_diagnostic diagnostic = nullptr;
spvBinaryToText(context, spirv.data(), spirv.size(),
SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT,
&text, &diagnostic);
// dump
if (diagnostic == nullptr)
out << text->str;
else
spvDiagnosticPrint(diagnostic);
// teardown
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
#endif
}; // end namespace spv }; // end namespace spv

View File

@ -48,9 +48,6 @@ namespace spv {
// disassemble with glslang custom disassembler // disassemble with glslang custom disassembler
void Disassemble(std::ostream& out, const std::vector<unsigned int>&); void Disassemble(std::ostream& out, const std::vector<unsigned int>&);
// disassemble with SPIRV-Tools disassembler
void SpirvToolsDisassemble(std::ostream& out, const std::vector<unsigned int>& stream);
}; // end namespace spv }; // end namespace spv
#endif // disassembler_H #endif // disassembler_H

View File

@ -978,6 +978,7 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
spvOptions.generateDebugInfo = true; spvOptions.generateDebugInfo = true;
spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0; spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0; spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
spvOptions.disassemble = SpvToolsDisassembler;
glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions); glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions);
// Dump the spv to a file or stdout, etc., but only if not doing // Dump the spv to a file or stdout, etc., but only if not doing
@ -989,13 +990,6 @@ void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
} else { } else {
glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage)); glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
} }
#if ENABLE_OPT
if (SpvToolsDisassembler)
spv::SpirvToolsDisassemble(std::cout, spirv);
#else
if (SpvToolsDisassembler)
printf("SPIRV-Tools is not enabled; use -H for human readable SPIR-V\n");
#endif
if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv)) if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv))
spv::Disassemble(std::cout, spirv); spv::Disassemble(std::cout, spirv);
} }

View File

@ -41,6 +41,8 @@
#include "../Public/ShaderLang.h" #include "../Public/ShaderLang.h"
#include "Versions.h" #include "Versions.h"
#include <string>
#include <vector>
#include <algorithm> #include <algorithm>
#include <set> #include <set>
#include <array> #include <array>

0
gtests/TestFixture.h Normal file → Executable file
View File