Move to revision 31 of SPIR-V.

This commit is contained in:
John Kessenich 2015-08-06 22:53:06 -06:00
parent e24a74c320
commit 5e4b1242bf
77 changed files with 6050 additions and 5450 deletions

3
SPIRV/CMakeLists.txt Normal file → Executable file
View file

@ -10,7 +10,8 @@ set(SOURCES
disassemble.cpp)
set(HEADERS
spirv.h
spirv.hpp
GLSL.std.450.h
GlslangToSpv.h
SpvBuilder.h
SPVRemapper.h

300
SPIRV/GlslangToSpv.cpp Normal file → Executable file
View file

@ -39,14 +39,17 @@
// translate them to SPIR-V.
//
#include "spirv.h"
#include "spirv.hpp"
#include "GlslangToSpv.h"
#include "SpvBuilder.h"
#include "GLSL450Lib.h"
namespace spv {
#include "GLSL.std.450.h"
}
// Glslang includes
#include "../glslang/MachineIndependent/localintermediate.h"
#include "../glslang/MachineIndependent/SymbolTable.h"
#include "../glslang/Include/Common.h"
#include <string>
#include <map>
@ -85,6 +88,7 @@ protected:
spv::Id createSpvVariable(const glslang::TIntermSymbol*);
spv::Id getSampledType(const glslang::TSampler&);
spv::Id convertGlslangToSpvType(const glslang::TType& type);
void updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset);
bool isShaderEntrypoint(const glslang::TIntermAggregate* node);
void makeFunctions(const glslang::TIntermSequence&);
@ -93,6 +97,7 @@ protected:
void handleFunctionEntry(const glslang::TIntermAggregate* node);
void translateArguments(const glslang::TIntermSequence& glslangArguments, std::vector<spv::Id>& arguments);
spv::Id handleBuiltInFunctionCall(const glslang::TIntermAggregate*);
spv::Id handleTextureCall(spv::Decoration precision, glslang::TOperator, spv::Id typeId, glslang::TSampler, std::vector<spv::Id>& idArguments);
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
spv::Id createBinaryOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, spv::Id left, spv::Id right, glslang::TBasicType typeProxy, bool reduceComparison = true);
@ -100,7 +105,7 @@ protected:
spv::Id createConversion(glslang::TOperator op, spv::Decoration precision, spv::Id destTypeId, spv::Id operand);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
spv::Id createNoArgOperation(glslang::TOperator op);
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
void addDecoration(spv::Id id, spv::Decoration dec);
@ -208,9 +213,9 @@ spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
{
switch (type.getQualifier().precision) {
case glslang::EpqLow: return spv::DecorationPrecisionLow;
case glslang::EpqMedium: return spv::DecorationPrecisionMedium;
case glslang::EpqHigh: return spv::DecorationPrecisionHigh;
case glslang::EpqLow: return spv::DecorationRelaxedPrecision; // TODO: Map instead to 16-bit types?
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
case glslang::EpqHigh: return spv::NoPrecision;
default:
return spv::NoPrecision;
}
@ -255,12 +260,9 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
case glslang::EvqBuffer:
switch (type.getQualifier().layoutPacking) {
case glslang::ElpShared: return spv::DecorationGLSLShared;
case glslang::ElpStd140: return spv::DecorationGLSLStd140;
case glslang::ElpStd430: return spv::DecorationGLSLStd430;
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
default:
spv::MissingFunctionality("uniform block layout");
return spv::DecorationGLSLShared;
return (spv::Decoration)spv::BadValue;
}
case glslang::EvqVaryingIn:
case glslang::EvqVaryingOut:
@ -309,7 +311,6 @@ spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
switch (builtIn) {
case glslang::EbvPosition: return spv::BuiltInPosition;
case glslang::EbvPointSize: return spv::BuiltInPointSize;
case glslang::EbvClipVertex: return spv::BuiltInClipVertex;
case glslang::EbvClipDistance: return spv::BuiltInClipDistance;
case glslang::EbvCullDistance: return spv::BuiltInCullDistance;
case glslang::EbvVertexId: return spv::BuiltInVertexId;
@ -359,7 +360,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
stdBuiltins = builder.import("GLSL.std.450");
builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
shaderEntry = builder.makeMain();
builder.addEntryPoint(executionModel, shaderEntry);
builder.addEntryPoint(executionModel, shaderEntry, "main");
// Add the source extensions
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
@ -374,13 +375,16 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
unsigned int mode;
switch (glslangIntermediate->getStage()) {
case EShLangVertex:
builder.addCapability(spv::CapabilityShader);
break;
case EShLangTessControl:
builder.addCapability(spv::CapabilityTessellation);
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices());
break;
case EShLangTessEvaluation:
builder.addCapability(spv::CapabilityTessellation);
switch (glslangIntermediate->getInputPrimitive()) {
case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;
@ -397,6 +401,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
break;
case EShLangGeometry:
builder.addCapability(spv::CapabilityGeometry);
switch (glslangIntermediate->getInputPrimitive()) {
case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
@ -421,13 +426,17 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
break;
case EShLangFragment:
builder.addCapability(spv::CapabilityShader);
if (glslangIntermediate->getPixelCenterInteger())
builder.addExecutionMode(shaderEntry, spv::ExecutionModePixelCenterInteger);
if (glslangIntermediate->getOriginUpperLeft())
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginUpperLeft);
else
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOriginLowerLeft);
break;
case EShLangCompute:
builder.addCapability(spv::CapabilityShader);
break;
default:
@ -1051,7 +1060,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType() == glslang::EbtFloat || node->getType().getBasicType() == glslang::EbtDouble);
break;
default:
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands);
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
break;
}
}
@ -1311,9 +1320,11 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
case glslang::EbtSampler:
{
const glslang::TSampler& sampler = type.getSampler();
spvType = builder.makeSampler(getSampledType(sampler), TranslateDimensionality(sampler),
sampler.image ? spv::Builder::samplerContentImage : spv::Builder::samplerContentTextureFilter,
sampler.arrayed, sampler.shadow, sampler.ms);
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
sampler.image ? 2 : 1, spv::ImageFormatUnknown); // TODO: translate format, needed for GLSL image ops
// OpenGL "textures" need to be combined with a sampler
if (! sampler.image)
spvType = builder.makeSampledImageType(spvType);
}
break;
case glslang::EbtStruct:
@ -1350,6 +1361,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
structMap[glslangStruct] = spvType;
// Name and decorate the non-hidden members
int offset = -1;
for (int i = 0; i < (int)glslangStruct->size(); i++) {
glslang::TType& glslangType = *(*glslangStruct)[i].type;
int member = i;
@ -1368,6 +1380,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
builder.addMemberDecoration(spvType, member, spv::DecorationComponent, glslangType.getQualifier().layoutComponent);
if (glslangType.getQualifier().hasXfbOffset())
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutXfbOffset);
else {
// figure out what to do with offset, which is accumulating
int nextOffset;
updateMemberOffset(type, glslangType, offset, nextOffset);
if (offset >= 0)
builder.addMemberDecoration(spvType, member, spv::DecorationOffset, glslangType.getQualifier().layoutOffset);
offset = nextOffset;
}
// built-in variable decorations
spv::BuiltIn builtIn = TranslateBuiltInDecoration(glslangType.getQualifier().builtIn);
@ -1383,7 +1403,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
builder.addDecoration(spvType, spv::DecorationStream, type.getQualifier().layoutStream);
if (glslangIntermediate->getXfbMode()) {
if (type.getQualifier().hasXfbStride())
builder.addDecoration(spvType, spv::DecorationStride, type.getQualifier().layoutXfbStride);
builder.addDecoration(spvType, spv::DecorationXfbStride, type.getQualifier().layoutXfbStride);
if (type.getQualifier().hasXfbBuffer())
builder.addDecoration(spvType, spv::DecorationXfbBuffer, type.getQualifier().layoutXfbBuffer);
}
@ -1415,6 +1435,49 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
return spvType;
}
// Given a member type of a struct, realign the current offset for it, and compute
// the next (not yet aligned) offset for the next member, which will get aligned
// on the next call.
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
// -1 means a non-forced member offset (no decoration needed).
void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset)
{
// this will get a positive value when deemed necessary
nextOffset = -1;
bool forceOffset = structType.getQualifier().layoutPacking == glslang::ElpStd140 ||
structType.getQualifier().layoutPacking == glslang::ElpStd430;
// override anything in currentOffset with user-set offset
if (memberType.getQualifier().hasOffset())
currentOffset = memberType.getQualifier().layoutOffset;
// It could be that current linker usage in glslang updated all the layoutOffset,
// in which case the following code does not matter. But, that's not quite right
// once cross-compilation unit GLSL validation is done, as the original user
// settings are needed in layoutOffset, and then the following will come into play.
if (! forceOffset) {
if (! memberType.getQualifier().hasOffset())
currentOffset = -1;
return;
}
// Getting this far means we are forcing offsets
if (currentOffset < 0)
currentOffset = 0;
// Now, currentOffset is valid (either 0, or from a previous nextOffset),
// but possibly not yet correctly aligned.
int memberSize;
int memberAlignment = glslangIntermediate->getBaseAlignment(memberType, memberSize, memberType.getQualifier().layoutPacking == glslang::ElpStd140);
glslang::RoundToPow2(currentOffset, memberAlignment);
nextOffset = currentOffset + memberSize;
}
bool TGlslangToSpvTraverser::isShaderEntrypoint(const glslang::TIntermAggregate* node)
{
return node->getName() == "main(";
@ -1519,11 +1582,6 @@ spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TInterm
{
std::vector<spv::Id> arguments;
translateArguments(node->getSequence(), arguments);
std::vector<spv::Id> argTypes;
for (int a = 0; a < (int)arguments.size(); ++a)
argTypes.push_back(builder.getTypeId(arguments[a]));
spv::Decoration precision = TranslatePrecisionDecoration(node->getType());
if (node->getName() == "ftransform(") {
@ -1544,22 +1602,22 @@ spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TInterm
if (node->getName().find("textureSize", 0) != std::string::npos) {
if (arguments.size() > 1) {
params.lod = arguments[1];
return builder.createTextureQueryCall(spv::OpTextureQuerySizeLod, params);
return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params);
} else
return builder.createTextureQueryCall(spv::OpTextureQuerySize, params);
return builder.createTextureQueryCall(spv::OpImageQuerySize, params);
}
// special case the number of samples query
if (node->getName().find("textureSamples", 0) != std::string::npos)
return builder.createTextureQueryCall(spv::OpTextureQuerySamples, params);
return builder.createTextureQueryCall(spv::OpImageQuerySamples, params);
// special case the other queries
if (node->getName().find("Query", 0) != std::string::npos) {
if (node->getName().find("Levels", 0) != std::string::npos)
return builder.createTextureQueryCall(spv::OpTextureQueryLevels, params);
return builder.createTextureQueryCall(spv::OpImageQueryLevels, params);
else if (node->getName().find("Lod", 0) != std::string::npos) {
params.coords = arguments[1];
return builder.createTextureQueryCall(spv::OpTextureQueryLod, params);
return builder.createTextureQueryCall(spv::OpImageQueryLod, params);
} else
spv::MissingFunctionality("glslang texture query");
}
@ -1599,6 +1657,16 @@ spv::Id TGlslangToSpvTraverser::handleBuiltInFunctionCall(const glslang::TInterm
int extraArgs = 0;
if (cubeCompare)
params.Dref = arguments[2];
else if (sampler.shadow) {
std::vector<spv::Id> indexes;
int comp;
if (proj)
comp = 3;
else
comp = builder.getNumComponents(params.coords) - 1;
indexes.push_back(comp);
params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
}
if (lod) {
params.lod = arguments[2];
++extraArgs;
@ -1835,7 +1903,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, spv
break;
case glslang::EOpLogicalXor:
needMatchingVectors = false;
binOp = spv::OpLogicalXor;
binOp = spv::OpLogicalNotEqual;
break;
case glslang::EOpLessThan:
@ -1974,107 +2042,109 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
case glslang::EOpLogicalNot:
case glslang::EOpVectorLogicalNot:
unaryOp = spv::OpLogicalNot;
break;
case glslang::EOpBitwiseNot:
unaryOp = spv::OpNot;
break;
case glslang::EOpDeterminant:
libCall = GLSL_STD_450::Determinant;
libCall = spv::GLSLstd450Determinant;
break;
case glslang::EOpMatrixInverse:
libCall = GLSL_STD_450::MatrixInverse;
libCall = spv::GLSLstd450MatrixInverse;
break;
case glslang::EOpTranspose:
unaryOp = spv::OpTranspose;
break;
case glslang::EOpRadians:
libCall = GLSL_STD_450::Radians;
libCall = spv::GLSLstd450Radians;
break;
case glslang::EOpDegrees:
libCall = GLSL_STD_450::Degrees;
libCall = spv::GLSLstd450Degrees;
break;
case glslang::EOpSin:
libCall = GLSL_STD_450::Sin;
libCall = spv::GLSLstd450Sin;
break;
case glslang::EOpCos:
libCall = GLSL_STD_450::Cos;
libCall = spv::GLSLstd450Cos;
break;
case glslang::EOpTan:
libCall = GLSL_STD_450::Tan;
libCall = spv::GLSLstd450Tan;
break;
case glslang::EOpAcos:
libCall = GLSL_STD_450::Acos;
libCall = spv::GLSLstd450Acos;
break;
case glslang::EOpAsin:
libCall = GLSL_STD_450::Asin;
libCall = spv::GLSLstd450Asin;
break;
case glslang::EOpAtan:
libCall = GLSL_STD_450::Atan;
libCall = spv::GLSLstd450Atan;
break;
case glslang::EOpAcosh:
libCall = GLSL_STD_450::Acosh;
libCall = spv::GLSLstd450Acosh;
break;
case glslang::EOpAsinh:
libCall = GLSL_STD_450::Asinh;
libCall = spv::GLSLstd450Asinh;
break;
case glslang::EOpAtanh:
libCall = GLSL_STD_450::Atanh;
libCall = spv::GLSLstd450Atanh;
break;
case glslang::EOpTanh:
libCall = GLSL_STD_450::Tanh;
libCall = spv::GLSLstd450Tanh;
break;
case glslang::EOpCosh:
libCall = GLSL_STD_450::Cosh;
libCall = spv::GLSLstd450Cosh;
break;
case glslang::EOpSinh:
libCall = GLSL_STD_450::Sinh;
libCall = spv::GLSLstd450Sinh;
break;
case glslang::EOpLength:
libCall = GLSL_STD_450::Length;
libCall = spv::GLSLstd450Length;
break;
case glslang::EOpNormalize:
libCall = GLSL_STD_450::Normalize;
libCall = spv::GLSLstd450Normalize;
break;
case glslang::EOpExp:
libCall = GLSL_STD_450::Exp;
libCall = spv::GLSLstd450Exp;
break;
case glslang::EOpLog:
libCall = GLSL_STD_450::Log;
libCall = spv::GLSLstd450Log;
break;
case glslang::EOpExp2:
libCall = GLSL_STD_450::Exp2;
libCall = spv::GLSLstd450Exp2;
break;
case glslang::EOpLog2:
libCall = GLSL_STD_450::Log2;
libCall = spv::GLSLstd450Log2;
break;
case glslang::EOpSqrt:
libCall = GLSL_STD_450::Sqrt;
libCall = spv::GLSLstd450Sqrt;
break;
case glslang::EOpInverseSqrt:
libCall = GLSL_STD_450::InverseSqrt;
libCall = spv::GLSLstd450InverseSqrt;
break;
case glslang::EOpFloor:
libCall = GLSL_STD_450::Floor;
libCall = spv::GLSLstd450Floor;
break;
case glslang::EOpTrunc:
libCall = GLSL_STD_450::Trunc;
libCall = spv::GLSLstd450Trunc;
break;
case glslang::EOpRound:
libCall = GLSL_STD_450::Round;
libCall = spv::GLSLstd450Round;
break;
case glslang::EOpRoundEven:
libCall = GLSL_STD_450::RoundEven;
libCall = spv::GLSLstd450RoundEven;
break;
case glslang::EOpCeil:
libCall = GLSL_STD_450::Ceil;
libCall = spv::GLSLstd450Ceil;
break;
case glslang::EOpFract:
libCall = GLSL_STD_450::Fract;
libCall = spv::GLSLstd450Fract;
break;
case glslang::EOpIsNan:
@ -2084,35 +2154,23 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
unaryOp = spv::OpIsInf;
break;
case glslang::EOpFloatBitsToInt:
libCall = GLSL_STD_450::FloatBitsToInt;
break;
case glslang::EOpFloatBitsToUint:
libCall = GLSL_STD_450::FloatBitsToUint;
break;
case glslang::EOpIntBitsToFloat:
libCall = GLSL_STD_450::IntBitsToFloat;
break;
case glslang::EOpUintBitsToFloat:
libCall = GLSL_STD_450::UintBitsToFloat;
break;
case glslang::EOpPackSnorm2x16:
libCall = GLSL_STD_450::PackSnorm2x16;
libCall = spv::GLSLstd450PackSnorm2x16;
break;
case glslang::EOpUnpackSnorm2x16:
libCall = GLSL_STD_450::UnpackSnorm2x16;
libCall = spv::GLSLstd450UnpackSnorm2x16;
break;
case glslang::EOpPackUnorm2x16:
libCall = GLSL_STD_450::PackUnorm2x16;
libCall = spv::GLSLstd450PackUnorm2x16;
break;
case glslang::EOpUnpackUnorm2x16:
libCall = GLSL_STD_450::UnpackUnorm2x16;
libCall = spv::GLSLstd450UnpackUnorm2x16;
break;
case glslang::EOpPackHalf2x16:
libCall = GLSL_STD_450::PackHalf2x16;
libCall = spv::GLSLstd450PackHalf2x16;
break;
case glslang::EOpUnpackHalf2x16:
libCall = GLSL_STD_450::UnpackHalf2x16;
libCall = spv::GLSLstd450UnpackHalf2x16;
break;
case glslang::EOpDPdx:
@ -2151,10 +2209,16 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
break;
case glslang::EOpAbs:
libCall = GLSL_STD_450::Abs;
if (isFloat)
libCall = spv::GLSLstd450FAbs;
else
libCall = spv::GLSLstd450SAbs;
break;
case glslang::EOpSign:
libCall = GLSL_STD_450::Sign;
if (isFloat)
libCall = spv::GLSLstd450FSign;
else
libCall = spv::GLSLstd450SSign;
break;
default:
@ -2291,10 +2355,10 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
opCode = spv::OpAtomicIAdd;
break;
case glslang::EOpAtomicMin:
opCode = spv::OpAtomicIMin;
opCode = spv::OpAtomicSMin;
break;
case glslang::EOpAtomicMax:
opCode = spv::OpAtomicIMax;
opCode = spv::OpAtomicSMax;
break;
case glslang::EOpAtomicAnd:
opCode = spv::OpAtomicAnd;
@ -2331,8 +2395,8 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
std::vector<spv::Id> spvAtomicOperands; // hold the spv operands
auto opIt = operands.begin(); // walk the glslang operands
spvAtomicOperands.push_back(*(opIt++));
spvAtomicOperands.push_back(spv::ExecutionScopeDevice); // TBD: what is the correct scope?
spvAtomicOperands.push_back( spv::MemorySemanticsMaskNone); // TBD: what are the correct memory semantics?
spvAtomicOperands.push_back(builder.makeUintConstant(spv::ScopeDevice)); // TBD: what is the correct scope?
spvAtomicOperands.push_back(builder.makeUintConstant(spv::MemorySemanticsMaskNone)); // TBD: what are the correct memory semantics?
// Add the rest of the operands, skipping the first one, which was dealt with above.
// For some ops, there are none, for some 1, for compare-exchange, 2.
@ -2342,58 +2406,76 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
return builder.createOp(opCode, typeId, spvAtomicOperands);
}
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands)
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
{
bool isUnsigned = typeProxy == glslang::EbtUint;
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
spv::Op opCode = spv::OpNop;
int libCall = -1;
switch (op) {
case glslang::EOpMin:
libCall = GLSL_STD_450::Min;
if (isFloat)
libCall = spv::GLSLstd450FMin;
else if (isUnsigned)
libCall = spv::GLSLstd450UMin;
else
libCall = spv::GLSLstd450SMin;
break;
case glslang::EOpModf:
libCall = GLSL_STD_450::Modf;
libCall = spv::GLSLstd450Modf;
break;
case glslang::EOpMax:
libCall = GLSL_STD_450::Max;
if (isFloat)
libCall = spv::GLSLstd450FMax;
else if (isUnsigned)
libCall = spv::GLSLstd450UMax;
else
libCall = spv::GLSLstd450SMax;
break;
case glslang::EOpPow:
libCall = GLSL_STD_450::Pow;
libCall = spv::GLSLstd450Pow;
break;
case glslang::EOpDot:
opCode = spv::OpDot;
break;
case glslang::EOpAtan:
libCall = GLSL_STD_450::Atan2;
libCall = spv::GLSLstd450Atan2;
break;
case glslang::EOpClamp:
libCall = GLSL_STD_450::Clamp;
if (isFloat)
libCall = spv::GLSLstd450FClamp;
else if (isUnsigned)
libCall = spv::GLSLstd450UClamp;
else
libCall = spv::GLSLstd450SClamp;
break;
case glslang::EOpMix:
libCall = GLSL_STD_450::Mix;
libCall = spv::GLSLstd450Mix;
break;
case glslang::EOpStep:
libCall = GLSL_STD_450::Step;
libCall = spv::GLSLstd450Step;
break;
case glslang::EOpSmoothStep:
libCall = GLSL_STD_450::SmoothStep;
libCall = spv::GLSLstd450SmoothStep;
break;
case glslang::EOpDistance:
libCall = GLSL_STD_450::Distance;
libCall = spv::GLSLstd450Distance;
break;
case glslang::EOpCross:
libCall = GLSL_STD_450::Cross;
libCall = spv::GLSLstd450Cross;
break;
case glslang::EOpFaceForward:
libCall = GLSL_STD_450::FaceForward;
libCall = spv::GLSLstd450FaceForward;
break;
case glslang::EOpReflect:
libCall = GLSL_STD_450::Reflect;
libCall = spv::GLSLstd450Reflect;
break;
case glslang::EOpRefract:
libCall = GLSL_STD_450::Refract;
libCall = spv::GLSLstd450Refract;
break;
default:
@ -2444,26 +2526,26 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
builder.createNoResultOp(spv::OpEndPrimitive);
return 0;
case glslang::EOpBarrier:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
builder.createControlBarrier(spv::ExecutionScopeDevice);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory);
builder.createControlBarrier(spv::ScopeDevice, spv::ScopeDevice, spv::MemorySemanticsMaskNone);
return 0;
case glslang::EOpMemoryBarrier:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAllMemory);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAllMemory);
return 0;
case glslang::EOpMemoryBarrierAtomicCounter:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsAtomicCounterMemoryMask);
return 0;
case glslang::EOpMemoryBarrierBuffer:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsUniformMemoryMask);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsUniformMemoryMask);
return 0;
case glslang::EOpMemoryBarrierImage:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsImageMemoryMask);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
return 0;
case glslang::EOpMemoryBarrierShared:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
return 0;
case glslang::EOpGroupMemoryBarrier:
builder.createMemoryBarrier(spv::ExecutionScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
return 0;
default:
spv::MissingFunctionality("operation with no arguments");
@ -2495,7 +2577,7 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent);
if (glslangIntermediate->getXfbMode()) {
if (symbol->getQualifier().hasXfbStride())
builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
if (symbol->getQualifier().hasXfbBuffer())
builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
if (symbol->getQualifier().hasXfbOffset())
@ -2512,14 +2594,14 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
builder.addDecoration(id, spv::DecorationBinding, symbol->getQualifier().layoutBinding);
if (glslangIntermediate->getXfbMode()) {
if (symbol->getQualifier().hasXfbStride())
builder.addDecoration(id, spv::DecorationStride, symbol->getQualifier().layoutXfbStride);
builder.addDecoration(id, spv::DecorationXfbStride, symbol->getQualifier().layoutXfbStride);
if (symbol->getQualifier().hasXfbBuffer())
builder.addDecoration(id, spv::DecorationXfbBuffer, symbol->getQualifier().layoutXfbBuffer);
}
// built-in variable decorations
spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn);
if ((unsigned int)builtIn != spv::BadValue)
if (builtIn != spv::BadValue)
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
if (linkageOnly)

