SPIR-V: Move from Version .99 Rev 31 to Version 1.0, Rev 2.
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
#define GLSLstd450_H
|
||||
|
||||
const int GLSLstd450Version = 99;
|
||||
const int GLSLstd450Revision = 2;
|
||||
const int GLSLstd450Revision = 3;
|
||||
|
||||
enum GLSLstd450 {
|
||||
GLSLstd450Bad = 0, // Don't use
|
||||
@@ -82,47 +82,44 @@ enum GLSLstd450 {
|
||||
GLSLstd450FClamp = 43,
|
||||
GLSLstd450UClamp = 44,
|
||||
GLSLstd450SClamp = 45,
|
||||
GLSLstd450Mix = 46,
|
||||
GLSLstd450Step = 47,
|
||||
GLSLstd450SmoothStep = 48,
|
||||
GLSLstd450FMix = 46,
|
||||
GLSLstd450IMix = 47,
|
||||
GLSLstd450Step = 48,
|
||||
GLSLstd450SmoothStep = 49,
|
||||
|
||||
GLSLstd450Fma = 49,
|
||||
GLSLstd450Frexp = 50, // second operand needs an OpVariable to write to
|
||||
GLSLstd450FrexpStruct = 51, // no OpVariable operand
|
||||
GLSLstd450Ldexp = 52,
|
||||
GLSLstd450Fma = 50,
|
||||
GLSLstd450Frexp = 51, // second operand needs an OpVariable to write to
|
||||
GLSLstd450FrexpStruct = 52, // no OpVariable operand
|
||||
GLSLstd450Ldexp = 53,
|
||||
|
||||
GLSLstd450PackSnorm4x8 = 53,
|
||||
GLSLstd450PackUnorm4x8 = 54,
|
||||
GLSLstd450PackSnorm2x16 = 55,
|
||||
GLSLstd450PackUnorm2x16 = 56,
|
||||
GLSLstd450PackHalf2x16 = 57,
|
||||
GLSLstd450PackDouble2x32 = 58,
|
||||
GLSLstd450UnpackSnorm2x16 = 59,
|
||||
GLSLstd450UnpackUnorm2x16 = 60,
|
||||
GLSLstd450UnpackHalf2x16 = 61,
|
||||
GLSLstd450UnpackSnorm4x8 = 62,
|
||||
GLSLstd450UnpackUnorm4x8 = 63,
|
||||
GLSLstd450UnpackDouble2x32 = 64,
|
||||
GLSLstd450PackSnorm4x8 = 54,
|
||||
GLSLstd450PackUnorm4x8 = 55,
|
||||
GLSLstd450PackSnorm2x16 = 56,
|
||||
GLSLstd450PackUnorm2x16 = 57,
|
||||
GLSLstd450PackHalf2x16 = 58,
|
||||
GLSLstd450PackDouble2x32 = 59,
|
||||
GLSLstd450UnpackSnorm2x16 = 60,
|
||||
GLSLstd450UnpackUnorm2x16 = 61,
|
||||
GLSLstd450UnpackHalf2x16 = 62,
|
||||
GLSLstd450UnpackSnorm4x8 = 63,
|
||||
GLSLstd450UnpackUnorm4x8 = 64,
|
||||
GLSLstd450UnpackDouble2x32 = 65,
|
||||
|
||||
GLSLstd450Length = 65,
|
||||
GLSLstd450Distance = 66,
|
||||
GLSLstd450Cross = 67,
|
||||
GLSLstd450Normalize = 68,
|
||||
GLSLstd450FaceForward = 69,
|
||||
GLSLstd450Reflect = 70,
|
||||
GLSLstd450Refract = 71,
|
||||
GLSLstd450Length = 66,
|
||||
GLSLstd450Distance = 67,
|
||||
GLSLstd450Cross = 68,
|
||||
GLSLstd450Normalize = 69,
|
||||
GLSLstd450FaceForward = 70,
|
||||
GLSLstd450Reflect = 71,
|
||||
GLSLstd450Refract = 72,
|
||||
|
||||
GLSLstd450FindILSB = 72,
|
||||
GLSLstd450FindSMSB = 73,
|
||||
GLSLstd450FindUMSB = 74,
|
||||
GLSLstd450FindILsb = 73,
|
||||
GLSLstd450FindSMsb = 74,
|
||||
GLSLstd450FindUMsb = 75,
|
||||
|
||||
GLSLstd450InterpolateAtCentroid = 75,
|
||||
GLSLstd450InterpolateAtSample = 76,
|
||||
GLSLstd450InterpolateAtOffset = 77,
|
||||
|
||||
GLSLstd450AddCarry = 78, // These three should move to the core instruction set
|
||||
GLSLstd450SubBorrow = 79,
|
||||
GLSLstd450MulExtended = 80,
|
||||
GLSLstd450InterpolateAtCentroid = 76,
|
||||
GLSLstd450InterpolateAtSample = 77,
|
||||
GLSLstd450InterpolateAtOffset = 78,
|
||||
|
||||
GLSLstd450Count
|
||||
};
|
||||
|
||||
@@ -60,7 +60,10 @@ namespace spv {
|
||||
|
||||
namespace {
|
||||
|
||||
const int GlslangMagic = 0x51a;
|
||||
// For low-order part of the generator's magic number. Bump up
|
||||
// when there is a change in the style (e.g., if SSA form changes,
|
||||
// or a different instruction sequence to do something gets used).
|
||||
const int GeneratorVersion = 1;
|
||||
|
||||
//
|
||||
// The main holder of information for translating glslang to SPIR-V.
|
||||
@@ -113,13 +116,16 @@ protected:
|
||||
spv::Id createNoArgOperation(glslang::TOperator op);
|
||||
spv::Id getSymbolId(const glslang::TIntermSymbol* node);
|
||||
void addDecoration(spv::Id id, spv::Decoration dec);
|
||||
void addDecoration(spv::Id id, spv::Decoration dec, unsigned value);
|
||||
void addMemberDecoration(spv::Id id, int member, spv::Decoration dec);
|
||||
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst);
|
||||
spv::Id createSpvSpecConstant(const glslang::TIntermTyped&);
|
||||
spv::Id createSpvConstant(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant);
|
||||
bool isTrivialLeaf(const glslang::TIntermTyped* node);
|
||||
bool isTrivial(const glslang::TIntermTyped* node);
|
||||
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
|
||||
|
||||
spv::Function* shaderEntry;
|
||||
spv::Instruction* entryPoint;
|
||||
int sequenceDepth;
|
||||
|
||||
// There is a 1:1 mapping between a spv builder and a module; this is thread safe
|
||||
@@ -169,7 +175,7 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage)
|
||||
case EShLangFragment: return spv::ExecutionModelFragment;
|
||||
case EShLangCompute: return spv::ExecutionModelGLCompute;
|
||||
default:
|
||||
spv::MissingFunctionality("GLSL stage");
|
||||
assert(0);
|
||||
return spv::ExecutionModelFragment;
|
||||
}
|
||||
}
|
||||
@@ -191,12 +197,12 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
||||
// TODO: how are we distuingishing between default and non-default non-writable uniforms? Do default uniforms even exist?
|
||||
} else {
|
||||
switch (type.getQualifier().storage) {
|
||||
case glslang::EvqShared: return spv::StorageClassWorkgroupLocal; break;
|
||||
case glslang::EvqGlobal: return spv::StorageClassPrivateGlobal;
|
||||
case glslang::EvqShared: return spv::StorageClassWorkgroup; break;
|
||||
case glslang::EvqGlobal: return spv::StorageClassPrivate;
|
||||
case glslang::EvqConstReadOnly: return spv::StorageClassFunction;
|
||||
case glslang::EvqTemporary: return spv::StorageClassFunction;
|
||||
default:
|
||||
spv::MissingFunctionality("unknown glslang storage class");
|
||||
assert(0);
|
||||
return spv::StorageClassFunction;
|
||||
}
|
||||
}
|
||||
@@ -206,14 +212,14 @@ spv::StorageClass TranslateStorageClass(const glslang::TType& type)
|
||||
spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
|
||||
{
|
||||
switch (sampler.dim) {
|
||||
case glslang::Esd1D: return spv::Dim1D;
|
||||
case glslang::Esd2D: return spv::Dim2D;
|
||||
case glslang::Esd3D: return spv::Dim3D;
|
||||
case glslang::EsdCube: return spv::DimCube;
|
||||
case glslang::EsdRect: return spv::DimRect;
|
||||
case glslang::EsdBuffer: return spv::DimBuffer;
|
||||
case glslang::Esd1D: return spv::Dim1D;
|
||||
case glslang::Esd2D: return spv::Dim2D;
|
||||
case glslang::Esd3D: return spv::Dim3D;
|
||||
case glslang::EsdCube: return spv::DimCube;
|
||||
case glslang::EsdRect: return spv::DimRect;
|
||||
case glslang::EsdBuffer: return spv::DimBuffer;
|
||||
default:
|
||||
spv::MissingFunctionality("unknown sampler dimension");
|
||||
assert(0);
|
||||
return spv::Dim2D;
|
||||
}
|
||||
}
|
||||
@@ -240,7 +246,7 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type)
|
||||
case glslang::EvqVaryingIn: return spv::DecorationBlock;
|
||||
case glslang::EvqVaryingOut: return spv::DecorationBlock;
|
||||
default:
|
||||
spv::MissingFunctionality("kind of block");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -275,11 +281,10 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
|
||||
}
|
||||
case glslang::EvqVaryingIn:
|
||||
case glslang::EvqVaryingOut:
|
||||
if (type.getQualifier().layoutPacking != glslang::ElpNone)
|
||||
spv::MissingFunctionality("in/out block layout");
|
||||
assert(type.getQualifier().layoutPacking == glslang::ElpNone);
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
default:
|
||||
spv::MissingFunctionality("block storage qualification");
|
||||
assert(0);
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
}
|
||||
}
|
||||
@@ -287,12 +292,16 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type)
|
||||
}
|
||||
|
||||
// Translate glslang type to SPIR-V interpolation decorations.
|
||||
// Returns spv::Decoration(spv::BadValue) when no decoration
|
||||
// should be applied.
|
||||
spv::Decoration TranslateInterpolationDecoration(const glslang::TType& type)
|
||||
{
|
||||
if (type.getQualifier().smooth)
|
||||
return spv::DecorationSmooth;
|
||||
if (type.getQualifier().smooth) {
|
||||
// Smooth decoration doesn't exist in SPIR-V 1.0
|
||||
return (spv::Decoration)spv::BadValue;
|
||||
}
|
||||
if (type.getQualifier().nopersp)
|
||||
return spv::DecorationNoperspective;
|
||||
return spv::DecorationNoPerspective;
|
||||
else if (type.getQualifier().patch)
|
||||
return spv::DecorationPatch;
|
||||
else if (type.getQualifier().flat)
|
||||
@@ -344,8 +353,6 @@ spv::BuiltIn TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn)
|
||||
case glslang::EbvSampleId: return spv::BuiltInSampleId;
|
||||
case glslang::EbvSamplePosition: return spv::BuiltInSamplePosition;
|
||||
case glslang::EbvSampleMask: return spv::BuiltInSampleMask;
|
||||
case glslang::EbvFragColor: return spv::BuiltInFragColor;
|
||||
case glslang::EbvFragData: return spv::BuiltInFragColor;
|
||||
case glslang::EbvFragDepth: return spv::BuiltInFragDepth;
|
||||
case glslang::EbvHelperInvocation: return spv::BuiltInHelperInvocation;
|
||||
case glslang::EbvNumWorkGroups: return spv::BuiltInNumWorkgroups;
|
||||
@@ -414,7 +421,7 @@ spv::ImageFormat TranslateImageFormat(const glslang::TType& type)
|
||||
|
||||
TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* glslangIntermediate)
|
||||
: TIntermTraverser(true, false, true), shaderEntry(0), sequenceDepth(0),
|
||||
builder(GlslangMagic),
|
||||
builder((glslang::GetKhronosToolId() << 16) | GeneratorVersion),
|
||||
inMain(false), mainTerminated(false), linkageOnly(false),
|
||||
glslangIntermediate(glslangIntermediate)
|
||||
{
|
||||
@@ -425,7 +432,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, "main");
|
||||
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, "main");
|
||||
|
||||
// Add the source extensions
|
||||
const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions();
|
||||
@@ -451,9 +458,9 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
||||
case EShLangTessEvaluation:
|
||||
builder.addCapability(spv::CapabilityTessellation);
|
||||
switch (glslangIntermediate->getInputPrimitive()) {
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
|
||||
case glslang::ElgQuads: mode = spv::ExecutionModeInputQuads; break;
|
||||
case glslang::ElgIsolines: mode = spv::ExecutionModeInputIsolines; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
|
||||
case glslang::ElgQuads: mode = spv::ExecutionModeQuads; break;
|
||||
case glslang::ElgIsolines: mode = spv::ExecutionModeIsolines; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
}
|
||||
if (mode != spv::BadValue)
|
||||
@@ -486,7 +493,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
||||
case glslang::ElgPoints: mode = spv::ExecutionModeInputPoints; break;
|
||||
case glslang::ElgLines: mode = spv::ExecutionModeInputLines; break;
|
||||
case glslang::ElgLinesAdjacency: mode = spv::ExecutionModeInputLinesAdjacency; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeInputTriangles; break;
|
||||
case glslang::ElgTriangles: mode = spv::ExecutionModeTriangles; break;
|
||||
case glslang::ElgTrianglesAdjacency: mode = spv::ExecutionModeInputTrianglesAdjacency; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
}
|
||||
@@ -520,7 +527,6 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(const glslang::TIntermediate* gls
|
||||
builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests);
|
||||
|
||||
switch(glslangIntermediate->getDepth()) {
|
||||
case glslang::EldAny: mode = spv::ExecutionModeDepthAny; break;
|
||||
case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break;
|
||||
case glslang::EldLess: mode = spv::ExecutionModeDepthLess; break;
|
||||
default: mode = spv::BadValue; break;
|
||||
@@ -591,6 +597,11 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol)
|
||||
builder.setAccessChainRValue(id);
|
||||
else
|
||||
builder.setAccessChainLValue(id);
|
||||
} else {
|
||||
// finish off the entry-point SPV instruction by adding the Input/Output <id>
|
||||
spv::StorageClass sc = builder.getStorageClass(id);
|
||||
if (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)
|
||||
entryPoint->addIdOperand(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,8 +650,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
node->getType().getBasicType());
|
||||
|
||||
// these all need their counterparts in createBinaryOperation()
|
||||
if (rValue == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation");
|
||||
assert(rValue != spv::NoResult);
|
||||
}
|
||||
|
||||
// store the result
|
||||
@@ -660,20 +670,13 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
|
||||
// Add the next element in the chain
|
||||
|
||||
int index = 0;
|
||||
if (node->getRight()->getAsConstantUnion() == 0)
|
||||
spv::MissingFunctionality("direct index without a constant node");
|
||||
else
|
||||
index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
|
||||
int index = node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
|
||||
if (node->getLeft()->getBasicType() == glslang::EbtBlock && node->getOp() == glslang::EOpIndexDirectStruct) {
|
||||
// This may be, e.g., an anonymous block-member selection, which generally need
|
||||
// index remapping due to hidden members in anonymous blocks.
|
||||
std::vector<int>& remapper = memberRemapper[node->getLeft()->getType().getStruct()];
|
||||
if (remapper.size() == 0)
|
||||
spv::MissingFunctionality("block without member remapping");
|
||||
else
|
||||
index = remapper[index];
|
||||
assert(remapper.size() > 0);
|
||||
index = remapper[index];
|
||||
}
|
||||
|
||||
if (! node->getLeft()->getType().isArray() &&
|
||||
@@ -766,7 +769,7 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
|
||||
node->getLeft()->getType().getBasicType());
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang binary operation");
|
||||
spv::MissingFunctionality("unknown glslang binary operation");
|
||||
} else {
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
@@ -832,7 +835,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
|
||||
// if not, then possibly an operation
|
||||
if (! result)
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getBasicType());
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operand, node->getOperand()->getBasicType());
|
||||
|
||||
if (result) {
|
||||
builder.clearAccessChain();
|
||||
@@ -862,8 +865,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
spv::Id result = createBinaryOperation(op, TranslatePrecisionDecoration(node->getType()),
|
||||
convertGlslangToSpvType(node->getType()), operand, one,
|
||||
node->getType().getBasicType());
|
||||
if (result == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation for unary");
|
||||
assert(result != spv::NoResult);
|
||||
|
||||
// The result of operation is always stored, but conditionally the
|
||||
// consumed result. The consumed result is always an r-value.
|
||||
@@ -886,7 +888,7 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
|
||||
return false;
|
||||
|
||||
default:
|
||||
spv::MissingFunctionality("glslang unary");
|
||||
spv::MissingFunctionality("unknown glslang unary");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -990,13 +992,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
{
|
||||
if (node->isUserDefined())
|
||||
result = handleUserFunctionCall(node);
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang function call");
|
||||
glslang::TConstUnionArray emptyConsts;
|
||||
int nextConst = 0;
|
||||
result = createSpvConstant(node->getType(), emptyConsts, nextConst);
|
||||
}
|
||||
assert(result);
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
|
||||
@@ -1053,12 +1049,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
for (int c = 0; c < (int)arguments.size(); ++c)
|
||||
constituents.push_back(arguments[c]);
|
||||
constructed = builder.createCompositeConstruct(resultTypeId, constituents);
|
||||
} else {
|
||||
if (isMatrix)
|
||||
constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
|
||||
else
|
||||
constructed = builder.createConstructor(precision, arguments, resultTypeId);
|
||||
}
|
||||
} else if (isMatrix)
|
||||
constructed = builder.createMatrixConstructor(precision, arguments, resultTypeId);
|
||||
else
|
||||
constructed = builder.createConstructor(precision, arguments, resultTypeId);
|
||||
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(constructed);
|
||||
@@ -1131,21 +1125,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
atomic = true;
|
||||
break;
|
||||
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
case glslang::EOpBitfieldExtract:
|
||||
case glslang::EOpBitfieldInsert:
|
||||
spv::MissingFunctionality("integer aggregate");
|
||||
break;
|
||||
|
||||
case glslang::EOpFma:
|
||||
case glslang::EOpFrexp:
|
||||
case glslang::EOpLdexp:
|
||||
spv::MissingFunctionality("fma/frexp/ldexp aggregate");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1171,9 +1150,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
left->getType().getBasicType(), reduceComparison);
|
||||
|
||||
// code above should only make binOp that exists in createBinaryOperation
|
||||
if (result == 0)
|
||||
spv::MissingFunctionality("createBinaryOperation for aggregate");
|
||||
|
||||
assert(result != spv::NoResult);
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(result);
|
||||
|
||||
@@ -1192,7 +1169,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
// special case l-value operands; there are just a few
|
||||
bool lvalue = false;
|
||||
switch (node->getOp()) {
|
||||
//case glslang::EOpFrexp:
|
||||
case glslang::EOpFrexp:
|
||||
case glslang::EOpModf:
|
||||
if (arg == 1)
|
||||
lvalue = true;
|
||||
@@ -1208,9 +1185,16 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
if (arg == 0)
|
||||
lvalue = true;
|
||||
break;
|
||||
//case glslang::EOpUAddCarry:
|
||||
//case glslang::EOpUSubBorrow:
|
||||
//case glslang::EOpUMulExtended:
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
if (arg == 2)
|
||||
lvalue = true;
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
if (arg >= 2)
|
||||
lvalue = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1230,7 +1214,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
result = createNoArgOperation(node->getOp());
|
||||
break;
|
||||
case 1:
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), node->getType().getBasicType());
|
||||
result = createUnaryOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands.front(), glslangOperands[0]->getAsTyped()->getBasicType());
|
||||
break;
|
||||
default:
|
||||
result = createMiscOperation(node->getOp(), precision, convertGlslangToSpvType(node->getType()), operands, node->getBasicType());
|
||||
@@ -1242,7 +1226,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
|
||||
return false;
|
||||
|
||||
if (! result) {
|
||||
spv::MissingFunctionality("glslang aggregate");
|
||||
spv::MissingFunctionality("unknown glslang aggregate");
|
||||
return true;
|
||||
} else {
|
||||
builder.clearAccessChain();
|
||||
@@ -1350,7 +1334,7 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
|
||||
void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node)
|
||||
{
|
||||
int nextConst = 0;
|
||||
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst);
|
||||
spv::Id constant = createSpvConstant(node->getType(), node->getConstArray(), nextConst, false);
|
||||
|
||||
builder.clearAccessChain();
|
||||
builder.setAccessChainRValue(constant);
|
||||
@@ -1418,7 +1402,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T
|
||||
break;
|
||||
|
||||
default:
|
||||
spv::MissingFunctionality("branch type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1429,9 +1413,9 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol*
|
||||
{
|
||||
// First, steer off constants, which are not SPIR-V variables, but
|
||||
// can still have a mapping to a SPIR-V Id.
|
||||
// This includes specialization constants.
|
||||
if (node->getQualifier().storage == glslang::EvqConst) {
|
||||
int nextConst = 0;
|
||||
return createSpvConstant(node->getType(), node->getConstArray(), nextConst);
|
||||
return createSpvSpecConstant(*node);
|
||||
}
|
||||
|
||||
// Now, handle actual variables
|
||||
@@ -1453,7 +1437,7 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler)
|
||||
case glslang::EbtInt: return builder.makeIntType(32);
|
||||
case glslang::EbtUint: return builder.makeUintType(32);
|
||||
default:
|
||||
spv::MissingFunctionality("sampled type");
|
||||
assert(0);
|
||||
return builder.makeFloatType(32);
|
||||
}
|
||||
}
|
||||
@@ -1474,8 +1458,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
switch (type.getBasicType()) {
|
||||
case glslang::EbtVoid:
|
||||
spvType = builder.makeVoidType();
|
||||
if (type.isArray())
|
||||
spv::MissingFunctionality("array of void");
|
||||
assert (! type.isArray());
|
||||
break;
|
||||
case glslang::EbtFloat:
|
||||
spvType = builder.makeFloatType(32);
|
||||
@@ -1499,12 +1482,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
case glslang::EbtSampler:
|
||||
{
|
||||
const glslang::TSampler& sampler = type.getSampler();
|
||||
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
|
||||
sampler.image ? 2 : 1, TranslateImageFormat(type));
|
||||
// OpenGL "textures" need to be combined with a sampler
|
||||
if (! sampler.image)
|
||||
spvType = builder.makeSampledImageType(spvType);
|
||||
}
|
||||
// an image is present, make its type
|
||||
spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.shadow, sampler.arrayed, sampler.ms,
|
||||
sampler.image ? 2 : 1, TranslateImageFormat(type));
|
||||
if (! sampler.image) {
|
||||
spvType = builder.makeSampledImageType(spvType);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case glslang::EbtStruct:
|
||||
case glslang::EbtBlock:
|
||||
@@ -1593,7 +1577,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
}
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("basic type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1620,10 +1604,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
|
||||
spvType = builder.makeArrayType(spvType, type.getOuterArraySize());
|
||||
}
|
||||
|
||||
// TODO: layout still needs to be done hierarchically for arrays of arrays, which
|
||||
// TODO: explicit layout still needs to be done hierarchically for arrays of arrays, which
|
||||
// may still require additional "link time" support from the front-end
|
||||
// for arrays of arrays
|
||||
if (explicitLayout)
|
||||
|
||||
// We need to decorate array strides for types needing explicit layout,
|
||||
// except for the very top if it is an array of blocks; that array is
|
||||
// not laid out in memory in a way needing a stride.
|
||||
if (explicitLayout && type.getBasicType() != glslang::EbtBlock)
|
||||
builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
|
||||
}
|
||||
|
||||
@@ -1883,8 +1871,11 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
operands.push_back(*(opIt++));
|
||||
if (node->getOp() == glslang::EOpImageStore)
|
||||
operands.push_back(*(opIt++));
|
||||
// TODO: add 'sample' operand
|
||||
if (node->getOp() == glslang::EOpImageLoad) {
|
||||
if (sampler.ms) {
|
||||
operands.push_back(spv::ImageOperandsSampleMask);
|
||||
operands.push_back(*(opIt++));
|
||||
}
|
||||
return builder.createOp(spv::OpImageRead, convertGlslangToSpvType(node->getType()), operands);
|
||||
} else if (node->getOp() == glslang::EOpImageStore) {
|
||||
builder.createNoResultOp(spv::OpImageWrite, operands);
|
||||
@@ -1909,8 +1900,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
}
|
||||
|
||||
// Check for texture functions other than queries
|
||||
if (cracked.gather)
|
||||
spv::MissingFunctionality("texture gather");
|
||||
|
||||
// check for bias argument
|
||||
bool bias = false;
|
||||
@@ -1925,14 +1914,18 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
bias = true;
|
||||
}
|
||||
|
||||
bool cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
|
||||
|
||||
// set the rest of the arguments
|
||||
|
||||
params.coords = arguments[1];
|
||||
int extraArgs = 0;
|
||||
if (cubeCompare)
|
||||
|
||||
// sort out where Dref is coming from
|
||||
if (sampler.shadow && sampler.dim == glslang::EsdCube && sampler.arrayed)
|
||||
params.Dref = arguments[2];
|
||||
else if (sampler.shadow) {
|
||||
else if (sampler.shadow && cracked.gather) {
|
||||
params.Dref = arguments[2];
|
||||
++extraArgs;
|
||||
} else if (sampler.shadow) {
|
||||
std::vector<spv::Id> indexes;
|
||||
int comp;
|
||||
if (cracked.proj)
|
||||
@@ -1954,20 +1947,28 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
|
||||
params.gradY = arguments[3 + extraArgs];
|
||||
extraArgs += 2;
|
||||
}
|
||||
//if (gather && compare) {
|
||||
// params.compare = arguments[2 + extraArgs];
|
||||
// ++extraArgs;
|
||||
//}
|
||||
if (cracked.offset || cracked.offsets) {
|
||||
if (cracked.offset) {
|
||||
params.offset = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
} else if (cracked.offsets) {
|
||||
params.offsets = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
}
|
||||
if (bias) {
|
||||
params.bias = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
}
|
||||
if (cracked.gather && ! sampler.shadow) {
|
||||
// default component is 0, if missing, otherwise an argument
|
||||
if (2 + extraArgs < (int)arguments.size()) {
|
||||
params.comp = arguments[2 + extraArgs];
|
||||
++extraArgs;
|
||||
} else {
|
||||
params.comp = builder.makeIntConstant(0);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, params);
|
||||
return builder.createTextureCall(precision, convertGlslangToSpvType(node->getType()), cracked.fetch, cracked.proj, cracked.gather, params);
|
||||
}
|
||||
|
||||
spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAggregate* node)
|
||||
@@ -2308,6 +2309,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
||||
{
|
||||
spv::Op unaryOp = spv::OpNop;
|
||||
int libCall = -1;
|
||||
bool isUnsigned = typeProxy == glslang::EbtUint;
|
||||
bool isFloat = typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble;
|
||||
|
||||
switch (op) {
|
||||
@@ -2538,11 +2540,13 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, spv:
|
||||
unaryOp = spv::OpBitCount;
|
||||
break;
|
||||
case glslang::EOpFindLSB:
|
||||
libCall = spv::GLSLstd450FindILSB;
|
||||
libCall = spv::GLSLstd450FindILsb;
|
||||
break;
|
||||
case glslang::EOpFindMSB:
|
||||
spv::MissingFunctionality("signed vs. unsigned FindMSB");
|
||||
libCall = spv::GLSLstd450FindSMSB;
|
||||
if (isUnsigned)
|
||||
libCall = spv::GLSLstd450FindUMsb;
|
||||
else
|
||||
libCall = spv::GLSLstd450FindSMsb;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2717,7 +2721,7 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
|
||||
opCode = spv::OpAtomicLoad;
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("missing nested atomic");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2754,6 +2758,11 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
|
||||
spv::Op opCode = spv::OpNop;
|
||||
int libCall = -1;
|
||||
int consumedOperands = operands.size();
|
||||
spv::Id typeId0 = 0;
|
||||
if (consumedOperands > 0)
|
||||
typeId0 = builder.getTypeId(operands[0]);
|
||||
spv::Id frexpIntType = 0;
|
||||
|
||||
switch (op) {
|
||||
case glslang::EOpMin:
|
||||
@@ -2794,7 +2803,10 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
libCall = spv::GLSLstd450SClamp;
|
||||
break;
|
||||
case glslang::EOpMix:
|
||||
libCall = spv::GLSLstd450Mix;
|
||||
if (isFloat)
|
||||
libCall = spv::GLSLstd450FMix;
|
||||
else
|
||||
libCall = spv::GLSLstd450IMix;
|
||||
break;
|
||||
case glslang::EOpStep:
|
||||
libCall = spv::GLSLstd450Step;
|
||||
@@ -2819,6 +2831,52 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
libCall = spv::GLSLstd450Refract;
|
||||
break;
|
||||
|
||||
case glslang::EOpAddCarry:
|
||||
opCode = spv::OpIAddCarry;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpSubBorrow:
|
||||
opCode = spv::OpISubBorrow;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
opCode = spv::OpUMulExtended;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpIMulExtended:
|
||||
opCode = spv::OpSMulExtended;
|
||||
typeId = builder.makeStructResultType(typeId0, typeId0);
|
||||
consumedOperands = 2;
|
||||
break;
|
||||
case glslang::EOpBitfieldExtract:
|
||||
if (isUnsigned)
|
||||
opCode = spv::OpBitFieldUExtract;
|
||||
else
|
||||
opCode = spv::OpBitFieldSExtract;
|
||||
break;
|
||||
case glslang::EOpBitfieldInsert:
|
||||
opCode = spv::OpBitFieldInsert;
|
||||
break;
|
||||
|
||||
case glslang::EOpFma:
|
||||
libCall = spv::GLSLstd450Fma;
|
||||
break;
|
||||
case glslang::EOpFrexp:
|
||||
libCall = spv::GLSLstd450FrexpStruct;
|
||||
if (builder.getNumComponents(operands[0]) == 1)
|
||||
frexpIntType = builder.makeIntegerType(32, true);
|
||||
else
|
||||
frexpIntType = builder.makeVectorType(builder.makeIntegerType(32, true), builder.getNumComponents(operands[0]));
|
||||
typeId = builder.makeStructResultType(typeId0, frexpIntType);
|
||||
consumedOperands = 1;
|
||||
break;
|
||||
case glslang::EOpLdexp:
|
||||
libCall = spv::GLSLstd450Ldexp;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -2827,7 +2885,7 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
if (libCall >= 0)
|
||||
id = builder.createBuiltinCall(precision, typeId, stdBuiltins, libCall, operands);
|
||||
else {
|
||||
switch (operands.size()) {
|
||||
switch (consumedOperands) {
|
||||
case 0:
|
||||
// should all be handled by visitAggregate and createNoArgOperation
|
||||
assert(0);
|
||||
@@ -2839,16 +2897,34 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
|
||||
case 2:
|
||||
id = builder.createBinOp(opCode, typeId, operands[0], operands[1]);
|
||||
break;
|
||||
case 3:
|
||||
id = builder.createTriOp(opCode, typeId, operands[0], operands[1], operands[2]);
|
||||
break;
|
||||
default:
|
||||
// These do not exist yet
|
||||
assert(0 && "operation with more than 3 operands");
|
||||
// anything 3 or over doesn't have l-value operands, so all should be consumed
|
||||
assert(consumedOperands == operands.size());
|
||||
id = builder.createOp(opCode, typeId, operands);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the return types that were structures
|
||||
switch (op) {
|
||||
case glslang::EOpAddCarry:
|
||||
case glslang::EOpSubBorrow:
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
||||
id = builder.createCompositeExtract(id, typeId0, 0);
|
||||
break;
|
||||
case glslang::EOpUMulExtended:
|
||||
case glslang::EOpIMulExtended:
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 0), operands[3]);
|
||||
builder.createStore(builder.createCompositeExtract(id, typeId0, 1), operands[2]);
|
||||
break;
|
||||
case glslang::EOpFrexp:
|
||||
builder.createStore(builder.createCompositeExtract(id, frexpIntType, 1), operands[1]);
|
||||
id = builder.createCompositeExtract(id, typeId0, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
builder.setPrecision(id, precision);
|
||||
|
||||
return id;
|
||||
@@ -2883,13 +2959,13 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op)
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsImageMemoryMask);
|
||||
return 0;
|
||||
case glslang::EOpMemoryBarrierShared:
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupLocalMemoryMask);
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupMemoryMask);
|
||||
return 0;
|
||||
case glslang::EOpGroupMemoryBarrier:
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsWorkgroupGlobalMemoryMask);
|
||||
builder.createMemoryBarrier(spv::ScopeDevice, spv::MemorySemanticsCrossWorkgroupMemoryMask);
|
||||
return 0;
|
||||
default:
|
||||
spv::MissingFunctionality("operation with no arguments");
|
||||
spv::MissingFunctionality("unknown operation with no arguments");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2945,31 +3021,57 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
|
||||
if (builtIn != spv::BadValue)
|
||||
builder.addDecoration(id, spv::DecorationBuiltIn, (int)builtIn);
|
||||
|
||||
if (linkageOnly)
|
||||
builder.addDecoration(id, spv::DecorationNoStaticUse);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add no-operand decoration to an object
|
||||
void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addDecoration(id, dec);
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add a one-operand decoration to an object
|
||||
void TGlslangToSpvTraverser::addDecoration(spv::Id id, spv::Decoration dec, unsigned value)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addDecoration(id, dec, value);
|
||||
}
|
||||
|
||||
// If 'dec' is valid, add a no-operand decoration to a struct member
|
||||
void TGlslangToSpvTraverser::addMemberDecoration(spv::Id id, int member, spv::Decoration dec)
|
||||
{
|
||||
if (dec != spv::BadValue)
|
||||
builder.addMemberDecoration(id, (unsigned)member, dec);
|
||||
}
|
||||
|
||||
// Make a full tree of instructions to build a SPIR-V specialization constant,
|
||||
// or regularly constant if possible.
|
||||
//
|
||||
// TBD: this is not yet done, nor verified to be the best design, it does do the leaf symbols though
|
||||
//
|
||||
// Recursively walk the nodes. The nodes form a tree whose leaves are
|
||||
// regular constants, which themselves are trees that createSpvConstant()
|
||||
// recursively walks. So, this function walks the "top" of the tree:
|
||||
// - emit specialization constant-building instructions for specConstant
|
||||
// - when running into a non-spec-constant, switch to createSpvConstant()
|
||||
spv::Id TGlslangToSpvTraverser::createSpvSpecConstant(const glslang::TIntermTyped& node)
|
||||
{
|
||||
assert(node.getQualifier().storage == glslang::EvqConst);
|
||||
|
||||
// hand off to the non-spec-constant path
|
||||
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
|
||||
int nextConst = 0;
|
||||
return createSpvConstant(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), nextConst, false);
|
||||
}
|
||||
|
||||
// Use 'consts' as the flattened glslang source of scalar constants to recursively
|
||||
// build the aggregate SPIR-V constant.
|
||||
//
|
||||
// If there are not enough elements present in 'consts', 0 will be substituted;
|
||||
// an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
|
||||
//
|
||||
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst)
|
||||
spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
|
||||
{
|
||||
// vector of constants for SPIR-V
|
||||
std::vector<spv::Id> spvConsts;
|
||||
@@ -2980,15 +3082,15 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
||||
if (glslangType.isArray()) {
|
||||
glslang::TType elementType(glslangType, 0);
|
||||
for (int i = 0; i < glslangType.getOuterArraySize(); ++i)
|
||||
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(elementType, consts, nextConst, false));
|
||||
} else if (glslangType.isMatrix()) {
|
||||
glslang::TType vectorType(glslangType, 0);
|
||||
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
|
||||
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(vectorType, consts, nextConst, false));
|
||||
} else if (glslangType.getStruct()) {
|
||||
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
|
||||
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
|
||||
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst));
|
||||
spvConsts.push_back(createSpvConstant(*iter->type, consts, nextConst, false));
|
||||
} else if (glslangType.isVector()) {
|
||||
for (unsigned int i = 0; i < (unsigned int)glslangType.getVectorSize(); ++i) {
|
||||
bool zero = nextConst >= consts.size();
|
||||
@@ -3009,7 +3111,7 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
||||
spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst()));
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("constant vector type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
++nextConst;
|
||||
@@ -3020,22 +3122,22 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TType& glslangT
|
||||
spv::Id scalar = 0;
|
||||
switch (glslangType.getBasicType()) {
|
||||
case glslang::EbtInt:
|
||||
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst());
|
||||
scalar = builder.makeIntConstant(zero ? 0 : consts[nextConst].getIConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtUint:
|
||||
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst());
|
||||
scalar = builder.makeUintConstant(zero ? 0 : consts[nextConst].getUConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtFloat:
|
||||
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst());
|
||||
scalar = builder.makeFloatConstant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtDouble:
|
||||
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst());
|
||||
scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant);
|
||||
break;
|
||||
case glslang::EbtBool:
|
||||
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst());
|
||||
scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant);
|
||||
break;
|
||||
default:
|
||||
spv::MissingFunctionality("constant scalar type");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
++nextConst;
|
||||
@@ -3180,7 +3282,7 @@ void GetSpirvVersion(std::string& version)
|
||||
{
|
||||
const int bufSize = 100;
|
||||
char buf[bufSize];
|
||||
snprintf(buf, bufSize, "%d, Revision %d", spv::Version, spv::Revision);
|
||||
snprintf(buf, bufSize, "0x%08x, Revision %d", spv::Version, spv::Revision);
|
||||
version = buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -446,7 +446,6 @@ namespace spv {
|
||||
idFn(asId(word++));
|
||||
break;
|
||||
|
||||
case spv::OperandOptionalId:
|
||||
case spv::OperandVariableIds:
|
||||
for (unsigned i = 0; i < numOperands; ++i)
|
||||
idFn(asId(word++));
|
||||
|
||||
@@ -55,14 +55,12 @@
|
||||
|
||||
namespace spv {
|
||||
|
||||
const int SpvBuilderMagic = 0xBB;
|
||||
|
||||
Builder::Builder(unsigned int userNumber) :
|
||||
Builder::Builder(unsigned int magicNumber) :
|
||||
source(SourceLanguageUnknown),
|
||||
sourceVersion(0),
|
||||
addressModel(AddressingModelLogical),
|
||||
memoryModel(MemoryModelGLSL450),
|
||||
builderNumber(userNumber << 16 | SpvBuilderMagic),
|
||||
builderNumber(magicNumber),
|
||||
buildPoint(0),
|
||||
uniqueId(0),
|
||||
mainFunction(0)
|
||||
@@ -112,6 +110,20 @@ Id Builder::makeBoolType()
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeSamplerType()
|
||||
{
|
||||
Instruction* type;
|
||||
if (groupedTypes[OpTypeSampler].size() == 0) {
|
||||
type = new Instruction(getUniqueId(), NoType, OpTypeSampler);
|
||||
groupedTypes[OpTypeSampler].push_back(type);
|
||||
constantsTypesGlobals.push_back(type);
|
||||
module.mapInstruction(type);
|
||||
} else
|
||||
type = groupedTypes[OpTypeSampler].back();
|
||||
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makePointer(StorageClass storageClass, Id pointee)
|
||||
{
|
||||
// try to find it
|
||||
@@ -176,8 +188,15 @@ Id Builder::makeFloatType(int width)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// Make a struct without checking for duplication.
|
||||
// See makeStructResultType() for non-decorated structs
|
||||
// needed as the result of some instructions, which does
|
||||
// check for duplicates.
|
||||
Id Builder::makeStructType(std::vector<Id>& members, const char* name)
|
||||
{
|
||||
// Don't look for previous one, because in the general case,
|
||||
// structs can be duplicated except for decorations.
|
||||
|
||||
// not found, make it
|
||||
Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct);
|
||||
for (int op = 0; op < (int)members.size(); ++op)
|
||||
@@ -190,6 +209,30 @@ Id Builder::makeStructType(std::vector<Id>& members, const char* name)
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// Make a struct for the simple results of several instructions,
|
||||
// checking for duplication.
|
||||
Id Builder::makeStructResultType(Id type0, Id type1)
|
||||
{
|
||||
// try to find it
|
||||
Instruction* type;
|
||||
for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) {
|
||||
type = groupedTypes[OpTypeStruct][t];
|
||||
if (type->getNumOperands() != 2)
|
||||
continue;
|
||||
if (type->getIdOperand(0) != type0 ||
|
||||
type->getIdOperand(1) != type1)
|
||||
continue;
|
||||
return type->getResultId();
|
||||
}
|
||||
|
||||
// not found, make it
|
||||
std::vector<spv::Id> members;
|
||||
members.push_back(type0);
|
||||
members.push_back(type1);
|
||||
|
||||
return makeStructType(members, "ResType");
|
||||
}
|
||||
|
||||
Id Builder::makeVectorType(Id component, int size)
|
||||
{
|
||||
// try to find it
|
||||
@@ -387,7 +430,7 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
|
||||
case OpTypePointer:
|
||||
return getMostBasicTypeClass(instr->getIdOperand(1));
|
||||
default:
|
||||
MissingFunctionality("getMostBasicTypeClass");
|
||||
assert(0);
|
||||
return OpTypeFloat;
|
||||
}
|
||||
}
|
||||
@@ -406,7 +449,7 @@ int Builder::getNumTypeComponents(Id typeId) const
|
||||
case OpTypeMatrix:
|
||||
return instr->getImmediateOperand(1);
|
||||
default:
|
||||
MissingFunctionality("getNumTypeComponents on non bool/int/float/vector/matrix");
|
||||
assert(0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -434,7 +477,7 @@ Id Builder::getScalarTypeId(Id typeId) const
|
||||
case OpTypePointer:
|
||||
return getScalarTypeId(getContainedTypeId(typeId));
|
||||
default:
|
||||
MissingFunctionality("getScalarTypeId");
|
||||
assert(0);
|
||||
return NoResult;
|
||||
}
|
||||
}
|
||||
@@ -457,7 +500,7 @@ Id Builder::getContainedTypeId(Id typeId, int member) const
|
||||
case OpTypeStruct:
|
||||
return instr->getIdOperand(member);
|
||||
default:
|
||||
MissingFunctionality("getContainedTypeId");
|
||||
assert(0);
|
||||
return NoResult;
|
||||
}
|
||||
}
|
||||
@@ -470,12 +513,12 @@ Id Builder::getContainedTypeId(Id typeId) const
|
||||
|
||||
// See if a scalar constant of this type has already been created, so it
|
||||
// can be reused rather than duplicated. (Required by the specification).
|
||||
Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
|
||||
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const
|
||||
{
|
||||
Instruction* constant;
|
||||
for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
|
||||
constant = groupedConstants[typeClass][i];
|
||||
if (constant->getNumOperands() == 1 &&
|
||||
if (constant->getOpCode() == opcode &&
|
||||
constant->getTypeId() == typeId &&
|
||||
constant->getImmediateOperand(0) == value)
|
||||
return constant->getResultId();
|
||||
@@ -485,12 +528,12 @@ Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned value) const
|
||||
}
|
||||
|
||||
// Version of findScalarConstant (see above) for scalars that take two operands (e.g. a 'double').
|
||||
Id Builder::findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const
|
||||
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const
|
||||
{
|
||||
Instruction* constant;
|
||||
for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) {
|
||||
constant = groupedConstants[typeClass][i];
|
||||
if (constant->getNumOperands() == 2 &&
|
||||
if (constant->getOpCode() == opcode &&
|
||||
constant->getTypeId() == typeId &&
|
||||
constant->getImmediateOperand(0) == v1 &&
|
||||
constant->getImmediateOperand(1) == v2)
|
||||
@@ -524,18 +567,17 @@ bool Builder::isConstantOpCode(Op opcode) const
|
||||
}
|
||||
}
|
||||
|
||||
Id Builder::makeBoolConstant(bool b)
|
||||
Id Builder::makeBoolConstant(bool b, bool specConstant)
|
||||
{
|
||||
Id typeId = makeBoolType();
|
||||
Instruction* constant;
|
||||
Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse);
|
||||
|
||||
// See if we already made it
|
||||
Id existing = 0;
|
||||
for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) {
|
||||
constant = groupedConstants[OpTypeBool][i];
|
||||
if (constant->getTypeId() == typeId &&
|
||||
(b ? (constant->getOpCode() == OpConstantTrue) :
|
||||
(constant->getOpCode() == OpConstantFalse)))
|
||||
if (constant->getTypeId() == typeId && constant->getOpCode() == opcode)
|
||||
existing = constant->getResultId();
|
||||
}
|
||||
|
||||
@@ -543,7 +585,7 @@ Id Builder::makeBoolConstant(bool b)
|
||||
return existing;
|
||||
|
||||
// Make it
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, b ? OpConstantTrue : OpConstantFalse);
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
|
||||
constantsTypesGlobals.push_back(c);
|
||||
groupedConstants[OpTypeBool].push_back(c);
|
||||
module.mapInstruction(c);
|
||||
@@ -551,13 +593,14 @@ Id Builder::makeBoolConstant(bool b)
|
||||
return c->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeIntConstant(Id typeId, unsigned value)
|
||||
Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant)
|
||||
{
|
||||
Id existing = findScalarConstant(OpTypeInt, typeId, value);
|
||||
Op opcode = specConstant ? OpSpecConstant : OpConstant;
|
||||
Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value);
|
||||
if (existing)
|
||||
return existing;
|
||||
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
|
||||
c->addImmediateOperand(value);
|
||||
constantsTypesGlobals.push_back(c);
|
||||
groupedConstants[OpTypeInt].push_back(c);
|
||||
@@ -566,15 +609,16 @@ Id Builder::makeIntConstant(Id typeId, unsigned value)
|
||||
return c->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeFloatConstant(float f)
|
||||
Id Builder::makeFloatConstant(float f, bool specConstant)
|
||||
{
|
||||
Op opcode = specConstant ? OpSpecConstant : OpConstant;
|
||||
Id typeId = makeFloatType(32);
|
||||
unsigned value = *(unsigned int*)&f;
|
||||
Id existing = findScalarConstant(OpTypeFloat, typeId, value);
|
||||
Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value);
|
||||
if (existing)
|
||||
return existing;
|
||||
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
|
||||
c->addImmediateOperand(value);
|
||||
constantsTypesGlobals.push_back(c);
|
||||
groupedConstants[OpTypeFloat].push_back(c);
|
||||
@@ -583,17 +627,18 @@ Id Builder::makeFloatConstant(float f)
|
||||
return c->getResultId();
|
||||
}
|
||||
|
||||
Id Builder::makeDoubleConstant(double d)
|
||||
Id Builder::makeDoubleConstant(double d, bool specConstant)
|
||||
{
|
||||
Op opcode = specConstant ? OpSpecConstant : OpConstant;
|
||||
Id typeId = makeFloatType(64);
|
||||
unsigned long long value = *(unsigned long long*)&d;
|
||||
unsigned op1 = value & 0xFFFFFFFF;
|
||||
unsigned op2 = value >> 32;
|
||||
Id existing = findScalarConstant(OpTypeFloat, typeId, op1, op2);
|
||||
Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2);
|
||||
if (existing)
|
||||
return existing;
|
||||
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, OpConstant);
|
||||
Instruction* c = new Instruction(getUniqueId(), typeId, opcode);
|
||||
c->addImmediateOperand(op1);
|
||||
c->addImmediateOperand(op2);
|
||||
constantsTypesGlobals.push_back(c);
|
||||
@@ -644,7 +689,7 @@ Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
|
||||
case OpTypeMatrix:
|
||||
break;
|
||||
default:
|
||||
MissingFunctionality("Constant composite type in Builder");
|
||||
assert(0);
|
||||
return makeFloatConstant(0.0);
|
||||
}
|
||||
|
||||
@@ -662,7 +707,7 @@ Id Builder::makeCompositeConstant(Id typeId, std::vector<Id>& members)
|
||||
return c->getResultId();
|
||||
}
|
||||
|
||||
void Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
|
||||
Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name)
|
||||
{
|
||||
Instruction* entryPoint = new Instruction(OpEntryPoint);
|
||||
entryPoint->addImmediateOperand(model);
|
||||
@@ -670,6 +715,8 @@ void Builder::addEntryPoint(ExecutionModel model, Function* function, const char
|
||||
entryPoint->addStringOperand(name);
|
||||
|
||||
entryPoints.push_back(entryPoint);
|
||||
|
||||
return entryPoint;
|
||||
}
|
||||
|
||||
// Currently relying on the fact that all 'value' of interest are small non-negative values.
|
||||
@@ -720,6 +767,8 @@ void Builder::addLine(Id target, Id fileName, int lineNum, int column)
|
||||
|
||||
void Builder::addDecoration(Id id, Decoration decoration, int num)
|
||||
{
|
||||
if (decoration == (spv::Decoration)spv::BadValue)
|
||||
return;
|
||||
Instruction* dec = new Instruction(OpDecorate);
|
||||
dec->addIdOperand(id);
|
||||
dec->addImmediateOperand(decoration);
|
||||
@@ -833,25 +882,14 @@ Id Builder::createVariable(StorageClass storageClass, Id type, const char* name)
|
||||
inst->addImmediateOperand(storageClass);
|
||||
|
||||
switch (storageClass) {
|
||||
case StorageClassUniformConstant:
|
||||
case StorageClassUniform:
|
||||
case StorageClassInput:
|
||||
case StorageClassOutput:
|
||||
case StorageClassWorkgroupLocal:
|
||||
case StorageClassPrivateGlobal:
|
||||
case StorageClassWorkgroupGlobal:
|
||||
case StorageClassAtomicCounter:
|
||||
constantsTypesGlobals.push_back(inst);
|
||||
module.mapInstruction(inst);
|
||||
break;
|
||||
|
||||
case StorageClassFunction:
|
||||
// Validation rules require the declaration in the entry block
|
||||
buildPoint->getParent().addLocalVariable(inst);
|
||||
break;
|
||||
|
||||
default:
|
||||
MissingFunctionality("storage class in createVariable");
|
||||
constantsTypesGlobals.push_back(inst);
|
||||
module.mapInstruction(inst);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1175,7 +1213,7 @@ Id Builder::createBuiltinCall(Decoration /*precision*/, Id resultType, Id builti
|
||||
|
||||
// Accept all parameters needed to create a texture instruction.
|
||||
// Create the correct instruction based on the inputs, and make the call.
|
||||
Id Builder::createTextureCall(Decoration precision, Id resultType, bool fetch, bool proj, const TextureParameters& parameters)
|
||||
Id Builder::createTextureCall(Decoration precision, Id resultType, bool fetch, bool proj, bool gather, const TextureParameters& parameters)
|
||||
{
|
||||
static const int maxTextureArgs = 10;
|
||||
Id texArgs[maxTextureArgs] = {};
|
||||
@@ -1189,6 +1227,8 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool fetch, b
|
||||
texArgs[numArgs++] = parameters.coords;
|
||||
if (parameters.Dref)
|
||||
texArgs[numArgs++] = parameters.Dref;
|
||||
if (parameters.comp)
|
||||
texArgs[numArgs++] = parameters.comp;
|
||||
|
||||
//
|
||||
// Set up the optional arguments
|
||||
@@ -1238,6 +1278,11 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool fetch, b
|
||||
opCode = OpImageSampleImplicitLod;
|
||||
if (fetch) {
|
||||
opCode = OpImageFetch;
|
||||
} else if (gather) {
|
||||
if (parameters.Dref)
|
||||
opCode = OpImageDrefGather;
|
||||
else
|
||||
opCode = OpImageGather;
|
||||
} else if (xplicit) {
|
||||
if (parameters.Dref) {
|
||||
if (proj)
|
||||
@@ -1281,6 +1326,7 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool fetch, b
|
||||
}
|
||||
}
|
||||
|
||||
// Build the SPIR-V instruction
|
||||
Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode);
|
||||
for (int op = 0; op < optArgNum; ++op)
|
||||
textureInst->addIdOperand(texArgs[op]);
|
||||
@@ -1324,8 +1370,12 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter
|
||||
case Dim3D:
|
||||
numComponents = 3;
|
||||
break;
|
||||
case DimSubpassData:
|
||||
MissingFunctionality("input-attachment dim");
|
||||
break;
|
||||
|
||||
default:
|
||||
MissingFunctionality("texture query dimensionality");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if (isArrayedImageType(getImageType(parameters.sampler)))
|
||||
@@ -1345,7 +1395,8 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter
|
||||
resultType = makeIntType(32);
|
||||
break;
|
||||
default:
|
||||
MissingFunctionality("Texture query op code");
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
Instruction* query = new Instruction(getUniqueId(), resultType, opCode);
|
||||
@@ -1359,57 +1410,6 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter
|
||||
return query->getResultId();
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
//Id Builder::createSamplePositionCall(Decoration precision, Id returnType, Id sampleIdx)
|
||||
//{
|
||||
// // Return type is only flexible type
|
||||
// Function* opCode = (fSamplePosition, returnType);
|
||||
//
|
||||
// Instruction* instr = (opCode, sampleIdx);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
|
||||
// Comments in header
|
||||
//Id Builder::createBitFieldExtractCall(Decoration precision, Id id, Id offset, Id bits, bool isSigned)
|
||||
//{
|
||||
// Op opCode = isSigned ? sBitFieldExtract
|
||||
// : uBitFieldExtract;
|
||||
//
|
||||
// if (isScalar(offset) == false || isScalar(bits) == false)
|
||||
// MissingFunctionality("bitFieldExtract operand types");
|
||||
//
|
||||
// // Dest and value are matching flexible types
|
||||
// Function* opCode = (opCode, id->getType(), id->getType());
|
||||
//
|
||||
// assert(opCode);
|
||||
//
|
||||
// Instruction* instr = (opCode, id, offset, bits);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
|
||||
// Comments in header
|
||||
//Id Builder::createBitFieldInsertCall(Decoration precision, Id base, Id insert, Id offset, Id bits)
|
||||
//{
|
||||
// Op opCode = bitFieldInsert;
|
||||
//
|
||||
// if (isScalar(offset) == false || isScalar(bits) == false)
|
||||
// MissingFunctionality("bitFieldInsert operand types");
|
||||
//
|
||||
// // Dest, base, and insert are matching flexible types
|
||||
// Function* opCode = (opCode, base->getType(), base->getType(), base->getType());
|
||||
//
|
||||
// assert(opCode);
|
||||
//
|
||||
// Instruction* instr = (opCode, base, insert, offset, bits);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
|
||||
// Comments in header
|
||||
Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal)
|
||||
{
|
||||
@@ -1488,115 +1488,6 @@ Id Builder::createCompare(Decoration precision, Id value1, Id value2, bool equal
|
||||
//return result;
|
||||
}
|
||||
|
||||
// Comments in header
|
||||
//Id Builder::createOperation(Decoration precision, Op opCode, Id operand)
|
||||
//{
|
||||
// Op* opCode = 0;
|
||||
//
|
||||
// // Handle special return types here. Things that don't have same result type as parameter
|
||||
// switch (opCode) {
|
||||
// case fIsNan:
|
||||
// case fIsInf:
|
||||
// break;
|
||||
// case fFloatBitsToInt:
|
||||
// break;
|
||||
// case fIntBitsTofloat:
|
||||
// break;
|
||||
// case fPackSnorm2x16:
|
||||
// case fPackUnorm2x16:
|
||||
// case fPackHalf2x16:
|
||||
// break;
|
||||
// case fUnpackUnorm2x16:
|
||||
// case fUnpackSnorm2x16:
|
||||
// case fUnpackHalf2x16:
|
||||
// break;
|
||||
//
|
||||
// case fFrexp:
|
||||
// case fLdexp:
|
||||
// case fPackUnorm4x8:
|
||||
// case fPackSnorm4x8:
|
||||
// case fUnpackUnorm4x8:
|
||||
// case fUnpackSnorm4x8:
|
||||
// case fPackDouble2x32:
|
||||
// case fUnpackDouble2x32:
|
||||
// break;
|
||||
// case fLength:
|
||||
// // scalar result type
|
||||
// break;
|
||||
// case any:
|
||||
// case all:
|
||||
// // fixed result type
|
||||
// break;
|
||||
// case fModF:
|
||||
// // modf() will return a struct that the caller must decode
|
||||
// break;
|
||||
// default:
|
||||
// // Unary operations that have operand and dest with same flexible type
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// assert(opCode);
|
||||
//
|
||||
// Instruction* instr = (opCode, operand);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
//
|
||||
//// Comments in header
|
||||
//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1)
|
||||
//{
|
||||
// Function* opCode = 0;
|
||||
//
|
||||
// // Handle special return types here. Things that don't have same result type as parameter
|
||||
// switch (opCode) {
|
||||
// case fDistance:
|
||||
// case fDot2:
|
||||
// case fDot3:
|
||||
// case fDot4:
|
||||
// // scalar result type
|
||||
// break;
|
||||
// case fStep:
|
||||
// // first argument can be scalar, return and second argument match
|
||||
// break;
|
||||
// case fSmoothStep:
|
||||
// // first argument can be scalar, return and second argument match
|
||||
// break;
|
||||
// default:
|
||||
// // Binary operations that have operand and dest with same flexible type
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// assert(opCode);
|
||||
//
|
||||
// Instruction* instr = (opCode, operand0, operand1);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
//
|
||||
//Id Builder::createOperation(Decoration precision, Op opCode, Id operand0, Id operand1, Id operand2)
|
||||
//{
|
||||
// Function* opCode;
|
||||
//
|
||||
// // Handle special return types here. Things that don't have same result type as parameter
|
||||
// switch (opCode) {
|
||||
// case fSmoothStep:
|
||||
// // first argument can be scalar, return and second argument match
|
||||
// break;
|
||||
// default:
|
||||
// // Use operand0 type as result type
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// assert(opCode);
|
||||
//
|
||||
// Instruction* instr = (opCode, operand0, operand1, operand2);
|
||||
// setPrecision(instr, precision);
|
||||
//
|
||||
// return instr;
|
||||
//}
|
||||
|
||||
// OpCompositeConstruct
|
||||
Id Builder::createCompositeConstruct(Id typeId, std::vector<Id>& constituents)
|
||||
{
|
||||
@@ -1625,11 +1516,8 @@ Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sourc
|
||||
Id scalarTypeId = getScalarTypeId(resultTypeId);
|
||||
std::vector<Id> constituents; // accumulate the arguments for OpCompositeConstruct
|
||||
for (unsigned int i = 0; i < sources.size(); ++i) {
|
||||
if (isAggregate(sources[i]))
|
||||
MissingFunctionality("aggregate in vector constructor");
|
||||
|
||||
assert(! isAggregate(sources[i]));
|
||||
unsigned int sourceSize = getNumComponents(sources[i]);
|
||||
|
||||
unsigned int sourcesToUse = sourceSize;
|
||||
if (sourcesToUse + targetComponent > numTargetComponents)
|
||||
sourcesToUse = numTargetComponents - targetComponent;
|
||||
@@ -1790,7 +1678,7 @@ void Builder::If::makeEndIf()
|
||||
|
||||
// Go back to the headerBlock and make the flow control split
|
||||
builder.setBuildPoint(headerBlock);
|
||||
builder.createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
|
||||
builder.createSelectionMerge(mergeBlock, SelectionControlMaskNone);
|
||||
if (elseBlock)
|
||||
builder.createConditionalBranch(condition, thenBlock, elseBlock);
|
||||
else
|
||||
@@ -1814,7 +1702,7 @@ void Builder::makeSwitch(Id selector, int numSegments, std::vector<int>& caseVal
|
||||
Block* mergeBlock = new Block(getUniqueId(), function);
|
||||
|
||||
// make and insert the switch's selection-merge instruction
|
||||
createMerge(OpSelectionMerge, mergeBlock, SelectionControlMaskNone);
|
||||
createSelectionMerge(mergeBlock, SelectionControlMaskNone);
|
||||
|
||||
// make the switch instruction
|
||||
Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch);
|
||||
@@ -1898,7 +1786,7 @@ void Builder::makeNewLoop(bool loopTestFirst)
|
||||
getBuildPoint()->addInstruction(loop.isFirstIteration);
|
||||
|
||||
// Mark the end of the structured loop. This must exist in the loop header block.
|
||||
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
|
||||
createLoopMerge(loop.merge, loop.header, LoopControlMaskNone);
|
||||
|
||||
// Generate code to see if this is the first iteration of the loop.
|
||||
// It needs to be in its own block, since the loop merge and
|
||||
@@ -1912,7 +1800,7 @@ void Builder::makeNewLoop(bool loopTestFirst)
|
||||
// Control flow after this "if" normally reconverges at the loop body.
|
||||
// However, the loop test has a "break branch" out of this selection
|
||||
// construct because it can transfer control to the loop merge block.
|
||||
createMerge(OpSelectionMerge, loop.body, SelectionControlMaskNone);
|
||||
createSelectionMerge(loop.body, SelectionControlMaskNone);
|
||||
|
||||
Block* loopTest = new Block(getUniqueId(), *loop.function);
|
||||
createConditionalBranch(loop.isFirstIteration->getResultId(), loop.body, loopTest);
|
||||
@@ -1930,7 +1818,7 @@ void Builder::createLoopTestBranch(Id condition)
|
||||
// the body, then this is a loop merge. Otherwise the loop merge
|
||||
// has already been generated and this is a conditional merge.
|
||||
if (loop.testFirst) {
|
||||
createMerge(OpLoopMerge, loop.merge, LoopControlMaskNone);
|
||||
createLoopMerge(loop.merge, loop.header, LoopControlMaskNone);
|
||||
// Branching to the "body" block will keep control inside
|
||||
// the loop.
|
||||
createConditionalBranch(condition, loop.body, loop.merge);
|
||||
@@ -1943,7 +1831,7 @@ void Builder::createLoopTestBranch(Id condition)
|
||||
// of a merge instruction, and a block can't be the target of more
|
||||
// than one merge instruction, we need to make an intermediate block.
|
||||
Block* stayInLoopBlock = new Block(getUniqueId(), *loop.function);
|
||||
createMerge(OpSelectionMerge, stayInLoopBlock, SelectionControlMaskNone);
|
||||
createSelectionMerge(stayInLoopBlock, SelectionControlMaskNone);
|
||||
|
||||
// This is the loop test.
|
||||
createConditionalBranch(condition, stayInLoopBlock, loop.merge);
|
||||
@@ -2047,12 +1935,13 @@ void Builder::accessChainStore(Id rvalue)
|
||||
{
|
||||
assert(accessChain.isRValue == false);
|
||||
|
||||
transferAccessChainSwizzle(true);
|
||||
Id base = collapseAccessChain();
|
||||
|
||||
if (accessChain.swizzle.size() && accessChain.component != NoResult)
|
||||
MissingFunctionality("simultaneous l-value swizzle and dynamic component selection");
|
||||
|
||||
// If swizzle exists, it is out-of-order or not full, we must load the target vector,
|
||||
// If swizzle still exists, it is out-of-order or not full, we must load the target vector,
|
||||
// extract and insert elements to perform writeMask and/or swizzle.
|
||||
Id source = NoResult;
|
||||
if (accessChain.swizzle.size()) {
|
||||
@@ -2078,8 +1967,9 @@ Id Builder::accessChainLoad(Id resultType)
|
||||
Id id;
|
||||
|
||||
if (accessChain.isRValue) {
|
||||
// transfer access chain, but keep it static, so we can stay in registers
|
||||
transferAccessChainSwizzle(false);
|
||||
if (accessChain.indexChain.size() > 0) {
|
||||
mergeAccessChainSwizzle(); // TODO: optimization: look at applying this optimization more widely
|
||||
Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType;
|
||||
|
||||
// if all the accesses are constants, we can use OpCompositeExtract
|
||||
@@ -2113,6 +2003,7 @@ Id Builder::accessChainLoad(Id resultType)
|
||||
} else
|
||||
id = accessChain.base;
|
||||
} else {
|
||||
transferAccessChainSwizzle(true);
|
||||
// load through the access chain
|
||||
id = createLoad(collapseAccessChain());
|
||||
}
|
||||
@@ -2142,6 +2033,7 @@ Id Builder::accessChainGetLValue()
|
||||
{
|
||||
assert(accessChain.isRValue == false);
|
||||
|
||||
transferAccessChainSwizzle(true);
|
||||
Id lvalue = collapseAccessChain();
|
||||
|
||||
// If swizzle exists, it is out-of-order or not full, we must load the target vector,
|
||||
@@ -2162,7 +2054,26 @@ void Builder::dump(std::vector<unsigned int>& out) const
|
||||
out.push_back(uniqueId + 1);
|
||||
out.push_back(0);
|
||||
|
||||
// First instructions, some created on the spot here:
|
||||
// Capabilities
|
||||
for (auto cap : capabilities) {
|
||||
Instruction capInst(0, 0, OpCapability);
|
||||
capInst.addImmediateOperand(cap);
|
||||
capInst.dump(out);
|
||||
}
|
||||
|
||||
// TBD: OpExtension ...
|
||||
|
||||
dumpInstructions(out, imports);
|
||||
Instruction memInst(0, 0, OpMemoryModel);
|
||||
memInst.addImmediateOperand(addressModel);
|
||||
memInst.addImmediateOperand(memoryModel);
|
||||
memInst.dump(out);
|
||||
|
||||
// Instructions saved up while building:
|
||||
dumpInstructions(out, entryPoints);
|
||||
dumpInstructions(out, executionModes);
|
||||
|
||||
// Debug instructions
|
||||
if (source != SourceLanguageUnknown) {
|
||||
Instruction sourceInst(0, 0, OpSource);
|
||||
sourceInst.addImmediateOperand(source);
|
||||
@@ -2174,28 +2085,12 @@ 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);
|
||||
memInst.addImmediateOperand(memoryModel);
|
||||
memInst.dump(out);
|
||||
|
||||
// Instructions saved up while building:
|
||||
dumpInstructions(out, entryPoints);
|
||||
dumpInstructions(out, executionModes);
|
||||
dumpInstructions(out, names);
|
||||
dumpInstructions(out, lines);
|
||||
|
||||
// Annotation instructions
|
||||
dumpInstructions(out, decorations);
|
||||
|
||||
dumpInstructions(out, constantsTypesGlobals);
|
||||
dumpInstructions(out, externals);
|
||||
|
||||
@@ -2207,10 +2102,13 @@ void Builder::dump(std::vector<unsigned int>& out) const
|
||||
// Protected methods.
|
||||
//
|
||||
|
||||
// Turn the described access chain in 'accessChain' into an instruction
|
||||
// computing its address. This *cannot* include complex swizzles, which must
|
||||
// be handled after this is called, but it does include swizzles that select
|
||||
// an individual element, as a single address of a scalar type can be
|
||||
// computed by an OpAccessChain instruction.
|
||||
Id Builder::collapseAccessChain()
|
||||
{
|
||||
// TODO: bring in an individual component swizzle here, so that a pointer
|
||||
// all the way to the component level can be created.
|
||||
assert(accessChain.isRValue == false);
|
||||
|
||||
if (accessChain.indexChain.size() > 0) {
|
||||
@@ -2222,9 +2120,12 @@ Id Builder::collapseAccessChain()
|
||||
return accessChain.instr;
|
||||
} else
|
||||
return accessChain.base;
|
||||
|
||||
// note that non-trivial swizzling is left pending...
|
||||
}
|
||||
|
||||
// clear out swizzle if it is redundant
|
||||
// clear out swizzle if it is redundant, that is reselecting the same components
|
||||
// that would be present without the swizzle.
|
||||
void Builder::simplifyAccessChainSwizzle()
|
||||
{
|
||||
// If the swizzle has fewer components than the vector, it is subsetting, and must stay
|
||||
@@ -2244,29 +2145,45 @@ void Builder::simplifyAccessChainSwizzle()
|
||||
accessChain.preSwizzleBaseType = NoType;
|
||||
}
|
||||
|
||||
// clear out swizzle if it can become part of the indexes
|
||||
void Builder::mergeAccessChainSwizzle()
|
||||
// To the extent any swizzling can become part of the chain
|
||||
// of accesses instead of a post operation, make it so.
|
||||
// If 'dynamic' is true, include transfering a non-static component index,
|
||||
// otherwise, only transfer static indexes.
|
||||
//
|
||||
// Also, Boolean vectors are likely to be special. While
|
||||
// for external storage, they should only be integer types,
|
||||
// function-local bool vectors could use sub-word indexing,
|
||||
// so keep that as a separate Insert/Extract on a loaded vector.
|
||||
void Builder::transferAccessChainSwizzle(bool dynamic)
|
||||
{
|
||||
// is there even a chance of doing something? Need a single-component swizzle
|
||||
if ((accessChain.swizzle.size() > 1) ||
|
||||
(accessChain.swizzle.size() == 0 && accessChain.component == NoResult))
|
||||
// too complex?
|
||||
if (accessChain.swizzle.size() > 1)
|
||||
return;
|
||||
|
||||
// TODO: optimization: remove this, but for now confine this to non-dynamic accesses
|
||||
// (the above test is correct when this is removed.)
|
||||
if (accessChain.component != NoResult)
|
||||
// non existent?
|
||||
if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult)
|
||||
return;
|
||||
|
||||
// move the swizzle over to the indexes
|
||||
if (accessChain.swizzle.size() == 1)
|
||||
// single component...
|
||||
|
||||
// skip doing it for Boolean vectors
|
||||
if (isBoolType(getContainedTypeId(accessChain.preSwizzleBaseType)))
|
||||
return;
|
||||
|
||||
if (accessChain.swizzle.size() == 1) {
|
||||
// handle static component
|
||||
accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front()));
|
||||
else
|
||||
accessChain.swizzle.clear();
|
||||
// note, the only valid remaining dynamic access would be to this one
|
||||
// component, so don't bother even looking at accessChain.component
|
||||
accessChain.preSwizzleBaseType = NoType;
|
||||
accessChain.component = NoResult;
|
||||
} else if (dynamic && accessChain.component != NoResult) {
|
||||
// handle dynamic component
|
||||
accessChain.indexChain.push_back(accessChain.component);
|
||||
|
||||
// now there is no need to track this swizzle
|
||||
accessChain.component = NoResult;
|
||||
accessChain.preSwizzleBaseType = NoType;
|
||||
accessChain.swizzle.clear();
|
||||
accessChain.preSwizzleBaseType = NoType;
|
||||
accessChain.component = NoResult;
|
||||
}
|
||||
}
|
||||
|
||||
// Utility method for creating a new block and setting the insert point to
|
||||
@@ -2292,14 +2209,23 @@ void Builder::createBranch(Block* block)
|
||||
block->addPredecessor(buildPoint);
|
||||
}
|
||||
|
||||
void Builder::createMerge(Op mergeCode, Block* mergeBlock, unsigned int control)
|
||||
void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control)
|
||||
{
|
||||
Instruction* merge = new Instruction(mergeCode);
|
||||
Instruction* merge = new Instruction(OpSelectionMerge);
|
||||
merge->addIdOperand(mergeBlock->getId());
|
||||
merge->addImmediateOperand(control);
|
||||
buildPoint->addInstruction(merge);
|
||||
}
|
||||
|
||||
void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control)
|
||||
{
|
||||
Instruction* merge = new Instruction(OpLoopMerge);
|
||||
merge->addIdOperand(mergeBlock->getId());
|
||||
merge->addIdOperand(continueBlock->getId());
|
||||
merge->addImmediateOperand(control);
|
||||
buildPoint->addInstruction(merge);
|
||||
}
|
||||
|
||||
void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock)
|
||||
{
|
||||
Instruction* branch = new Instruction(OpBranchConditional);
|
||||
|
||||
@@ -99,12 +99,14 @@ public:
|
||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
||||
Id makeFloatType(int width);
|
||||
Id makeStructType(std::vector<Id>& members, const char*);
|
||||
Id makeStructResultType(Id type0, Id type1);
|
||||
Id makeVectorType(Id component, int size);
|
||||
Id makeMatrixType(Id component, int cols, int rows);
|
||||
Id makeArrayType(Id element, unsigned size);
|
||||
Id makeRuntimeArray(Id element);
|
||||
Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
|
||||
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
|
||||
Id makeSamplerType();
|
||||
Id makeSampledImageType(Id imageType);
|
||||
|
||||
// For querying about types.
|
||||
@@ -118,12 +120,14 @@ public:
|
||||
Id getScalarTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId) const;
|
||||
Id getContainedTypeId(Id typeId, int) const;
|
||||
StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
|
||||
|
||||
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
|
||||
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
|
||||
bool isVector(Id resultId) const { return isVectorType(getTypeId(resultId)); }
|
||||
bool isMatrix(Id resultId) const { return isMatrixType(getTypeId(resultId)); }
|
||||
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
|
||||
bool isBoolType(Id typeId) const { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
|
||||
|
||||
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
|
||||
bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; }
|
||||
@@ -140,6 +144,7 @@ public:
|
||||
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
|
||||
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
|
||||
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); }
|
||||
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
|
||||
|
||||
int getTypeNumColumns(Id typeId) const
|
||||
{
|
||||
@@ -172,18 +177,17 @@ public:
|
||||
}
|
||||
|
||||
// For making new constants (will return old constant if the requested one was already made).
|
||||
Id makeBoolConstant(bool b);
|
||||
Id makeIntConstant(Id typeId, unsigned value);
|
||||
Id makeIntConstant(int i) { return makeIntConstant(makeIntType(32), (unsigned)i); }
|
||||
Id makeUintConstant(unsigned u) { return makeIntConstant(makeUintType(32), u); }
|
||||
Id makeFloatConstant(float f);
|
||||
Id makeDoubleConstant(double d);
|
||||
Id makeBoolConstant(bool b, bool specConstant = false);
|
||||
Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); }
|
||||
Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); }
|
||||
Id makeFloatConstant(float f, bool specConstant = false);
|
||||
Id makeDoubleConstant(double d, bool specConstant = false);
|
||||
|
||||
// Turn the array of constants into a proper spv constant of the requested type.
|
||||
Id makeCompositeConstant(Id type, std::vector<Id>& comps);
|
||||
|
||||
// Methods for adding information outside the CFG.
|
||||
void addEntryPoint(ExecutionModel, Function*, const char* name);
|
||||
Instruction* addEntryPoint(ExecutionModel, Function*, const char* name);
|
||||
void addExecutionMode(Function*, ExecutionMode mode, int value1 = -1, int value2 = -1, int value3 = -1);
|
||||
void addName(Id, const char* name);
|
||||
void addMemberName(Id, int member, const char* name);
|
||||
@@ -296,10 +300,11 @@ public:
|
||||
Id gradX;
|
||||
Id gradY;
|
||||
Id sample;
|
||||
Id comp;
|
||||
};
|
||||
|
||||
// Select the correct texture operation based on all inputs, and emit the correct instruction
|
||||
Id createTextureCall(Decoration precision, Id resultType, bool fetch, bool proj, const TextureParameters&);
|
||||
Id createTextureCall(Decoration precision, Id resultType, bool fetch, bool proj, bool gather, const TextureParameters&);
|
||||
|
||||
// Emit the OpTextureQuery* instruction that was passed in.
|
||||
// Figure out the right return value and type, and return it.
|
||||
@@ -426,13 +431,13 @@ public:
|
||||
//
|
||||
|
||||
struct AccessChain {
|
||||
Id base; // for l-values, pointer to the base object, for r-values, the base object
|
||||
Id base; // for l-values, pointer to the base object, for r-values, the base object
|
||||
std::vector<Id> indexChain;
|
||||
Id instr; // the instruction that generates this access chain
|
||||
std::vector<unsigned> swizzle;
|
||||
Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle
|
||||
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
|
||||
bool isRValue;
|
||||
Id instr; // cache the instruction that generates this access chain
|
||||
std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number
|
||||
Id component; // a dynamic component index, can coexist with a swizzle, done after the swizzle, NoResult if not present
|
||||
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present
|
||||
bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
|
||||
};
|
||||
|
||||
//
|
||||
@@ -490,15 +495,17 @@ public:
|
||||
void dump(std::vector<unsigned int>&) const;
|
||||
|
||||
protected:
|
||||
Id findScalarConstant(Op typeClass, Id typeId, unsigned value) const;
|
||||
Id findScalarConstant(Op typeClass, Id typeId, unsigned v1, unsigned v2) const;
|
||||
Id makeIntConstant(Id typeId, unsigned value, bool specConstant);
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const;
|
||||
Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) const;
|
||||
Id findCompositeConstant(Op typeClass, std::vector<Id>& comps) const;
|
||||
Id collapseAccessChain();
|
||||
void transferAccessChainSwizzle(bool dynamic);
|
||||
void simplifyAccessChainSwizzle();
|
||||
void mergeAccessChainSwizzle();
|
||||
void createAndSetNoPredecessorBlock(const char*);
|
||||
void createBranch(Block* block);
|
||||
void createMerge(Op, Block*, unsigned int control);
|
||||
void createSelectionMerge(Block* mergeBlock, unsigned int control);
|
||||
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control);
|
||||
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
|
||||
void dumpInstructions(std::vector<unsigned int>&, const std::vector<Instruction*>&) const;
|
||||
|
||||
|
||||
@@ -48,15 +48,17 @@
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace spv {
|
||||
// Include C-based headers that don't have a namespace
|
||||
#include "SPIRV/GLSL.std.450.h"
|
||||
}
|
||||
const char* GlslStd450DebugNames[spv::GLSLstd450Count];
|
||||
|
||||
#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;
|
||||
@@ -92,7 +94,7 @@ protected:
|
||||
void outputMask(OperandClass operandClass, unsigned mask);
|
||||
void disassembleImmediates(int numOperands);
|
||||
void disassembleIds(int numOperands);
|
||||
void disassembleString();
|
||||
int disassembleString();
|
||||
void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands);
|
||||
|
||||
// Data
|
||||
@@ -128,10 +130,10 @@ void SpirvStream::validate()
|
||||
}
|
||||
|
||||
// Version
|
||||
out << "// Module Version " << stream[word++] << std::endl;
|
||||
out << "// Module Version " << std::hex << stream[word++] << std::endl;
|
||||
|
||||
// Generator's magic number
|
||||
out << "// Generated by (magic number): " << std::setbase(16) << stream[word++] << std::setbase(10) << std::endl;
|
||||
out << "// Generated by (magic number): " << std::hex << stream[word++] << std::dec << std::endl;
|
||||
|
||||
// Result <id> bound
|
||||
bound = stream[word++];
|
||||
@@ -280,15 +282,18 @@ void SpirvStream::disassembleIds(int numOperands)
|
||||
}
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleString()
|
||||
// return the number of operands consumed by the string
|
||||
int SpirvStream::disassembleString()
|
||||
{
|
||||
int startWord = word;
|
||||
|
||||
out << " \"";
|
||||
|
||||
char* wordString;
|
||||
const char* wordString;
|
||||
bool done = false;
|
||||
do {
|
||||
unsigned int content = stream[word];
|
||||
wordString = (char*)&content;
|
||||
wordString = (const char*)&content;
|
||||
for (int charCount = 0; charCount < 4; ++charCount) {
|
||||
if (*wordString == 0) {
|
||||
done = true;
|
||||
@@ -300,6 +305,8 @@ void SpirvStream::disassembleString()
|
||||
} while (! done);
|
||||
|
||||
out << "\"";
|
||||
|
||||
return word - startWord;
|
||||
}
|
||||
|
||||
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands)
|
||||
@@ -389,15 +396,15 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
case OperandScope:
|
||||
case OperandMemorySemantics:
|
||||
disassembleIds(1);
|
||||
--numOperands;
|
||||
// Get names for printing "(XXX)" for readability, *after* this id
|
||||
if (opCode == OpName)
|
||||
idDescriptor[stream[word - 1]] = (const char*)(&stream[word]);
|
||||
break;
|
||||
case OperandOptionalId:
|
||||
case OperandVariableIds:
|
||||
disassembleIds(numOperands);
|
||||
return;
|
||||
case OperandOptionalImage:
|
||||
case OperandImageOperands:
|
||||
outputMask(OperandImageOperands, stream[word++]);
|
||||
--numOperands;
|
||||
disassembleIds(numOperands);
|
||||
@@ -440,6 +447,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
return;
|
||||
case OperandLiteralNumber:
|
||||
disassembleImmediates(1);
|
||||
--numOperands;
|
||||
if (opCode == OpExtInst) {
|
||||
ExtInstSet extInstSet = GLSL450Inst;
|
||||
if (0 == memcmp("OpenCL", (const char*)(idDescriptor[stream[word-2]].c_str()), 6)) {
|
||||
@@ -447,15 +455,16 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
}
|
||||
unsigned entrypoint = stream[word - 1];
|
||||
if (extInstSet == GLSL450Inst) {
|
||||
if (entrypoint < spv::GLSLstd450Count) {
|
||||
if (entrypoint < GLSLstd450Count) {
|
||||
out << "(" << GlslStd450DebugNames[entrypoint] << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OperandOptionalLiteralString:
|
||||
case OperandLiteralString:
|
||||
disassembleString();
|
||||
return;
|
||||
numOperands -= disassembleString();
|
||||
break;
|
||||
default:
|
||||
assert(operandClass >= OperandSource && operandClass < OperandOpcode);
|
||||
|
||||
@@ -463,10 +472,9 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode,
|
||||
outputMask(operandClass, stream[word++]);
|
||||
else
|
||||
out << OperandClassParams[operandClass].getName(stream[word++]);
|
||||
|
||||
--numOperands;
|
||||
break;
|
||||
}
|
||||
--numOperands;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -508,9 +516,9 @@ void GLSLstd450GetDebugNames(const char** names)
|
||||
names[GLSLstd450Exp2] = "Exp2";
|
||||
names[GLSLstd450Log2] = "Log2";
|
||||
names[GLSLstd450Sqrt] = "Sqrt";
|
||||
names[GLSLstd450InverseSqrt] = "Inversesqrt";
|
||||
names[GLSLstd450InverseSqrt] = "InverseSqrt";
|
||||
names[GLSLstd450Determinant] = "Determinant";
|
||||
names[GLSLstd450MatrixInverse] = "Inverse";
|
||||
names[GLSLstd450MatrixInverse] = "MatrixInverse";
|
||||
names[GLSLstd450Modf] = "Modf";
|
||||
names[GLSLstd450ModfStruct] = "ModfStruct";
|
||||
names[GLSLstd450FMin] = "FMin";
|
||||
@@ -522,9 +530,10 @@ void GLSLstd450GetDebugNames(const char** names)
|
||||
names[GLSLstd450FClamp] = "FClamp";
|
||||
names[GLSLstd450SClamp] = "SClamp";
|
||||
names[GLSLstd450UClamp] = "UClamp";
|
||||
names[GLSLstd450Mix] = "Mix";
|
||||
names[GLSLstd450FMix] = "FMix";
|
||||
names[GLSLstd450IMix] = "IMix";
|
||||
names[GLSLstd450Step] = "Step";
|
||||
names[GLSLstd450SmoothStep] = "Smoothstep";
|
||||
names[GLSLstd450SmoothStep] = "SmoothStep";
|
||||
names[GLSLstd450Fma] = "Fma";
|
||||
names[GLSLstd450Frexp] = "Frexp";
|
||||
names[GLSLstd450FrexpStruct] = "FrexpStruct";
|
||||
@@ -545,15 +554,12 @@ void GLSLstd450GetDebugNames(const char** names)
|
||||
names[GLSLstd450Distance] = "Distance";
|
||||
names[GLSLstd450Cross] = "Cross";
|
||||
names[GLSLstd450Normalize] = "Normalize";
|
||||
names[GLSLstd450FaceForward] = "Faceforward";
|
||||
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[GLSLstd450FindILsb] = "FindILsb";
|
||||
names[GLSLstd450FindSMsb] = "FindSMsb";
|
||||
names[GLSLstd450FindUMsb] = "FindUMsb";
|
||||
names[GLSLstd450InterpolateAtCentroid] = "InterpolateAtCentroid";
|
||||
names[GLSLstd450InterpolateAtSample] = "InterpolateAtSample";
|
||||
names[GLSLstd450InterpolateAtOffset] = "InterpolateAtOffset";
|
||||
|
||||
595
SPIRV/doc.cpp
595
SPIRV/doc.cpp
File diff suppressed because it is too large
Load Diff
11
SPIRV/doc.h
11
SPIRV/doc.h
@@ -116,10 +116,9 @@ enum OpcodeClass {
|
||||
enum OperandClass {
|
||||
OperandNone,
|
||||
OperandId,
|
||||
OperandOptionalId,
|
||||
OperandOptionalImage,
|
||||
OperandVariableIds,
|
||||
OperandOptionalLiteral,
|
||||
OperandOptionalLiteralString,
|
||||
OperandVariableLiterals,
|
||||
OperandVariableIdLiteral,
|
||||
OperandVariableLiteralId,
|
||||
@@ -168,18 +167,22 @@ typedef std::vector<Capability> EnumCaps;
|
||||
class OperandParameters {
|
||||
public:
|
||||
OperandParameters() { }
|
||||
void push(OperandClass oc, const char* d)
|
||||
void push(OperandClass oc, const char* d, bool opt = false)
|
||||
{
|
||||
opClass.push_back(oc);
|
||||
desc.push_back(d);
|
||||
optional.push_back(opt);
|
||||
}
|
||||
void setOptional();
|
||||
OperandClass getClass(int op) const { return opClass[op]; }
|
||||
const char* getDesc(int op) const { return desc[op]; }
|
||||
bool isOptional(int op) const { return optional[op]; }
|
||||
int getNum() const { return (int)opClass.size(); }
|
||||
|
||||
protected:
|
||||
std::vector<OperandClass> opClass;
|
||||
std::vector<const char*> desc;
|
||||
std::vector<bool> optional;
|
||||
};
|
||||
|
||||
// Parameterize an enumerant
|
||||
@@ -240,7 +243,7 @@ protected:
|
||||
int resultPresent : 1;
|
||||
};
|
||||
|
||||
const int OpcodeCeiling = 305;
|
||||
const int OpcodeCeiling = 320;
|
||||
|
||||
// The set of objects that hold all the instruction/operand
|
||||
// parameterization information.
|
||||
|
||||
136
SPIRV/spirv.hpp
136
SPIRV/spirv.hpp
@@ -25,7 +25,6 @@
|
||||
// This header is automatically generated by the same tool that creates
|
||||
// the Binary Section of the SPIR-V specification.
|
||||
|
||||
// Specification revision 31.
|
||||
// Enumeration tokens for SPIR-V, in various styles:
|
||||
// C, C++, C++11, JSON, Lua, Python
|
||||
//
|
||||
@@ -47,9 +46,12 @@ namespace spv {
|
||||
|
||||
typedef unsigned int Id;
|
||||
|
||||
#define SPV_VERSION 10000
|
||||
#define SPV_REVISION 2
|
||||
|
||||
static const unsigned int MagicNumber = 0x07230203;
|
||||
static const unsigned int Version = 99;
|
||||
static const unsigned int Revision = 31;
|
||||
static const unsigned int Version = 0x00010000;
|
||||
static const unsigned int Revision = 2;
|
||||
static const unsigned int OpCodeMask = 0xffff;
|
||||
static const unsigned int WordCountShift = 16;
|
||||
|
||||
@@ -57,7 +59,8 @@ enum SourceLanguage {
|
||||
SourceLanguageUnknown = 0,
|
||||
SourceLanguageESSL = 1,
|
||||
SourceLanguageGLSL = 2,
|
||||
SourceLanguageOpenCL = 3,
|
||||
SourceLanguageOpenCL_C = 3,
|
||||
SourceLanguageOpenCL_CPP = 4,
|
||||
};
|
||||
|
||||
enum ExecutionModel {
|
||||
@@ -96,7 +99,6 @@ enum ExecutionMode {
|
||||
ExecutionModePointMode = 10,
|
||||
ExecutionModeXfb = 11,
|
||||
ExecutionModeDepthReplacing = 12,
|
||||
ExecutionModeDepthAny = 13,
|
||||
ExecutionModeDepthGreater = 14,
|
||||
ExecutionModeDepthLess = 15,
|
||||
ExecutionModeDepthUnchanged = 16,
|
||||
@@ -105,10 +107,10 @@ enum ExecutionMode {
|
||||
ExecutionModeInputPoints = 19,
|
||||
ExecutionModeInputLines = 20,
|
||||
ExecutionModeInputLinesAdjacency = 21,
|
||||
ExecutionModeInputTriangles = 22,
|
||||
ExecutionModeTriangles = 22,
|
||||
ExecutionModeInputTrianglesAdjacency = 23,
|
||||
ExecutionModeInputQuads = 24,
|
||||
ExecutionModeInputIsolines = 25,
|
||||
ExecutionModeQuads = 24,
|
||||
ExecutionModeIsolines = 25,
|
||||
ExecutionModeOutputVertices = 26,
|
||||
ExecutionModeOutputPoints = 27,
|
||||
ExecutionModeOutputLineStrip = 28,
|
||||
@@ -122,11 +124,12 @@ enum StorageClass {
|
||||
StorageClassInput = 1,
|
||||
StorageClassUniform = 2,
|
||||
StorageClassOutput = 3,
|
||||
StorageClassWorkgroupLocal = 4,
|
||||
StorageClassWorkgroupGlobal = 5,
|
||||
StorageClassPrivateGlobal = 6,
|
||||
StorageClassWorkgroup = 4,
|
||||
StorageClassCrossWorkgroup = 5,
|
||||
StorageClassPrivate = 6,
|
||||
StorageClassFunction = 7,
|
||||
StorageClassGeneric = 8,
|
||||
StorageClassPushConstant = 9,
|
||||
StorageClassAtomicCounter = 10,
|
||||
StorageClassImage = 11,
|
||||
};
|
||||
@@ -138,6 +141,7 @@ enum Dim {
|
||||
DimCube = 3,
|
||||
DimRect = 4,
|
||||
DimBuffer = 5,
|
||||
DimSubpassData = 6,
|
||||
};
|
||||
|
||||
enum SamplerAddressingMode {
|
||||
@@ -235,6 +239,7 @@ enum ImageChannelDataType {
|
||||
ImageChannelDataTypeHalfFloat = 13,
|
||||
ImageChannelDataTypeFloat = 14,
|
||||
ImageChannelDataTypeUnormInt24 = 15,
|
||||
ImageChannelDataTypeUnormInt101010_2 = 16,
|
||||
};
|
||||
|
||||
enum ImageOperandsShift {
|
||||
@@ -245,6 +250,7 @@ enum ImageOperandsShift {
|
||||
ImageOperandsOffsetShift = 4,
|
||||
ImageOperandsConstOffsetsShift = 5,
|
||||
ImageOperandsSampleShift = 6,
|
||||
ImageOperandsMinLodShift = 7,
|
||||
};
|
||||
|
||||
enum ImageOperandsMask {
|
||||
@@ -256,6 +262,7 @@ enum ImageOperandsMask {
|
||||
ImageOperandsOffsetMask = 0x00000010,
|
||||
ImageOperandsConstOffsetsMask = 0x00000020,
|
||||
ImageOperandsSampleMask = 0x00000040,
|
||||
ImageOperandsMinLodMask = 0x00000080,
|
||||
};
|
||||
|
||||
enum FPFastMathModeShift {
|
||||
@@ -317,8 +324,7 @@ enum Decoration {
|
||||
DecorationGLSLPacked = 9,
|
||||
DecorationCPacked = 10,
|
||||
DecorationBuiltIn = 11,
|
||||
DecorationSmooth = 12,
|
||||
DecorationNoperspective = 13,
|
||||
DecorationNoPerspective = 13,
|
||||
DecorationFlat = 14,
|
||||
DecorationPatch = 15,
|
||||
DecorationCentroid = 16,
|
||||
@@ -329,10 +335,9 @@ enum Decoration {
|
||||
DecorationVolatile = 21,
|
||||
DecorationConstant = 22,
|
||||
DecorationCoherent = 23,
|
||||
DecorationNonwritable = 24,
|
||||
DecorationNonreadable = 25,
|
||||
DecorationNonWritable = 24,
|
||||
DecorationNonReadable = 25,
|
||||
DecorationUniform = 26,
|
||||
DecorationNoStaticUse = 27,
|
||||
DecorationSaturatedConversion = 28,
|
||||
DecorationStream = 29,
|
||||
DecorationLocation = 30,
|
||||
@@ -347,6 +352,9 @@ enum Decoration {
|
||||
DecorationFPRoundingMode = 39,
|
||||
DecorationFPFastMathMode = 40,
|
||||
DecorationLinkageAttributes = 41,
|
||||
DecorationNoContraction = 42,
|
||||
DecorationInputAttachmentIndex = 43,
|
||||
DecorationAlignment = 44,
|
||||
};
|
||||
|
||||
enum BuiltIn {
|
||||
@@ -370,7 +378,6 @@ enum BuiltIn {
|
||||
BuiltInSampleId = 18,
|
||||
BuiltInSamplePosition = 19,
|
||||
BuiltInSampleMask = 20,
|
||||
BuiltInFragColor = 21,
|
||||
BuiltInFragDepth = 22,
|
||||
BuiltInHelperInvocation = 23,
|
||||
BuiltInNumWorkgroups = 24,
|
||||
@@ -384,13 +391,14 @@ enum BuiltIn {
|
||||
BuiltInEnqueuedWorkgroupSize = 32,
|
||||
BuiltInGlobalOffset = 33,
|
||||
BuiltInGlobalLinearId = 34,
|
||||
BuiltInWorkgroupLinearId = 35,
|
||||
BuiltInSubgroupSize = 36,
|
||||
BuiltInSubgroupMaxSize = 37,
|
||||
BuiltInNumSubgroups = 38,
|
||||
BuiltInNumEnqueuedSubgroups = 39,
|
||||
BuiltInSubgroupId = 40,
|
||||
BuiltInSubgroupLocalInvocationId = 41,
|
||||
BuiltInVertexIndex = 42,
|
||||
BuiltInInstanceIndex = 43,
|
||||
};
|
||||
|
||||
enum SelectionControlShift {
|
||||
@@ -431,41 +439,43 @@ enum FunctionControlMask {
|
||||
};
|
||||
|
||||
enum MemorySemanticsShift {
|
||||
MemorySemanticsRelaxedShift = 0,
|
||||
MemorySemanticsSequentiallyConsistentShift = 1,
|
||||
MemorySemanticsAcquireShift = 2,
|
||||
MemorySemanticsReleaseShift = 3,
|
||||
MemorySemanticsUniformMemoryShift = 4,
|
||||
MemorySemanticsSubgroupMemoryShift = 5,
|
||||
MemorySemanticsWorkgroupLocalMemoryShift = 6,
|
||||
MemorySemanticsWorkgroupGlobalMemoryShift = 7,
|
||||
MemorySemanticsAtomicCounterMemoryShift = 8,
|
||||
MemorySemanticsImageMemoryShift = 9,
|
||||
MemorySemanticsAcquireShift = 1,
|
||||
MemorySemanticsReleaseShift = 2,
|
||||
MemorySemanticsAcquireReleaseShift = 3,
|
||||
MemorySemanticsSequentiallyConsistentShift = 4,
|
||||
MemorySemanticsUniformMemoryShift = 6,
|
||||
MemorySemanticsSubgroupMemoryShift = 7,
|
||||
MemorySemanticsWorkgroupMemoryShift = 8,
|
||||
MemorySemanticsCrossWorkgroupMemoryShift = 9,
|
||||
MemorySemanticsAtomicCounterMemoryShift = 10,
|
||||
MemorySemanticsImageMemoryShift = 11,
|
||||
};
|
||||
|
||||
enum MemorySemanticsMask {
|
||||
MemorySemanticsMaskNone = 0,
|
||||
MemorySemanticsRelaxedMask = 0x00000001,
|
||||
MemorySemanticsSequentiallyConsistentMask = 0x00000002,
|
||||
MemorySemanticsAcquireMask = 0x00000004,
|
||||
MemorySemanticsReleaseMask = 0x00000008,
|
||||
MemorySemanticsUniformMemoryMask = 0x00000010,
|
||||
MemorySemanticsSubgroupMemoryMask = 0x00000020,
|
||||
MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
|
||||
MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
|
||||
MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
|
||||
MemorySemanticsImageMemoryMask = 0x00000200,
|
||||
MemorySemanticsAcquireMask = 0x00000002,
|
||||
MemorySemanticsReleaseMask = 0x00000004,
|
||||
MemorySemanticsAcquireReleaseMask = 0x00000008,
|
||||
MemorySemanticsSequentiallyConsistentMask = 0x00000010,
|
||||
MemorySemanticsUniformMemoryMask = 0x00000040,
|
||||
MemorySemanticsSubgroupMemoryMask = 0x00000080,
|
||||
MemorySemanticsWorkgroupMemoryMask = 0x00000100,
|
||||
MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200,
|
||||
MemorySemanticsAtomicCounterMemoryMask = 0x00000400,
|
||||
MemorySemanticsImageMemoryMask = 0x00000800,
|
||||
};
|
||||
|
||||
enum MemoryAccessShift {
|
||||
MemoryAccessVolatileShift = 0,
|
||||
MemoryAccessAlignedShift = 1,
|
||||
MemoryAccessNontemporalShift = 2,
|
||||
};
|
||||
|
||||
enum MemoryAccessMask {
|
||||
MemoryAccessMaskNone = 0,
|
||||
MemoryAccessVolatileMask = 0x00000001,
|
||||
MemoryAccessAlignedMask = 0x00000002,
|
||||
MemoryAccessNontemporalMask = 0x00000004,
|
||||
};
|
||||
|
||||
enum Scope {
|
||||
@@ -514,7 +524,6 @@ enum Capability {
|
||||
CapabilityImageBasic = 13,
|
||||
CapabilityImageReadWrite = 14,
|
||||
CapabilityImageMipmap = 15,
|
||||
CapabilityImageSRGBWrite = 16,
|
||||
CapabilityPipes = 17,
|
||||
CapabilityGroups = 18,
|
||||
CapabilityDeviceEnqueue = 19,
|
||||
@@ -524,7 +533,6 @@ enum Capability {
|
||||
CapabilityTessellationPointSize = 23,
|
||||
CapabilityGeometryPointSize = 24,
|
||||
CapabilityImageGatherExtended = 25,
|
||||
CapabilityStorageImageExtendedFormats = 26,
|
||||
CapabilityStorageImageMultisample = 27,
|
||||
CapabilityUniformBufferArrayDynamicIndexing = 28,
|
||||
CapabilitySampledImageArrayDynamicIndexing = 29,
|
||||
@@ -534,11 +542,33 @@ enum Capability {
|
||||
CapabilityCullDistance = 33,
|
||||
CapabilityImageCubeArray = 34,
|
||||
CapabilitySampleRateShading = 35,
|
||||
CapabilityImageRect = 36,
|
||||
CapabilitySampledRect = 37,
|
||||
CapabilityGenericPointer = 38,
|
||||
CapabilityInt8 = 39,
|
||||
CapabilityInputAttachment = 40,
|
||||
CapabilitySparseResidency = 41,
|
||||
CapabilityMinLod = 42,
|
||||
CapabilitySampled1D = 43,
|
||||
CapabilityImage1D = 44,
|
||||
CapabilitySampledCubeArray = 45,
|
||||
CapabilitySampledBuffer = 46,
|
||||
CapabilityImageBuffer = 47,
|
||||
CapabilityImageMSArray = 48,
|
||||
CapabilityStorageImageExtendedFormats = 49,
|
||||
CapabilityImageQuery = 50,
|
||||
CapabilityDerivativeControl = 51,
|
||||
CapabilityInterpolationFunction = 52,
|
||||
CapabilityTransformFeedback = 53,
|
||||
CapabilityGeometryStreams = 54,
|
||||
CapabilityStorageImageReadWithoutFormat = 55,
|
||||
CapabilityStorageImageWriteWithoutFormat = 56,
|
||||
};
|
||||
|
||||
enum Op {
|
||||
OpNop = 0,
|
||||
OpUndef = 1,
|
||||
OpSourceContinued = 2,
|
||||
OpSource = 3,
|
||||
OpSourceExtension = 4,
|
||||
OpName = 5,
|
||||
@@ -572,6 +602,7 @@ enum Op {
|
||||
OpTypeReserveId = 36,
|
||||
OpTypeQueue = 37,
|
||||
OpTypePipe = 38,
|
||||
OpTypeForwardPointer = 39,
|
||||
OpConstantTrue = 41,
|
||||
OpConstantFalse = 42,
|
||||
OpConstant = 43,
|
||||
@@ -598,6 +629,7 @@ enum Op {
|
||||
OpPtrAccessChain = 67,
|
||||
OpArrayLength = 68,
|
||||
OpGenericPtrMemSemantics = 69,
|
||||
OpInBoundsPtrAccessChain = 70,
|
||||
OpDecorate = 71,
|
||||
OpMemberDecorate = 72,
|
||||
OpDecorationGroup = 73,
|
||||
@@ -625,7 +657,7 @@ enum Op {
|
||||
OpImageDrefGather = 97,
|
||||
OpImageRead = 98,
|
||||
OpImageWrite = 99,
|
||||
OpImageQueryDim = 100,
|
||||
OpImage = 100,
|
||||
OpImageQueryFormat = 101,
|
||||
OpImageQueryOrder = 102,
|
||||
OpImageQuerySizeLod = 103,
|
||||
@@ -674,7 +706,8 @@ enum Op {
|
||||
OpDot = 148,
|
||||
OpIAddCarry = 149,
|
||||
OpISubBorrow = 150,
|
||||
OpIMulExtended = 151,
|
||||
OpUMulExtended = 151,
|
||||
OpSMulExtended = 152,
|
||||
OpAny = 154,
|
||||
OpAll = 155,
|
||||
OpIsNan = 156,
|
||||
@@ -769,8 +802,8 @@ enum Op {
|
||||
OpUnreachable = 255,
|
||||
OpLifetimeStart = 256,
|
||||
OpLifetimeStop = 257,
|
||||
OpAsyncGroupCopy = 259,
|
||||
OpWaitGroupEvents = 260,
|
||||
OpGroupAsyncCopy = 259,
|
||||
OpGroupWaitEvents = 260,
|
||||
OpGroupAll = 261,
|
||||
OpGroupAny = 262,
|
||||
OpGroupBroadcast = 263,
|
||||
@@ -811,6 +844,21 @@ enum Op {
|
||||
OpCaptureEventProfilingInfo = 302,
|
||||
OpGetDefaultQueue = 303,
|
||||
OpBuildNDRange = 304,
|
||||
OpImageSparseSampleImplicitLod = 305,
|
||||
OpImageSparseSampleExplicitLod = 306,
|
||||
OpImageSparseSampleDrefImplicitLod = 307,
|
||||
OpImageSparseSampleDrefExplicitLod = 308,
|
||||
OpImageSparseSampleProjImplicitLod = 309,
|
||||
OpImageSparseSampleProjExplicitLod = 310,
|
||||
OpImageSparseSampleProjDrefImplicitLod = 311,
|
||||
OpImageSparseSampleProjDrefExplicitLod = 312,
|
||||
OpImageSparseFetch = 313,
|
||||
OpImageSparseGather = 314,
|
||||
OpImageSparseDrefGather = 315,
|
||||
OpImageSparseTexelsResident = 316,
|
||||
OpNoLine = 317,
|
||||
OpAtomicFlagTestAndSet = 318,
|
||||
OpAtomicFlagClear = 319,
|
||||
};
|
||||
|
||||
// Overload operator| for mask bit combining
|
||||
|
||||
@@ -74,18 +74,14 @@ const MemorySemanticsMask MemorySemanticsAllMemory = (MemorySemanticsMask)0x3FF;
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), string(0) { }
|
||||
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), string(0) { }
|
||||
virtual ~Instruction()
|
||||
{
|
||||
delete string;
|
||||
}
|
||||
Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode) { }
|
||||
explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode) { }
|
||||
virtual ~Instruction() {}
|
||||
void addIdOperand(Id id) { operands.push_back(id); }
|
||||
void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); }
|
||||
void addStringOperand(const char* str)
|
||||
{
|
||||
originalString = str;
|
||||
string = new std::vector<unsigned int>;
|
||||
unsigned int word;
|
||||
char* wordString = (char*)&word;
|
||||
char* wordPtr = wordString;
|
||||
@@ -96,7 +92,7 @@ public:
|
||||
*(wordPtr++) = c;
|
||||
++charCount;
|
||||
if (charCount == 4) {
|
||||
string->push_back(word);
|
||||
addImmediateOperand(word);
|
||||
wordPtr = wordString;
|
||||
charCount = 0;
|
||||
}
|
||||
@@ -107,7 +103,7 @@ public:
|
||||
// pad with 0s
|
||||
for (; charCount < 4; ++charCount)
|
||||
*(wordPtr++) = 0;
|
||||
string->push_back(word);
|
||||
addImmediateOperand(word);
|
||||
}
|
||||
}
|
||||
Op getOpCode() const { return opCode; }
|
||||
@@ -128,8 +124,6 @@ public:
|
||||
if (resultId)
|
||||
++wordCount;
|
||||
wordCount += (unsigned int)operands.size();
|
||||
if (string)
|
||||
wordCount += (unsigned int)string->size();
|
||||
|
||||
// Write out the beginning of the instruction
|
||||
out.push_back(((wordCount) << WordCountShift) | opCode);
|
||||
@@ -141,9 +135,6 @@ public:
|
||||
// Write out the operands
|
||||
for (int op = 0; op < (int)operands.size(); ++op)
|
||||
out.push_back(operands[op]);
|
||||
if (string)
|
||||
for (int op = 0; op < (int)string->size(); ++op)
|
||||
out.push_back((*string)[op]);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -152,7 +143,6 @@ protected:
|
||||
Id typeId;
|
||||
Op opCode;
|
||||
std::vector<Id> operands;
|
||||
std::vector<unsigned int>* string; // usually non-existent
|
||||
std::string originalString; // could be optimized away; convenience for getting string operand
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user