SPIR-V: Move from Version .99 Rev 31 to Version 1.0, Rev 2.

This commit is contained in:
John Kessenich
2015-11-15 21:33:39 -07:00
parent 1c77f3a8d2
commit 55e7d11ce8
117 changed files with 6740 additions and 5997 deletions

View File

@@ -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
};

View File

@@ -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;
}

View File

@@ -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++));

View File

@@ -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);

View File

@@ -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;

View File

@@ -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";

File diff suppressed because it is too large Load Diff

View File

@@ -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.

View File

@@ -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

View File

@@ -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
};