SPIR-V: Move from Version .99 Rev 31 to Version 1.0, Rev 2.
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index c005197..c5342ac 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -60,7 +60,10 @@
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 @@
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 @@
case EShLangFragment: return spv::ExecutionModelFragment;
case EShLangCompute: return spv::ExecutionModelGLCompute;
default:
- spv::MissingFunctionality("GLSL stage");
+ assert(0);
return spv::ExecutionModelFragment;
}
}
@@ -191,12 +197,12 @@
// 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::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 @@
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 @@
}
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 @@
}
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
return false;
default:
- spv::MissingFunctionality("glslang unary");
+ spv::MissingFunctionality("unknown glslang unary");
break;
}
@@ -990,13 +992,7 @@
{
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
return false;
if (! result) {
- spv::MissingFunctionality("glslang aggregate");
+ spv::MissingFunctionality("unknown glslang aggregate");
return true;
} else {
builder.clearAccessChain();
@@ -1350,7 +1334,7 @@
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 @@
break;
default:
- spv::MissingFunctionality("branch type");
+ assert(0);
break;
}
@@ -1429,9 +1413,9 @@
{
// 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 @@
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 @@
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 @@
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 @@
}
break;
default:
- spv::MissingFunctionality("basic type");
+ assert(0);
break;
}
@@ -1620,10 +1604,14 @@
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 @@
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 @@
}
// 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 @@
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 @@
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::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 @@
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 @@
opCode = spv::OpAtomicLoad;
break;
default:
- spv::MissingFunctionality("missing nested atomic");
+ assert(0);
break;
}
@@ -2754,6 +2758,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
{
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;
}