50
SPIRV/SPVRemapper.cpp Normal file → Executable file
View file

@ -82,6 +82,8 @@ namespace spv {
case spv::OpTypeFloat: // fall through...
case spv::OpTypePointer: return range_t(2, 3);
case spv::OpTypeInt: return range_t(2, 4);
// TODO: case spv::OpTypeImage:
// TODO: case spv::OpTypeSampledImage:
case spv::OpTypeSampler: return range_t(3, 8);
case spv::OpTypeVector: // fall through
case spv::OpTypeMatrix: // ...
@ -164,8 +166,8 @@ namespace spv {
case spv::OpTypeFloat:
case spv::OpTypeVector:
case spv::OpTypeMatrix:
case spv::OpTypeImage:
case spv::OpTypeSampler:
case spv::OpTypeFilter:
case spv::OpTypeArray:
case spv::OpTypeRuntimeArray:
case spv::OpTypeStruct:
@ -184,12 +186,11 @@ namespace spv {
bool spirvbin_t::isConstOp(spv::Op opCode) const
{
switch (opCode) {
case spv::OpConstantNullObject: error("unimplemented constant type");
case spv::OpConstantNull: error("unimplemented constant type");
case spv::OpConstantSampler: error("unimplemented constant type");
case spv::OpConstantTrue:
case spv::OpConstantFalse:
case spv::OpConstantNullPointer:
case spv::OpConstantComposite:
case spv::OpConstant: return true;
default: return false;
@ -486,7 +487,7 @@ namespace spv {
case spv::OperandFunction:
case spv::OperandMemorySemantics:
case spv::OperandMemoryAccess:
case spv::OperandExecutionScope:
case spv::OperandScope:
case spv::OperandGroupOperation:
case spv::OperandKernelEnqueueFlags:
case spv::OperandKernelProfilingInfo:
@ -610,19 +611,14 @@ namespace spv {
fnId = asId(start + 2);
break;
case spv::OpTextureSample:
case spv::OpTextureSampleDref:
case spv::OpTextureSampleLod:
case spv::OpTextureSampleProj:
case spv::OpTextureSampleGrad:
case spv::OpTextureSampleOffset:
case spv::OpTextureSampleProjLod:
case spv::OpTextureSampleProjGrad:
case spv::OpTextureSampleLodOffset:
case spv::OpTextureSampleProjOffset:
case spv::OpTextureSampleGradOffset:
case spv::OpTextureSampleProjLodOffset:
case spv::OpTextureSampleProjGradOffset:
case spv::OpImageSampleImplicitLod:
case spv::OpImageSampleExplicitLod:
case spv::OpImageSampleDrefImplicitLod:
case spv::OpImageSampleDrefExplicitLod:
case spv::OpImageSampleProjImplicitLod:
case spv::OpImageSampleProjExplicitLod:
case spv::OpImageSampleProjDrefImplicitLod:
case spv::OpImageSampleProjDrefExplicitLod:
case spv::OpDot:
case spv::OpCompositeExtract:
case spv::OpCompositeInsert:
@ -668,7 +664,7 @@ namespace spv {
process(
[&](spv::Op opCode, unsigned start) {
// Add inputs and uniforms to the map
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
if ((opCode == spv::OpVariable && asWordCount(start) == 4) &&
(spv[start+3] == spv::StorageClassUniform ||
spv[start+3] == spv::StorageClassUniformConstant ||
spv[start+3] == spv::StorageClassInput))
@ -695,7 +691,7 @@ namespace spv {
process(
[&](spv::Op opCode, unsigned start) {
// Add inputs and uniforms to the map
if (((opCode == spv::OpVariable && asWordCount(start) == 4) || (opCode == spv::OpVariableArray)) &&
if ((opCode == spv::OpVariable && asWordCount(start) == 4) &&
(spv[start+3] == spv::StorageClassOutput))
fnLocalVars.insert(asId(start+2));
@ -729,8 +725,7 @@ namespace spv {
const int wordCount = asWordCount(start);
// Add local variables to the map
if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4) ||
(opCode == spv::OpVariableArray && spv[start+3] == spv::StorageClassFunction))
if ((opCode == spv::OpVariable && spv[start+3] == spv::StorageClassFunction && asWordCount(start) == 4))
fnLocalVars.insert(asId(start+2));
// Ignore process vars referenced via access chain
@ -1008,14 +1003,14 @@ namespace spv {
return 6 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
case spv::OpTypeMatrix:
return 30 + hashType(typePos(spv[typeStart+2])) * (spv[typeStart+3] - 1);
case spv::OpTypeSampler:
case spv::OpTypeImage:
return 120 + hashType(typePos(spv[typeStart+2])) +
spv[typeStart+3] + // dimensionality
spv[typeStart+4] * 8 * 16 + // content
spv[typeStart+4] * 8 * 16 + // depth
spv[typeStart+5] * 4 * 16 + // arrayed
spv[typeStart+6] * 2 * 16 + // compare
spv[typeStart+7] * 1 * 16; // multisampled
case spv::OpTypeFilter:
spv[typeStart+6] * 2 * 16 + // multisampled
spv[typeStart+7] * 1 * 16; // format
case spv::OpTypeSampler:
return 500;
case spv::OpTypeArray:
return 501 + hashType(typePos(spv[typeStart+2])) * spv[typeStart+3];
@ -1045,12 +1040,11 @@ namespace spv {
case spv::OpTypeQueue: return 300003;
case spv::OpTypePipe: return 300004;
case spv::OpConstantNullObject: return 300005;
case spv::OpConstantNull: return 300005;
case spv::OpConstantSampler: return 300006;
case spv::OpConstantTrue: return 300007;
case spv::OpConstantFalse: return 300008;
case spv::OpConstantNullPointer: return 300009;
case spv::OpConstantComposite:
{
std::uint32_t hash = 300011 + hashType(typePos(spv[typeStart+1]));

2
SPIRV/SPVRemapper.h Normal file → Executable file
View file

@ -101,7 +101,7 @@ public:
#include <set>
#include <cassert>
#include "spirv.h"
#include "spirv.hpp"
#include "spvIR.h"
namespace spv {

198
SPIRV/SpvBuilder.cpp Normal file → Executable file
View file

@ -295,31 +295,54 @@ Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
return type->getResultId();
}
Id Builder::makeSampler(Id sampledType, Dim dim, samplerContent content, bool arrayed, bool shadow, bool ms)
Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format)
{
// try to find it
Instruction* type;
for (int t = 0; t < (int)groupedTypes[OpTypeSampler].size(); ++t) {
type = groupedTypes[OpTypeSampler][t];
for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) {
type = groupedTypes[OpTypeImage][t];
if (type->getIdOperand(0) == sampledType &&
type->getImmediateOperand(1) == (unsigned int)dim &&
type->getImmediateOperand(2) == (unsigned int)content &&
type->getImmediateOperand(2) == ( depth ? 1u : 0u) &&
type->getImmediateOperand(3) == (arrayed ? 1u : 0u) &&
type->getImmediateOperand(4) == ( shadow ? 1u : 0u) &&
type->getImmediateOperand(5) == ( ms ? 1u : 0u))
type->getImmediateOperand(4) == ( ms ? 1u : 0u) &&
type->getImmediateOperand(5) == sampled &&
type->getImmediateOperand(6) == (unsigned int)format)
return type->getResultId();
}
// not found, make it
type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
type = new Instruction(getUniqueId(), NoType, OpTypeImage);
type->addIdOperand(sampledType);
type->addImmediateOperand( dim);
type->addImmediateOperand(content);
type->addImmediateOperand( depth ? 1 : 0);
type->addImmediateOperand(arrayed ? 1 : 0);
type->addImmediateOperand( shadow ? 1 : 0);
type->addImmediateOperand( ms ? 1 : 0);
type->addImmediateOperand(sampled);
type->addImmediateOperand((unsigned int)format);
groupedTypes[OpTypeSampler].push_back(type);
groupedTypes[OpTypeImage].push_back(type);
constantsTypesGlobals.push_back(type);
module.mapInstruction(type);
return type->getResultId();
}
Id Builder::makeSampledImageType(Id imageType)
{
// try to find it
Instruction* type;
for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) {
type = groupedTypes[OpTypeSampledImage][t];
if (type->getIdOperand(0) == imageType)
return type->getResultId();
}
// not found, make it
type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage);
type->addIdOperand(imageType);
groupedTypes[OpTypeSampledImage].push_back(type);
constantsTypesGlobals.push_back(type);
module.mapInstruction(type);
@ -606,11 +629,12 @@ Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
return c->getResultId();
}
void Builder::addEntryPoint(ExecutionModel model, Function* function)
void Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
{
Instruction* entryPoint = new Instruction(OpEntryPoint);
entryPoint->addImmediateOperand(model);
entryPoint->addIdOperand(function->getId());
entryPoint->addStringOperand(name);
entryPoints.push_back(entryPoint);
}
@ -945,18 +969,20 @@ void Builder::createNoResultOp(Op opCode, Id operand)
buildPoint->addInstruction(op);
}
void Builder::createControlBarrier(unsigned executionScope)
void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics)
{
Instruction* op = new Instruction(OpControlBarrier);
op->addImmediateOperand(executionScope);
op->addImmediateOperand(makeUintConstant(execution));
op->addImmediateOperand(makeUintConstant(memory));
op->addImmediateOperand(makeUintConstant(semantics));
buildPoint->addInstruction(op);
}
void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics)
{
Instruction* op = new Instruction(OpMemoryBarrier);
op->addImmediateOperand(executionScope);
op->addImmediateOperand(memorySemantics);
op->addImmediateOperand(makeUintConstant(executionScope));
op->addImmediateOperand(makeUintConstant(memorySemantics));
buildPoint->addInstruction(op);
}
@ -991,7 +1017,7 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3)
return op->getResultId();
}
Id Builder::createOp(Op opCode, Id typeId, std::vector<Id>& operands)
Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands)
{
Instruction* op = new Instruction(getUniqueId(), typeId, opCode);
for (auto operand : operands)
@ -1107,64 +1133,95 @@ Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builti
// Create the correct instruction based on the inputs, and make the call.
Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, const TextureParameters& parameters)
{
static const int maxTextureArgs = 5;
static const int maxTextureArgs = 10;
Id texArgs[maxTextureArgs] = {};
//
// Set up the arguments
// Set up the fixed arguments
//
int numArgs = 0;
bool xplicit = false;
texArgs[numArgs++] = parameters.sampler;
texArgs[numArgs++] = parameters.coords;
if (parameters.gradX) {
texArgs[numArgs++] = parameters.gradX;
texArgs[numArgs++] = parameters.gradY;
}
if (parameters.lod)
texArgs[numArgs++] = parameters.lod;
if (parameters.offset)
texArgs[numArgs++] = parameters.offset;
if (parameters.bias)
texArgs[numArgs++] = parameters.bias;
if (parameters.Dref)
texArgs[numArgs++] = parameters.Dref;
//
// Set up the optional arguments
//
int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments
++numArgs; // speculatively make room for the mask operand
ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand
if (parameters.bias) {
mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask);
texArgs[numArgs++] = parameters.bias;
}
if (parameters.lod) {
mask = (ImageOperandsMask)(mask | ImageOperandsLodMask);
texArgs[numArgs++] = parameters.lod;
xplicit = true;
}
if (parameters.gradX) {
mask = (ImageOperandsMask)(mask | ImageOperandsGradMask);
texArgs[numArgs++] = parameters.gradX;
texArgs[numArgs++] = parameters.gradY;
xplicit = true;
}
if (parameters.offset) {
mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask);
texArgs[numArgs++] = parameters.offset;
}
// TBD: if Offset is constant, use ImageOperandsConstOffsetMask
if (parameters.offsets) {
mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask);
texArgs[numArgs++] = parameters.offsets;
}
if (parameters.sample) {
mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask);
texArgs[numArgs++] = parameters.sample;
}
if (mask == ImageOperandsMaskNone)
--numArgs; // undo speculative reservation for the mask argument
else
texArgs[optArgNum] = mask;
//
// Set up the instruction
//
Op opCode;
if (proj && parameters.gradX && parameters.offset)
opCode = OpTextureSampleProjGradOffset;
else if (proj && parameters.lod && parameters.offset)
opCode = OpTextureSampleProjLodOffset;
else if (parameters.gradX && parameters.offset)
opCode = OpTextureSampleGradOffset;
else if (proj && parameters.offset)
opCode = OpTextureSampleProjOffset;
else if (parameters.lod && parameters.offset)
opCode = OpTextureSampleLodOffset;
else if (proj && parameters.gradX)
opCode = OpTextureSampleProjGrad;
else if (proj && parameters.lod)
opCode = OpTextureSampleProjLod;
else if (parameters.offset)
opCode = OpTextureSampleOffset;
else if (parameters.gradX)
opCode = OpTextureSampleGrad;
else if (proj)
opCode = OpTextureSampleProj;
else if (parameters.lod)
opCode = OpTextureSampleLod;
else if (parameters.Dref)
opCode = OpTextureSampleDref;
else
opCode = OpTextureSample;
opCode = OpImageSampleImplicitLod;
if (xplicit) {
if (parameters.Dref) {
if (proj)
opCode = OpImageSampleProjDrefExplicitLod;
else
opCode = OpImageSampleDrefExplicitLod;
} else {
if (proj)
opCode = OpImageSampleProjExplicitLod;
else
opCode = OpImageSampleExplicitLod;
}
} else {
if (parameters.Dref) {
if (proj)
opCode = OpImageSampleProjDrefImplicitLod;
else
opCode = OpImageSampleDrefImplicitLod;
} else {
if (proj)
opCode = OpImageSampleProjImplicitLod;
else
opCode = OpImageSampleImplicitLod;
}
}
Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
for (int op = 0; op < numArgs; ++op)
for (int op = 0; op < optArgNum; ++op)
textureInst->addIdOperand(texArgs[op]);
if (optArgNum < numArgs)
textureInst->addImmediateOperand(texArgs[optArgNum]);
for (int op = optArgNum + 1; op < numArgs; ++op)
textureInst->addIdOperand(texArgs[op]);
setPrecision(textureInst->getResultId(), precision);
buildPoint->addInstruction(textureInst);
@ -1176,13 +1233,13 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool proj, co
Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters)
{
// Figure out the result type
Id resultType = NoType;
Id resultType = 0;
switch (opCode) {
case OpTextureQuerySize:
case OpTextureQuerySizeLod:
case OpImageQuerySize:
case OpImageQuerySizeLod:
{
int numComponents;
switch (getDimensionality(parameters.sampler)) {
switch (getTypeDimensionality(getImageType(parameters.sampler))) {
case Dim1D:
case DimBuffer:
numComponents = 1;
@ -1199,7 +1256,7 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter
MissingFunctionality("texture query dimensionality");
break;
}
if (isArrayedSampler(parameters.sampler))
if (isArrayedImageType(getImageType(parameters.sampler)))
++numComponents;
if (numComponents == 1)
resultType = makeIntType(32);
@ -1208,11 +1265,11 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter
break;
}
case OpTextureQueryLod:
case OpImageQueryLod:
resultType = makeVectorType(makeFloatType(32), 2);
break;
case OpTextureQueryLevels:
case OpTextureQuerySamples:
case OpImageQueryLevels:
case OpImageQuerySamples:
resultType = makeIntType(32);
break;
default:
@ -2040,7 +2097,16 @@ void Builder::dump(std::vector<unsigned int>& out) const
extInst.addStringOperand(extensions[e]);
extInst.dump(out);
}
// TBD: OpExtension ...
// Capabilities
for (auto cap : capabilities) {
Instruction capInst(0, 0, OpCapability);
capInst.addImmediateOperand(cap);
capInst.dump(out);
}
dumpInstructions(out, imports);
Instruction memInst(0, 0, OpMemoryModel);
memInst.addImmediateOperand(addressModel);

40
SPIRV/SpvBuilder.h Normal file → Executable file
View file

@ -48,7 +48,7 @@
#ifndef SpvBuilder_H
#define SpvBuilder_H
#include "spirv.h"
#include "spirv.hpp"
#include "spvIR.h"
#include <algorithm>
@ -77,6 +77,8 @@ public:
memoryModel = mem;
}
void addCapability(spv::Capability cap) { capabilities.push_back(cap); }
// To get a new <id> for anything needing a new one.
Id getUniqueId() { return ++uniqueId; }
@ -101,12 +103,8 @@ public:
Id makeMatrixType(Id component, int cols, int rows);
Id makeArrayType(Id element, unsigned size);
Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
enum samplerContent {
samplerContentTexture,
samplerContentImage,
samplerContentTextureFilter
};
Id makeSampler(Id sampledType, Dim, samplerContent, bool arrayed, bool shadow, bool ms);
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
Id makeSampledImageType(Id imageType);
// For querying about types.
Id getTypeId(Id resultId) const { return module.getTypeId(resultId); }
@ -133,7 +131,9 @@ public:
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
bool isArrayType(Id typeId) const { return getTypeClass(typeId) == OpTypeArray; }
bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId); }
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
@ -151,15 +151,20 @@ public:
}
int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); }
Dim getDimensionality(Id resultId) const
Dim getTypeDimensionality(Id typeId) const
{
assert(isSamplerType(getTypeId(resultId)));
return (Dim)module.getInstruction(getTypeId(resultId))->getImmediateOperand(1);
assert(isImageType(typeId));
return (Dim)module.getInstruction(typeId)->getImmediateOperand(1);
}
bool isArrayedSampler(Id resultId) const
Id getImageType(Id resultId) const
{
assert(isSamplerType(getTypeId(resultId)));
return module.getInstruction(getTypeId(resultId))->getImmediateOperand(3) != 0;
assert(isSampledImageType(getTypeId(resultId)));
return module.getInstruction(getTypeId(resultId))->getIdOperand(0);
}
bool isArrayedImageType(Id typeId) const
{
assert(isImageType(typeId));
return module.getInstruction(typeId)->getImmediateOperand(3) != 0;
}
// For making new constants (will return old constant if the requested one was already made).
@ -174,7 +179,7 @@ public:
Id makeCompositeConstant(Id type, std::vector<Id>& comps);
// Methods for adding information outside the CFG.
void addEntryPoint(ExecutionModel, Function*);
void addEntryPoint(ExecutionModel, Function*, const char* name);
void addExecutionMode(Function*, ExecutionMode mode, int value = -1);
void addName(Id, const char* name);
void addMemberName(Id, int member, const char* name);
@ -233,12 +238,12 @@ public:
void createNoResultOp(Op);
void createNoResultOp(Op, Id operand);
void createControlBarrier(unsigned executionScope);
void createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask);
void createMemoryBarrier(unsigned executionScope, unsigned memorySemantics);
Id createUnaryOp(Op, Id typeId, Id operand);
Id createBinOp(Op, Id typeId, Id operand1, Id operand2);
Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3);
Id createOp(Op, Id typeId, std::vector<Id>& operands);
Id createOp(Op, Id typeId, const std::vector<Id>& operands);
Id createFunctionCall(spv::Function*, std::vector<spv::Id>&);
// Take an rvalue (source) and a set of channels to extract from it to
@ -283,8 +288,10 @@ public:
Id lod;
Id Dref;
Id offset;
Id offsets;
Id gradX;
Id gradY;
Id sample;
};
// Select the correct texture operation based on all inputs, and emit the correct instruction
@ -497,6 +504,7 @@ protected:
std::vector<const char*> extensions;
AddressingModel addressModel;
MemoryModel memoryModel;
std::vector<spv::Capability> capabilities;
int builderNumber;
Module module;
Block* buildPoint;

