Merge pull request #1460 from KhronosGroup/postprocess
Non-Functional: Add postprocess as more robust way to add capabilities
This commit is contained in:
commit
e0bc65b2c1
@ -3,6 +3,7 @@ set(SOURCES
|
|||||||
InReadableOrder.cpp
|
InReadableOrder.cpp
|
||||||
Logger.cpp
|
Logger.cpp
|
||||||
SpvBuilder.cpp
|
SpvBuilder.cpp
|
||||||
|
SpvPostProcess.cpp
|
||||||
doc.cpp
|
doc.cpp
|
||||||
disassemble.cpp)
|
disassemble.cpp)
|
||||||
|
|
||||||
|
@ -1191,6 +1191,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
|
|||||||
// Finish creating SPV, after the traversal is complete.
|
// Finish creating SPV, after the traversal is complete.
|
||||||
void TGlslangToSpvTraverser::finishSpv()
|
void TGlslangToSpvTraverser::finishSpv()
|
||||||
{
|
{
|
||||||
|
// Finish the entry point function
|
||||||
if (! entryPointTerminated) {
|
if (! entryPointTerminated) {
|
||||||
builder.setBuildPoint(shaderEntry->getLastBlock());
|
builder.setBuildPoint(shaderEntry->getLastBlock());
|
||||||
builder.leaveFunction();
|
builder.leaveFunction();
|
||||||
@ -1200,7 +1201,9 @@ void TGlslangToSpvTraverser::finishSpv()
|
|||||||
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it)
|
||||||
entryPoint->addIdOperand(*it);
|
entryPoint->addIdOperand(*it);
|
||||||
|
|
||||||
builder.eliminateDeadDecorations();
|
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||||
|
// based on the resulting SPIR-V.
|
||||||
|
builder.postProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the SPV into 'out'.
|
// Write the SPV into 'out'.
|
||||||
@ -4627,27 +4630,21 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
|||||||
unaryOp = spv::OpFwidth;
|
unaryOp = spv::OpFwidth;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpDPdxFine:
|
case glslang::EOpDPdxFine:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpDPdxFine;
|
unaryOp = spv::OpDPdxFine;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpDPdyFine:
|
case glslang::EOpDPdyFine:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpDPdyFine;
|
unaryOp = spv::OpDPdyFine;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpFwidthFine:
|
case glslang::EOpFwidthFine:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpFwidthFine;
|
unaryOp = spv::OpFwidthFine;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpDPdxCoarse:
|
case glslang::EOpDPdxCoarse:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpDPdxCoarse;
|
unaryOp = spv::OpDPdxCoarse;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpDPdyCoarse:
|
case glslang::EOpDPdyCoarse:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpDPdyCoarse;
|
unaryOp = spv::OpDPdyCoarse;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpFwidthCoarse:
|
case glslang::EOpFwidthCoarse:
|
||||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
|
||||||
unaryOp = spv::OpFwidthCoarse;
|
unaryOp = spv::OpFwidthCoarse;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpInterpolateAtCentroid:
|
case glslang::EOpInterpolateAtCentroid:
|
||||||
@ -4655,7 +4652,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
|||||||
if (typeProxy == glslang::EbtFloat16)
|
if (typeProxy == glslang::EbtFloat16)
|
||||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||||
#endif
|
#endif
|
||||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
|
||||||
libCall = spv::GLSLstd450InterpolateAtCentroid;
|
libCall = spv::GLSLstd450InterpolateAtCentroid;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpAny:
|
case glslang::EOpAny:
|
||||||
@ -4791,8 +4787,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
|||||||
#endif
|
#endif
|
||||||
#ifdef NV_EXTENSIONS
|
#ifdef NV_EXTENSIONS
|
||||||
case glslang::EOpSubgroupPartition:
|
case glslang::EOpSubgroupPartition:
|
||||||
builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
|
|
||||||
builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);
|
|
||||||
unaryOp = spv::OpGroupNonUniformPartitionNV;
|
unaryOp = spv::OpGroupNonUniformPartitionNV;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
@ -6087,7 +6081,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||||||
if (typeProxy == glslang::EbtFloat16)
|
if (typeProxy == glslang::EbtFloat16)
|
||||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||||
#endif
|
#endif
|
||||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
|
||||||
libCall = spv::GLSLstd450InterpolateAtSample;
|
libCall = spv::GLSLstd450InterpolateAtSample;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpInterpolateAtOffset:
|
case glslang::EOpInterpolateAtOffset:
|
||||||
@ -6095,7 +6088,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
|||||||
if (typeProxy == glslang::EbtFloat16)
|
if (typeProxy == glslang::EbtFloat16)
|
||||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||||
#endif
|
#endif
|
||||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
|
||||||
libCall = spv::GLSLstd450InterpolateAtOffset;
|
libCall = spv::GLSLstd450InterpolateAtOffset;
|
||||||
break;
|
break;
|
||||||
case glslang::EOpAddCarry:
|
case glslang::EOpAddCarry:
|
||||||
|
@ -1774,9 +1774,6 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse,
|
|||||||
// Comments in header
|
// Comments in header
|
||||||
Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
|
Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
|
||||||
{
|
{
|
||||||
// All these need a capability
|
|
||||||
addCapability(CapabilityImageQuery);
|
|
||||||
|
|
||||||
// Figure out the result type
|
// Figure out the result type
|
||||||
Id resultType = 0;
|
Id resultType = 0;
|
||||||
switch (opCode) {
|
switch (opCode) {
|
||||||
@ -2483,42 +2480,6 @@ Id Builder::accessChainGetInferredType()
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// comment in header
|
|
||||||
void Builder::eliminateDeadDecorations() {
|
|
||||||
std::unordered_set<const Block*> reachable_blocks;
|
|
||||||
std::unordered_set<Id> unreachable_definitions;
|
|
||||||
// Collect IDs defined in unreachable blocks. For each function, label the
|
|
||||||
// reachable blocks first. Then for each unreachable block, collect the
|
|
||||||
// result IDs of the instructions in it.
|
|
||||||
for (std::vector<Function*>::const_iterator fi = module.getFunctions().cbegin();
|
|
||||||
fi != module.getFunctions().cend(); fi++) {
|
|
||||||
Function* f = *fi;
|
|
||||||
Block* entry = f->getEntryBlock();
|
|
||||||
inReadableOrder(entry, [&reachable_blocks](const Block* b) {
|
|
||||||
reachable_blocks.insert(b);
|
|
||||||
});
|
|
||||||
for (std::vector<Block*>::const_iterator bi = f->getBlocks().cbegin();
|
|
||||||
bi != f->getBlocks().cend(); bi++) {
|
|
||||||
Block* b = *bi;
|
|
||||||
if (!reachable_blocks.count(b)) {
|
|
||||||
for (std::vector<std::unique_ptr<Instruction> >::const_iterator
|
|
||||||
ii = b->getInstructions().cbegin();
|
|
||||||
ii != b->getInstructions().cend(); ii++) {
|
|
||||||
Instruction* i = ii->get();
|
|
||||||
unreachable_definitions.insert(i->getResultId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
|
|
||||||
[&unreachable_definitions](std::unique_ptr<Instruction>& I) -> bool {
|
|
||||||
Instruction* inst = I.get();
|
|
||||||
Id decoration_id = inst->getIdOperand(0);
|
|
||||||
return unreachable_definitions.count(decoration_id) != 0;
|
|
||||||
}),
|
|
||||||
decorations.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::dump(std::vector<unsigned int>& out) const
|
void Builder::dump(std::vector<unsigned int>& out) const
|
||||||
{
|
{
|
||||||
// Header, before first instructions:
|
// Header, before first instructions:
|
||||||
|
@ -563,9 +563,15 @@ public:
|
|||||||
// based on the type of the base and the chain of dereferences.
|
// based on the type of the base and the chain of dereferences.
|
||||||
Id accessChainGetInferredType();
|
Id accessChainGetInferredType();
|
||||||
|
|
||||||
// Remove OpDecorate instructions whose operands are defined in unreachable
|
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||||
// blocks.
|
// based on the resulting SPIR-V.
|
||||||
void eliminateDeadDecorations();
|
void postProcess();
|
||||||
|
|
||||||
|
// Hook to visit each instruction in a block in a function
|
||||||
|
void postProcess(Instruction& inst);
|
||||||
|
// Hook to visit each instruction in a reachable block in a function.
|
||||||
|
void postProcessReachable(Instruction& inst);
|
||||||
|
|
||||||
void dump(std::vector<unsigned int>&) const;
|
void dump(std::vector<unsigned int>&) const;
|
||||||
|
|
||||||
void createBranch(Block* block);
|
void createBranch(Block* block);
|
||||||
|
164
SPIRV/SpvPostProcess.cpp
Executable file
164
SPIRV/SpvPostProcess.cpp
Executable file
@ -0,0 +1,164 @@
|
|||||||
|
//
|
||||||
|
// Copyright (C) 2016-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.
|
||||||
|
|
||||||
|
//
|
||||||
|
// Post-processing for SPIR-V IR, in internal form, not standard binary form.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "SpvBuilder.h"
|
||||||
|
|
||||||
|
#include "spirv.hpp"
|
||||||
|
#include "GlslangToSpv.h"
|
||||||
|
#include "SpvBuilder.h"
|
||||||
|
namespace spv {
|
||||||
|
#include "GLSL.std.450.h"
|
||||||
|
#include "GLSL.ext.KHR.h"
|
||||||
|
#include "GLSL.ext.EXT.h"
|
||||||
|
#ifdef AMD_EXTENSIONS
|
||||||
|
#include "GLSL.ext.AMD.h"
|
||||||
|
#endif
|
||||||
|
#ifdef NV_EXTENSIONS
|
||||||
|
#include "GLSL.ext.NV.h"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace spv {
|
||||||
|
|
||||||
|
// Called for each instruction in a block.
|
||||||
|
void Builder::postProcess(Instruction& inst)
|
||||||
|
{
|
||||||
|
// Add capabilities based simply on the opcode.
|
||||||
|
switch (inst.getOpCode()) {
|
||||||
|
case OpExtInst:
|
||||||
|
switch (inst.getIdOperand(1)) {
|
||||||
|
case GLSLstd450InterpolateAtCentroid:
|
||||||
|
case GLSLstd450InterpolateAtSample:
|
||||||
|
case GLSLstd450InterpolateAtOffset:
|
||||||
|
addCapability(CapabilityInterpolationFunction);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OpDPdxFine:
|
||||||
|
case OpDPdyFine:
|
||||||
|
case OpFwidthFine:
|
||||||
|
case OpDPdxCoarse:
|
||||||
|
case OpDPdyCoarse:
|
||||||
|
case OpFwidthCoarse:
|
||||||
|
addCapability(CapabilityDerivativeControl);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpImageQueryLod:
|
||||||
|
case OpImageQuerySize:
|
||||||
|
case OpImageQuerySizeLod:
|
||||||
|
case OpImageQuerySamples:
|
||||||
|
case OpImageQueryLevels:
|
||||||
|
addCapability(CapabilityImageQuery);
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef NV_EXTENSIONS
|
||||||
|
case OpGroupNonUniformPartitionNV:
|
||||||
|
addExtension(E_SPV_NV_shader_subgroup_partitioned);
|
||||||
|
addCapability(CapabilityGroupNonUniformPartitionedNV);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called for each instruction in a reachable block.
|
||||||
|
void Builder::postProcessReachable(Instruction& inst)
|
||||||
|
{
|
||||||
|
// did have code here, but questionable to do so without deleting the instructions
|
||||||
|
}
|
||||||
|
|
||||||
|
// comment in header
|
||||||
|
void Builder::postProcess()
|
||||||
|
{
|
||||||
|
std::unordered_set<const Block*> reachableBlocks;
|
||||||
|
std::unordered_set<Id> unreachableDefinitions;
|
||||||
|
// Collect IDs defined in unreachable blocks. For each function, label the
|
||||||
|
// reachable blocks first. Then for each unreachable block, collect the
|
||||||
|
// result IDs of the instructions in it.
|
||||||
|
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
|
||||||
|
Function* f = *fi;
|
||||||
|
Block* entry = f->getEntryBlock();
|
||||||
|
inReadableOrder(entry, [&reachableBlocks](const Block* b) { reachableBlocks.insert(b); });
|
||||||
|
for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
|
||||||
|
Block* b = *bi;
|
||||||
|
if (reachableBlocks.count(b) == 0) {
|
||||||
|
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
|
||||||
|
unreachableDefinitions.insert(ii->get()->getResultId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove unneeded decorations, for unreachable instructions
|
||||||
|
decorations.erase(std::remove_if(decorations.begin(), decorations.end(),
|
||||||
|
[&unreachableDefinitions](std::unique_ptr<Instruction>& I) -> bool {
|
||||||
|
Id decoration_id = I.get()->getIdOperand(0);
|
||||||
|
return unreachableDefinitions.count(decoration_id) != 0;
|
||||||
|
}),
|
||||||
|
decorations.end());
|
||||||
|
|
||||||
|
// Add per-instruction capabilities, extensions, etc.,
|
||||||
|
|
||||||
|
// process all reachable instructions...
|
||||||
|
for (auto bi = reachableBlocks.cbegin(); bi != reachableBlocks.cend(); ++bi) {
|
||||||
|
const Block* block = *bi;
|
||||||
|
const auto function = [this](const std::unique_ptr<Instruction>& inst) { postProcessReachable(*inst.get()); };
|
||||||
|
std::for_each(block->getInstructions().begin(), block->getInstructions().end(), function);
|
||||||
|
}
|
||||||
|
|
||||||
|
// process all block-contained instructions
|
||||||
|
for (auto fi = module.getFunctions().cbegin(); fi != module.getFunctions().cend(); fi++) {
|
||||||
|
Function* f = *fi;
|
||||||
|
for (auto bi = f->getBlocks().cbegin(); bi != f->getBlocks().cend(); bi++) {
|
||||||
|
Block* b = *bi;
|
||||||
|
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
|
||||||
|
postProcess(*ii->get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // end spv namespace
|
Loading…
x
Reference in New Issue
Block a user