Fix long lines in the SPIR-V generator, retrigger bots.

This commit is contained in:
John Kessenich 2020-03-03 10:25:07 -07:00
parent bbbd9a2a1f
commit 8985fc9108
3 changed files with 283 additions and 153 deletions

View File

@ -187,7 +187,8 @@ protected:
void makeGlobalInitializers(const glslang::TIntermSequence&); void makeGlobalInitializers(const glslang::TIntermSequence&);
void visitFunctions(const glslang::TIntermSequence&); void visitFunctions(const glslang::TIntermSequence&);
void handleFunctionEntry(const glslang::TIntermAggregate* node); void handleFunctionEntry(const glslang::TIntermAggregate* node);
void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); void translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments); void translateArguments(glslang::TIntermUnary& node, std::vector<spv::Id>& arguments);
spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node); spv::Id createImageTextureFunctionCall(glslang::TIntermOperator* node);
spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*); spv::Id handleUserFunctionCall(const glslang::TIntermAggregate*);
@ -196,23 +197,31 @@ protected:
glslang::TBasicType typeProxy, bool reduceComparison = true); glslang::TBasicType typeProxy, bool reduceComparison = true);
spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right); spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right);
spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand, spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand,
glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); glslang::TBasicType typeProxy,
const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand, spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand,
glslang::TBasicType typeProxy); glslang::TBasicType typeProxy);
spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand, spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand,
glslang::TBasicType typeProxy); glslang::TBasicType typeProxy);
spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize); spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize);
spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize);
spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, spv::Id typeId, std::vector<spv::Id>& operands); const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags);
spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy); glslang::TBasicType typeProxy);
spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation,
spv::Id typeId, std::vector<spv::Id>& operands);
spv::Id createSubgroupOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands,
glslang::TBasicType typeProxy);
spv::Id createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId,
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy);
spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId); spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId);
spv::Id getSymbolId(const glslang::TIntermSymbol* node); spv::Id getSymbolId(const glslang::TIntermSymbol* node);
void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier); void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier);
spv::Id createSpvConstant(const glslang::TIntermTyped&); spv::Id createSpvConstant(const glslang::TIntermTyped&);
spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&,
int& nextConst, bool specConstant);
bool isTrivialLeaf(const glslang::TIntermTyped* node); bool isTrivialLeaf(const glslang::TIntermTyped* node);
bool isTrivial(const glslang::TIntermTyped* node); bool isTrivial(const glslang::TIntermTyped* node);
spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right);
@ -233,7 +242,8 @@ protected:
spv::Builder builder; spv::Builder builder;
bool inEntryPoint; bool inEntryPoint;
bool entryPointTerminated; bool entryPointTerminated;
bool linkageOnly; // true when visiting the set of objects in the AST present only for establishing interface, whether or not they were statically used bool linkageOnly; // true when visiting the set of objects in the AST present only for
// establishing interface, whether or not they were statically used
std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface std::set<spv::Id> iOSet; // all input/output variables from either static use or declaration of interface
const glslang::TIntermediate* glslangIntermediate; const glslang::TIntermediate* glslangIntermediate;
bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp bool nanMinMaxClamp; // true if use NMin/NMax/NClamp instead of FMin/FMax/FClamp
@ -241,7 +251,8 @@ protected:
std::unordered_map<const char*, spv::Id> extBuiltinMap; std::unordered_map<const char*, spv::Id> extBuiltinMap;
std::unordered_map<int, spv::Id> symbolValues; std::unordered_map<int, spv::Id> symbolValues;
std::unordered_set<int> rValueParameters; // set of formal function parameters passed as rValues, rather than a pointer std::unordered_set<int> rValueParameters; // set of formal function parameters passed as rValues,
// rather than a pointer
std::unordered_map<std::string, spv::Function*> functionMap; std::unordered_map<std::string, spv::Function*> functionMap;
std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount]; std::unordered_map<const glslang::TTypeList*, spv::Id> structMap[glslang::ElpCount][glslang::ElmCount];
// for mapping glslang block indices to spv indices (e.g., due to hidden members): // for mapping glslang block indices to spv indices (e.g., due to hidden members):
@ -374,7 +385,8 @@ spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useSto
} }
// Translate glslang type to SPIR-V memory decorations. // Translate glslang type to SPIR-V memory decorations.
void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory, bool useVulkanMemoryModel) void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector<spv::Decoration>& memory,
bool useVulkanMemoryModel)
{ {
if (!useVulkanMemoryModel) { if (!useVulkanMemoryModel) {
if (qualifier.isCoherent()) if (qualifier.isCoherent())
@ -640,7 +652,8 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope(
// is generated only when using the variable in an executable instruction, but not when // is generated only when using the variable in an executable instruction, but not when
// just declaring a struct member variable with it. This is true for PointSize, // just declaring a struct member variable with it. This is true for PointSize,
// ClipDistance, and CullDistance. // ClipDistance, and CullDistance.
spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn, bool memberDeclaration) spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltInVariable builtIn,
bool memberDeclaration)
{ {
switch (builtIn) { switch (builtIn) {
case glslang::EbvPointSize: case glslang::EbvPointSize:
@ -1106,7 +1119,8 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy
} }
} }
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(const glslang::TIntermSelection& selectionNode) const spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(
const glslang::TIntermSelection& selectionNode) const
{ {
if (selectionNode.getFlatten()) if (selectionNode.getFlatten())
return spv::SelectionControlFlattenMask; return spv::SelectionControlFlattenMask;
@ -1115,7 +1129,8 @@ spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSelectionControl(cons
return spv::SelectionControlMaskNone; return spv::SelectionControlMaskNone;
} }
spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode) const spv::SelectionControlMask TGlslangToSpvTraverser::TranslateSwitchControl(const glslang::TIntermSwitch& switchNode)
const
{ {
if (switchNode.getFlatten()) if (switchNode.getFlatten())
return spv::SelectionControlFlattenMask; return spv::SelectionControlFlattenMask;
@ -1350,16 +1365,17 @@ bool HasNonLayoutQualifiers(const glslang::TType& type, const glslang::TQualifie
// Implement the TGlslangToSpvTraverser class. // Implement the TGlslangToSpvTraverser class.
// //
TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const glslang::TIntermediate* glslangIntermediate, TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion,
spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) const glslang::TIntermediate* glslangIntermediate,
: TIntermTraverser(true, false, true), spv::SpvBuildLogger* buildLogger, glslang::SpvOptions& options) :
options(options), TIntermTraverser(true, false, true),
shaderEntry(nullptr), currentFunction(nullptr), options(options),
sequenceDepth(0), logger(buildLogger), shaderEntry(nullptr), currentFunction(nullptr),
builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger), sequenceDepth(0), logger(buildLogger),
inEntryPoint(false), entryPointTerminated(false), linkageOnly(false), builder(spvVersion, (glslang::GetKhronosToolId() << 16) | glslang::GetSpirvGeneratorVersion(), logger),
glslangIntermediate(glslangIntermediate), inEntryPoint(false), entryPointTerminated(false), linkageOnly(false),
nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp()) glslangIntermediate(glslangIntermediate),
nanMinMaxClamp(glslangIntermediate->getNanMinMaxClamp())
{ {
spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage()); spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage());
@ -1402,7 +1418,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT; addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
builder.addIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, spv::Spv_1_5); builder.addIncorporatedExtension(spv::E_SPV_EXT_physical_storage_buffer, spv::Spv_1_5);
builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT); builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
}; }
if (glslangIntermediate->usingVulkanMemoryModel()) { if (glslangIntermediate->usingVulkanMemoryModel()) {
memoryModel = spv::MemoryModelVulkanKHR; memoryModel = spv::MemoryModelVulkanKHR;
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
@ -1520,7 +1536,8 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
glslang::TLayoutGeometry primitive; glslang::TLayoutGeometry primitive;
if (glslangIntermediate->getStage() == EShLangTessControl) { if (glslangIntermediate->getStage() == EShLangTessControl) {
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
glslangIntermediate->getVertices());
primitive = glslangIntermediate->getOutputPrimitive(); primitive = glslangIntermediate->getOutputPrimitive();
} else { } else {
primitive = glslangIntermediate->getInputPrimitive(); primitive = glslangIntermediate->getInputPrimitive();
@ -1599,8 +1616,10 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, const gl
glslangIntermediate->getLocalSize(1), glslangIntermediate->getLocalSize(1),
glslangIntermediate->getLocalSize(2)); glslangIntermediate->getLocalSize(2));
if (glslangIntermediate->getStage() == EShLangMeshNV) { if (glslangIntermediate->getStage() == EShLangMeshNV) {
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices,
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV, glslangIntermediate->getPrimitives()); glslangIntermediate->getVertices());
builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV,
glslangIntermediate->getPrimitives());
switch (glslangIntermediate->getOutputPrimitive()) { switch (glslangIntermediate->getOutputPrimitive()) {
case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break; case glslang::ElgPoints: mode = spv::ExecutionModeOutputPoints; break;
@ -1847,7 +1866,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
int dummySize; int dummySize;
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()), builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
TranslateCoherent(node->getLeft()->getType()), TranslateCoherent(node->getLeft()->getType()),
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); glslangIntermediate->getBaseAlignmentScalar(
node->getLeft()->getType(), dummySize));
} else { } else {
// Load through a block reference is performed with a dot operator that // Load through a block reference is performed with a dot operator that
@ -1877,7 +1897,9 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
} }
// normal case for indexing array or structure or block // normal case for indexing array or structure or block
builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment()); builder.accessChainPush(builder.makeIntConstant(spvIndex),
TranslateCoherent(node->getLeft()->getType()),
node->getLeft()->getType().getBufferReferenceAlignment());
// Add capabilities here for accessing PointSize and clip/cull distance. // Add capabilities here for accessing PointSize and clip/cull distance.
// We have deferred generation of associated capabilities until now. // We have deferred generation of associated capabilities until now.
@ -1914,9 +1936,11 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
int dummySize; int dummySize;
builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()), builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
TranslateCoherent(node->getLeft()->getType()), TranslateCoherent(node->getLeft()->getType()),
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
dummySize));
} else } else
builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()), node->getLeft()->getType().getBufferReferenceAlignment()); builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()),
node->getLeft()->getType().getBufferReferenceAlignment());
} }
return false; return false;
case glslang::EOpVectorSwizzle: case glslang::EOpVectorSwizzle:
@ -1927,7 +1951,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
int dummySize; int dummySize;
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()), builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
TranslateCoherent(node->getLeft()->getType()), TranslateCoherent(node->getLeft()->getType()),
glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize)); glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(),
dummySize));
} }
return false; return false;
case glslang::EOpMatrixSwizzle: case glslang::EOpMatrixSwizzle:
@ -1943,7 +1968,8 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T
if (isTrivial(node->getRight()->getAsTyped())) if (isTrivial(node->getRight()->getAsTyped()))
break; // handle below as a normal binary operation break; // handle below as a normal binary operation
// otherwise, we need to do dynamic short circuiting on the right operand // otherwise, we need to do dynamic short circuiting on the right operand
spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(), *node->getRight()->getAsTyped()); spv::Id result = createShortCircuit(node->getOp(), *node->getLeft()->getAsTyped(),
*node->getRight()->getAsTyped());
builder.clearAccessChain(); builder.clearAccessChain();
builder.setAccessChainRValue(result); builder.setAccessChainRValue(result);
} }
@ -2091,7 +2117,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
} else { } else {
glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
block->traverse(this); block->traverse(this);
unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()->getConstArray()[0].getUConst(); unsigned int member = node->getOperand()->getAsBinaryNode()->getRight()->getAsConstantUnion()
->getConstArray()[0].getUConst();
length = builder.createArrayLength(builder.accessChainGetLValue(), member); length = builder.createArrayLength(builder.accessChainGetLValue(), member);
} }
@ -2117,7 +2144,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
// Does it need a swizzle inversion? If so, evaluation is inverted; // Does it need a swizzle inversion? If so, evaluation is inverted;
// operate first on the swizzle base, then apply the swizzle. // operate first on the swizzle base, then apply the swizzle.
spv::Id invertedType = spv::NoType; spv::Id invertedType = spv::NoType;
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
invertedType : convertGlslangToSpvType(node->getType()); };
if (node->getOp() == glslang::EOpInterpolateAtCentroid) if (node->getOp() == glslang::EOpInterpolateAtCentroid)
invertedType = getInvertedSwizzleType(*node->getOperand()); invertedType = getInvertedSwizzleType(*node->getOperand());
@ -2154,11 +2182,13 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI
// it could be a conversion // it could be a conversion
if (! result) if (! result)
result = createConversion(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType()); result = createConversion(node->getOp(), decorations, resultType(), operand,
node->getOperand()->getBasicType());
// if not, then possibly an operation // if not, then possibly an operation
if (! result) if (! result)
result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, node->getOperand()->getBasicType(), lvalueCoherentFlags); result = createUnaryOperation(node->getOp(), decorations, resultType(), operand,
node->getOperand()->getBasicType(), lvalueCoherentFlags);
if (result) { if (result) {
if (invertedType) { if (invertedType) {
@ -2251,7 +2281,8 @@ spv::Id TGlslangToSpvTraverser::createCompositeConstruct(spv::Id resultTypeId, s
std::vector<spv::Id> rTypeConstituents; std::vector<spv::Id> rTypeConstituents;
int numrTypeConstituents = builder.getNumTypeConstituents(rType); int numrTypeConstituents = builder.getNumTypeConstituents(rType);
for (int i = 0; i < numrTypeConstituents; ++i) { for (int i = 0; i < numrTypeConstituents; ++i) {
rTypeConstituents.push_back(builder.createCompositeExtract(constituent, builder.getContainedTypeId(rType, i), i)); rTypeConstituents.push_back(builder.createCompositeExtract(constituent,
builder.getContainedTypeId(rType, i), i));
} }
constituents[c] = createCompositeConstruct(lType, rTypeConstituents); constituents[c] = createCompositeConstruct(lType, rTypeConstituents);
} else { } else {
@ -2278,10 +2309,13 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
spv::Id result = spv::NoResult; spv::Id result = spv::NoResult;
spv::Id invertedType = spv::NoType; // to use to override the natural type of the node spv::Id invertedType = spv::NoType; // to use to override the natural type of the node
spv::Builder::AccessChain complexLvalue; // for holding swizzling l-values too complex for SPIR-V, for at out parameter spv::Builder::AccessChain complexLvalue; // for holding swizzling l-values too complex for SPIR-V,
// for at out parameter
spv::Id temporaryLvalue = spv::NoResult; // temporary to pass, as proxy for complexLValue spv::Id temporaryLvalue = spv::NoResult; // temporary to pass, as proxy for complexLValue
auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ? invertedType : convertGlslangToSpvType(node->getType()); }; auto resultType = [&invertedType, &node, this](){ return invertedType != spv::NoType ?
invertedType :
convertGlslangToSpvType(node->getType()); };
// try texturing // try texturing
result = createImageTextureFunctionCall(node); result = createImageTextureFunctionCall(node);
@ -2385,7 +2419,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
builder.setLine(node->getLoc().line, node->getLoc().getFilename()); builder.setLine(node->getLoc().line, node->getLoc().getFilename());
if (node->isUserDefined()) if (node->isUserDefined())
result = handleUserFunctionCall(node); result = handleUserFunctionCall(node);
// assert(result); // this can happen for bad shaders because the call graph completeness checking is not yet done
if (result) { if (result) {
builder.clearAccessChain(); builder.clearAccessChain();
builder.setAccessChainRValue(result); builder.setAccessChainRValue(result);
@ -2736,7 +2769,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
// //
if (glslangOperands[0]->getAsOperator() && if (glslangOperands[0]->getAsOperator() &&
glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle) glslangOperands[0]->getAsOperator()->getOp() == glslang::EOpVectorSwizzle)
invertedType = convertGlslangToSpvType(glslangOperands[0]->getAsBinaryNode()->getLeft()->getType()); invertedType = convertGlslangToSpvType(
glslangOperands[0]->getAsBinaryNode()->getLeft()->getType());
} }
break; break;
case glslang::EOpAtomicLoad: case glslang::EOpAtomicLoad:
@ -2796,8 +2830,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
builder.setAccessChain(save); builder.setAccessChain(save);
// Point to the first element of the array. // Point to the first element of the array.
builder.accessChainPush(elementId, TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()), builder.accessChainPush(elementId,
glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment()); TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()),
glslangOperands[arg]->getAsTyped()->getType().getBufferReferenceAlignment());
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags; spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
unsigned int alignment = builder.getAccessChain().alignment; unsigned int alignment = builder.getAccessChain().alignment;
@ -2807,7 +2842,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask; memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask;
if (node->getOp() == glslang::EOpCooperativeMatrixStore) if (node->getOp() == glslang::EOpCooperativeMatrixStore)
memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask; memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask;
if (builder.getStorageClass(builder.getAccessChain().base) == spv::StorageClassPhysicalStorageBufferEXT) { if (builder.getStorageClass(builder.getAccessChain().base) ==
spv::StorageClassPhysicalStorageBufferEXT) {
memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
} }
@ -2817,8 +2853,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
memoryAccessOperands.push_back(spv::IdImmediate(false, alignment)); memoryAccessOperands.push_back(spv::IdImmediate(false, alignment));
} }
if (memoryAccess & (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) { if (memoryAccess &
memoryAccessOperands.push_back(spv::IdImmediate(true, builder.makeUintConstant(TranslateMemoryScope(coherentFlags)))); (spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask)) {
memoryAccessOperands.push_back(spv::IdImmediate(true,
builder.makeUintConstant(TranslateMemoryScope(coherentFlags))));
} }
} else if (arg == 2) { } else if (arg == 2) {
continue; continue;
@ -2834,7 +2872,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
// receive the result, and must later swizzle that into the original // receive the result, and must later swizzle that into the original
// l-value. // l-value.
complexLvalue = builder.getAccessChain(); complexLvalue = builder.getAccessChain();
temporaryLvalue = builder.createVariable(spv::StorageClassFunction, builder.accessChainGetInferredType(), "swizzleTemp"); temporaryLvalue = builder.createVariable(spv::StorageClassFunction,
builder.accessChainGetInferredType(), "swizzleTemp");
operands.push_back(temporaryLvalue); operands.push_back(temporaryLvalue);
} else { } else {
operands.push_back(builder.accessChainGetLValue()); operands.push_back(builder.accessChainGetLValue());
@ -2879,7 +2918,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt
#endif #endif
if (atomic) { if (atomic) {
// Handle all atomics // Handle all atomics
result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags); result = createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(),
lvalueCoherentFlags);
} else { } else {
// Pass through to generic operations. // Pass through to generic operations.
switch (glslangOperands.size()) { switch (glslangOperands.size()) {
@ -3113,7 +3153,8 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
defaultSegment = (int)codeSegments.size(); defaultSegment = (int)codeSegments.size();
else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) { else if (child->getAsBranchNode() && child->getAsBranchNode()->getFlowOp() == glslang::EOpCase) {
valueIndexToSegment[caseValues.size()] = (int)codeSegments.size(); valueIndexToSegment[caseValues.size()] = (int)codeSegments.size();
caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()->getConstArray()[0].getIConst()); caseValues.push_back(child->getAsBranchNode()->getExpression()->getAsConstantUnion()
->getConstArray()[0].getIConst());
} else } else
codeSegments.push_back(child); codeSegments.push_back(child);
} }
@ -3126,7 +3167,8 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T
// make the switch statement // make the switch statement
std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call std::vector<spv::Block*> segmentBlocks; // returned, as the blocks allocated in the call
builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment, segmentBlocks); builder.makeSwitch(selector, control, (int)codeSegments.size(), caseValues, valueIndexToSegment, defaultSegment,
segmentBlocks);
// emit all the code in the segments // emit all the code in the segments
breakForLoop.push(false); breakForLoop.push(false);
@ -3383,7 +3425,8 @@ spv::Id TGlslangToSpvTraverser::getInvertedSwizzleType(const glslang::TIntermTyp
// When inverting a swizzle with a parent op, this function // When inverting a swizzle with a parent op, this function
// will apply the swizzle operation to a completed parent operation. // will apply the swizzle operation to a completed parent operation.
spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node, spv::Id parentResult) spv::Id TGlslangToSpvTraverser::createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped& node,
spv::Id parentResult)
{ {
std::vector<unsigned> swizzle; std::vector<unsigned> swizzle;
convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle); convertSwizzle(*node.getAsBinaryNode()->getRight()->getAsAggregate(), swizzle);
@ -3648,7 +3691,8 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
{ {
// Create a vector of struct types for SPIR-V to consume // Create a vector of struct types for SPIR-V to consume
std::vector<spv::Id> spvMembers; std::vector<spv::Id> spvMembers;
int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0, except sometimes for blocks int memberDelta = 0; // how much the member's index changes from glslang to SPIR-V, normally 0,
// except sometimes for blocks
std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers; std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
for (int i = 0; i < (int)glslangMembers->size(); i++) { for (int i = 0; i < (int)glslangMembers->size(); i++) {
glslang::TType& glslangMember = *(*glslangMembers)[i].type; glslang::TType& glslangMember = *(*glslangMembers)[i].type;
@ -3684,10 +3728,12 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy
deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier)); deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier));
} }
spvMembers.push_back( spvMembers.push_back(
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, true)); convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember,
true));
} else { } else {
spvMembers.push_back( spvMembers.push_back(
convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, false)); convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember,
false));
} }
} }
} }
@ -3875,11 +3921,11 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
alignment |= type.getBufferReferenceAlignment(); alignment |= type.getBufferReferenceAlignment();
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type), spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
TranslateNonUniformDecoration(type.getQualifier()), TranslateNonUniformDecoration(type.getQualifier()),
nominalTypeId, nominalTypeId,
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask), spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
TranslateMemoryScope(coherentFlags), TranslateMemoryScope(coherentFlags),
alignment); alignment);
// Need to convert to abstract types when necessary // Need to convert to abstract types when necessary
if (type.getBasicType() == glslang::EbtBool) { if (type.getBasicType() == glslang::EbtBool) {
@ -3893,7 +3939,8 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type)
int vecSize = builder.getNumTypeComponents(nominalTypeId); int vecSize = builder.getNumTypeComponents(nominalTypeId);
spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize); spv::Id bvecType = builder.makeVectorType(builder.makeBoolType(), vecSize);
if (nominalTypeId != bvecType) if (nominalTypeId != bvecType)
loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId, makeSmearedConstant(builder.makeUintConstant(0), vecSize)); loadedId = builder.createBinOp(spv::OpINotEqual, bvecType, loadedId,
makeSmearedConstant(builder.makeUintConstant(0), vecSize));
} }
} }
@ -3942,7 +3989,8 @@ void TGlslangToSpvTraverser::accessChainStore(const glslang::TType& type, spv::I
alignment |= type.getBufferReferenceAlignment(); alignment |= type.getBufferReferenceAlignment();
builder.accessChainStore(rvalue, builder.accessChainStore(rvalue,
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerVisibleKHRMask), spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) &
~spv::MemoryAccessMakePointerVisibleKHRMask),
TranslateMemoryScope(coherentFlags), alignment); TranslateMemoryScope(coherentFlags), alignment);
} }
@ -4003,7 +4051,8 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id
// set up the target storage // set up the target storage
builder.clearAccessChain(); builder.clearAccessChain();
builder.setAccessChainLValue(lValue); builder.setAccessChainLValue(lValue);
builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), type.getBufferReferenceAlignment()); builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type),
type.getBufferReferenceAlignment());
// store the member // store the member
multiTypeStore(glslangElementType, elementRValue); multiTypeStore(glslangElementType, elementRValue);
@ -4023,7 +4072,8 @@ void TGlslangToSpvTraverser::multiTypeStore(const glslang::TType& type, spv::Id
// set up the target storage // set up the target storage
builder.clearAccessChain(); builder.clearAccessChain();
builder.setAccessChainLValue(lValue); builder.setAccessChainLValue(lValue);
builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), type.getBufferReferenceAlignment()); builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type),
type.getBufferReferenceAlignment());
// store the member // store the member
multiTypeStore(glslangMemberType, memberRValue); multiTypeStore(glslangMemberType, memberRValue);
@ -4058,18 +4108,21 @@ glslang::TLayoutPacking TGlslangToSpvTraverser::getExplicitLayout(const glslang:
} }
// Given an array type, returns the integer stride required for that array // Given an array type, returns the integer stride required for that array
int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) int TGlslangToSpvTraverser::getArrayStride(const glslang::TType& arrayType, glslang::TLayoutPacking explicitLayout,
glslang::TLayoutMatrix matrixLayout)
{ {
int size; int size;
int stride; int stride;
glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); glslangIntermediate->getMemberAlignment(arrayType, size, stride, explicitLayout,
matrixLayout == glslang::ElmRowMajor);
return stride; return stride;
} }
// Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix // Given a matrix type, or array (of array) of matrixes type, returns the integer stride required for that matrix
// when used as a member of an interface block // when used as a member of an interface block
int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, glslang::TLayoutPacking explicitLayout,
glslang::TLayoutMatrix matrixLayout)
{ {
glslang::TType elementType; glslang::TType elementType;
elementType.shallowCopy(matrixType); elementType.shallowCopy(matrixType);
@ -4077,7 +4130,8 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl
int size; int size;
int stride; int stride;
glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout, matrixLayout == glslang::ElmRowMajor); glslangIntermediate->getMemberAlignment(elementType, size, stride, explicitLayout,
matrixLayout == glslang::ElmRowMajor);
return stride; return stride;
} }
@ -4088,8 +4142,8 @@ int TGlslangToSpvTraverser::getMatrixStride(const glslang::TType& matrixType, gl
// 'currentOffset' should be passed in already initialized, ready to modify, and reflecting // 'currentOffset' should be passed in already initialized, ready to modify, and reflecting
// the migration of data from nextOffset -> currentOffset. It should be -1 on the first call. // the migration of data from nextOffset -> currentOffset. It should be -1 on the first call.
// -1 means a non-forced member offset (no decoration needed). // -1 means a non-forced member offset (no decoration needed).
void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType, int& currentOffset, int& nextOffset, void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType, const glslang::TType& memberType,
glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout) int& currentOffset, int& nextOffset, glslang::TLayoutPacking explicitLayout, glslang::TLayoutMatrix matrixLayout)
{ {
// this will get a positive value when deemed necessary // this will get a positive value when deemed necessary
nextOffset = -1; nextOffset = -1;
@ -4119,7 +4173,8 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType
int memberSize; int memberSize;
int dummyStride; int dummyStride;
int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor); int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout,
matrixLayout == glslang::ElmRowMajor);
// Adjust alignment for HLSL rules // Adjust alignment for HLSL rules
// TODO: make this consistent in early phases of code: // TODO: make this consistent in early phases of code:
@ -4138,7 +4193,8 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType
glslang::RoundToPow2(currentOffset, memberAlignment); glslang::RoundToPow2(currentOffset, memberAlignment);
// Bump up to vec4 if there is a bad straddle // Bump up to vec4 if there is a bad straddle
if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, currentOffset)) if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize,
currentOffset))
glslang::RoundToPow2(currentOffset, 16); glslang::RoundToPow2(currentOffset, 16);
nextOffset = currentOffset + memberSize; nextOffset = currentOffset + memberSize;
@ -4210,7 +4266,8 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier,
// Make all the functions, skeletally, without actually visiting their bodies. // Make all the functions, skeletally, without actually visiting their bodies.
void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions) void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslFunctions)
{ {
const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type, bool useVulkanMemoryModel) { const auto getParamDecorations = [&](std::vector<spv::Decoration>& decorations, const glslang::TType& type,
bool useVulkanMemoryModel) {
spv::Decoration paramPrecision = TranslatePrecisionDecoration(type); spv::Decoration paramPrecision = TranslatePrecisionDecoration(type);
if (paramPrecision != spv::NoPrecision) if (paramPrecision != spv::NoPrecision)
decorations.push_back(paramPrecision); decorations.push_back(paramPrecision);
@ -4308,7 +4365,8 @@ void TGlslangToSpvTraverser::makeGlobalInitializers(const glslang::TIntermSequen
builder.setBuildPoint(shaderEntry->getLastBlock()); builder.setBuildPoint(shaderEntry->getLastBlock());
for (int i = 0; i < (int)initializers.size(); ++i) { for (int i = 0; i < (int)initializers.size(); ++i) {
glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate(); glslang::TIntermAggregate* initializer = initializers[i]->getAsAggregate();
if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() != glslang::EOpLinkerObjects) { if (initializer && initializer->getOp() != glslang::EOpFunction && initializer->getOp() !=
glslang::EOpLinkerObjects) {
// We're on a top-level node that's not a function. Treat as an initializer, whose // We're on a top-level node that's not a function. Treat as an initializer, whose
// code goes into the beginning of the entry point. // code goes into the beginning of the entry point.
@ -4336,7 +4394,8 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate
builder.setBuildPoint(functionBlock); builder.setBuildPoint(functionBlock);
} }
void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments, spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector<spv::Id>& arguments,
spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
{ {
const glslang::TIntermSequence& glslangArguments = node.getSequence(); const glslang::TIntermSequence& glslangArguments = node.getSequence();
@ -4349,7 +4408,8 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate&
sampler = glslangArguments[0]->getAsTyped()->getType().getSampler(); sampler = glslangArguments[0]->getAsTyped()->getType().getSampler();
cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow;
#ifndef GLSLANG_WEB #ifndef GLSLANG_WEB
f16ShadowCompare = sampler.shadow && glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16; f16ShadowCompare = sampler.shadow &&
glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16;
#endif #endif
} }
@ -4725,7 +4785,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
operands.push_back(imageOperand); operands.push_back(imageOperand);
} }
if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) { if (mask & spv::ImageOperandsMakeTexelVisibleKHRMask) {
spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(TranslateCoherent(imageType))) }; spv::IdImmediate imageOperand = { true, builder.makeUintConstant(TranslateMemoryScope(
TranslateCoherent(imageType))) };
operands.push_back(imageOperand); operands.push_back(imageOperand);
} }
@ -4764,7 +4825,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
for (; opIt != arguments.end(); ++opIt) for (; opIt != arguments.end(); ++opIt)
operands.push_back(*opIt); operands.push_back(*opIt);
return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), lvalueCoherentFlags); return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(),
lvalueCoherentFlags);
} }
} }
@ -4789,7 +4851,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
std::vector<spv::Id> comps; std::vector<spv::Id> comps;
comps.push_back(zero); comps.push_back(zero);
comps.push_back(zero); comps.push_back(zero);
operands.push_back(builder.makeCompositeConstant(builder.makeVectorType(builder.makeIntType(32), 2), comps)); operands.push_back(builder.makeCompositeConstant(
builder.makeVectorType(builder.makeIntType(32), 2), comps));
} }
for (; opIt != arguments.end(); ++opIt) for (; opIt != arguments.end(); ++opIt)
@ -4878,7 +4941,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
else else
dRefComp = builder.getNumComponents(params.coords) - 1; dRefComp = builder.getNumComponents(params.coords) - 1;
indexes.push_back(dRefComp); indexes.push_back(dRefComp);
params.Dref = builder.createCompositeExtract(params.coords, builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes); params.Dref = builder.createCompositeExtract(params.coords,
builder.getScalarTypeId(builder.getTypeId(params.coords)), indexes);
} }
// lod // lod
@ -5003,7 +5067,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
flags.clear(); flags.clear();
builder.accessChainPush(builder.makeIntConstant(i), flags, 0); builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1)); builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1),
i+1));
} }
return builder.createCompositeExtract(res, resultType(), 0); return builder.createCompositeExtract(res, resultType(), 0);
} }
@ -5026,10 +5091,9 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO
// copy the projective coordinate if we have to // copy the projective coordinate if we have to
if (projTargetComp != projSourceComp) { if (projTargetComp != projSourceComp) {
spv::Id projComp = builder.createCompositeExtract(params.coords, spv::Id projComp = builder.createCompositeExtract(params.coords,
builder.getScalarTypeId(builder.getTypeId(params.coords)), builder.getScalarTypeId(builder.getTypeId(params.coords)), projSourceComp);
projSourceComp);
params.coords = builder.createCompositeInsert(projComp, params.coords, params.coords = builder.createCompositeInsert(projComp, params.coords,
builder.getTypeId(params.coords), projTargetComp); builder.getTypeId(params.coords), projTargetComp);
} }
} }
@ -5109,7 +5173,8 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg
++lValueCount; ++lValueCount;
} else if (writableParam(qualifiers[a])) { } else if (writableParam(qualifiers[a])) {
// need space to hold the copy // need space to hold the copy
arg = builder.createVariable(spv::StorageClassFunction, builder.getContainedTypeId(function->getParamType(a)), "param"); arg = builder.createVariable(spv::StorageClassFunction,
builder.getContainedTypeId(function->getParamType(a)), "param");
if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) { if (qualifiers[a] == glslang::EvqIn || qualifiers[a] == glslang::EvqInOut) {
// need to copy the input into output space // need to copy the input into output space
builder.setAccessChain(lValues[lValueCount]); builder.setAccessChain(lValues[lValueCount]);
@ -5524,7 +5589,7 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecora
} }
spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId, spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId,
spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
{ {
spv::Op unaryOp = spv::OpNop; spv::Op unaryOp = spv::OpNop;
int extBuiltins = -1; int extBuiltins = -1;
@ -6417,7 +6482,9 @@ spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vector
} }
// For glslang ops that map to SPV atomic opCodes // For glslang ops that map to SPV atomic opCodes
spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/,
spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy,
const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags)
{ {
spv::Op opCode = spv::OpNop; spv::Op opCode = spv::OpNop;
@ -6433,12 +6500,14 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
case glslang::EOpAtomicMin: case glslang::EOpAtomicMin:
case glslang::EOpImageAtomicMin: case glslang::EOpImageAtomicMin:
case glslang::EOpAtomicCounterMin: case glslang::EOpAtomicCounterMin:
opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMin : spv::OpAtomicSMin; opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ?
spv::OpAtomicUMin : spv::OpAtomicSMin;
break; break;
case glslang::EOpAtomicMax: case glslang::EOpAtomicMax:
case glslang::EOpImageAtomicMax: case glslang::EOpImageAtomicMax:
case glslang::EOpAtomicCounterMax: case glslang::EOpAtomicCounterMax:
opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ? spv::OpAtomicUMax : spv::OpAtomicSMax; opCode = (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) ?
spv::OpAtomicUMax : spv::OpAtomicSMax;
break; break;
case glslang::EOpAtomicAnd: case glslang::EOpAtomicAnd:
case glslang::EOpImageAtomicAnd: case glslang::EOpImageAtomicAnd:
@ -6503,7 +6572,8 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
scopeId = builder.makeUintConstant(spv::ScopeDevice); scopeId = builder.makeUintConstant(spv::ScopeDevice);
} }
// semantics default to relaxed // semantics default to relaxed
spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() && glslangIntermediate->usingVulkanMemoryModel() ? spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() &&
glslangIntermediate->usingVulkanMemoryModel() ?
spv::MemorySemanticsVolatileMask : spv::MemorySemanticsVolatileMask :
spv::MemorySemanticsMaskNone); spv::MemorySemanticsMaskNone);
spv::Id semanticsId2 = semanticsId; spv::Id semanticsId2 = semanticsId;
@ -6516,20 +6586,24 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
valueId = operands[2]; valueId = operands[2];
if (operands.size() > 3) { if (operands.size() > 3) {
scopeId = operands[3]; scopeId = operands[3];
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5])); semanticsId = builder.makeUintConstant(
semanticsId2 = builder.makeUintConstant(builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7])); builder.getConstantScalar(operands[4]) | builder.getConstantScalar(operands[5]));
semanticsId2 = builder.makeUintConstant(
builder.getConstantScalar(operands[6]) | builder.getConstantScalar(operands[7]));
} }
} else if (opCode == spv::OpAtomicLoad) { } else if (opCode == spv::OpAtomicLoad) {
if (operands.size() > 1) { if (operands.size() > 1) {
scopeId = operands[1]; scopeId = operands[1];
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3])); semanticsId = builder.makeUintConstant(
builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]));
} }
} else { } else {
// atomic store or RMW // atomic store or RMW
valueId = operands[1]; valueId = operands[1];
if (operands.size() > 2) { if (operands.size() > 2) {
scopeId = operands[2]; scopeId = operands[2];
semanticsId = builder.makeUintConstant(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4])); semanticsId = builder.makeUintConstant
(builder.getConstantScalar(operands[3]) | builder.getConstantScalar(operands[4]));
} }
} }
@ -6574,7 +6648,8 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv
} }
// Create group invocation operations. // Create group invocation operations.
spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy) spv::Id TGlslangToSpvTraverser::createInvocationsOperation(glslang::TOperator op, spv::Id typeId,
std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
{ {
bool isUnsigned = isTypeUnsignedInt(typeProxy); bool isUnsigned = isTypeUnsignedInt(typeProxy);
bool isFloat = isTypeFloat(typeProxy); bool isFloat = isTypeFloat(typeProxy);
@ -6788,8 +6863,10 @@ spv::Id TGlslangToSpvTraverser::CreateInvocationsVectorOperation(spv::Op op, spv
op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax || op == spv::OpGroupFMax || op == spv::OpGroupUMax || op == spv::OpGroupSMax ||
op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast || op == spv::OpGroupFAdd || op == spv::OpGroupIAdd || op == spv::OpGroupBroadcast ||
op == spv::OpSubgroupReadInvocationKHR || op == spv::OpSubgroupReadInvocationKHR ||
op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD || op == spv::OpGroupFMinNonUniformAMD || op == spv::OpGroupUMinNonUniformAMD ||
op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD || op == spv::OpGroupSMaxNonUniformAMD || op == spv::OpGroupSMinNonUniformAMD ||
op == spv::OpGroupFMaxNonUniformAMD || op == spv::OpGroupUMaxNonUniformAMD ||
op == spv::OpGroupSMaxNonUniformAMD ||
op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD); op == spv::OpGroupFAddNonUniformAMD || op == spv::OpGroupIAddNonUniformAMD);
// Handle group invocation operations scalar by scalar. // Handle group invocation operations scalar by scalar.
@ -7178,7 +7255,8 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s
return builder.createOp(opCode, typeId, spvGroupOperands); return builder.createOp(opCode, typeId, spvGroupOperands);
} }
spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy) spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::Decoration precision,
spv::Id typeId, std::vector<spv::Id>& operands, glslang::TBasicType typeProxy)
{ {
bool isUnsigned = isTypeUnsignedInt(typeProxy); bool isUnsigned = isTypeUnsignedInt(typeProxy);
bool isFloat = isTypeFloat(typeProxy); bool isFloat = isTypeFloat(typeProxy);
@ -7280,14 +7358,16 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
unsigned int executionScope = builder.getConstantScalar(operands[0]); unsigned int executionScope = builder.getConstantScalar(operands[0]);
unsigned int memoryScope = builder.getConstantScalar(operands[1]); unsigned int memoryScope = builder.getConstantScalar(operands[1]);
unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]); unsigned int semantics = builder.getConstantScalar(operands[2]) | builder.getConstantScalar(operands[3]);
builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope, (spv::MemorySemanticsMask)semantics); builder.createControlBarrier((spv::Scope)executionScope, (spv::Scope)memoryScope,
(spv::MemorySemanticsMask)semantics);
if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask | if (semantics & (spv::MemorySemanticsMakeAvailableKHRMask |
spv::MemorySemanticsMakeVisibleKHRMask | spv::MemorySemanticsMakeVisibleKHRMask |
spv::MemorySemanticsOutputMemoryKHRMask | spv::MemorySemanticsOutputMemoryKHRMask |
spv::MemorySemanticsVolatileMask)) { spv::MemorySemanticsVolatileMask)) {
builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
} }
if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice || memoryScope == spv::ScopeDevice)) { if (glslangIntermediate->usingVulkanMemoryModel() && (executionScope == spv::ScopeDevice ||
memoryScope == spv::ScopeDevice)) {
builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR);
} }
return 0; return 0;
@ -7370,7 +7450,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
if (builder.getNumComponents(operands[0]) == 1) if (builder.getNumComponents(operands[0]) == 1)
frexpIntType = builder.makeIntegerType(width, true); frexpIntType = builder.makeIntegerType(width, true);
else else
frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true), builder.getNumComponents(operands[0])); frexpIntType = builder.makeVectorType(builder.makeIntegerType(width, true),
builder.getNumComponents(operands[0]));
typeId = builder.makeStructResultType(typeId0, frexpIntType); typeId = builder.makeStructResultType(typeId0, frexpIntType);
consumedOperands = 1; consumedOperands = 1;
} }
@ -7580,7 +7661,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv::
spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId) spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId)
{ {
// GLSL memory barriers use queuefamily scope in new model, device scope in old model // GLSL memory barriers use queuefamily scope in new model, device scope in old model
spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice; spv::Scope memoryBarrierScope = glslangIntermediate->usingVulkanMemoryModel() ?
spv::ScopeQueueFamilyKHR : spv::ScopeDevice;
switch (op) { switch (op) {
case glslang::EOpBarrier: case glslang::EOpBarrier:
@ -7809,7 +7891,8 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
#ifndef GLSLANG_WEB #ifndef GLSLANG_WEB
if (symbol->getType().isImage()) { if (symbol->getType().isImage()) {
std::vector<spv::Decoration> memory; std::vector<spv::Decoration> memory;
TranslateMemoryDecoration(symbol->getType().getQualifier(), memory, glslangIntermediate->usingVulkanMemoryModel()); TranslateMemoryDecoration(symbol->getType().getQualifier(), memory,
glslangIntermediate->usingVulkanMemoryModel());
for (unsigned int i = 0; i < memory.size(); ++i) for (unsigned int i = 0; i < memory.size(); ++i)
builder.addDecoration(id, memory[i]); builder.addDecoration(id, memory[i]);
} }
@ -7863,7 +7946,8 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol
} }
if (symbol->isReference()) { if (symbol->isReference()) {
builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); builder.addDecoration(id, symbol->getType().getQualifier().restrict ?
spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
} }
#endif #endif
@ -7925,8 +8009,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n
// hand off to the non-spec-constant path // hand off to the non-spec-constant path
assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr); assert(node.getAsConstantUnion() != nullptr || node.getAsSymbolNode() != nullptr);
int nextConst = 0; int nextConst = 0;
return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ? node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(), return createSpvConstantFromConstUnionArray(node.getType(), node.getAsConstantUnion() ?
nextConst, false); node.getAsConstantUnion()->getConstArray() : node.getAsSymbolNode()->getConstArray(),
nextConst, false);
} }
// We now know we have a specialization constant to build // We now know we have a specialization constant to build
@ -7979,7 +8064,8 @@ spv::Id TGlslangToSpvTraverser::createSpvConstant(const glslang::TIntermTyped& n
// If there are not enough elements present in 'consts', 0 will be substituted; // 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. // an empty 'consts' can be used to create a fully zeroed SPIR-V constant.
// //
spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType, const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant) spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glslang::TType& glslangType,
const glslang::TConstUnionArray& consts, int& nextConst, bool specConstant)
{ {
// vector of constants for SPIR-V // vector of constants for SPIR-V
std::vector<spv::Id> spvConsts; std::vector<spv::Id> spvConsts;
@ -8197,7 +8283,8 @@ bool TGlslangToSpvTraverser::isTrivial(const glslang::TIntermTyped* node)
// Emit short-circuiting code, where 'right' is never evaluated unless // Emit short-circuiting code, where 'right' is never evaluated unless
// the left side is true (for &&) or false (for ||). // the left side is true (for &&) or false (for ||).
spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left, glslang::TIntermTyped& right) spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslang::TIntermTyped& left,
glslang::TIntermTyped& right)
{ {
spv::Id boolTypeId = builder.makeBoolType(); spv::Id boolTypeId = builder.makeBoolType();

View File

@ -496,7 +496,8 @@ Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes)
return type->getResultId(); return type->getResultId();
} }
Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled,
ImageFormat format)
{ {
assert(sampled == 1 || sampled == 2); assert(sampled == 1 || sampled == 2);
@ -1270,7 +1271,8 @@ Function* Builder::makeEntryPoint(const char* entryPoint)
// Comments in header // Comments in header
Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name,
const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry) const std::vector<Id>& paramTypes,
const std::vector<std::vector<Decoration>>& decorations, Block **entry)
{ {
// Make the function and initial instructions in it // Make the function and initial instructions in it
Id typeId = makeFunctionType(returnType, paramTypes); Id typeId = makeFunctionType(returnType, paramTypes);
@ -1373,7 +1375,8 @@ Id Builder::createUndefined(Id type)
} }
// av/vis/nonprivate are unnecessary and illegal for some storage classes. // av/vis/nonprivate are unnecessary and illegal for some storage classes.
spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
const
{ {
switch (sc) { switch (sc) {
case spv::StorageClassUniform: case spv::StorageClassUniform:
@ -1392,7 +1395,8 @@ spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAc
} }
// Comments in header // Comments in header
void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope,
unsigned int alignment)
{ {
Instruction* store = new Instruction(OpStore); Instruction* store = new Instruction(OpStore);
store->addIdOperand(lValue); store->addIdOperand(lValue);
@ -1495,7 +1499,8 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index)
// Generate code for spec constants if in spec constant operation // Generate code for spec constants if in spec constant operation
// generation mode. // generation mode.
if (generatingOpCodeForSpecConst) { if (generatingOpCodeForSpecConst) {
return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index)); return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite),
std::vector<Id>(1, index));
} }
Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract);
extract->addIdOperand(composite); extract->addIdOperand(composite);
@ -1697,7 +1702,8 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& opera
return op->getResultId(); return op->getResultId();
} }
Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals) Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands,
const std::vector<unsigned>& literals)
{ {
Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp);
op->addImmediateOperand((unsigned) opCode); op->addImmediateOperand((unsigned) opCode);
@ -2187,7 +2193,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b
if (constituent == 0) if (constituent == 0)
resultId = subResultId; resultId = subResultId;
else else
resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision); resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId),
precision);
} }
return resultId; return resultId;
@ -2196,7 +2203,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b
// OpCompositeConstruct // OpCompositeConstruct
Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents) Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents)
{ {
assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 &&
getNumTypeConstituents(typeId) == (int)constituents.size()));
if (generatingOpCodeForSpecConst) { if (generatingOpCodeForSpecConst) {
// Sometime, even in spec-constant-op mode, the constant composite to be // Sometime, even in spec-constant-op mode, the constant composite to be
@ -2609,7 +2617,8 @@ void Builder::clearAccessChain()
} }
// Comments in header // Comments in header
void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
{ {
accessChain.coherentFlags |= coherentFlags; accessChain.coherentFlags |= coherentFlags;
accessChain.alignment |= alignment; accessChain.alignment |= alignment;
@ -2663,7 +2672,8 @@ void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, sp
} }
// Comments in header // Comments in header
Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType,
spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
{ {
Id id; Id id;
@ -3075,7 +3085,8 @@ void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const
dumpSourceInstructions(iItr->first, *iItr->second, out); dumpSourceInstructions(iItr->first, *iItr->second, out);
} }
void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const void Builder::dumpInstructions(std::vector<unsigned int>& out,
const std::vector<std::unique_ptr<Instruction> >& instructions) const
{ {
for (int i = 0; i < (int)instructions.size(); ++i) { for (int i = 0; i < (int)instructions.size(); ++i) {
instructions[i]->dump(out); instructions[i]->dump(out);

View File

@ -196,7 +196,8 @@ public:
Id getContainedTypeId(Id typeId) const; Id getContainedTypeId(Id typeId) const;
Id getContainedTypeId(Id typeId, int) const; Id getContainedTypeId(Id typeId, int) const;
StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); } StorageClass getTypeStorageClass(Id typeId) const { return module.getStorageClass(typeId); }
ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } ImageFormat getImageTypeFormat(Id typeId) const
{ return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); }
bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); }
bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); }
@ -206,12 +207,17 @@ public:
bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); } bool isAggregate(Id resultId) const { return isAggregateType(getTypeId(resultId)); }
bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); } bool isSampledImage(Id resultId) const { return isSampledImageType(getTypeId(resultId)); }
bool isBoolType(Id typeId) { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); } bool isBoolType(Id typeId)
bool isIntType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; } { return groupedTypes[OpTypeBool].size() > 0 && typeId == groupedTypes[OpTypeBool].back()->getResultId(); }
bool isUintType(Id typeId) const { return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; } bool isIntType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) != 0; }
bool isUintType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeInt && module.getInstruction(typeId)->getImmediateOperand(1) == 0; }
bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; } bool isFloatType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat; }
bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; } bool isPointerType(Id typeId) const { return getTypeClass(typeId) == OpTypePointer; }
bool isScalarType(Id typeId) const { return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt || getTypeClass(typeId) == OpTypeBool; } bool isScalarType(Id typeId) const
{ return getTypeClass(typeId) == OpTypeFloat || getTypeClass(typeId) == OpTypeInt ||
getTypeClass(typeId) == OpTypeBool; }
bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; } bool isVectorType(Id typeId) const { return getTypeClass(typeId) == OpTypeVector; }
bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; } bool isMatrixType(Id typeId) const { return getTypeClass(typeId) == OpTypeMatrix; }
bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; } bool isStructType(Id typeId) const { return getTypeClass(typeId) == OpTypeStruct; }
@ -221,7 +227,8 @@ public:
#else #else
bool isCooperativeMatrixType(Id typeId)const { return getTypeClass(typeId) == OpTypeCooperativeMatrixNV; } bool isCooperativeMatrixType(Id typeId)const { return getTypeClass(typeId) == OpTypeCooperativeMatrixNV; }
#endif #endif
bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); } bool isAggregateType(Id typeId) const
{ return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); }
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; } bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; } bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; } bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
@ -233,7 +240,8 @@ public:
bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); } bool isConstant(Id resultId) const { return isConstantOpCode(getOpCode(resultId)); }
bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; } bool isConstantScalar(Id resultId) const { return getOpCode(resultId) == OpConstant; }
bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); } bool isSpecConstant(Id resultId) const { return isSpecConstantOpCode(getOpCode(resultId)); }
unsigned int getConstantScalar(Id resultId) const { return module.getInstruction(resultId)->getImmediateOperand(0); } unsigned int getConstantScalar(Id resultId) const
{ return module.getInstruction(resultId)->getImmediateOperand(0); }
StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); } StorageClass getStorageClass(Id resultId) const { return getTypeStorageClass(getTypeId(resultId)); }
int getScalarTypeWidth(Id typeId) const int getScalarTypeWidth(Id typeId) const
@ -275,14 +283,22 @@ public:
// For making new constants (will return old constant if the requested one was already made). // For making new constants (will return old constant if the requested one was already made).
Id makeBoolConstant(bool b, bool specConstant = false); Id makeBoolConstant(bool b, bool specConstant = false);
Id makeInt8Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); } Id makeInt8Constant(int i, bool specConstant = false)
Id makeUint8Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(8), u, specConstant); } { return makeIntConstant(makeIntType(8), (unsigned)i, specConstant); }
Id makeInt16Constant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); } Id makeUint8Constant(unsigned u, bool specConstant = false)
Id makeUint16Constant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(16), u, specConstant); } { return makeIntConstant(makeUintType(8), u, specConstant); }
Id makeIntConstant(int i, bool specConstant = false) { return makeIntConstant(makeIntType(32), (unsigned)i, specConstant); } Id makeInt16Constant(int i, bool specConstant = false)
Id makeUintConstant(unsigned u, bool specConstant = false) { return makeIntConstant(makeUintType(32), u, specConstant); } { return makeIntConstant(makeIntType(16), (unsigned)i, specConstant); }
Id makeInt64Constant(long long i, bool specConstant = false) { return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); } Id makeUint16Constant(unsigned u, bool specConstant = false)
Id makeUint64Constant(unsigned long long u, bool specConstant = false) { return makeInt64Constant(makeUintType(64), u, specConstant); } { return makeIntConstant(makeUintType(16), u, specConstant); }
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 makeInt64Constant(long long i, bool specConstant = false)
{ return makeInt64Constant(makeIntType(64), (unsigned long long)i, specConstant); }
Id makeUint64Constant(unsigned long long u, bool specConstant = false)
{ return makeInt64Constant(makeUintType(64), u, specConstant); }
Id makeFloatConstant(float f, bool specConstant = false); Id makeFloatConstant(float f, bool specConstant = false);
Id makeDoubleConstant(double d, bool specConstant = false); Id makeDoubleConstant(double d, bool specConstant = false);
Id makeFloat16Constant(float f16, bool specConstant = false); Id makeFloat16Constant(float f16, bool specConstant = false);
@ -313,8 +329,8 @@ public:
// Make a shader-style function, and create its entry block if entry is non-zero. // Make a shader-style function, and create its entry block if entry is non-zero.
// Return the function, pass back the entry. // Return the function, pass back the entry.
// The returned pointer is only valid for the lifetime of this builder. // The returned pointer is only valid for the lifetime of this builder.
Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, const std::vector<Id>& paramTypes, Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name,
const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0); const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& precisions, Block **entry = 0);
// Create a return. An 'implicit' return is one not appearing in the source // Create a return. An 'implicit' return is one not appearing in the source
// code. In the case of an implicit return, no post-return block is inserted. // code. In the case of an implicit return, no post-return block is inserted.
@ -333,10 +349,12 @@ public:
Id createUndefined(Id type); Id createUndefined(Id type);
// Store into an Id and return the l-value // Store into an Id and return the l-value
void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); void createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
// Load from an Id and return it // Load from an Id and return it
Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
// Create an OpAccessChain instruction // Create an OpAccessChain instruction
Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets); Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
@ -495,7 +513,7 @@ public:
// recursion stack can hold the memory for it. // recursion stack can hold the memory for it.
// //
void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues, void makeSwitch(Id condition, unsigned int control, int numSegments, const std::vector<int>& caseValues,
const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB); // return argument const std::vector<int>& valueToSegment, int defaultSegment, std::vector<Block*>& segmentBB);
// Add a branch to the innermost switch's merge block. // Add a branch to the innermost switch's merge block.
void addSwitchBreak(); void addSwitchBreak();
@ -569,10 +587,13 @@ public:
std::vector<Id> indexChain; std::vector<Id> indexChain;
Id instr; // cache the instruction that generates this access chain Id instr; // cache the instruction that generates this access chain
std::vector<unsigned> swizzle; // each std::vector element selects the next GLSL component number 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 component; // a dynamic component index, can coexist with a swizzle,
Id preSwizzleBaseType; // dereferenced type, before swizzle or component is applied; NoType unless a swizzle or component is present // 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 bool isRValue; // true if 'base' is an r-value, otherwise, base is an l-value
unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment. Only tracks base and (optional) component selection alignment. unsigned int alignment; // bitwise OR of alignment values passed in. Accumulates worst alignment.
// Only tracks base and (optional) component selection alignment.
// Accumulate whether anything in the chain of structures has coherent decorations. // Accumulate whether anything in the chain of structures has coherent decorations.
struct CoherentFlags { struct CoherentFlags {
@ -655,11 +676,13 @@ public:
} }
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle // push new swizzle onto the end of any existing swizzle, merging into a single swizzle
void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment); void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType,
AccessChain::CoherentFlags coherentFlags, unsigned int alignment);
// push a dynamic component selection onto the access chain, only applicable with a // push a dynamic component selection onto the access chain, only applicable with a
// non-trivial swizzle or no swizzle // non-trivial swizzle or no swizzle
void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags,
unsigned int alignment)
{ {
if (accessChain.swizzle.size() != 1) { if (accessChain.swizzle.size() != 1) {
accessChain.component = component; accessChain.component = component;
@ -671,10 +694,13 @@ public:
} }
// use accessChain and swizzle to store value // use accessChain and swizzle to store value
void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone,
spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
// use accessChain and swizzle to load an r-value // use accessChain and swizzle to load an r-value
Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0); Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType,
spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax,
unsigned int alignment = 0);
// Return whether or not the access chain can be represented in SPIR-V // Return whether or not the access chain can be represented in SPIR-V
// as an l-value. // as an l-value.
@ -708,7 +734,8 @@ public:
void createBranch(Block* block); void createBranch(Block* block);
void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock); void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock);
void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, const std::vector<unsigned int>& operands); void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control,
const std::vector<unsigned int>& operands);
// Sets to generate opcode for specialization constants. // Sets to generate opcode for specialization constants.
void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; }
@ -734,7 +761,8 @@ public:
void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const; void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector<unsigned int>&) const;
void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const; void dumpInstructions(std::vector<unsigned int>&, const std::vector<std::unique_ptr<Instruction> >&) const;
void dumpModuleProcesses(std::vector<unsigned int>&) const; void dumpModuleProcesses(std::vector<unsigned int>&) const;
spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const; spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc)
const;
unsigned int spvVersion; // the version of SPIR-V to emit in the header unsigned int spvVersion; // the version of SPIR-V to emit in the header
SourceLanguage source; SourceLanguage source;
@ -769,10 +797,14 @@ public:
std::vector<std::unique_ptr<Instruction> > externals; std::vector<std::unique_ptr<Instruction> > externals;
std::vector<std::unique_ptr<Function> > functions; std::vector<std::unique_ptr<Function> > functions;
// not output, internally used for quick & dirty canonical (unique) creation // not output, internally used for quick & dirty canonical (unique) creation
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants; // map type opcodes to constant inst.
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants; // map struct-id to constant instructions // map type opcodes to constant inst.
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes; // map type opcodes to type instructions std::unordered_map<unsigned int, std::vector<Instruction*>> groupedConstants;
// map struct-id to constant instructions
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedStructConstants;
// map type opcodes to type instructions
std::unordered_map<unsigned int, std::vector<Instruction*>> groupedTypes;
// stack of switches // stack of switches
std::stack<Block*> switchMerges; std::stack<Block*> switchMerges;