209
SPIRV/disassemble.cpp Normal file → Executable file
View file

@ -1,5 +1,5 @@
//
//Copyright (C) 2014 LunarG, Inc.
//Copyright (C) 2014-2015 LunarG, Inc.
//
//All rights reserved.
//
@ -21,16 +21,16 @@
//
//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 MERCHANTAstreamITY AND FITNESS
//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 LIAstreamITY, WHETHER IN CONTRACT, STRICT
//LIAstreamITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//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
//POSSIstreamITY OF SUCH DAMAGE.
//POSSIBILITY OF SUCH DAMAGE.
//
// Author: John Kessenich, LunarG
@ -41,25 +41,34 @@
//
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iomanip>
#include <stack>
#include <sstream>
#include "GLSL450Lib.h"
extern const char* GlslStd450DebugNames[GLSL_STD_450::Count];
#include <cstring>
#include "disassemble.h"
#include "doc.h"
namespace spv {
#include "GLSL.std.450.h"
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
void Kill(std::ostream& out, const char* message)
{
out << std::endl << "Disassembly failed: " << message << std::endl;
exit(1);
}
// used to identify the extended instruction library imported when printing
enum ExtInstSet {
GLSL450Inst,
OpenCLExtInst,
};
// Container class for a single instance of a SPIR-V stream, with methods for disassembly.
class SpirvStream {
public:
@ -70,9 +79,8 @@ public:
void processInstructions();
protected:
SpirvStream(SpirvStream&);
SpirvStream& operator=(SpirvStream&);
SpirvStream(const SpirvStream&);
SpirvStream& operator=(const SpirvStream&);
Op getOpCode(int id) const { return idInstruction[id] ? (Op)(stream[idInstruction[id]] & OpCodeMask) : OpNop; }
// Output methods
@ -81,6 +89,7 @@ protected:
void outputResultId(Id id);
void outputTypeId(Id id);
void outputId(Id id);
void outputMask(OperandClass operandClass, unsigned mask);
void disassembleImmediates(int numOperands);
void disassembleIds(int numOperands);
void disassembleString();
@ -241,6 +250,18 @@ void SpirvStream::outputId(Id id)
out << "(" << idDescriptor[id] << ")";
}
void SpirvStream::outputMask(OperandClass operandClass, unsigned mask)
{
if (mask == 0)
out << "None";
else {
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
if (mask & (1 << m))
out << OperandClassParams[operandClass].getName(m) << " ";
}
}
}
void SpirvStream::disassembleImmediates(int numOperands)
{
for (int i = 0; i < numOperands; ++i) {
@ -294,8 +315,9 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
nestedControl.push(nextNestedControl);
nextNestedControl = 0;
}
} else if (opCode == OpExtInstImport)
} else if (opCode == OpExtInstImport) {
idDescriptor[resultId] = (char*)(&stream[word]);
}
else {
if (idDescriptor[resultId].size() == 0) {
switch (opCode) {
@ -337,27 +359,35 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
// Process the operands. Note, a new context-dependent set could be
// swapped in mid-traversal.
// Handle textures specially, so can put out helpful strings.
if (opCode == OpTypeSampler) {
// Handle images specially, so can put out helpful strings.
if (opCode == OpTypeImage) {
out << " ";
disassembleIds(1);
out << " " << DimensionString((Dim)stream[word++]);
switch (stream[word++]) {
case 0: out << " texture"; break;
case 1: out << " image"; break;
case 2: out << " filter+texture"; break;
}
out << (stream[word++] != 0 ? " array" : "");
out << (stream[word++] != 0 ? " depth" : "");
out << (stream[word++] != 0 ? " array" : "");
out << (stream[word++] != 0 ? " multi-sampled" : "");
switch (stream[word++]) {
case 0: out << " runtime"; break;
case 1: out << " sampled"; break;
case 2: out << " nonsampled"; break;
}
out << " format:" << ImageFormatString((ImageFormat)stream[word++]);
if (numOperands == 8) {
out << " " << AccessQualifierString(stream[word++]);
}
return;
}
// Handle all the parameterized operands
for (int op = 0; op < InstructionDesc[opCode].operands.getNum(); ++op) {
for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) {
out << " ";
OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op);
switch (operandClass) {
case OperandId:
case OperandScope:
case OperandMemorySemantics:
disassembleIds(1);
// Get names for printing "(XXX)" for readability, *after* this id
if (opCode == OpName)
@ -367,15 +397,34 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
case OperandVariableIds:
disassembleIds(numOperands);
return;
case OperandOptionalImage:
outputMask(operandClass, stream[word++]);
--numOperands;
disassembleIds(numOperands);
return;
case OperandOptionalLiteral:
case OperandVariableLiterals:
if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) ||
(opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) {
if (opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn ||
opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn) {
out << BuiltInString(stream[word++]);
--numOperands;
++op;
}
disassembleImmediates(numOperands);
return;
case OperandVariableIdLiteral:
while (numOperands > 0) {
out << std::endl;
outputResultId(0);
outputTypeId(0);
outputIndent();
out << " Type ";
disassembleIds(1);
out << ", member ";
disassembleImmediates(1);
numOperands -= 2;
}
return;
case OperandVariableLiteralId:
while (numOperands > 0) {
out << std::endl;
@ -392,9 +441,16 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
case OperandLiteralNumber:
disassembleImmediates(1);
if (opCode == OpExtInst) {
ExtInstSet extInstSet = GLSL450Inst;
if (0 == memcmp("OpenCL", (char*)(idDescriptor[stream[word-2]].c_str()), 6)) {
extInstSet = OpenCLExtInst;
}
unsigned entrypoint = stream[word - 1];
if (entrypoint < GLSL_STD_450::Count)
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
if (extInstSet == GLSL450Inst) {
if (entrypoint < spv::GLSLstd450Count) {
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
}
}
}
break;
case OperandLiteralString:
@ -403,18 +459,9 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
default:
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
if (OperandClassParams[operandClass].bitmask) {
unsigned int mask = stream[word++];
if (mask == 0)
out << "None";
else {
for (int m = 0; m < OperandClassParams[operandClass].ceiling; ++m) {
if (mask & (1 << m))
out << OperandClassParams[operandClass].getName(m) << " ";
}
}
break;
} else
if (OperandClassParams[operandClass].bitmask)
outputMask(operandClass, stream[word++]);
else
out << OperandClassParams[operandClass].getName(stream[word++]);
break;
@ -425,9 +472,97 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
return;
}
void GLSLstd450GetDebugNames(const char** names)
{
for (int i = 0; i < GLSLstd450Count; ++i)
names[i] = "Unknown";
names[GLSLstd450Round] = "Round";
names[GLSLstd450RoundEven] = "RoundEven";
names[GLSLstd450Trunc] = "Trunc";
names[GLSLstd450FAbs] = "FAbs";
names[GLSLstd450SAbs] = "SAbs";
names[GLSLstd450FSign] = "FSign";
names[GLSLstd450SSign] = "SSign";
names[GLSLstd450Floor] = "Floor";
names[GLSLstd450Ceil] = "Ceil";
names[GLSLstd450Fract] = "Fract";
names[GLSLstd450Radians] = "Radians";
names[GLSLstd450Degrees] = "Degrees";
names[GLSLstd450Sin] = "Sin";
names[GLSLstd450Cos] = "Cos";
names[GLSLstd450Tan] = "Tan";
names[GLSLstd450Asin] = "Asin";
names[GLSLstd450Acos] = "Acos";
names[GLSLstd450Atan] = "Atan";
names[GLSLstd450Sinh] = "Sinh";
names[GLSLstd450Cosh] = "Cosh";
names[GLSLstd450Tanh] = "Tanh";
names[GLSLstd450Asinh] = "Asinh";
names[GLSLstd450Acosh] = "Acosh";
names[GLSLstd450Atanh] = "Atanh";
names[GLSLstd450Atan2] = "Atan2";
names[GLSLstd450Pow] = "Pow";
names[GLSLstd450Exp] = "Exp";
names[GLSLstd450Log] = "Log";
names[GLSLstd450Exp2] = "Exp2";
names[GLSLstd450Log2] = "Log2";
names[GLSLstd450Sqrt] = "Sqrt";
names[GLSLstd450InverseSqrt] = "Inversesqrt";
names[GLSLstd450Determinant] = "Determinant";
names[GLSLstd450MatrixInverse] = "Inverse";
names[GLSLstd450Modf] = "Modf";
names[GLSLstd450ModfStruct] = "ModfStruct";
names[GLSLstd450FMin] = "FMin";
names[GLSLstd450SMin] = "SMin";
names[GLSLstd450UMin] = "UMin";
names[GLSLstd450FMax] = "FMax";
names[GLSLstd450SMax] = "SMax";
names[GLSLstd450UMax] = "UMax";
names[GLSLstd450FClamp] = "FClamp";
names[GLSLstd450SClamp] = "SClamp";
names[GLSLstd450UClamp] = "UClamp";
names[GLSLstd450Mix] = "Mix";
names[GLSLstd450Step] = "Step";
names[GLSLstd450SmoothStep] = "Smoothstep";
names[GLSLstd450Fma] = "Fma";
names[GLSLstd450Frexp] = "Frexp";
names[GLSLstd450FrexpStruct] = "FrexpStruct";
names[GLSLstd450Ldexp] = "Ldexp";
names[GLSLstd450PackSnorm4x8] = "PackSnorm4x8";
names[GLSLstd450PackUnorm4x8] = "PackUnorm4x8";
names[GLSLstd450PackSnorm2x16] = "PackSnorm2x16";
names[GLSLstd450PackUnorm2x16] = "PackUnorm2x16";
names[GLSLstd450PackHalf2x16] = "PackHalf2x16";
names[GLSLstd450PackDouble2x32] = "PackDouble2x32";
names[GLSLstd450UnpackSnorm2x16] = "UnpackSnorm2x16";
names[GLSLstd450UnpackUnorm2x16] = "UnpackUnorm2x16";
names[GLSLstd450UnpackHalf2x16] = "UnpackHalf2x16";
names[GLSLstd450UnpackSnorm4x8] = "UnpackSnorm4x8";
names[GLSLstd450UnpackUnorm4x8] = "UnpackUnorm4x8";
names[GLSLstd450UnpackDouble2x32] = "UnpackDouble2x32";
names[GLSLstd450Length] = "Length";
names[GLSLstd450Distance] = "Distance";
names[GLSLstd450Cross] = "Cross";
names[GLSLstd450Normalize] = "Normalize";
names[GLSLstd450FaceForward] = "Faceforward";
names[GLSLstd450Reflect] = "Reflect";
names[GLSLstd450Refract] = "Refract";
names[GLSLstd450AddCarry] = "UaddCarry";
names[GLSLstd450SubBorrow] = "UsubBorrow";
names[GLSLstd450MulExtended] = "UmulExtended";
names[GLSLstd450FindILSB] = "FindILsb";
names[GLSLstd450FindSMSB] = "FindSMsb";
names[GLSLstd450FindUMSB] = "FindUMsb";
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
}
void Disassemble(std::ostream& out, const std::vector<unsigned int>& stream)
{
SpirvStream SpirvStream(out, stream);
GLSLstd450GetDebugNames(GlslStd450DebugNames);
SpirvStream.validate();
SpirvStream.processInstructions();
}

2
SPIRV/disassemble.h Normal file → Executable file
View file

@ -1,5 +1,5 @@
//
//Copyright (C) 2014 LunarG, Inc.
//Copyright (C) 2014-2015 LunarG, Inc.
//
//All rights reserved.
//

1977
SPIRV/doc.cpp Normal file → Executable file

File diff suppressed because it is too large Load diff

46
SPIRV/doc.h Normal file → Executable file
View file

@ -1,5 +1,5 @@
//
//Copyright (C) 2014 LunarG, Inc.
//Copyright (C) 2014-2015 LunarG, Inc.
//
//All rights reserved.
//
@ -40,7 +40,7 @@
// Parameterize the SPIR-V enumerants.
//
#include "spirv.h"
#include "spirv.hpp"
#include <vector>
@ -64,6 +64,10 @@ const char* LoopControlString(int);
const char* FunctionControlString(int);
const char* SamplerAddressingModeString(int);
const char* SamplerFilterModeString(int);
const char* ImageFormatString(int);
const char* ImageChannelOrderString(int);
const char* ImageChannelTypeString(int);
const char* ImageOperands(int);
const char* FPFastMathString(int);
const char* FPRoundingModeString(int);
const char* LinkageTypeString(int);
@ -75,11 +79,12 @@ const char* ExecutionScopeString(int);
const char* GroupOperationString(int);
const char* KernelEnqueueFlagsString(int);
const char* KernelProfilingInfoString(int);
const char* CapabilityString(int);
const char* OpcodeString(int);
// For grouping opcodes into subsections
enum OpcodeClass {
OpClassMisc, // default, until opcode is classified
OpClassMisc,
OpClassDebug,
OpClassAnnotate,
OpClassExtension,
@ -88,10 +93,11 @@ enum OpcodeClass {
OpClassConstant,
OpClassMemory,
OpClassFunction,
OpClassTexture,
OpClassImage,
OpClassConvert,
OpClassComposite,
OpClassArithmetic,
OpClassBit,
OpClassRelationalLogical,
OpClassDerivative,
OpClassFlowControl,
@ -102,7 +108,8 @@ enum OpcodeClass {
OpClassDeviceSideEnqueue,
OpClassPipe,
OpClassCount
OpClassCount,
OpClassMissing // all instructions start out as missing
};
// For parameterizing operands.
@ -110,8 +117,11 @@ enum OperandClass {
OperandNone,
OperandId,
OperandOptionalId,
OperandOptionalImage,
OperandVariableIds,
OperandOptionalLiteral,
OperandVariableLiterals,
OperandVariableIdLiteral,
OperandVariableLiteralId,
OperandLiteralNumber,
OperandLiteralString,
@ -124,6 +134,10 @@ enum OperandClass {
OperandDimensionality,
OperandSamplerAddressingMode,
OperandSamplerFilterMode,
OperandSamplerImageFormat,
OperandImageChannelOrder,
OperandImageChannelDataType,
OperandImageOperands,
OperandFPFastMath,
OperandFPRoundingMode,
OperandLinkageType,
@ -136,29 +150,17 @@ enum OperandClass {
OperandFunction,
OperandMemorySemantics,
OperandMemoryAccess,
OperandExecutionScope,
OperandScope,
OperandGroupOperation,
OperandKernelEnqueueFlags,
OperandKernelProfilingInfo,
OperandCapability,
OperandOpcode,
OperandCount
};
// Set of capabilities. Generally, something is assumed to be in core,
// if nothing else is said. So, these are used to identify when something
// requires a specific capability to be declared.
enum Capability {
CapMatrix,
CapShader,
CapGeom,
CapTess,
CapAddr,
CapLink,
CapKernel
};
// Any specific enum can have a set of capabilities that allow it:
typedef std::vector<Capability> EnumCaps;
@ -213,8 +215,8 @@ public:
class InstructionParameters {
public:
InstructionParameters() :
opDesc(0),
opClass(OpClassMisc),
opDesc("TBD"),
opClass(OpClassMissing),
typePresent(true), // most normal, only exceptions have to be spelled out
resultPresent(true) // most normal, only exceptions have to be spelled out
{ }
@ -238,7 +240,7 @@ protected:
int resultPresent : 1;
};
const int OpcodeCeiling = 267;
const int OpcodeCeiling = 305;
// The set of objects that hold all the instruction/operand
// parameterization information.

2
SPIRV/spvIR.h Normal file → Executable file
View file

@ -50,7 +50,7 @@
#ifndef spvIR_H
#define spvIR_H
#include "spirv.h"
#include "spirv.hpp"
#include <vector>
#include <iostream>