mirror of
https://github.com/RPCS3/glslang.git
synced 2024-11-24 03:39:51 +00:00
Non-Functional: Add postprocess as more robust way to add capabilities
When capabilities are needed for specific SPIR-V instructions, it is fragile to do so based on GLSL/AST usage; it should be based on actual instructions they got translated to.
This commit is contained in:
parent
e99a26810f
commit
f04c51b3bd
@ -3,6 +3,7 @@ set(SOURCES
|
||||
InReadableOrder.cpp
|
||||
Logger.cpp
|
||||
SpvBuilder.cpp
|
||||
SpvPostProcess.cpp
|
||||
doc.cpp
|
||||
disassemble.cpp)
|
||||
|
||||
|
@ -1191,6 +1191,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
|
||||
// Finish creating SPV, after the traversal is complete.
|
||||
void TGlslangToSpvTraverser::finishSpv()
|
||||
{
|
||||
// Finish the entry point function
|
||||
if (! entryPointTerminated) {
|
||||
builder.setBuildPoint(shaderEntry->getLastBlock());
|
||||
builder.leaveFunction();
|
||||
@ -1200,7 +1201,9 @@ void TGlslangToSpvTraverser::finishSpv()
|
||||
for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++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'.
|
||||
@ -4627,27 +4630,21 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
||||
unaryOp = spv::OpFwidth;
|
||||
break;
|
||||
case glslang::EOpDPdxFine:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpDPdxFine;
|
||||
break;
|
||||
case glslang::EOpDPdyFine:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpDPdyFine;
|
||||
break;
|
||||
case glslang::EOpFwidthFine:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpFwidthFine;
|
||||
break;
|
||||
case glslang::EOpDPdxCoarse:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpDPdxCoarse;
|
||||
break;
|
||||
case glslang::EOpDPdyCoarse:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpDPdyCoarse;
|
||||
break;
|
||||
case glslang::EOpFwidthCoarse:
|
||||
builder.addCapability(spv::CapabilityDerivativeControl);
|
||||
unaryOp = spv::OpFwidthCoarse;
|
||||
break;
|
||||
case glslang::EOpInterpolateAtCentroid:
|
||||
@ -4655,7 +4652,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
||||
if (typeProxy == glslang::EbtFloat16)
|
||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||
#endif
|
||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
||||
libCall = spv::GLSLstd450InterpolateAtCentroid;
|
||||
break;
|
||||
case glslang::EOpAny:
|
||||
@ -4791,8 +4787,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe
|
||||
#endif
|
||||
#ifdef NV_EXTENSIONS
|
||||
case glslang::EOpSubgroupPartition:
|
||||
builder.addExtension(spv::E_SPV_NV_shader_subgroup_partitioned);
|
||||
builder.addCapability(spv::CapabilityGroupNonUniformPartitionedNV);
|
||||
unaryOp = spv::OpGroupNonUniformPartitionNV;
|
||||
break;
|
||||
#endif
|
||||
@ -6087,7 +6081,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
if (typeProxy == glslang::EbtFloat16)
|
||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||
#endif
|
||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
||||
libCall = spv::GLSLstd450InterpolateAtSample;
|
||||
break;
|
||||
case glslang::EOpInterpolateAtOffset:
|
||||
@ -6095,7 +6088,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
if (typeProxy == glslang::EbtFloat16)
|
||||
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
|
||||
#endif
|
||||
builder.addCapability(spv::CapabilityInterpolationFunction);
|
||||
libCall = spv::GLSLstd450InterpolateAtOffset;
|
||||
break;
|
||||
case glslang::EOpAddCarry:
|
||||
|
@ -1774,9 +1774,6 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse,
|
||||
// Comments in header
|
||||
Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult)
|
||||
{
|
||||
// All these need a capability
|
||||
addCapability(CapabilityImageQuery);
|
||||
|
||||
// Figure out the result type
|
||||
Id resultType = 0;
|
||||
switch (opCode) {
|
||||
@ -2483,42 +2480,6 @@ Id Builder::accessChainGetInferredType()
|
||||
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
|
||||
{
|
||||
// Header, before first instructions:
|
||||
|
@ -563,9 +563,15 @@ public:
|
||||
// based on the type of the base and the chain of dereferences.
|
||||
Id accessChainGetInferredType();
|
||||
|
||||
// Remove OpDecorate instructions whose operands are defined in unreachable
|
||||
// blocks.
|
||||
void eliminateDeadDecorations();
|
||||
// Add capabilities, extensions, remove unneeded decorations, etc.,
|
||||
// based on the resulting SPIR-V.
|
||||
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 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…
Reference in New Issue
Block a user