GL_EXT_buffer_reference
diff --git a/SPIRV/GLSL.ext.KHR.h b/SPIRV/GLSL.ext.KHR.h
index 16b0d9c..333442b 100644
--- a/SPIRV/GLSL.ext.KHR.h
+++ b/SPIRV/GLSL.ext.KHR.h
@@ -40,5 +40,6 @@
static const char* const E_SPV_KHR_storage_buffer_storage_class = "SPV_KHR_storage_buffer_storage_class";
static const char* const E_SPV_KHR_post_depth_coverage = "SPV_KHR_post_depth_coverage";
static const char* const E_SPV_KHR_vulkan_memory_model = "SPV_KHR_vulkan_memory_model";
+static const char* const E_SPV_EXT_physical_storage_buffer = "SPV_EXT_physical_storage_buffer";
#endif // #ifndef GLSLextKHR_H
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index 6dc25ab..c7cab84 100644
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -145,9 +145,9 @@
spv::Id getInvertedSwizzleType(const glslang::TIntermTyped&);
spv::Id createInvertedSwizzle(spv::Decoration precision, const glslang::TIntermTyped&, spv::Id parentResult);
void convertSwizzle(const glslang::TIntermAggregate&, std::vector<unsigned>& swizzle);
- spv::Id convertGlslangToSpvType(const glslang::TType& type);
+ spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false);
spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&,
- bool lastBufferBlockMember);
+ bool lastBufferBlockMember, bool forwardReferenceOnly = false);
bool filterMember(const glslang::TType& member);
spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct,
glslang::TLayoutPacking, const glslang::TQualifier&);
@@ -211,6 +211,15 @@
builder.addExtension(ext);
}
+ unsigned int getBufferReferenceAlignment(const glslang::TType &type) const {
+ if (type.getBasicType() == glslang::EbtReference) {
+ return type.getReferentType()->getQualifier().hasBufferReferenceAlign() ?
+ (1u << type.getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u;
+ } else {
+ return 0;
+ }
+ }
+
glslang::SpvOptions& options;
spv::Function* shaderEntry;
spv::Function* currentFunction;
@@ -237,6 +246,8 @@
std::unordered_map<const glslang::TTypeList*, std::vector<int> > memberRemapper;
std::stack<bool> breakForLoop; // false means break for switch
std::unordered_map<std::string, const glslang::TIntermSymbol*> counterOriginator;
+ // Map pointee types for EbtReference to their forward pointers
+ std::map<const glslang::TType *, spv::Id> forwardPointers;
};
//
@@ -1303,12 +1314,22 @@
builder.addInclude(iItr->first, iItr->second);
}
stdBuiltins = builder.import("GLSL.std.450");
+
+ spv::AddressingModel addressingModel = spv::AddressingModelLogical;
+ spv::MemoryModel memoryModel = spv::MemoryModelGLSL450;
+
+ if (glslangIntermediate->usingPhysicalStorageBuffer()) {
+ addressingModel = spv::AddressingModelPhysicalStorageBuffer64EXT;
+ builder.addExtension(spv::E_SPV_EXT_physical_storage_buffer);
+ builder.addCapability(spv::CapabilityPhysicalStorageBufferAddressesEXT);
+ };
if (glslangIntermediate->usingVulkanMemoryModel()) {
- builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelVulkanKHR);
+ memoryModel = spv::MemoryModelVulkanKHR;
+ builder.addCapability(spv::CapabilityVulkanMemoryModelKHR);
builder.addExtension(spv::E_SPV_KHR_vulkan_memory_model);
- } else {
- builder.setMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
}
+ builder.setMemoryModel(addressingModel, memoryModel);
+
shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str());
entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str());
@@ -1681,8 +1702,24 @@
// so short circuit the access-chain stuff with a swizzle.
std::vector<unsigned> swizzle;
swizzle.push_back(glslangIndex);
- builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
+ int dummySize;
+ builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
+ TranslateCoherent(node->getLeft()->getType()),
+ glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
} else {
+
+ // Load through a block reference is performed with a dot operator that
+ // is mapped to EOpIndexDirectStruct. When we get to the actual reference,
+ // do a load and reset the access chain.
+ if (node->getLeft()->getBasicType() == glslang::EbtReference &&
+ !node->getLeft()->getType().isArray() &&
+ node->getOp() == glslang::EOpIndexDirectStruct)
+ {
+ spv::Id left = accessChainLoad(node->getLeft()->getType());
+ builder.clearAccessChain();
+ builder.setAccessChainLValue(left);
+ }
+
int spvIndex = glslangIndex;
if (node->getLeft()->getBasicType() == glslang::EbtBlock &&
node->getOp() == glslang::EOpIndexDirectStruct)
@@ -1695,7 +1732,7 @@
}
// normal case for indexing array or structure or block
- builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()));
+ builder.accessChainPush(builder.makeIntConstant(spvIndex), TranslateCoherent(node->getLeft()->getType()), getBufferReferenceAlignment(node->getLeft()->getType()));
// Add capabilities here for accessing PointSize and clip/cull distance.
// We have deferred generation of associated capabilities until now.
@@ -1728,10 +1765,13 @@
// restore the saved access chain
builder.setAccessChain(partial);
- if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector())
- builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()));
- else
- builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()));
+ if (! node->getLeft()->getType().isArray() && node->getLeft()->getType().isVector()) {
+ int dummySize;
+ builder.accessChainPushComponent(index, convertGlslangToSpvType(node->getLeft()->getType()),
+ TranslateCoherent(node->getLeft()->getType()),
+ glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
+ } else
+ builder.accessChainPush(index, TranslateCoherent(node->getLeft()->getType()), getBufferReferenceAlignment(node->getLeft()->getType()));
}
return false;
case glslang::EOpVectorSwizzle:
@@ -1739,7 +1779,10 @@
node->getLeft()->traverse(this);
std::vector<unsigned> swizzle;
convertSwizzle(*node->getRight()->getAsAggregate(), swizzle);
- builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()));
+ int dummySize;
+ builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
+ TranslateCoherent(node->getLeft()->getType()),
+ glslangIntermediate->getBaseAlignmentScalar(node->getLeft()->getType(), dummySize));
}
return false;
case glslang::EOpMatrixSwizzle:
@@ -2178,6 +2221,7 @@
case glslang::EOpConstructU64Vec4:
case glslang::EOpConstructStruct:
case glslang::EOpConstructTextureSampler:
+ case glslang::EOpConstructReference:
{
builder.setLine(node->getLoc().line, node->getLoc().getFilename());
std::vector<spv::Id> arguments;
@@ -2829,6 +2873,7 @@
builder.addCapability(spv::CapabilityStorageUniform16);
break;
case spv::StorageClassStorageBuffer:
+ case spv::StorageClassPhysicalStorageBufferEXT:
addPre13Extension(spv::E_SPV_KHR_16bit_storage);
builder.addCapability(spv::CapabilityStorageUniformBufferBlock16);
break;
@@ -2910,16 +2955,17 @@
// Convert from a glslang type to an SPV type, by calling into a
// recursive version of this function. This establishes the inherited
// layout state rooted from the top-level type.
-spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type)
+spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly)
{
- return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false);
+ return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly);
}
// Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id.
// explicitLayout can be kept the same throughout the hierarchical recursive walk.
// Mutually recursive with convertGlslangStructToSpvType().
spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& type,
- glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier, bool lastBufferBlockMember)
+ glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier,
+ bool lastBufferBlockMember, bool forwardReferenceOnly)
{
spv::Id spvType = spv::NoResult;
@@ -3014,6 +3060,23 @@
spvType = convertGlslangStructToSpvType(type, glslangMembers, explicitLayout, qualifier);
}
break;
+ case glslang::EbtReference:
+ {
+ // Make the forward pointer, then recurse to convert the structure type, then
+ // patch up the forward pointer with a real pointer type.
+ if (forwardPointers.find(type.getReferentType()) == forwardPointers.end()) {
+ spv::Id forwardId = builder.makeForwardPointer(spv::StorageClassPhysicalStorageBufferEXT);
+ forwardPointers[type.getReferentType()] = forwardId;
+ }
+ spvType = forwardPointers[type.getReferentType()];
+ if (!forwardReferenceOnly) {
+ spv::Id referentType = convertGlslangToSpvType(*type.getReferentType());
+ builder.makePointerFromForwardPointer(spv::StorageClassPhysicalStorageBufferEXT,
+ forwardPointers[type.getReferentType()],
+ referentType);
+ }
+ }
+ break;
default:
assert(0);
break;
@@ -3121,6 +3184,7 @@
// Create a vector of struct types for SPIR-V to consume
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
+ std::vector<std::pair<glslang::TType*, glslang::TQualifier> > deferredForwardPointers;
for (int i = 0; i < (int)glslangMembers->size(); i++) {
glslang::TType& glslangMember = *(*glslangMembers)[i].type;
if (glslangMember.hiddenMember()) {
@@ -3144,8 +3208,19 @@
// recurse
bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer &&
i == (int)glslangMembers->size() - 1;
- spvMembers.push_back(
- convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember));
+
+ // Make forward pointers for any pointer members, and create a list of members to
+ // convert to spirv types after creating the struct.
+ if (glslangMember.getBasicType() == glslang::EbtReference) {
+ if (forwardPointers.find(glslangMember.getReferentType()) == forwardPointers.end()) {
+ deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier));
+ }
+ spvMembers.push_back(
+ convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, true));
+ } else {
+ spvMembers.push_back(
+ convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, false));
+ }
}
}
@@ -3157,6 +3232,11 @@
// Decorate it
decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType);
+ for (int i = 0; i < deferredForwardPointers.size(); ++i) {
+ auto it = deferredForwardPointers[i];
+ convertGlslangToSpvType(*it.first, explicitLayout, it.second, false);
+ }
+
return spvType;
}
@@ -3320,11 +3400,15 @@
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
coherentFlags |= TranslateCoherent(type);
+ unsigned int alignment = builder.getAccessChain().alignment;
+ alignment |= getBufferReferenceAlignment(type);
+
spv::Id loadedId = builder.accessChainLoad(TranslatePrecisionDecoration(type),
TranslateNonUniformDecoration(type.getQualifier()),
nominalTypeId,
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask),
- TranslateMemoryScope(coherentFlags));
+ TranslateMemoryScope(coherentFlags),
+ alignment);
// Need to convert to abstract types when necessary
if (type.getBasicType() == glslang::EbtBool) {
@@ -3383,9 +3467,12 @@
spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags;
coherentFlags |= TranslateCoherent(type);
+ unsigned int alignment = builder.getAccessChain().alignment;
+ alignment |= getBufferReferenceAlignment(type);
+
builder.accessChainStore(rvalue,
spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerVisibleKHRMask),
- TranslateMemoryScope(coherentFlags));
+ TranslateMemoryScope(coherentFlags), alignment);
}
// For storing when types match at the glslang level, but not might match at the
@@ -3431,7 +3518,7 @@
// set up the target storage
builder.clearAccessChain();
builder.setAccessChainLValue(lValue);
- builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type));
+ builder.accessChainPush(builder.makeIntConstant(index), TranslateCoherent(type), getBufferReferenceAlignment(type));
// store the member
multiTypeStore(glslangElementType, elementRValue);
@@ -3451,7 +3538,7 @@
// set up the target storage
builder.clearAccessChain();
builder.setAccessChainLValue(lValue);
- builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type));
+ builder.accessChainPush(builder.makeIntConstant(m), TranslateCoherent(type), getBufferReferenceAlignment(type));
// store the member
multiTypeStore(glslangMemberType, memberRValue);
@@ -3638,11 +3725,22 @@
// Make all the functions, skeletally, without actually visiting their bodies.
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);
if (paramPrecision != spv::NoPrecision)
decorations.push_back(paramPrecision);
TranslateMemoryDecoration(type.getQualifier(), decorations, useVulkanMemoryModel);
+ if (type.getBasicType() == glslang::EbtReference) {
+ // Original and non-writable params pass the pointer directly and
+ // use restrict/aliased, others are stored to a pointer in Function
+ // memory and use RestrictPointer/AliasedPointer.
+ if (originalParam(type.getQualifier().storage, type, false) ||
+ !writableParam(type.getQualifier().storage)) {
+ decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrict : spv::DecorationAliased);
+ } else {
+ decorations.push_back(type.getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
+ }
+ }
};
for (int f = 0; f < (int)glslFunctions.size(); ++f) {
@@ -4459,7 +4557,7 @@
spv::Builder::AccessChain::CoherentFlags flags;
flags.clear();
- builder.accessChainPush(builder.makeIntConstant(i), flags);
+ builder.accessChainPush(builder.makeIntConstant(i), flags, 0);
builder.accessChainStore(builder.createCompositeExtract(res, builder.getContainedTypeId(resType, i+1), i+1));
}
return builder.createCompositeExtract(res, resultType(), 0);
@@ -5330,6 +5428,9 @@
unaryOp = spv::OpGroupNonUniformPartitionNV;
break;
#endif
+ case glslang::EOpConstructReference:
+ unaryOp = spv::OpBitcast;
+ break;
default:
return 0;
}
@@ -5782,6 +5883,12 @@
// For normal run-time conversion instruction, use OpBitcast.
convOp = spv::OpBitcast;
break;
+ case glslang::EOpConvUint64ToPtr:
+ convOp = spv::OpConvertUToPtr;
+ break;
+ case glslang::EOpConvPtrToUint64:
+ convOp = spv::OpConvertPtrToU;
+ break;
default:
break;
}
@@ -7247,6 +7354,10 @@
symbol->getType().getQualifier().semanticName);
}
+ if (symbol->getBasicType() == glslang::EbtReference) {
+ builder.addDecoration(id, symbol->getType().getQualifier().restrict ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT);
+ }
+
return id;
}
@@ -7375,7 +7486,7 @@
glslang::TType vectorType(glslangType, 0);
for (int col = 0; col < glslangType.getMatrixCols(); ++col)
spvConsts.push_back(createSpvConstantFromConstUnionArray(vectorType, consts, nextConst, false));
- } else if (glslangType.getStruct()) {
+ } else if (glslangType.isStruct()) {
glslang::TVector<glslang::TTypeLoc>::const_iterator iter;
for (iter = glslangType.getStruct()->begin(); iter != glslangType.getStruct()->end(); ++iter)
spvConsts.push_back(createSpvConstantFromConstUnionArray(*iter->type, consts, nextConst, false));
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index 9ba3158..3375ec4 100755
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -194,6 +194,40 @@
return type->getResultId();
}
+Id Builder::makeForwardPointer(StorageClass storageClass)
+{
+ // Caching/uniquifying doesn't work here, because we don't know the
+ // pointee type and there can be multiple forward pointers of the same
+ // storage type. Somebody higher up in the stack must keep track.
+ Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer);
+ type->addImmediateOperand(storageClass);
+ constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
+Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee)
+{
+ // try to find it
+ Instruction* type;
+ for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
+ type = groupedTypes[OpTypePointer][t];
+ if (type->getImmediateOperand(0) == (unsigned)storageClass &&
+ type->getIdOperand(1) == pointee)
+ return type->getResultId();
+ }
+
+ type = new Instruction(forwardPointerType, NoType, OpTypePointer);
+ type->addImmediateOperand(storageClass);
+ type->addIdOperand(pointee);
+ groupedTypes[OpTypePointer].push_back(type);
+ constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type));
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
Id Builder::makeIntegerType(int width, bool hasSign)
{
// try to find it
@@ -576,6 +610,7 @@
case OpTypeBool:
case OpTypeInt:
case OpTypeFloat:
+ case OpTypePointer:
return 1;
case OpTypeVector:
case OpTypeMatrix:
@@ -669,17 +704,36 @@
return true;
}
return false;
+ case OpTypePointer:
+ return false;
case OpTypeVector:
case OpTypeMatrix:
case OpTypeArray:
case OpTypeRuntimeArray:
- case OpTypePointer:
return containsType(getContainedTypeId(typeId), typeOp, width);
default:
return typeClass == typeOp;
}
}
+// return true if the type is a pointer to PhysicalStorageBufferEXT or an
+// array of such pointers. These require restrict/aliased decorations.
+bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const
+{
+ const Instruction& instr = *module.getInstruction(typeId);
+
+ Op typeClass = instr.getOpCode();
+ switch (typeClass)
+ {
+ case OpTypePointer:
+ return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT;
+ case OpTypeArray:
+ return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId));
+ default:
+ return false;
+ }
+}
+
// 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, Op opcode, Id typeId, unsigned value)
@@ -1252,15 +1306,39 @@
return inst->getResultId();
}
+// av/vis/nonprivate are unnecessary and illegal for some storage classes.
+spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const
+{
+ switch (sc) {
+ case spv::StorageClassUniform:
+ case spv::StorageClassWorkgroup:
+ case spv::StorageClassStorageBuffer:
+ case spv::StorageClassPhysicalStorageBufferEXT:
+ break;
+ default:
+ memoryAccess = spv::MemoryAccessMask(memoryAccess &
+ ~(spv::MemoryAccessMakePointerAvailableKHRMask |
+ spv::MemoryAccessMakePointerVisibleKHRMask |
+ spv::MemoryAccessNonPrivatePointerKHRMask));
+ break;
+ }
+ return memoryAccess;
+}
+
// Comments in header
-void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
+void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
{
Instruction* store = new Instruction(OpStore);
store->addIdOperand(lValue);
store->addIdOperand(rValue);
+ memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
+
if (memoryAccess != MemoryAccessMaskNone) {
store->addImmediateOperand(memoryAccess);
+ if (memoryAccess & spv::MemoryAccessAlignedMask) {
+ store->addImmediateOperand(alignment);
+ }
if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) {
store->addIdOperand(makeUintConstant(scope));
}
@@ -1270,13 +1348,18 @@
}
// Comments in header
-Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
+Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
{
Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad);
load->addIdOperand(lValue);
+ memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue));
+
if (memoryAccess != MemoryAccessMaskNone) {
load->addImmediateOperand(memoryAccess);
+ if (memoryAccess & spv::MemoryAccessAlignedMask) {
+ load->addImmediateOperand(alignment);
+ }
if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) {
load->addIdOperand(makeUintConstant(scope));
}
@@ -2118,7 +2201,8 @@
// Go through the source arguments, each one could have either
// a single or multiple components to contribute.
for (unsigned int i = 0; i < sources.size(); ++i) {
- if (isScalar(sources[i]))
+
+ if (isScalar(sources[i]) || isPointer(sources[i]))
latchResult(sources[i]);
else if (isVector(sources[i]))
accumulateVectorConstituents(sources[i]);
@@ -2433,11 +2517,15 @@
accessChain.preSwizzleBaseType = NoType;
accessChain.isRValue = false;
accessChain.coherentFlags.clear();
+ accessChain.alignment = 0;
}
// Comments in header
-void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType)
+void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
{
+ accessChain.coherentFlags |= coherentFlags;
+ accessChain.alignment |= alignment;
+
// swizzles can be stacked in GLSL, but simplified to a single
// one here; the base type doesn't change
if (accessChain.preSwizzleBaseType == NoType)
@@ -2459,7 +2547,7 @@
}
// Comments in header
-void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
+void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
{
assert(accessChain.isRValue == false);
@@ -2477,11 +2565,17 @@
source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle);
}
- createStore(source, base, memoryAccess, scope);
+ // take LSB of alignment
+ alignment = alignment & ~(alignment & (alignment-1));
+ if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) {
+ memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
+ }
+
+ createStore(source, base, memoryAccess, scope, alignment);
}
// Comments in header
-Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope)
+Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment)
{
Id id;
@@ -2524,8 +2618,15 @@
id = accessChain.base; // no precision, it was set when this was defined
} else {
transferAccessChainSwizzle(true);
+
+ // take LSB of alignment
+ alignment = alignment & ~(alignment & (alignment-1));
+ if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) {
+ memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask);
+ }
+
// load through the access chain
- id = createLoad(collapseAccessChain(), memoryAccess, scope);
+ id = createLoad(collapseAccessChain(), memoryAccess, scope, alignment);
setPrecision(id, precision);
addDecoration(id, nonUniform);
}
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index 3af6ace..edeac1b 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -138,7 +138,9 @@
// For creating new types (will return old type if the requested one was already made).
Id makeVoidType();
Id makeBoolType();
- Id makePointer(StorageClass, Id type);
+ Id makePointer(StorageClass, Id pointee);
+ Id makeForwardPointer(StorageClass);
+ Id makePointerFromForwardPointer(StorageClass, Id forwardPointerType, Id pointee);
Id makeIntegerType(int width, bool hasSign); // generic
Id makeIntType(int width) { return makeIntegerType(width, true); }
Id makeUintType(int width) { return makeIntegerType(width, false); }
@@ -194,6 +196,7 @@
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
bool containsType(Id typeId, Op typeOp, unsigned int width) const;
+ bool containsPhysicalStorageBufferOrArray(Id typeId) const;
bool isConstantOpCode(Op opcode) const;
bool isSpecConstantOpCode(Op opcode) const;
@@ -300,10 +303,10 @@
Id createUndefined(Id type);
// 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);
+ 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
- Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
+ Id createLoad(Id lValue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
// Create an OpAccessChain instruction
Id createAccessChain(StorageClass, Id base, const std::vector<Id>& offsets);
@@ -535,6 +538,7 @@
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
+ 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.
struct CoherentFlags {
@@ -601,31 +605,34 @@
}
// push offset onto the end of the chain
- void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags)
+ void accessChainPush(Id offset, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
{
accessChain.indexChain.push_back(offset);
accessChain.coherentFlags |= coherentFlags;
+ accessChain.alignment |= alignment;
}
// push new swizzle onto the end of any existing swizzle, merging into a single swizzle
- void accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType);
+ 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
// non-trivial swizzle or no swizzle
- void accessChainPushComponent(Id component, Id preSwizzleBaseType)
+ void accessChainPushComponent(Id component, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment)
{
if (accessChain.swizzle.size() != 1) {
accessChain.component = component;
if (accessChain.preSwizzleBaseType == NoType)
accessChain.preSwizzleBaseType = preSwizzleBaseType;
}
+ accessChain.coherentFlags |= coherentFlags;
+ accessChain.alignment |= alignment;
}
// use accessChain and swizzle to store value
- void accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
+ 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
- Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax);
+ Id accessChainLoad(Decoration precision, Decoration nonUniform, Id ResultType, spv::MemoryAccessMask memoryAccess = spv::MemoryAccessMaskNone, spv::Scope scope = spv::ScopeMax, unsigned int alignment = 0);
// get the direct pointer for an l-value
Id accessChainGetLValue();
@@ -639,7 +646,7 @@
void postProcess();
// Hook to visit each instruction in a block in a function
- void postProcess(const Instruction&);
+ void postProcess(Instruction&);
// Hook to visit each instruction in a reachable block in a function.
void postProcessReachable(const Instruction&);
// Hook to visit each non-32-bit sized float/int operation in a block.
@@ -675,6 +682,7 @@
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 dumpModuleProcesses(std::vector<unsigned int>&) const;
+ spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const;
unsigned int spvVersion; // the version of SPIR-V to emit in the header
SourceLanguage source;
diff --git a/SPIRV/SpvPostProcess.cpp b/SPIRV/SpvPostProcess.cpp
index 5187530..04d594c 100755
--- a/SPIRV/SpvPostProcess.cpp
+++ b/SPIRV/SpvPostProcess.cpp
@@ -87,6 +87,7 @@
StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
if (width == 8) {
switch (storageClass) {
+ case StorageClassPhysicalStorageBufferEXT:
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
@@ -97,6 +98,7 @@
}
} else if (width == 16) {
switch (storageClass) {
+ case StorageClassPhysicalStorageBufferEXT:
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
@@ -151,7 +153,7 @@
}
// Called for each instruction that resides in a block.
-void Builder::postProcess(const Instruction& inst)
+void Builder::postProcess(Instruction& inst)
{
// Add capabilities based simply on the opcode.
switch (inst.getOpCode()) {
@@ -190,6 +192,88 @@
break;
#endif
+ case OpLoad:
+ case OpStore:
+ {
+ // For any load/store to a PhysicalStorageBufferEXT, walk the accesschain
+ // index list to compute the misalignment. The pre-existing alignment value
+ // (set via Builder::AccessChain::alignment) only accounts for the base of
+ // the reference type and any scalar component selection in the accesschain,
+ // and this function computes the rest from the SPIR-V Offset decorations.
+ Instruction *accessChain = module.getInstruction(inst.getIdOperand(0));
+ if (accessChain->getOpCode() == OpAccessChain) {
+ Instruction *base = module.getInstruction(accessChain->getIdOperand(0));
+ // Get the type of the base of the access chain. It must be a pointer type.
+ Id typeId = base->getTypeId();
+ Instruction *type = module.getInstruction(typeId);
+ assert(type->getOpCode() == OpTypePointer);
+ if (type->getImmediateOperand(0) != StorageClassPhysicalStorageBufferEXT) {
+ break;
+ }
+ // Get the pointee type.
+ typeId = type->getIdOperand(1);
+ type = module.getInstruction(typeId);
+ // Walk the index list for the access chain. For each index, find any
+ // misalignment that can apply when accessing the member/element via
+ // Offset/ArrayStride/MatrixStride decorations, and bitwise OR them all
+ // together.
+ int alignment = 0;
+ for (int i = 1; i < accessChain->getNumOperands(); ++i) {
+ Instruction *idx = module.getInstruction(accessChain->getIdOperand(i));
+ if (type->getOpCode() == OpTypeStruct) {
+ assert(idx->getOpCode() == OpConstant);
+ int c = idx->getImmediateOperand(0);
+
+ const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
+ if (decoration.get()->getOpCode() == OpMemberDecorate &&
+ decoration.get()->getIdOperand(0) == typeId &&
+ decoration.get()->getImmediateOperand(1) == c &&
+ (decoration.get()->getImmediateOperand(2) == DecorationOffset ||
+ decoration.get()->getImmediateOperand(2) == DecorationMatrixStride)) {
+ alignment |= decoration.get()->getImmediateOperand(3);
+ }
+ };
+ std::for_each(decorations.begin(), decorations.end(), function);
+ // get the next member type
+ typeId = type->getIdOperand(c);
+ type = module.getInstruction(typeId);
+ } else if (type->getOpCode() == OpTypeArray ||
+ type->getOpCode() == OpTypeRuntimeArray) {
+ const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
+ if (decoration.get()->getOpCode() == OpDecorate &&
+ decoration.get()->getIdOperand(0) == typeId &&
+ decoration.get()->getImmediateOperand(1) == DecorationArrayStride) {
+ alignment |= decoration.get()->getImmediateOperand(2);
+ }
+ };
+ std::for_each(decorations.begin(), decorations.end(), function);
+ // Get the element type
+ typeId = type->getIdOperand(0);
+ type = module.getInstruction(typeId);
+ } else {
+ // Once we get to any non-aggregate type, we're done.
+ break;
+ }
+ }
+ assert(inst.getNumOperands() >= 3);
+ unsigned int memoryAccess = inst.getImmediateOperand((inst.getOpCode() == OpStore) ? 2 : 1);
+ assert(memoryAccess & MemoryAccessAlignedMask);
+ // Compute the index of the alignment operand.
+ int alignmentIdx = 2;
+ if (memoryAccess & MemoryAccessVolatileMask)
+ alignmentIdx++;
+ if (inst.getOpCode() == OpStore)
+ alignmentIdx++;
+ // Merge new and old (mis)alignment
+ alignment |= inst.getImmediateOperand(alignmentIdx);
+ // Pick the LSB
+ alignment = alignment & ~(alignment & (alignment-1));
+ // update the Aligned operand
+ inst.setImmediateOperand(alignmentIdx, alignment);
+ }
+ break;
+ }
+
default:
break;
}
@@ -258,6 +342,47 @@
Block* b = *bi;
for (auto ii = b->getInstructions().cbegin(); ii != b->getInstructions().cend(); ii++)
postProcess(*ii->get());
+
+ // For all local variables that contain pointers to PhysicalStorageBufferEXT, check whether
+ // there is an existing restrict/aliased decoration. If we don't find one, add Aliased as the
+ // default.
+ for (auto vi = b->getLocalVariables().cbegin(); vi != b->getLocalVariables().cend(); vi++) {
+ const Instruction& inst = *vi->get();
+ Id resultId = inst.getResultId();
+ if (containsPhysicalStorageBufferOrArray(getDerefTypeId(resultId))) {
+ bool foundDecoration = false;
+ const auto function = [&](const std::unique_ptr<Instruction>& decoration) {
+ if (decoration.get()->getIdOperand(0) == resultId &&
+ decoration.get()->getOpCode() == OpDecorate &&
+ (decoration.get()->getImmediateOperand(1) == spv::DecorationAliasedPointerEXT ||
+ decoration.get()->getImmediateOperand(1) == spv::DecorationRestrictPointerEXT)) {
+ foundDecoration = true;
+ }
+ };
+ std::for_each(decorations.begin(), decorations.end(), function);
+ if (!foundDecoration) {
+ addDecoration(resultId, spv::DecorationAliasedPointerEXT);
+ }
+ }
+ }
+ }
+ }
+
+ // Look for any 8/16 bit type in physical storage buffer class, and set the
+ // appropriate capability. This happens in createSpvVariable for other storage
+ // classes, but there isn't always a variable for physical storage buffer.
+ for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) {
+ Instruction* type = groupedTypes[OpTypePointer][t];
+ if (type->getImmediateOperand(0) == (unsigned)StorageClassPhysicalStorageBufferEXT) {
+ if (containsType(type->getIdOperand(1), OpTypeInt, 8)) {
+ addExtension(spv::E_SPV_KHR_8bit_storage);
+ addCapability(spv::CapabilityStorageBuffer8BitAccess);
+ }
+ if (containsType(type->getIdOperand(1), OpTypeInt, 16) ||
+ containsType(type->getIdOperand(1), OpTypeFloat, 16)) {
+ addExtension(spv::E_SPV_KHR_16bit_storage);
+ addCapability(spv::CapabilityStorageBuffer16BitAccess);
+ }
}
}
}
diff --git a/SPIRV/disassemble.cpp b/SPIRV/disassemble.cpp
index 22c83ea..631173c 100644
--- a/SPIRV/disassemble.cpp
+++ b/SPIRV/disassemble.cpp
@@ -540,6 +540,14 @@
case OperandMemoryAccess:
outputMask(OperandMemoryAccess, stream[word++]);
--numOperands;
+ // Aligned is the only memory access operand that uses an immediate
+ // value, and it is also the first operand that uses a value at all.
+ if (stream[word-1] & MemoryAccessAlignedMask) {
+ disassembleImmediates(1);
+ numOperands--;
+ if (numOperands)
+ out << " ";
+ }
disassembleIds(numOperands);
return;
default:
diff --git a/SPIRV/doc.cpp b/SPIRV/doc.cpp
index b0b01fb..bd6df10 100644
--- a/SPIRV/doc.cpp
+++ b/SPIRV/doc.cpp
@@ -124,6 +124,8 @@
case 1: return "Physical32";
case 2: return "Physical64";
+ case AddressingModelPhysicalStorageBuffer64EXT: return "PhysicalStorageBuffer64EXT";
+
default: return "Bad";
}
}
@@ -220,6 +222,8 @@
case StorageClassIncomingCallableDataNV: return "IncomingCallableDataNV";
#endif
+ case StorageClassPhysicalStorageBufferEXT: return "PhysicalStorageBufferEXT";
+
default: return "Bad";
}
}
@@ -295,6 +299,8 @@
case DecorationNonUniformEXT: return "DecorationNonUniformEXT";
case DecorationHlslCounterBufferGOOGLE: return "DecorationHlslCounterBufferGOOGLE";
case DecorationHlslSemanticGOOGLE: return "DecorationHlslSemanticGOOGLE";
+ case DecorationRestrictPointerEXT: return "DecorationRestrictPointerEXT";
+ case DecorationAliasedPointerEXT: return "DecorationAliasedPointerEXT";
}
}
@@ -922,6 +928,8 @@
case CapabilityVulkanMemoryModelKHR: return "CapabilityVulkanMemoryModelKHR";
case CapabilityVulkanMemoryModelDeviceScopeKHR: return "CapabilityVulkanMemoryModelDeviceScopeKHR";
+ case CapabilityPhysicalStorageBufferAddressesEXT: return "CapabilityPhysicalStorageBufferAddressesEXT";
+
default: return "Bad";
}
}
diff --git a/SPIRV/spirv.hpp b/SPIRV/spirv.hpp
index 72e577a..44d0616 100644
--- a/SPIRV/spirv.hpp
+++ b/SPIRV/spirv.hpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018 The Khronos Group Inc.
+// Copyright (c) 2014-2019 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"),
@@ -26,14 +26,16 @@
// the Binary Section of the SPIR-V specification.
// Enumeration tokens for SPIR-V, in various styles:
-// C, C++, C++11, JSON, Lua, Python, C#
+// C, C++, C++11, JSON, Lua, Python, C#, D
//
// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
-// - C# will use enum classes in the Specification class located in the "Spv" namespace, e.g.: Spv.Specification.SourceLanguage.GLSL
+// - C# will use enum classes in the Specification class located in the "Spv" namespace,
+// e.g.: Spv.Specification.SourceLanguage.GLSL
+// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL
//
// Some tokens act like mask values, which can be OR'd together,
// while others are mutually exclusive. The mask-like ones have
@@ -48,11 +50,11 @@
typedef unsigned int Id;
#define SPV_VERSION 0x10300
-#define SPV_REVISION 1
+#define SPV_REVISION 6
static const unsigned int MagicNumber = 0x07230203;
static const unsigned int Version = 0x00010300;
-static const unsigned int Revision = 1;
+static const unsigned int Revision = 6;
static const unsigned int OpCodeMask = 0xffff;
static const unsigned int WordCountShift = 16;
@@ -89,6 +91,7 @@
AddressingModelLogical = 0,
AddressingModelPhysical32 = 1,
AddressingModelPhysical64 = 2,
+ AddressingModelPhysicalStorageBuffer64EXT = 5348,
AddressingModelMax = 0x7fffffff,
};
@@ -140,6 +143,11 @@
ExecutionModeLocalSizeId = 38,
ExecutionModeLocalSizeHintId = 39,
ExecutionModePostDepthCoverage = 4446,
+ ExecutionModeDenormPreserve = 4459,
+ ExecutionModeDenormFlushToZero = 4460,
+ ExecutionModeSignedZeroInfNanPreserve = 4461,
+ ExecutionModeRoundingModeRTE = 4462,
+ ExecutionModeRoundingModeRTZ = 4463,
ExecutionModeStencilRefReplacingEXT = 5027,
ExecutionModeOutputLinesNV = 5269,
ExecutionModeOutputPrimitivesNV = 5270,
@@ -169,6 +177,7 @@
StorageClassHitAttributeNV = 5339,
StorageClassIncomingRayPayloadNV = 5342,
StorageClassShaderRecordBufferNV = 5343,
+ StorageClassPhysicalStorageBufferEXT = 5349,
StorageClassMax = 0x7fffffff,
};
@@ -417,6 +426,8 @@
DecorationMaxByteOffset = 45,
DecorationAlignmentId = 46,
DecorationMaxByteOffsetId = 47,
+ DecorationNoSignedWrap = 4469,
+ DecorationNoUnsignedWrap = 4470,
DecorationExplicitInterpAMD = 4999,
DecorationOverrideCoverageNV = 5248,
DecorationPassthroughNV = 5250,
@@ -427,6 +438,8 @@
DecorationPerTaskNV = 5273,
DecorationPerVertexNV = 5285,
DecorationNonUniformEXT = 5300,
+ DecorationRestrictPointerEXT = 5355,
+ DecorationAliasedPointerEXT = 5356,
DecorationHlslCounterBufferGOOGLE = 5634,
DecorationHlslSemanticGOOGLE = 5635,
DecorationMax = 0x7fffffff,
@@ -756,6 +769,11 @@
CapabilityStorageBuffer8BitAccess = 4448,
CapabilityUniformAndStorageBuffer8BitAccess = 4449,
CapabilityStoragePushConstant8 = 4450,
+ CapabilityDenormPreserve = 4464,
+ CapabilityDenormFlushToZero = 4465,
+ CapabilitySignedZeroInfNanPreserve = 4466,
+ CapabilityRoundingModeRTE = 4467,
+ CapabilityRoundingModeRTZ = 4468,
CapabilityFloat16ImageAMD = 5008,
CapabilityImageGatherBiasLodAMD = 5009,
CapabilityFragmentMaskAMD = 5010,
@@ -791,6 +809,7 @@
CapabilityRayTracingNV = 5340,
CapabilityVulkanMemoryModelKHR = 5345,
CapabilityVulkanMemoryModelDeviceScopeKHR = 5346,
+ CapabilityPhysicalStorageBufferAddressesEXT = 5347,
CapabilityComputeDerivativeGroupLinearNV = 5350,
CapabilitySubgroupShuffleINTEL = 5568,
CapabilitySubgroupBufferBlockIOINTEL = 5569,
diff --git a/SPIRV/spvIR.h b/SPIRV/spvIR.h
index 8263960..8c2d0b6 100755
--- a/SPIRV/spvIR.h
+++ b/SPIRV/spvIR.h
@@ -102,6 +102,11 @@
operands.push_back(immediate);
idOperand.push_back(false);
}
+ void setImmediateOperand(unsigned idx, unsigned int immediate) {
+ assert(!idOperand[idx]);
+ operands[idx] = immediate;
+ }
+
void addStringOperand(const char* str)
{
unsigned int word;
@@ -203,6 +208,7 @@
const std::vector<std::unique_ptr<Instruction> >& getInstructions() const {
return instructions;
}
+ const std::vector<std::unique_ptr<Instruction> >& getLocalVariables() const { return localVariables; }
void setUnreachable() { unreachable = true; }
bool isUnreachable() const { return unreachable; }
// Returns the block's merge instruction, if one exists (otherwise null).
diff --git a/Test/baseResults/spv.bufferhandle1.frag.out b/Test/baseResults/spv.bufferhandle1.frag.out
new file mode 100644
index 0000000..906cb51
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle1.frag.out
@@ -0,0 +1,104 @@
+spv.bufferhandle1.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 52
+
+ Capability Shader
+ Capability CapabilityVulkanMemoryModelKHR
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ Extension "SPV_KHR_vulkan_memory_model"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT VulkanKHR
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 7 "t2"
+ MemberName 7(t2) 0 "f"
+ MemberName 7(t2) 1 "g"
+ Name 13 "blockType"
+ MemberName 13(blockType) 0 "a"
+ MemberName 13(blockType) 1 "b"
+ MemberName 13(blockType) 2 "c"
+ MemberName 13(blockType) 3 "d"
+ MemberName 13(blockType) 4 "e"
+ MemberName 13(blockType) 5 "f"
+ MemberName 13(blockType) 6 "g"
+ Name 15 "t"
+ Name 28 "j"
+ MemberDecorate 7(t2) 0 Offset 0
+ MemberDecorate 7(t2) 1 Offset 8
+ Decorate 7(t2) Block
+ Decorate 11 ArrayStride 4
+ MemberDecorate 13(blockType) 0 Offset 0
+ MemberDecorate 13(blockType) 1 Offset 4
+ MemberDecorate 13(blockType) 2 Offset 8
+ MemberDecorate 13(blockType) 3 Offset 12
+ MemberDecorate 13(blockType) 4 Offset 16
+ MemberDecorate 13(blockType) 5 Offset 32
+ MemberDecorate 13(blockType) 6 Offset 48
+ Decorate 13(blockType) Block
+ Decorate 15(t) DescriptorSet 0
+ Decorate 15(t) Binding 0
+ Decorate 28(j) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7(t2): TypeStruct 6 6
+ 8: TypeInt 32 1
+ 9: TypeInt 32 0
+ 10: 9(int) Constant 2
+ 11: TypeArray 8(int) 10
+ 12: TypeVector 8(int) 4
+ 13(blockType): TypeStruct 8(int) 8(int) 8(int) 8(int) 8(int) 11 12(ivec4)
+ 6: TypePointer PhysicalStorageBufferEXT 13(blockType)
+ 14: TypePointer StorageBuffer 7(t2)
+ 15(t): 14(ptr) Variable StorageBuffer
+ 16: 8(int) Constant 0
+ 17: TypePointer StorageBuffer 6(ptr)
+ 20: 8(int) Constant 1
+ 23: TypePointer PhysicalStorageBufferEXT 8(int)
+ 27: TypePointer Function 6(ptr)
+ 32: 8(int) Constant 3
+ 34: 8(int) Constant 2
+ 40: 8(int) Constant 5
+ 46: 8(int) Constant 6
+ 47: 9(int) Constant 1
+ 50: 9(int) Constant 5
+ 4(main): 2 Function None 3
+ 5: Label
+ 28(j): 27(ptr) Variable Function
+ 18: 17(ptr) AccessChain 15(t) 16
+ 19: 6(ptr) Load 18
+ 21: 17(ptr) AccessChain 15(t) 20
+ 22: 6(ptr) Load 21
+ 24: 23(ptr) AccessChain 22 16
+ 25: 8(int) Load 24 Aligned 16
+ 26: 23(ptr) AccessChain 19 20
+ Store 26 25 Aligned 4
+ 29: 17(ptr) AccessChain 15(t) 16
+ 30: 6(ptr) Load 29
+ Store 28(j) 30
+ 31: 6(ptr) Load 28(j)
+ 33: 6(ptr) Load 28(j)
+ 35: 23(ptr) AccessChain 33 34
+ 36: 8(int) Load 35 Aligned 8
+ 37: 23(ptr) AccessChain 31 32
+ Store 37 36 Aligned 4
+ 38: 6(ptr) Load 28(j)
+ 39: 6(ptr) Load 28(j)
+ 41: 23(ptr) AccessChain 39 40 20
+ 42: 8(int) Load 41 Aligned 4
+ 43: 23(ptr) AccessChain 38 32
+ Store 43 42 Aligned 4
+ 44: 6(ptr) Load 28(j)
+ 45: 6(ptr) Load 28(j)
+ 48: 23(ptr) AccessChain 45 46 47
+ 49: 8(int) Load 48 Aligned MakePointerVisibleKHR NonPrivatePointerKHR 4 50
+ 51: 23(ptr) AccessChain 44 32
+ Store 51 49 Aligned 4
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle10.frag.out b/Test/baseResults/spv.bufferhandle10.frag.out
new file mode 100644
index 0000000..bfaa2d8
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle10.frag.out
@@ -0,0 +1,73 @@
+spv.bufferhandle10.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 34
+
+ Capability Shader
+ Capability CapabilityVulkanMemoryModelKHR
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ Extension "SPV_KHR_vulkan_memory_model"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT VulkanKHR
+ EntryPoint Fragment 4 "main" 19
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_ARB_gpu_shader_int64"
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 7 "t2"
+ MemberName 7(t2) 0 "f"
+ Name 10 "blockType"
+ MemberName 10(blockType) 0 "x"
+ Name 12 "t"
+ Name 19 "i"
+ Name 28 "b"
+ MemberDecorate 7(t2) 0 Offset 0
+ Decorate 7(t2) Block
+ Decorate 9 ArrayStride 4
+ MemberDecorate 10(blockType) 0 Offset 0
+ Decorate 10(blockType) Block
+ Decorate 12(t) DescriptorSet 0
+ Decorate 12(t) Binding 0
+ Decorate 19(i) Flat
+ Decorate 19(i) Location 0
+ Decorate 28(b) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7(t2): TypeStruct 6
+ 8: TypeInt 32 0
+ 9: TypeRuntimeArray 8(int)
+ 10(blockType): TypeStruct 9
+ 6: TypePointer PhysicalStorageBufferEXT 10(blockType)
+ 11: TypePointer StorageBuffer 7(t2)
+ 12(t): 11(ptr) Variable StorageBuffer
+ 13: TypeInt 32 1
+ 14: 13(int) Constant 0
+ 15: TypePointer StorageBuffer 6(ptr)
+ 18: TypePointer Input 8(int)
+ 19(i): 18(ptr) Variable Input
+ 21: TypePointer PhysicalStorageBufferEXT 8(int)
+ 23: 8(int) Constant 1
+ 24: 8(int) Constant 5
+ 25: 8(int) Constant 0
+ 27: TypePointer Function 6(ptr)
+ 32: 8(int) Constant 2
+ 4(main): 2 Function None 3
+ 5: Label
+ 28(b): 27(ptr) Variable Function
+ 16: 15(ptr) AccessChain 12(t) 14
+ 17: 6(ptr) Load 16
+ 20: 8(int) Load 19(i)
+ 22: 21(ptr) AccessChain 17 14 20
+ 26: 8(int) AtomicIAdd 22 24 25 23
+ 29: 15(ptr) AccessChain 12(t) 14
+ 30: 6(ptr) Load 29
+ Store 28(b) 30
+ 31: 6(ptr) Load 28(b)
+ 33: 21(ptr) AccessChain 31 14 14
+ Store 33 32 Aligned MakePointerAvailableKHR NonPrivatePointerKHR 4 24
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle11.frag.out b/Test/baseResults/spv.bufferhandle11.frag.out
new file mode 100644
index 0000000..0764a00
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle11.frag.out
@@ -0,0 +1,118 @@
+spv.bufferhandle11.frag
+WARNING: 0:6: '' : all default precisions are highp; use precision statements to quiet warning, e.g.:
+ "precision mediump int; precision highp float;"
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 60
+
+ Capability Shader
+ Capability CapabilityStorageBuffer8BitAccess
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_8bit_storage"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ SourceExtension "GL_EXT_shader_16bit_storage"
+ SourceExtension "GL_EXT_shader_8bit_storage"
+ Name 4 "main"
+ Name 12 "compare_uint8_t(u1;u1;"
+ Name 10 "a"
+ Name 11 "b"
+ Name 20 "allOk"
+ Name 26 "PC"
+ MemberName 26(PC) 0 "block"
+ Name 28 "Block"
+ MemberName 28(Block) 0 "var"
+ Name 30 ""
+ Name 41 "param"
+ Name 42 "param"
+ Name 48 "AcBlock"
+ MemberName 48(AcBlock) 0 "ac_numPassed"
+ Name 50 ""
+ MemberDecorate 26(PC) 0 Offset 0
+ Decorate 26(PC) Block
+ MemberDecorate 28(Block) 0 Offset 0
+ Decorate 28(Block) Block
+ MemberDecorate 48(AcBlock) 0 Offset 0
+ Decorate 48(AcBlock) Block
+ Decorate 50 DescriptorSet 0
+ Decorate 50 Binding 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeInt 32 0
+ 7: TypePointer Function 6(int)
+ 8: TypeBool
+ 9: TypeFunction 8(bool) 7(ptr) 7(ptr)
+ 19: TypePointer Function 8(bool)
+ 21: 8(bool) ConstantTrue
+ TypeForwardPointer 25 PhysicalStorageBufferEXT
+ 26(PC): TypeStruct 25
+ 27: TypeInt 8 0
+ 28(Block): TypeStruct 27(int8_t)
+ 25: TypePointer PhysicalStorageBufferEXT 28(Block)
+ 29: TypePointer PushConstant 26(PC)
+ 30: 29(ptr) Variable PushConstant
+ 31: TypeInt 32 1
+ 32: 31(int) Constant 0
+ 33: TypePointer PushConstant 25(ptr)
+ 36: TypePointer PhysicalStorageBufferEXT 27(int8_t)
+ 40: 6(int) Constant 7
+ 48(AcBlock): TypeStruct 6(int)
+ 49: TypePointer StorageBuffer 48(AcBlock)
+ 50: 49(ptr) Variable StorageBuffer
+ 51: TypePointer StorageBuffer 6(int)
+ 54: 31(int) Constant 1
+ 58: 27(int8_t) Constant 9
+ 4(main): 2 Function None 3
+ 5: Label
+ 20(allOk): 19(ptr) Variable Function
+ 41(param): 7(ptr) Variable Function
+ 42(param): 7(ptr) Variable Function
+ Store 20(allOk) 21
+ 22: 8(bool) Load 20(allOk)
+ SelectionMerge 24 None
+ BranchConditional 22 23 24
+ 23: Label
+ 34: 33(ptr) AccessChain 30 32
+ 35: 25(ptr) Load 34
+ 37: 36(ptr) AccessChain 35 32
+ 38: 27(int8_t) Load 37 Aligned 16
+ 39: 6(int) UConvert 38
+ Store 41(param) 39
+ Store 42(param) 40
+ 43: 8(bool) FunctionCall 12(compare_uint8_t(u1;u1;) 41(param) 42(param)
+ Branch 24
+ 24: Label
+ 44: 8(bool) Phi 22 5 43 23
+ Store 20(allOk) 44
+ 45: 8(bool) Load 20(allOk)
+ SelectionMerge 47 None
+ BranchConditional 45 46 47
+ 46: Label
+ 52: 51(ptr) AccessChain 50 32
+ 53: 6(int) Load 52
+ 55: 6(int) IAdd 53 54
+ Store 52 55
+ Branch 47
+ 47: Label
+ 56: 33(ptr) AccessChain 30 32
+ 57: 25(ptr) Load 56
+ 59: 36(ptr) AccessChain 57 32
+ Store 59 58 Aligned 16
+ Return
+ FunctionEnd
+12(compare_uint8_t(u1;u1;): 8(bool) Function None 9
+ 10(a): 7(ptr) FunctionParameter
+ 11(b): 7(ptr) FunctionParameter
+ 13: Label
+ 14: 6(int) Load 10(a)
+ 15: 6(int) Load 11(b)
+ 16: 8(bool) IEqual 14 15
+ ReturnValue 16
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle12.frag.out b/Test/baseResults/spv.bufferhandle12.frag.out
new file mode 100644
index 0000000..38b390f
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle12.frag.out
@@ -0,0 +1,306 @@
+spv.bufferhandle12.frag
+WARNING: 0:6: '' : all default precisions are highp; use precision statements to quiet warning, e.g.:
+ "precision mediump int; precision highp float;"
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 183
+
+ Capability Shader
+ Capability StorageUniformBufferBlock16
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_16bit_storage"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ SourceExtension "GL_EXT_shader_16bit_storage"
+ SourceExtension "GL_EXT_shader_8bit_storage"
+ Name 4 "main"
+ Name 12 "compare_float(f1;f1;"
+ Name 10 "a"
+ Name 11 "b"
+ Name 19 "compare_vec3(vf3;vf3;"
+ Name 17 "a"
+ Name 18 "b"
+ Name 26 "compare_mat2x3(mf23;mf23;"
+ Name 24 "a"
+ Name 25 "b"
+ Name 34 "compare_ivec2(vi2;vi2;"
+ Name 32 "a"
+ Name 33 "b"
+ Name 42 "compare_uvec3(vu3;vu3;"
+ Name 40 "a"
+ Name 41 "b"
+ Name 46 "compare_float16_t(f1;f1;"
+ Name 44 "a"
+ Name 45 "b"
+ Name 56 "param"
+ Name 60 "param"
+ Name 66 "param"
+ Name 70 "param"
+ Name 77 "param"
+ Name 81 "param"
+ Name 89 "param"
+ Name 92 "param"
+ Name 99 "param"
+ Name 102 "param"
+ Name 131 "allOk"
+ Name 139 "PC"
+ MemberName 139(PC) 0 "blockB"
+ MemberName 139(PC) 1 "blockC"
+ MemberName 139(PC) 2 "blockD"
+ Name 141 "BlockB"
+ MemberName 141(BlockB) 0 "a"
+ MemberName 141(BlockB) 1 "b"
+ Name 142 "BlockC"
+ MemberName 142(BlockC) 0 "c"
+ Name 143 "BlockD"
+ MemberName 143(BlockD) 0 "d"
+ Name 145 ""
+ Name 157 "param"
+ Name 161 "param"
+ Name 167 "AcBlock"
+ MemberName 167(AcBlock) 0 "ac_numPassed"
+ Name 169 ""
+ MemberDecorate 139(PC) 0 Offset 0
+ MemberDecorate 139(PC) 1 Offset 8
+ MemberDecorate 139(PC) 2 Offset 16
+ Decorate 139(PC) Block
+ MemberDecorate 141(BlockB) 0 Offset 0
+ MemberDecorate 141(BlockB) 1 Offset 8
+ Decorate 141(BlockB) Block
+ MemberDecorate 142(BlockC) 0 ColMajor
+ MemberDecorate 142(BlockC) 0 RelaxedPrecision
+ MemberDecorate 142(BlockC) 0 Offset 0
+ MemberDecorate 142(BlockC) 0 MatrixStride 16
+ Decorate 142(BlockC) Block
+ MemberDecorate 143(BlockD) 0 RelaxedPrecision
+ MemberDecorate 143(BlockD) 0 Offset 0
+ Decorate 143(BlockD) Block
+ Decorate 160 RelaxedPrecision
+ MemberDecorate 167(AcBlock) 0 Offset 0
+ Decorate 167(AcBlock) Block
+ Decorate 169 DescriptorSet 0
+ Decorate 169 Binding 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypePointer Function 6(float)
+ 8: TypeBool
+ 9: TypeFunction 8(bool) 7(ptr) 7(ptr)
+ 14: TypeVector 6(float) 3
+ 15: TypePointer Function 14(fvec3)
+ 16: TypeFunction 8(bool) 15(ptr) 15(ptr)
+ 21: TypeMatrix 14(fvec3) 2
+ 22: TypePointer Function 21
+ 23: TypeFunction 8(bool) 22(ptr) 22(ptr)
+ 28: TypeInt 32 1
+ 29: TypeVector 28(int) 2
+ 30: TypePointer Function 29(ivec2)
+ 31: TypeFunction 8(bool) 30(ptr) 30(ptr)
+ 36: TypeInt 32 0
+ 37: TypeVector 36(int) 3
+ 38: TypePointer Function 37(ivec3)
+ 39: TypeFunction 8(bool) 38(ptr) 38(ptr)
+ 52: 6(float) Constant 1028443341
+ 57: 36(int) Constant 0
+ 67: 36(int) Constant 1
+ 78: 36(int) Constant 2
+ 88: 28(int) Constant 0
+ 98: 28(int) Constant 1
+ 111: TypeVector 8(bool) 2
+ 118: TypeVector 8(bool) 3
+ 130: TypePointer Function 8(bool)
+ 132: 8(bool) ConstantTrue
+ TypeForwardPointer 136 PhysicalStorageBufferEXT
+ TypeForwardPointer 137 PhysicalStorageBufferEXT
+ TypeForwardPointer 138 PhysicalStorageBufferEXT
+ 139(PC): TypeStruct 136 137 138
+ 140: TypeFloat 16
+ 141(BlockB): TypeStruct 140(float16_t) 29(ivec2)
+ 136: TypePointer PhysicalStorageBufferEXT 141(BlockB)
+ 142(BlockC): TypeStruct 21
+ 137: TypePointer PhysicalStorageBufferEXT 142(BlockC)
+ 143(BlockD): TypeStruct 37(ivec3)
+ 138: TypePointer PhysicalStorageBufferEXT 143(BlockD)
+ 144: TypePointer PushConstant 139(PC)
+ 145: 144(ptr) Variable PushConstant
+ 146: TypePointer PushConstant 137(ptr)
+ 149: 6(float) Constant 3231711232
+ 150: 6(float) Constant 1065353216
+ 151: 6(float) Constant 3235905536
+ 152: 14(fvec3) ConstantComposite 149 150 151
+ 153: 6(float) Constant 1073741824
+ 154: 6(float) Constant 1090519040
+ 155: 14(fvec3) ConstantComposite 150 153 154
+ 156: 21 ConstantComposite 152 155
+ 158: TypePointer PhysicalStorageBufferEXT 21
+ 167(AcBlock): TypeStruct 36(int)
+ 168: TypePointer StorageBuffer 167(AcBlock)
+ 169: 168(ptr) Variable StorageBuffer
+ 170: TypePointer StorageBuffer 36(int)
+ 174: 28(int) Constant 2
+ 175: TypePointer PushConstant 138(ptr)
+ 178: 36(int) Constant 8
+ 179: 36(int) Constant 5
+ 180: 37(ivec3) ConstantComposite 178 67 179
+ 181: TypePointer PhysicalStorageBufferEXT 37(ivec3)
+ 4(main): 2 Function None 3
+ 5: Label
+ 131(allOk): 130(ptr) Variable Function
+ 157(param): 22(ptr) Variable Function
+ 161(param): 22(ptr) Variable Function
+ Store 131(allOk) 132
+ 133: 8(bool) Load 131(allOk)
+ SelectionMerge 135 None
+ BranchConditional 133 134 135
+ 134: Label
+ 147: 146(ptr) AccessChain 145 98
+ 148: 137(ptr) Load 147
+ 159: 158(ptr) AccessChain 148 88
+ 160: 21 Load 159 Aligned 16
+ Store 157(param) 160
+ Store 161(param) 156
+ 162: 8(bool) FunctionCall 26(compare_mat2x3(mf23;mf23;) 157(param) 161(param)
+ Branch 135
+ 135: Label
+ 163: 8(bool) Phi 133 5 162 134
+ Store 131(allOk) 163
+ 164: 8(bool) Load 131(allOk)
+ SelectionMerge 166 None
+ BranchConditional 164 165 166
+ 165: Label
+ 171: 170(ptr) AccessChain 169 88
+ 172: 36(int) Load 171
+ 173: 36(int) IAdd 172 98
+ Store 171 173
+ Branch 166
+ 166: Label
+ 176: 175(ptr) AccessChain 145 174
+ 177: 138(ptr) Load 176
+ 182: 181(ptr) AccessChain 177 88
+ Store 182 180 Aligned 16
+ Return
+ FunctionEnd
+12(compare_float(f1;f1;): 8(bool) Function None 9
+ 10(a): 7(ptr) FunctionParameter
+ 11(b): 7(ptr) FunctionParameter
+ 13: Label
+ 48: 6(float) Load 10(a)
+ 49: 6(float) Load 11(b)
+ 50: 6(float) FSub 48 49
+ 51: 6(float) ExtInst 1(GLSL.std.450) 4(FAbs) 50
+ 53: 8(bool) FOrdLessThan 51 52
+ ReturnValue 53
+ FunctionEnd
+19(compare_vec3(vf3;vf3;): 8(bool) Function None 16
+ 17(a): 15(ptr) FunctionParameter
+ 18(b): 15(ptr) FunctionParameter
+ 20: Label
+ 56(param): 7(ptr) Variable Function
+ 60(param): 7(ptr) Variable Function
+ 66(param): 7(ptr) Variable Function
+ 70(param): 7(ptr) Variable Function
+ 77(param): 7(ptr) Variable Function
+ 81(param): 7(ptr) Variable Function
+ 58: 7(ptr) AccessChain 17(a) 57
+ 59: 6(float) Load 58
+ Store 56(param) 59
+ 61: 7(ptr) AccessChain 18(b) 57
+ 62: 6(float) Load 61
+ Store 60(param) 62
+ 63: 8(bool) FunctionCall 12(compare_float(f1;f1;) 56(param) 60(param)
+ SelectionMerge 65 None
+ BranchConditional 63 64 65
+ 64: Label
+ 68: 7(ptr) AccessChain 17(a) 67
+ 69: 6(float) Load 68
+ Store 66(param) 69
+ 71: 7(ptr) AccessChain 18(b) 67
+ 72: 6(float) Load 71
+ Store 70(param) 72
+ 73: 8(bool) FunctionCall 12(compare_float(f1;f1;) 66(param) 70(param)
+ Branch 65
+ 65: Label
+ 74: 8(bool) Phi 63 20 73 64
+ SelectionMerge 76 None
+ BranchConditional 74 75 76
+ 75: Label
+ 79: 7(ptr) AccessChain 17(a) 78
+ 80: 6(float) Load 79
+ Store 77(param) 80
+ 82: 7(ptr) AccessChain 18(b) 78
+ 83: 6(float) Load 82
+ Store 81(param) 83
+ 84: 8(bool) FunctionCall 12(compare_float(f1;f1;) 77(param) 81(param)
+ Branch 76
+ 76: Label
+ 85: 8(bool) Phi 74 65 84 75
+ ReturnValue 85
+ FunctionEnd
+26(compare_mat2x3(mf23;mf23;): 8(bool) Function None 23
+ 24(a): 22(ptr) FunctionParameter
+ 25(b): 22(ptr) FunctionParameter
+ 27: Label
+ 89(param): 15(ptr) Variable Function
+ 92(param): 15(ptr) Variable Function
+ 99(param): 15(ptr) Variable Function
+ 102(param): 15(ptr) Variable Function
+ 90: 15(ptr) AccessChain 24(a) 88
+ 91: 14(fvec3) Load 90
+ Store 89(param) 91
+ 93: 15(ptr) AccessChain 25(b) 88
+ 94: 14(fvec3) Load 93
+ Store 92(param) 94
+ 95: 8(bool) FunctionCall 19(compare_vec3(vf3;vf3;) 89(param) 92(param)
+ SelectionMerge 97 None
+ BranchConditional 95 96 97
+ 96: Label
+ 100: 15(ptr) AccessChain 24(a) 98
+ 101: 14(fvec3) Load 100
+ Store 99(param) 101
+ 103: 15(ptr) AccessChain 25(b) 98
+ 104: 14(fvec3) Load 103
+ Store 102(param) 104
+ 105: 8(bool) FunctionCall 19(compare_vec3(vf3;vf3;) 99(param) 102(param)
+ Branch 97
+ 97: Label
+ 106: 8(bool) Phi 95 27 105 96
+ ReturnValue 106
+ FunctionEnd
+34(compare_ivec2(vi2;vi2;): 8(bool) Function None 31
+ 32(a): 30(ptr) FunctionParameter
+ 33(b): 30(ptr) FunctionParameter
+ 35: Label
+ 109: 29(ivec2) Load 32(a)
+ 110: 29(ivec2) Load 33(b)
+ 112: 111(bvec2) IEqual 109 110
+ 113: 8(bool) All 112
+ ReturnValue 113
+ FunctionEnd
+42(compare_uvec3(vu3;vu3;): 8(bool) Function None 39
+ 40(a): 38(ptr) FunctionParameter
+ 41(b): 38(ptr) FunctionParameter
+ 43: Label
+ 116: 37(ivec3) Load 40(a)
+ 117: 37(ivec3) Load 41(b)
+ 119: 118(bvec3) IEqual 116 117
+ 120: 8(bool) All 119
+ ReturnValue 120
+ FunctionEnd
+46(compare_float16_t(f1;f1;): 8(bool) Function None 9
+ 44(a): 7(ptr) FunctionParameter
+ 45(b): 7(ptr) FunctionParameter
+ 47: Label
+ 123: 6(float) Load 44(a)
+ 124: 6(float) Load 45(b)
+ 125: 6(float) FSub 123 124
+ 126: 6(float) ExtInst 1(GLSL.std.450) 4(FAbs) 125
+ 127: 8(bool) FOrdLessThan 126 52
+ ReturnValue 127
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle13.frag.out b/Test/baseResults/spv.bufferhandle13.frag.out
new file mode 100644
index 0000000..1438086
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle13.frag.out
@@ -0,0 +1,118 @@
+spv.bufferhandle13.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 58
+
+ Capability Shader
+ Capability CapabilityVulkanMemoryModelKHR
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ Extension "SPV_KHR_vulkan_memory_model"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT VulkanKHR
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "t4"
+ MemberName 8(t4) 0 "j"
+ Name 11 "f1(1;"
+ Name 10 "y"
+ Name 16 "f2(1;"
+ Name 15 "y"
+ Name 19 "f3(1;"
+ Name 18 "y"
+ Name 22 "f4(1;"
+ Name 21 "y"
+ Name 34 "a"
+ Name 35 "t5"
+ MemberName 35(t5) 0 "m"
+ Name 37 "s5"
+ Name 42 "b"
+ Name 47 "param"
+ Name 52 "param"
+ Name 56 "g1"
+ Name 57 "g2"
+ MemberDecorate 8(t4) 0 Offset 0
+ Decorate 8(t4) Block
+ Decorate 10(y) Aliased
+ Decorate 15(y) DecorationAliasedPointerEXT
+ Decorate 18(y) Restrict
+ Decorate 18(y) Restrict
+ Decorate 21(y) Restrict
+ Decorate 21(y) DecorationRestrictPointerEXT
+ Decorate 34(a) DecorationAliasedPointerEXT
+ MemberDecorate 35(t5) 0 Offset 0
+ Decorate 35(t5) Block
+ Decorate 37(s5) DescriptorSet 0
+ Decorate 37(s5) Binding 0
+ Decorate 42(b) DecorationRestrictPointerEXT
+ Decorate 56(g1) DecorationAliasedPointerEXT
+ Decorate 57(g2) DecorationRestrictPointerEXT
+ Decorate 47(param) DecorationAliasedPointerEXT
+ Decorate 52(param) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7: TypeInt 32 1
+ 8(t4): TypeStruct 7(int)
+ 6: TypePointer PhysicalStorageBufferEXT 8(t4)
+ 9: TypeFunction 6(ptr) 6(ptr)
+ 13: TypePointer Function 6(ptr)
+ 14: TypeFunction 6(ptr) 13(ptr)
+ 35(t5): TypeStruct 6(ptr)
+ 36: TypePointer StorageBuffer 35(t5)
+ 37(s5): 36(ptr) Variable StorageBuffer
+ 38: 7(int) Constant 0
+ 39: TypePointer StorageBuffer 6(ptr)
+ 55: TypePointer Private 6(ptr)
+ 56(g1): 55(ptr) Variable Private
+ 4(main): 2 Function None 3
+ 5: Label
+ 34(a): 13(ptr) Variable Function
+ 42(b): 13(ptr) Variable Function
+ 47(param): 13(ptr) Variable Function
+ 52(param): 13(ptr) Variable Function
+ 57(g2): 13(ptr) Variable Function
+ 40: 39(ptr) AccessChain 37(s5) 38
+ 41: 6(ptr) Load 40
+ Store 34(a) 41
+ 43: 39(ptr) AccessChain 37(s5) 38
+ 44: 6(ptr) Load 43
+ Store 42(b) 44
+ 45: 6(ptr) Load 34(a)
+ 46: 6(ptr) FunctionCall 11(f1(1;) 45
+ 48: 6(ptr) Load 34(a)
+ Store 47(param) 48
+ 49: 6(ptr) FunctionCall 16(f2(1;) 47(param)
+ 50: 6(ptr) Load 34(a)
+ 51: 6(ptr) FunctionCall 19(f3(1;) 50
+ 53: 6(ptr) Load 34(a)
+ Store 52(param) 53
+ 54: 6(ptr) FunctionCall 22(f4(1;) 52(param)
+ Return
+ FunctionEnd
+ 11(f1(1;): 6(ptr) Function None 9
+ 10(y): 6(ptr) FunctionParameter
+ 12: Label
+ ReturnValue 10(y)
+ FunctionEnd
+ 16(f2(1;): 6(ptr) Function None 14
+ 15(y): 13(ptr) FunctionParameter
+ 17: Label
+ 26: 6(ptr) Load 15(y)
+ ReturnValue 26
+ FunctionEnd
+ 19(f3(1;): 6(ptr) Function None 9
+ 18(y): 6(ptr) FunctionParameter
+ 20: Label
+ ReturnValue 18(y)
+ FunctionEnd
+ 22(f4(1;): 6(ptr) Function None 14
+ 21(y): 13(ptr) FunctionParameter
+ 23: Label
+ 31: 6(ptr) Load 21(y)
+ ReturnValue 31
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle14.frag.out b/Test/baseResults/spv.bufferhandle14.frag.out
new file mode 100644
index 0000000..d8c2726
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle14.frag.out
@@ -0,0 +1,109 @@
+spv.bufferhandle14.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 46
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "T1"
+ MemberName 8(T1) 0 "i"
+ MemberName 8(T1) 1 "j"
+ MemberName 8(T1) 2 "k"
+ Name 10 "t1"
+ Name 20 "T2"
+ MemberName 20(T2) 0 "i"
+ MemberName 20(T2) 1 "j"
+ MemberName 20(T2) 2 "k"
+ Name 22 "t2"
+ Name 29 "T3"
+ MemberName 29(T3) 0 "i"
+ MemberName 29(T3) 1 "j"
+ MemberName 29(T3) 2 "k"
+ Name 31 "t3"
+ Name 38 "T4"
+ MemberName 38(T4) 0 "i"
+ MemberName 38(T4) 1 "j"
+ MemberName 38(T4) 2 "k"
+ Name 40 "t4"
+ MemberDecorate 8(T1) 0 Offset 0
+ MemberDecorate 8(T1) 1 Offset 4
+ MemberDecorate 8(T1) 2 Offset 8
+ Decorate 8(T1) Block
+ Decorate 10(t1) DecorationAliasedPointerEXT
+ MemberDecorate 20(T2) 0 Offset 0
+ MemberDecorate 20(T2) 1 Offset 4
+ MemberDecorate 20(T2) 2 Offset 8
+ Decorate 20(T2) Block
+ Decorate 22(t2) DecorationAliasedPointerEXT
+ MemberDecorate 29(T3) 0 Offset 0
+ MemberDecorate 29(T3) 1 Offset 4
+ MemberDecorate 29(T3) 2 Offset 8
+ Decorate 29(T3) Block
+ Decorate 31(t3) DecorationAliasedPointerEXT
+ MemberDecorate 38(T4) 0 Offset 0
+ MemberDecorate 38(T4) 1 Offset 4
+ MemberDecorate 38(T4) 2 Offset 8
+ Decorate 38(T4) Block
+ Decorate 40(t4) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7: TypeInt 32 1
+ 8(T1): TypeStruct 7(int) 7(int) 7(int)
+ 6: TypePointer PhysicalStorageBufferEXT 8(T1)
+ 9: TypePointer Function 6(ptr)
+ 12: 7(int) Constant 0
+ 14: 7(int) Constant 2
+ 15: TypePointer PhysicalStorageBufferEXT 7(int)
+ TypeForwardPointer 19 PhysicalStorageBufferEXT
+ 20(T2): TypeStruct 7(int) 7(int) 7(int)
+ 19: TypePointer PhysicalStorageBufferEXT 20(T2)
+ 21: TypePointer Function 19(ptr)
+ TypeForwardPointer 28 PhysicalStorageBufferEXT
+ 29(T3): TypeStruct 7(int) 7(int) 7(int)
+ 28: TypePointer PhysicalStorageBufferEXT 29(T3)
+ 30: TypePointer Function 28(ptr)
+ TypeForwardPointer 37 PhysicalStorageBufferEXT
+ 38(T4): TypeStruct 7(int) 7(int) 7(int)
+ 37: TypePointer PhysicalStorageBufferEXT 38(T4)
+ 39: TypePointer Function 37(ptr)
+ 4(main): 2 Function None 3
+ 5: Label
+ 10(t1): 9(ptr) Variable Function
+ 22(t2): 21(ptr) Variable Function
+ 31(t3): 30(ptr) Variable Function
+ 40(t4): 39(ptr) Variable Function
+ 11: 6(ptr) Load 10(t1)
+ 13: 6(ptr) Load 10(t1)
+ 16: 15(ptr) AccessChain 13 14
+ 17: 7(int) Load 16 Aligned 4
+ 18: 15(ptr) AccessChain 11 12
+ Store 18 17 Aligned 4
+ 23: 19(ptr) Load 22(t2)
+ 24: 19(ptr) Load 22(t2)
+ 25: 15(ptr) AccessChain 24 14
+ 26: 7(int) Load 25 Aligned 8
+ 27: 15(ptr) AccessChain 23 12
+ Store 27 26 Aligned 8
+ 32: 28(ptr) Load 31(t3)
+ 33: 28(ptr) Load 31(t3)
+ 34: 15(ptr) AccessChain 33 14
+ 35: 7(int) Load 34 Aligned 8
+ 36: 15(ptr) AccessChain 32 12
+ Store 36 35 Aligned 16
+ 41: 37(ptr) Load 40(t4)
+ 42: 37(ptr) Load 40(t4)
+ 43: 15(ptr) AccessChain 42 14
+ 44: 7(int) Load 43 Aligned 8
+ 45: 15(ptr) AccessChain 41 12
+ Store 45 44 Aligned 32
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle15.frag.out b/Test/baseResults/spv.bufferhandle15.frag.out
new file mode 100644
index 0000000..a4a434d
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle15.frag.out
@@ -0,0 +1,130 @@
+spv.bufferhandle15.frag
+WARNING: 0:16: '' : all default precisions are highp; use precision statements to quiet warning, e.g.:
+ "precision mediump int; precision highp float;"
+
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 60
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main" 37
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ SourceExtension "GL_EXT_scalar_block_layout"
+ Name 4 "main"
+ Name 9 "y"
+ Name 13 "T4"
+ MemberName 13(T4) 0 "t1"
+ MemberName 13(T4) 1 "t2"
+ MemberName 13(T4) 2 "t3"
+ Name 15 "T1"
+ MemberName 15(T1) 0 "x"
+ Name 22 "T2"
+ MemberName 22(T2) 0 "x"
+ Name 28 "S"
+ MemberName 28(S) 0 "a"
+ MemberName 28(S) 1 "b"
+ MemberName 28(S) 2 "c"
+ Name 29 "T3"
+ MemberName 29(T3) 0 "s"
+ Name 31 "t4"
+ Name 37 "i"
+ Name 52 "z"
+ MemberDecorate 13(T4) 0 Offset 0
+ MemberDecorate 13(T4) 1 Offset 8
+ MemberDecorate 13(T4) 2 Offset 16
+ Decorate 13(T4) Block
+ Decorate 14 ArrayStride 12
+ MemberDecorate 15(T1) 0 Offset 0
+ Decorate 15(T1) Block
+ Decorate 18 ArrayStride 12
+ Decorate 20 ArrayStride 24
+ Decorate 21 ArrayStride 96
+ MemberDecorate 22(T2) 0 Offset 0
+ Decorate 22(T2) Block
+ Decorate 26 ArrayStride 36
+ MemberDecorate 28(S) 0 Offset 0
+ MemberDecorate 28(S) 1 ColMajor
+ MemberDecorate 28(S) 1 RelaxedPrecision
+ MemberDecorate 28(S) 1 Offset 12
+ MemberDecorate 28(S) 1 MatrixStride 12
+ MemberDecorate 28(S) 2 Offset 156
+ MemberDecorate 29(T3) 0 Offset 0
+ Decorate 29(T3) Block
+ Decorate 31(t4) DescriptorSet 0
+ Decorate 31(t4) Binding 0
+ Decorate 37(i) Flat
+ Decorate 37(i) Location 0
+ Decorate 59 RelaxedPrecision
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeFloat 32
+ 7: TypeVector 6(float) 3
+ 8: TypePointer Function 7(fvec3)
+ TypeForwardPointer 10 PhysicalStorageBufferEXT
+ TypeForwardPointer 11 PhysicalStorageBufferEXT
+ TypeForwardPointer 12 PhysicalStorageBufferEXT
+ 13(T4): TypeStruct 10 11 12
+ 14: TypeRuntimeArray 7(fvec3)
+ 15(T1): TypeStruct 14
+ 10: TypePointer PhysicalStorageBufferEXT 15(T1)
+ 16: TypeInt 32 0
+ 17: 16(int) Constant 2
+ 18: TypeArray 7(fvec3) 17
+ 19: 16(int) Constant 4
+ 20: TypeArray 18 19
+ 21: TypeRuntimeArray 20
+ 22(T2): TypeStruct 21
+ 11: TypePointer PhysicalStorageBufferEXT 22(T2)
+ 23: TypeInt 32 1
+ 24: TypeVector 23(int) 3
+ 25: TypeMatrix 7(fvec3) 3
+ 26: TypeArray 25 19
+ 27: TypeVector 6(float) 4
+ 28(S): TypeStruct 24(ivec3) 26 27(fvec4)
+ 29(T3): TypeStruct 28(S)
+ 12: TypePointer PhysicalStorageBufferEXT 29(T3)
+ 30: TypePointer StorageBuffer 13(T4)
+ 31(t4): 30(ptr) Variable StorageBuffer
+ 32: 23(int) Constant 0
+ 33: TypePointer StorageBuffer 10(ptr)
+ 36: TypePointer Input 23(int)
+ 37(i): 36(ptr) Variable Input
+ 39: TypePointer PhysicalStorageBufferEXT 7(fvec3)
+ 42: 23(int) Constant 1
+ 43: TypePointer StorageBuffer 11(ptr)
+ 51: TypePointer Function 25
+ 53: 23(int) Constant 2
+ 54: TypePointer StorageBuffer 12(ptr)
+ 57: TypePointer PhysicalStorageBufferEXT 25
+ 4(main): 2 Function None 3
+ 5: Label
+ 9(y): 8(ptr) Variable Function
+ 52(z): 51(ptr) Variable Function
+ 34: 33(ptr) AccessChain 31(t4) 32
+ 35: 10(ptr) Load 34
+ 38: 23(int) Load 37(i)
+ 40: 39(ptr) AccessChain 35 32 38
+ 41: 7(fvec3) Load 40 Aligned 4
+ Store 9(y) 41
+ 44: 43(ptr) AccessChain 31(t4) 42
+ 45: 11(ptr) Load 44
+ 46: 23(int) Load 37(i)
+ 47: 23(int) Load 37(i)
+ 48: 23(int) Load 37(i)
+ 49: 39(ptr) AccessChain 45 32 46 47 48
+ 50: 7(fvec3) Load 49 Aligned 4
+ Store 9(y) 50
+ 55: 54(ptr) AccessChain 31(t4) 53
+ 56: 12(ptr) Load 55
+ 58: 57(ptr) AccessChain 56 32 42 32
+ 59: 25 Load 58 Aligned 4
+ Store 52(z) 59
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle2.frag.out b/Test/baseResults/spv.bufferhandle2.frag.out
new file mode 100644
index 0000000..fbcf16c
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle2.frag.out
@@ -0,0 +1,94 @@
+spv.bufferhandle2.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 45
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "blockType"
+ MemberName 8(blockType) 0 "a"
+ MemberName 8(blockType) 1 "b"
+ MemberName 8(blockType) 2 "c"
+ MemberName 8(blockType) 3 "d"
+ MemberName 8(blockType) 4 "e"
+ Name 13 "b1"
+ Name 14 "t2"
+ MemberName 14(t2) 0 "f"
+ MemberName 14(t2) 1 "g"
+ Name 16 "t"
+ Name 34 "b2"
+ Name 37 "b3"
+ MemberDecorate 8(blockType) 0 Offset 0
+ MemberDecorate 8(blockType) 1 Offset 4
+ MemberDecorate 8(blockType) 2 Offset 8
+ MemberDecorate 8(blockType) 3 Offset 12
+ MemberDecorate 8(blockType) 4 Offset 16
+ Decorate 8(blockType) Block
+ Decorate 13(b1) DecorationAliasedPointerEXT
+ MemberDecorate 14(t2) 0 Offset 0
+ MemberDecorate 14(t2) 1 Offset 8
+ Decorate 14(t2) Block
+ Decorate 16(t) DescriptorSet 0
+ Decorate 16(t) Binding 0
+ Decorate 34(b2) DecorationAliasedPointerEXT
+ Decorate 37(b3) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7: TypeInt 32 1
+ 8(blockType): TypeStruct 7(int) 7(int) 7(int) 7(int) 7(int)
+ 6: TypePointer PhysicalStorageBufferEXT 8(blockType)
+ 9: TypeInt 32 0
+ 10: 9(int) Constant 2
+ 11: TypeArray 6(ptr) 10
+ 12: TypePointer Function 11
+ 14(t2): TypeStruct 6(ptr) 6(ptr)
+ 15: TypePointer StorageBuffer 14(t2)
+ 16(t): 15(ptr) Variable StorageBuffer
+ 17: 7(int) Constant 0
+ 18: TypePointer StorageBuffer 6(ptr)
+ 21: 7(int) Constant 1
+ 25: TypePointer Function 6(ptr)
+ 30: TypePointer PhysicalStorageBufferEXT 7(int)
+ 4(main): 2 Function None 3
+ 5: Label
+ 13(b1): 12(ptr) Variable Function
+ 34(b2): 25(ptr) Variable Function
+ 37(b3): 25(ptr) Variable Function
+ 19: 18(ptr) AccessChain 16(t) 17
+ 20: 6(ptr) Load 19
+ 22: 18(ptr) AccessChain 16(t) 21
+ 23: 6(ptr) Load 22
+ 24: 11 CompositeConstruct 20 23
+ Store 13(b1) 24
+ 26: 25(ptr) AccessChain 13(b1) 17
+ 27: 6(ptr) Load 26
+ 28: 25(ptr) AccessChain 13(b1) 21
+ 29: 6(ptr) Load 28
+ 31: 30(ptr) AccessChain 29 21
+ 32: 7(int) Load 31 Aligned 4
+ 33: 30(ptr) AccessChain 27 17
+ Store 33 32 Aligned 16
+ 35: 18(ptr) AccessChain 16(t) 17
+ 36: 6(ptr) Load 35
+ Store 34(b2) 36
+ 38: 18(ptr) AccessChain 16(t) 21
+ 39: 6(ptr) Load 38
+ Store 37(b3) 39
+ 40: 6(ptr) Load 34(b2)
+ 41: 6(ptr) Load 37(b3)
+ 42: 30(ptr) AccessChain 41 21
+ 43: 7(int) Load 42 Aligned 4
+ 44: 30(ptr) AccessChain 40 17
+ Store 44 43 Aligned 16
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle3.frag.out b/Test/baseResults/spv.bufferhandle3.frag.out
new file mode 100644
index 0000000..a2cb85f
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle3.frag.out
@@ -0,0 +1,105 @@
+spv.bufferhandle3.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 50
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main" 42
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 9 "t4"
+ MemberName 9(t4) 0 "j"
+ MemberName 9(t4) 1 "k"
+ Name 10 "t3"
+ MemberName 10(t3) 0 "h"
+ Name 14 "foo(1;"
+ Name 13 "y"
+ Name 19 "t5"
+ MemberName 19(t5) 0 "m"
+ Name 21 "s5"
+ Name 23 "param"
+ Name 38 "t4"
+ MemberName 38(t4) 0 "j"
+ MemberName 38(t4) 1 "k"
+ Name 40 "x"
+ Name 42 "k"
+ MemberDecorate 9(t4) 0 Offset 0
+ MemberDecorate 9(t4) 1 Offset 8
+ Decorate 9(t4) Block
+ MemberDecorate 10(t3) 0 Offset 0
+ Decorate 10(t3) Block
+ Decorate 13(y) DecorationAliasedPointerEXT
+ MemberDecorate 19(t5) 0 Offset 0
+ Decorate 19(t5) Block
+ Decorate 21(s5) DescriptorSet 0
+ Decorate 21(s5) Binding 0
+ MemberDecorate 38(t4) 0 Offset 0
+ MemberDecorate 38(t4) 1 Offset 8
+ Decorate 38(t4) Block
+ Decorate 40(x) DescriptorSet 1
+ Decorate 40(x) Binding 2
+ Decorate 42(k) Flat
+ Decorate 42(k) DecorationAliasedPointerEXT
+ Decorate 23(param) DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7: TypeInt 32 1
+ TypeForwardPointer 8 PhysicalStorageBufferEXT
+ 9(t4): TypeStruct 7(int) 8
+ 10(t3): TypeStruct 7(int)
+ 8: TypePointer PhysicalStorageBufferEXT 10(t3)
+ 6: TypePointer PhysicalStorageBufferEXT 9(t4)
+ 11: TypePointer Function 6(ptr)
+ 12: TypeFunction 6(ptr) 11(ptr)
+ 19(t5): TypeStruct 6(ptr)
+ 20: TypePointer StorageBuffer 19(t5)
+ 21(s5): 20(ptr) Variable StorageBuffer
+ 22: 7(int) Constant 0
+ 24: TypePointer StorageBuffer 6(ptr)
+ 30: 7(int) Constant 1
+ 31: TypePointer PhysicalStorageBufferEXT 8(ptr)
+ 34: TypePointer PhysicalStorageBufferEXT 7(int)
+ 38(t4): TypeStruct 7(int) 8(ptr)
+ 39: TypePointer StorageBuffer 38(t4)
+ 40(x): 39(ptr) Variable StorageBuffer
+ 41: TypePointer Input 6(ptr)
+ 42(k): 41(ptr) Variable Input
+ 48: TypePointer StorageBuffer 7(int)
+ 4(main): 2 Function None 3
+ 5: Label
+ 23(param): 11(ptr) Variable Function
+ 25: 24(ptr) AccessChain 21(s5) 22
+ 26: 6(ptr) Load 25
+ Store 23(param) 26
+ 27: 6(ptr) FunctionCall 14(foo(1;) 23(param)
+ 28: 24(ptr) AccessChain 21(s5) 22
+ 29: 6(ptr) Load 28
+ 32: 31(ptr) AccessChain 29 30
+ 33: 8(ptr) Load 32 Aligned 8
+ 35: 34(ptr) AccessChain 33 22
+ 36: 7(int) Load 35 Aligned 16
+ 37: 34(ptr) AccessChain 27 22
+ Store 37 36 Aligned 16
+ 43: 6(ptr) Load 42(k)
+ 44: 31(ptr) AccessChain 43 30
+ 45: 8(ptr) Load 44 Aligned 8
+ 46: 34(ptr) AccessChain 45 22
+ 47: 7(int) Load 46 Aligned 16
+ 49: 48(ptr) AccessChain 40(x) 22
+ Store 49 47
+ Return
+ FunctionEnd
+ 14(foo(1;): 6(ptr) Function None 12
+ 13(y): 11(ptr) FunctionParameter
+ 15: Label
+ 16: 6(ptr) Load 13(y)
+ ReturnValue 16
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle4.frag.out b/Test/baseResults/spv.bufferhandle4.frag.out
new file mode 100644
index 0000000..08de871
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle4.frag.out
@@ -0,0 +1,118 @@
+spv.bufferhandle4.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 61
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "t4"
+ MemberName 8(t4) 0 "j"
+ MemberName 8(t4) 1 "k"
+ Name 10 "t3"
+ MemberName 10(t3) 0 "h"
+ MemberName 10(t3) 1 "i"
+ Name 11 "t4"
+ MemberName 11(t4) 0 "j"
+ MemberName 11(t4) 1 "k"
+ Name 13 "x"
+ Name 19 "t5"
+ MemberName 19(t5) 0 "m"
+ Name 21 "s5"
+ Name 43 "b"
+ MemberDecorate 8(t4) 0 Offset 0
+ MemberDecorate 8(t4) 1 Offset 8
+ Decorate 8(t4) Block
+ MemberDecorate 10(t3) 0 Offset 0
+ MemberDecorate 10(t3) 1 Offset 8
+ Decorate 10(t3) Block
+ MemberDecorate 11(t4) 0 Offset 0
+ MemberDecorate 11(t4) 1 Offset 8
+ Decorate 11(t4) Block
+ Decorate 13(x) DescriptorSet 1
+ Decorate 13(x) Binding 2
+ MemberDecorate 19(t5) 0 Offset 0
+ Decorate 19(t5) Block
+ Decorate 21(s5) DescriptorSet 0
+ Decorate 21(s5) Binding 0
+ Decorate 47 DecorationAliasedPointerEXT
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeInt 32 1
+ TypeForwardPointer 7 PhysicalStorageBufferEXT
+ 8(t4): TypeStruct 6(int) 7
+ TypeForwardPointer 9 PhysicalStorageBufferEXT
+ 10(t3): TypeStruct 6(int) 9
+ 11(t4): TypeStruct 6(int) 7
+ 9: TypePointer PhysicalStorageBufferEXT 11(t4)
+ 7: TypePointer PhysicalStorageBufferEXT 10(t3)
+ 12: TypePointer StorageBuffer 8(t4)
+ 13(x): 12(ptr) Variable StorageBuffer
+ 14: 6(int) Constant 1
+ 15: TypePointer StorageBuffer 7(ptr)
+ 18: 6(int) Constant 0
+ 19(t5): TypeStruct 9(ptr)
+ 20: TypePointer StorageBuffer 19(t5)
+ 21(s5): 20(ptr) Variable StorageBuffer
+ 22: TypePointer StorageBuffer 9(ptr)
+ 25: TypePointer PhysicalStorageBufferEXT 7(ptr)
+ 28: TypePointer PhysicalStorageBufferEXT 9(ptr)
+ 37: TypePointer PhysicalStorageBufferEXT 6(int)
+ 41: TypeBool
+ 42: TypePointer Function 41(bool)
+ 44: 41(bool) ConstantTrue
+ 46: TypePointer Function 9(ptr)
+ 4(main): 2 Function None 3
+ 5: Label
+ 43(b): 42(ptr) Variable Function
+ 47: 46(ptr) Variable Function
+ 16: 15(ptr) AccessChain 13(x) 14
+ 17: 7(ptr) Load 16
+ 23: 22(ptr) AccessChain 21(s5) 18
+ 24: 9(ptr) Load 23
+ 26: 25(ptr) AccessChain 24 14
+ 27: 7(ptr) Load 26 Aligned 8
+ 29: 28(ptr) AccessChain 27 14
+ 30: 9(ptr) Load 29 Aligned 8
+ 31: 25(ptr) AccessChain 30 14
+ 32: 7(ptr) Load 31 Aligned 8
+ 33: 28(ptr) AccessChain 32 14
+ 34: 9(ptr) Load 33 Aligned 8
+ 35: 25(ptr) AccessChain 34 14
+ 36: 7(ptr) Load 35 Aligned 8
+ 38: 37(ptr) AccessChain 36 18
+ 39: 6(int) Load 38 Aligned 16
+ 40: 37(ptr) AccessChain 17 18
+ Store 40 39 Aligned 16
+ Store 43(b) 44
+ 45: 41(bool) Load 43(b)
+ SelectionMerge 49 None
+ BranchConditional 45 48 52
+ 48: Label
+ 50: 22(ptr) AccessChain 21(s5) 18
+ 51: 9(ptr) Load 50
+ Store 47 51
+ Branch 49
+ 52: Label
+ 53: 22(ptr) AccessChain 21(s5) 18
+ 54: 9(ptr) Load 53
+ 55: 25(ptr) AccessChain 54 14
+ 56: 7(ptr) Load 55 Aligned 8
+ 57: 28(ptr) AccessChain 56 14
+ 58: 9(ptr) Load 57 Aligned 8
+ Store 47 58
+ Branch 49
+ 49: Label
+ 59: 9(ptr) Load 47
+ 60: 22(ptr) AccessChain 21(s5) 18
+ Store 60 59
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle5.frag.out b/Test/baseResults/spv.bufferhandle5.frag.out
new file mode 100644
index 0000000..3656408
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle5.frag.out
@@ -0,0 +1,52 @@
+spv.bufferhandle5.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 22
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "t4"
+ MemberName 8(t4) 0 "j"
+ MemberName 8(t4) 1 "k"
+ Name 9 "t3"
+ MemberName 9(t3) 0 "h"
+ Name 11 "x"
+ MemberDecorate 8(t4) 0 Offset 0
+ MemberDecorate 8(t4) 1 Offset 8
+ Decorate 8(t4) Block
+ MemberDecorate 9(t3) 0 Offset 0
+ Decorate 9(t3) Block
+ Decorate 11(x) DescriptorSet 1
+ Decorate 11(x) Binding 2
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeInt 32 1
+ TypeForwardPointer 7 PhysicalStorageBufferEXT
+ 8(t4): TypeStruct 6(int) 7
+ 9(t3): TypeStruct 6(int)
+ 7: TypePointer PhysicalStorageBufferEXT 9(t3)
+ 10: TypePointer Uniform 8(t4)
+ 11(x): 10(ptr) Variable Uniform
+ 12: 6(int) Constant 1
+ 13: TypePointer Uniform 7(ptr)
+ 16: 6(int) Constant 0
+ 17: TypePointer Uniform 6(int)
+ 20: TypePointer PhysicalStorageBufferEXT 6(int)
+ 4(main): 2 Function None 3
+ 5: Label
+ 14: 13(ptr) AccessChain 11(x) 12
+ 15: 7(ptr) Load 14
+ 18: 17(ptr) AccessChain 11(x) 16
+ 19: 6(int) Load 18
+ 21: 20(ptr) AccessChain 15 16
+ Store 21 19 Aligned 16
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle6.frag.out b/Test/baseResults/spv.bufferhandle6.frag.out
new file mode 100644
index 0000000..54db3cf
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle6.frag.out
@@ -0,0 +1,238 @@
+spv.bufferhandle6.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 165
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main" 154
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "accum"
+ Name 15 "T1"
+ MemberName 15(T1) 0 "a"
+ MemberName 15(T1) 1 "b"
+ MemberName 15(T1) 2 "c"
+ MemberName 15(T1) 3 "d"
+ Name 18 "T1"
+ MemberName 18(T1) 0 "a"
+ MemberName 18(T1) 1 "b"
+ MemberName 18(T1) 2 "c"
+ MemberName 18(T1) 3 "d"
+ Name 21 "x"
+ Name 30 "Block"
+ MemberName 30(Block) 0 "identity"
+ Name 32 "pc"
+ Name 136 "color"
+ Name 149 "image0_0"
+ Name 154 "gl_FragCoord"
+ Decorate 12 ArrayStride 4
+ Decorate 14 ArrayStride 8
+ MemberDecorate 15(T1) 0 Offset 0
+ MemberDecorate 15(T1) 1 Offset 32
+ MemberDecorate 15(T1) 2 Offset 48
+ MemberDecorate 15(T1) 3 Offset 80
+ Decorate 15(T1) Block
+ Decorate 16 ArrayStride 4
+ Decorate 17 ArrayStride 8
+ MemberDecorate 18(T1) 0 Offset 0
+ MemberDecorate 18(T1) 1 Offset 32
+ MemberDecorate 18(T1) 2 Offset 48
+ MemberDecorate 18(T1) 3 Offset 80
+ Decorate 18(T1) Block
+ Decorate 19 ArrayStride 8
+ Decorate 21(x) DescriptorSet 3
+ Decorate 21(x) Binding 1
+ Decorate 29 ArrayStride 4
+ MemberDecorate 30(Block) 0 Offset 0
+ Decorate 30(Block) Block
+ Decorate 149(image0_0) DescriptorSet 3
+ Decorate 149(image0_0) Binding 0
+ Decorate 154(gl_FragCoord) BuiltIn FragCoord
+ 2: TypeVoid
+ 3: TypeFunction 2
+ 6: TypeInt 32 1
+ 7: TypePointer Function 6(int)
+ 9: 6(int) Constant 0
+ 10: TypeInt 32 0
+ 11: 10(int) Constant 2
+ 12: TypeArray 6(int) 11
+ TypeForwardPointer 13 PhysicalStorageBufferEXT
+ 14: TypeArray 13 11
+ 15(T1): TypeStruct 12 6(int) 14 13
+ 16: TypeArray 6(int) 11
+ 17: TypeArray 13 11
+ 18(T1): TypeStruct 16 6(int) 17 13
+ 13: TypePointer PhysicalStorageBufferEXT 18(T1)
+ 19: TypeArray 13(ptr) 11
+ 20: TypePointer StorageBuffer 15(T1)
+ 21(x): 20(ptr) Variable StorageBuffer
+ 22: TypePointer StorageBuffer 6(int)
+ 28: 10(int) Constant 32
+ 29: TypeArray 6(int) 28
+ 30(Block): TypeStruct 29
+ 31: TypePointer PushConstant 30(Block)
+ 32(pc): 31(ptr) Variable PushConstant
+ 33: 6(int) Constant 1
+ 34: TypePointer PushConstant 6(int)
+ 44: 6(int) Constant 2
+ 48: TypePointer StorageBuffer 13(ptr)
+ 51: TypePointer PhysicalStorageBufferEXT 6(int)
+ 54: 6(int) Constant 3
+ 64: 6(int) Constant 4
+ 72: 6(int) Constant 5
+ 82: 6(int) Constant 6
+ 94: 6(int) Constant 7
+ 104: 6(int) Constant 8
+ 112: 6(int) Constant 9
+ 122: 6(int) Constant 10
+ 130: 6(int) Constant 11
+ 134: TypeVector 10(int) 4
+ 135: TypePointer Function 134(ivec4)
+ 138: TypeBool
+ 140: 10(int) Constant 0
+ 141: 134(ivec4) ConstantComposite 140 140 140 140
+ 142: 10(int) Constant 1
+ 143: 134(ivec4) ConstantComposite 142 140 140 142
+ 144: TypeVector 138(bool) 4
+ 147: TypeImage 10(int) 2D nonsampled format:R32ui
+ 148: TypePointer UniformConstant 147
+ 149(image0_0): 148(ptr) Variable UniformConstant
+ 151: TypeFloat 32
+ 152: TypeVector 151(float) 4
+ 153: TypePointer Input 152(fvec4)
+154(gl_FragCoord): 153(ptr) Variable Input
+ 155: TypePointer Input 151(float)
+ 162: TypeVector 6(int) 2
+ 4(main): 2 Function None 3
+ 5: Label
+ 8(accum): 7(ptr) Variable Function
+ 136(color): 135(ptr) Variable Function
+ Store 8(accum) 9
+ 23: 22(ptr) AccessChain 21(x) 9 9
+ 24: 6(int) Load 23
+ 25: 6(int) ISub 24 9
+ 26: 6(int) Load 8(accum)
+ 27: 6(int) BitwiseOr 26 25
+ Store 8(accum) 27
+ 35: 34(ptr) AccessChain 32(pc) 9 33
+ 36: 6(int) Load 35
+ 37: 22(ptr) AccessChain 21(x) 9 36
+ 38: 6(int) Load 37
+ 39: 6(int) ISub 38 33
+ 40: 6(int) Load 8(accum)
+ 41: 6(int) BitwiseOr 40 39
+ Store 8(accum) 41
+ 42: 22(ptr) AccessChain 21(x) 33
+ 43: 6(int) Load 42
+ 45: 6(int) ISub 43 44
+ 46: 6(int) Load 8(accum)
+ 47: 6(int) BitwiseOr 46 45
+ Store 8(accum) 47
+ 49: 48(ptr) AccessChain 21(x) 44 9
+ 50: 13(ptr) Load 49
+ 52: 51(ptr) AccessChain 50 9 9
+ 53: 6(int) Load 52 Aligned 4
+ 55: 6(int) ISub 53 54
+ 56: 6(int) Load 8(accum)
+ 57: 6(int) BitwiseOr 56 55
+ Store 8(accum) 57
+ 58: 48(ptr) AccessChain 21(x) 44 9
+ 59: 13(ptr) Load 58
+ 60: 34(ptr) AccessChain 32(pc) 9 33
+ 61: 6(int) Load 60
+ 62: 51(ptr) AccessChain 59 9 61
+ 63: 6(int) Load 62 Aligned 4
+ 65: 6(int) ISub 63 64
+ 66: 6(int) Load 8(accum)
+ 67: 6(int) BitwiseOr 66 65
+ Store 8(accum) 67
+ 68: 48(ptr) AccessChain 21(x) 44 9
+ 69: 13(ptr) Load 68
+ 70: 51(ptr) AccessChain 69 33
+ 71: 6(int) Load 70 Aligned 16
+ 73: 6(int) ISub 71 72
+ 74: 6(int) Load 8(accum)
+ 75: 6(int) BitwiseOr 74 73
+ Store 8(accum) 75
+ 76: 34(ptr) AccessChain 32(pc) 9 33
+ 77: 6(int) Load 76
+ 78: 48(ptr) AccessChain 21(x) 44 77
+ 79: 13(ptr) Load 78
+ 80: 51(ptr) AccessChain 79 9 9
+ 81: 6(int) Load 80 Aligned 4
+ 83: 6(int) ISub 81 82
+ 84: 6(int) Load 8(accum)
+ 85: 6(int) BitwiseOr 84 83
+ Store 8(accum) 85
+ 86: 34(ptr) AccessChain 32(pc) 9 33
+ 87: 6(int) Load 86
+ 88: 48(ptr) AccessChain 21(x) 44 87
+ 89: 13(ptr) Load 88
+ 90: 34(ptr) AccessChain 32(pc) 9 33
+ 91: 6(int) Load 90
+ 92: 51(ptr) AccessChain 89 9 91
+ 93: 6(int) Load 92 Aligned 4
+ 95: 6(int) ISub 93 94
+ 96: 6(int) Load 8(accum)
+ 97: 6(int) BitwiseOr 96 95
+ Store 8(accum) 97
+ 98: 34(ptr) AccessChain 32(pc) 9 33
+ 99: 6(int) Load 98
+ 100: 48(ptr) AccessChain 21(x) 44 99
+ 101: 13(ptr) Load 100
+ 102: 51(ptr) AccessChain 101 33
+ 103: 6(int) Load 102 Aligned 16
+ 105: 6(int) ISub 103 104
+ 106: 6(int) Load 8(accum)
+ 107: 6(int) BitwiseOr 106 105
+ Store 8(accum) 107
+ 108: 48(ptr) AccessChain 21(x) 54
+ 109: 13(ptr) Load 108
+ 110: 51(ptr) AccessChain 109 9 9
+ 111: 6(int) Load 110 Aligned 4
+ 113: 6(int) ISub 111 112
+ 114: 6(int) Load 8(accum)
+ 115: 6(int) BitwiseOr 114 113
+ Store 8(accum) 115
+ 116: 48(ptr) AccessChain 21(x) 54
+ 117: 13(ptr) Load 116
+ 118: 34(ptr) AccessChain 32(pc) 9 33
+ 119: 6(int) Load 118
+ 120: 51(ptr) AccessChain 117 9 119
+ 121: 6(int) Load 120 Aligned 4
+ 123: 6(int) ISub 121 122
+ 124: 6(int) Load 8(accum)
+ 125: 6(int) BitwiseOr 124 123
+ Store 8(accum) 125
+ 126: 48(ptr) AccessChain 21(x) 54
+ 127: 13(ptr) Load 126
+ 128: 51(ptr) AccessChain 127 33
+ 129: 6(int) Load 128 Aligned 16
+ 131: 6(int) ISub 129 130
+ 132: 6(int) Load 8(accum)
+ 133: 6(int) BitwiseOr 132 131
+ Store 8(accum) 133
+ 137: 6(int) Load 8(accum)
+ 139: 138(bool) INotEqual 137 9
+ 145: 144(bvec4) CompositeConstruct 139 139 139 139
+ 146: 134(ivec4) Select 145 141 143
+ Store 136(color) 146
+ 150: 147 Load 149(image0_0)
+ 156: 155(ptr) AccessChain 154(gl_FragCoord) 140
+ 157: 151(float) Load 156
+ 158: 6(int) ConvertFToS 157
+ 159: 155(ptr) AccessChain 154(gl_FragCoord) 142
+ 160: 151(float) Load 159
+ 161: 6(int) ConvertFToS 160
+ 163: 162(ivec2) CompositeConstruct 158 161
+ 164: 134(ivec4) Load 136(color)
+ ImageWrite 150 163 164
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle7.frag.out b/Test/baseResults/spv.bufferhandle7.frag.out
new file mode 100644
index 0000000..4a52596
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle7.frag.out
@@ -0,0 +1,77 @@
+spv.bufferhandle7.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 24
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 7 "t2"
+ MemberName 7(t2) 0 "f"
+ MemberName 7(t2) 1 "g"
+ Name 9 "blockType"
+ MemberName 9(blockType) 0 "a"
+ MemberName 9(blockType) 1 "b"
+ MemberName 9(blockType) 2 "c"
+ MemberName 9(blockType) 3 "d"
+ MemberName 9(blockType) 4 "e"
+ Name 11 "t"
+ Name 14 "t3"
+ MemberName 14(t3) 0 "f"
+ Name 15 "t2"
+ MemberName 15(t2) 0 "f"
+ MemberName 15(t2) 1 "g"
+ Name 17 "u"
+ MemberDecorate 7(t2) 0 Offset 0
+ MemberDecorate 7(t2) 1 Offset 8
+ Decorate 7(t2) Block
+ MemberDecorate 9(blockType) 0 Offset 0
+ MemberDecorate 9(blockType) 1 Offset 4
+ MemberDecorate 9(blockType) 2 Offset 8
+ MemberDecorate 9(blockType) 3 Offset 12
+ MemberDecorate 9(blockType) 4 Offset 16
+ Decorate 9(blockType) Block
+ Decorate 11(t) DescriptorSet 0
+ Decorate 11(t) Binding 0
+ MemberDecorate 14(t3) 0 Offset 0
+ Decorate 14(t3) Block
+ MemberDecorate 15(t2) 0 Offset 0
+ MemberDecorate 15(t2) 1 Offset 8
+ Decorate 15(t2) Block
+ Decorate 17(u) DescriptorSet 0
+ Decorate 17(u) Binding 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7(t2): TypeStruct 6 6
+ 8: TypeInt 32 1
+ 9(blockType): TypeStruct 8(int) 8(int) 8(int) 8(int) 8(int)
+ 6: TypePointer PhysicalStorageBufferEXT 9(blockType)
+ 10: TypePointer StorageBuffer 7(t2)
+ 11(t): 10(ptr) Variable StorageBuffer
+ 12: 8(int) Constant 0
+ TypeForwardPointer 13 PhysicalStorageBufferEXT
+ 14(t3): TypeStruct 13
+ 15(t2): TypeStruct 6(ptr) 6(ptr)
+ 13: TypePointer PhysicalStorageBufferEXT 15(t2)
+ 16: TypePointer StorageBuffer 14(t3)
+ 17(u): 16(ptr) Variable StorageBuffer
+ 18: TypePointer StorageBuffer 13(ptr)
+ 22: TypePointer StorageBuffer 6(ptr)
+ 4(main): 2 Function None 3
+ 5: Label
+ 19: 18(ptr) AccessChain 17(u) 12
+ 20: 13(ptr) Load 19
+ 21: 6(ptr) Bitcast 20
+ 23: 22(ptr) AccessChain 11(t) 12
+ Store 23 21
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle8.frag.out b/Test/baseResults/spv.bufferhandle8.frag.out
new file mode 100644
index 0000000..168da81
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle8.frag.out
@@ -0,0 +1,89 @@
+spv.bufferhandle8.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 27
+
+ Capability Shader
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main"
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "Blah"
+ MemberName 8(Blah) 0 "t1"
+ MemberName 8(Blah) 1 "t2"
+ Name 10 "T1"
+ MemberName 10(T1) 0 "x"
+ Name 11 "T2"
+ MemberName 11(T2) 0 "x"
+ Name 13 "T3"
+ MemberName 13(T3) 0 "Bindings"
+ Name 15 "t3"
+ Name 23 "t2"
+ MemberName 23(t2) 0 "f"
+ MemberName 23(t2) 1 "g"
+ Name 24 "blockType"
+ MemberName 24(blockType) 0 "a"
+ MemberName 24(blockType) 1 "b"
+ MemberName 24(blockType) 2 "c"
+ MemberName 24(blockType) 3 "d"
+ MemberName 24(blockType) 4 "e"
+ Name 26 "t"
+ MemberDecorate 8(Blah) 0 Offset 0
+ MemberDecorate 8(Blah) 1 Offset 8
+ MemberDecorate 10(T1) 0 Offset 0
+ Decorate 10(T1) Block
+ MemberDecorate 11(T2) 0 Offset 0
+ Decorate 11(T2) Block
+ Decorate 12 ArrayStride 16
+ MemberDecorate 13(T3) 0 Offset 0
+ Decorate 13(T3) Block
+ Decorate 15(t3) DescriptorSet 0
+ Decorate 15(t3) Binding 0
+ MemberDecorate 23(t2) 0 Offset 0
+ MemberDecorate 23(t2) 1 Offset 8
+ Decorate 23(t2) Block
+ MemberDecorate 24(blockType) 0 Offset 0
+ MemberDecorate 24(blockType) 1 Offset 4
+ MemberDecorate 24(blockType) 2 Offset 8
+ MemberDecorate 24(blockType) 3 Offset 12
+ MemberDecorate 24(blockType) 4 Offset 16
+ Decorate 24(blockType) Block
+ Decorate 26(t) DescriptorSet 0
+ Decorate 26(t) Binding 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ TypeForwardPointer 7 PhysicalStorageBufferEXT
+ 8(Blah): TypeStruct 6 7
+ 9: TypeInt 32 1
+ 10(T1): TypeStruct 9(int)
+ 6: TypePointer PhysicalStorageBufferEXT 10(T1)
+ 11(T2): TypeStruct 9(int)
+ 7: TypePointer PhysicalStorageBufferEXT 11(T2)
+ 12: TypeRuntimeArray 8(Blah)
+ 13(T3): TypeStruct 12
+ 14: TypePointer StorageBuffer 13(T3)
+ 15(t3): 14(ptr) Variable StorageBuffer
+ 16: 9(int) Constant 0
+ 17: 9(int) Constant 1
+ 18: TypePointer StorageBuffer 8(Blah)
+ TypeForwardPointer 22 PhysicalStorageBufferEXT
+ 23(t2): TypeStruct 22 22
+ 24(blockType): TypeStruct 9(int) 9(int) 9(int) 9(int) 9(int)
+ 22: TypePointer PhysicalStorageBufferEXT 24(blockType)
+ 25: TypePointer StorageBuffer 23(t2)
+ 26(t): 25(ptr) Variable StorageBuffer
+ 4(main): 2 Function None 3
+ 5: Label
+ 19: 18(ptr) AccessChain 15(t3) 16 17
+ 20: 8(Blah) Load 19
+ 21: 18(ptr) AccessChain 15(t3) 16 16
+ Store 21 20
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle9.frag.out b/Test/baseResults/spv.bufferhandle9.frag.out
new file mode 100644
index 0000000..e74be8a
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle9.frag.out
@@ -0,0 +1,114 @@
+spv.bufferhandle9.frag
+// Module Version 10000
+// Generated by (magic number): 80007
+// Id's are bound by 56
+
+ Capability Shader
+ Capability Int64
+ Capability CapabilityPhysicalStorageBufferAddressesEXT
+ Extension "SPV_EXT_physical_storage_buffer"
+ Extension "SPV_KHR_storage_buffer_storage_class"
+ 1: ExtInstImport "GLSL.std.450"
+ MemoryModel PhysicalStorageBuffer64EXT GLSL450
+ EntryPoint Fragment 4 "main" 16 19
+ ExecutionMode 4 OriginUpperLeft
+ Source GLSL 450
+ SourceExtension "GL_ARB_gpu_shader_int64"
+ SourceExtension "GL_EXT_buffer_reference"
+ Name 4 "main"
+ Name 8 "blockType"
+ MemberName 8(blockType) 0 "a"
+ MemberName 8(blockType) 1 "b"
+ MemberName 8(blockType) 2 "c"
+ MemberName 8(blockType) 3 "d"
+ MemberName 8(blockType) 4 "e"
+ Name 13 "b1"
+ Name 16 "h"
+ Name 19 "i"
+ Name 34 "b2"
+ Name 37 "b3"
+ Name 46 "j"
+ Name 53 "t2"
+ MemberName 53(t2) 0 "f"
+ MemberName 53(t2) 1 "g"
+ Name 55 "t"
+ MemberDecorate 8(blockType) 0 Offset 0
+ MemberDecorate 8(blockType) 1 Offset 4
+ MemberDecorate 8(blockType) 2 Offset 8
+ MemberDecorate 8(blockType) 3 Offset 12
+ MemberDecorate 8(blockType) 4 Offset 16
+ Decorate 8(blockType) Block
+ Decorate 13(b1) DecorationAliasedPointerEXT
+ Decorate 16(h) Flat
+ Decorate 19(i) Flat
+ Decorate 34(b2) DecorationAliasedPointerEXT
+ Decorate 37(b3) DecorationAliasedPointerEXT
+ MemberDecorate 53(t2) 0 Offset 0
+ MemberDecorate 53(t2) 1 Offset 8
+ Decorate 53(t2) Block
+ Decorate 55(t) DescriptorSet 0
+ Decorate 55(t) Binding 0
+ 2: TypeVoid
+ 3: TypeFunction 2
+ TypeForwardPointer 6 PhysicalStorageBufferEXT
+ 7: TypeInt 32 1
+ 8(blockType): TypeStruct 7(int) 7(int) 7(int) 7(int) 7(int)
+ 6: TypePointer PhysicalStorageBufferEXT 8(blockType)
+ 9: TypeInt 32 0
+ 10: 9(int) Constant 2
+ 11: TypeArray 6(ptr) 10
+ 12: TypePointer Function 11
+ 14: TypeInt 64 0
+ 15: TypePointer Input 14(int64_t)
+ 16(h): 15(ptr) Variable Input
+ 19(i): 15(ptr) Variable Input
+ 23: 7(int) Constant 0
+ 24: TypePointer Function 6(ptr)
+ 27: 7(int) Constant 1
+ 30: TypePointer PhysicalStorageBufferEXT 7(int)
+ 45: TypePointer Function 14(int64_t)
+ 50: 14(int64_t) Constant 256 0
+ 53(t2): TypeStruct 6(ptr) 6(ptr)
+ 54: TypePointer StorageBuffer 53(t2)
+ 55(t): 54(ptr) Variable StorageBuffer
+ 4(main): 2 Function None 3
+ 5: Label
+ 13(b1): 12(ptr) Variable Function
+ 34(b2): 24(ptr) Variable Function
+ 37(b3): 24(ptr) Variable Function
+ 46(j): 45(ptr) Variable Function
+ 17: 14(int64_t) Load 16(h)
+ 18: 6(ptr) ConvertUToPtr 17
+ 20: 14(int64_t) Load 19(i)
+ 21: 6(ptr) ConvertUToPtr 20
+ 22: 11 CompositeConstruct 18 21
+ Store 13(b1) 22
+ 25: 24(ptr) AccessChain 13(b1) 23
+ 26: 6(ptr) Load 25
+ 28: 24(ptr) AccessChain 13(b1) 27
+ 29: 6(ptr) Load 28
+ 31: 30(ptr) AccessChain 29 27
+ 32: 7(int) Load 31 Aligned 4
+ 33: 30(ptr) AccessChain 26 23
+ Store 33 32 Aligned 16
+ 35: 14(int64_t) Load 16(h)
+ 36: 6(ptr) ConvertUToPtr 35
+ Store 34(b2) 36
+ 38: 14(int64_t) Load 19(i)
+ 39: 6(ptr) ConvertUToPtr 38
+ Store 37(b3) 39
+ 40: 6(ptr) Load 34(b2)
+ 41: 6(ptr) Load 37(b3)
+ 42: 30(ptr) AccessChain 41 27
+ 43: 7(int) Load 42 Aligned 4
+ 44: 30(ptr) AccessChain 40 23
+ Store 44 43 Aligned 16
+ 47: 6(ptr) Load 34(b2)
+ 48: 14(int64_t) ConvertPtrToU 47
+ Store 46(j) 48
+ 49: 14(int64_t) Load 46(j)
+ 51: 14(int64_t) IAdd 49 50
+ 52: 6(ptr) ConvertUToPtr 51
+ Store 34(b2) 52
+ Return
+ FunctionEnd
diff --git a/Test/baseResults/spv.bufferhandle_Error.frag.out b/Test/baseResults/spv.bufferhandle_Error.frag.out
new file mode 100644
index 0000000..a1ee9a4
--- /dev/null
+++ b/Test/baseResults/spv.bufferhandle_Error.frag.out
@@ -0,0 +1,25 @@
+spv.bufferhandle_Error.frag
+ERROR: 0:7: 'buffer_reference' : can only be used with buffer
+ERROR: 0:9: 'buffer_reference' : cannot declare a default, can only be used on a block
+ERROR: 0:10: 'buffer_reference' : can only be used with buffer
+ERROR: 0:10: 'buffer_reference' : cannot declare a default, can only be used on a block
+ERROR: 0:11: 'buffer_reference' : can only be used with buffer
+ERROR: 0:11: 'buffer_reference' : cannot declare a default, can only be used on a block
+ERROR: 0:12: 'buffer_reference' : can only be used with buffer
+ERROR: 0:12: 'buffer_reference' : cannot declare a default, can only be used on a block
+ERROR: 0:13: 'buffer_reference' : can only be used with buffer
+ERROR: 0:13: 'buffer_reference' : can only be used with buffer
+ERROR: 0:14: 'output block' : not supported in this stage: fragment
+ERROR: 0:14: 'buffer_reference' : can only be used with buffer
+ERROR: 0:14: 'buffer_reference' : can only be used with buffer
+ERROR: 0:30: 'length' : array must be declared with a size before using this method
+ERROR: 0:31: 'length' : array must be declared with a size before using this method
+ERROR: 0:35: '=' : cannot convert from 'layout( column_major std430) buffer reference' to ' temp reference'
+ERROR: 0:40: 'assign' : cannot convert from 'layout( column_major std430) buffer reference' to 'layout( column_major std430) buffer reference'
+ERROR: 0:41: 'assign' : cannot convert from 'layout( column_major std430) buffer reference' to 'layout( column_major std430) buffer reference'
+ERROR: 0:42: 'assign' : cannot convert from 'layout( column_major std430) buffer reference' to 'layout( column_major std430) buffer reference'
+ERROR: 0:45: '' : syntax error, unexpected LEFT_BRACE, expecting COMMA or SEMICOLON
+ERROR: 20 compilation errors. No code generated.
+
+
+SPIR-V is not generated for failed compile or link
diff --git a/Test/spv.bufferhandle1.frag b/Test/spv.bufferhandle1.frag
new file mode 100644
index 0000000..14acac1
--- /dev/null
+++ b/Test/spv.bufferhandle1.frag
@@ -0,0 +1,28 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+#pragma use_vulkan_memory_model
+
+layout(buffer_reference, std430) buffer blockType {
+ layout(offset = 0) int a;
+ layout(offset = 4) int b;
+ layout(offset = 8) int c;
+ layout(offset = 12) int d;
+ layout(offset = 16) int e;
+ layout(offset = 32) int f[2];
+ coherent layout(offset = 48) ivec4 g;
+};
+
+layout(std430) buffer t2 {
+ blockType f;
+ blockType g;
+} t;
+
+void main() {
+ t.f.b = t.g.a;
+
+ blockType j = t.f;
+ j.d = j.c;
+ j.d = j.f[1];
+ j.d = j.g.y;
+}
diff --git a/Test/spv.bufferhandle10.frag b/Test/spv.bufferhandle10.frag
new file mode 100644
index 0000000..1d537e4
--- /dev/null
+++ b/Test/spv.bufferhandle10.frag
@@ -0,0 +1,23 @@
+#version 450
+
+#extension GL_ARB_gpu_shader_int64 : enable
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer blockType {
+ uint x[];
+};
+
+layout(std430) buffer t2 {
+ blockType f;
+} t;
+
+layout(location = 0) flat in uint i;
+
+void main() {
+
+ atomicAdd(t.f.x[i], 1);
+
+ coherent blockType b = t.f;
+ b.x[0] = 2;
+
+}
diff --git a/Test/spv.bufferhandle11.frag b/Test/spv.bufferhandle11.frag
new file mode 100644
index 0000000..14d05dc
--- /dev/null
+++ b/Test/spv.bufferhandle11.frag
@@ -0,0 +1,26 @@
+#version 450
+#extension GL_EXT_shader_16bit_storage : enable
+#extension GL_EXT_shader_8bit_storage : enable
+#extension GL_EXT_buffer_reference : enable
+
+layout(std140, binding = 0) buffer AcBlock { highp uint ac_numPassed; };
+
+layout(std140, buffer_reference) buffer Block
+{
+ uint8_t var;
+};
+layout (push_constant, std430) uniform PC {
+ Block block;
+};
+
+bool compare_uint8_t (highp uint a, highp uint b) { return a == b; }
+
+void main (void)
+{
+ bool allOk = true;
+ allOk = allOk && compare_uint8_t(uint(block.var), 7u);
+ if (allOk)
+ ac_numPassed++;
+
+ block.var = uint8_t(9u);
+}
\ No newline at end of file
diff --git a/Test/spv.bufferhandle12.frag b/Test/spv.bufferhandle12.frag
new file mode 100644
index 0000000..cb7ec6a
--- /dev/null
+++ b/Test/spv.bufferhandle12.frag
@@ -0,0 +1,42 @@
+#version 450
+#extension GL_EXT_shader_16bit_storage : enable
+#extension GL_EXT_shader_8bit_storage : enable
+#extension GL_EXT_buffer_reference : enable
+
+layout(std140, binding = 0) buffer AcBlock { highp uint ac_numPassed; };
+
+layout(std430, column_major, buffer_reference) buffer BlockB
+{
+ float16_t a;
+ highp ivec2 b;
+};
+layout(std430, buffer_reference) buffer BlockC
+{
+ mediump mat2x3 c;
+};
+layout(std430, row_major, buffer_reference) buffer BlockD
+{
+ lowp uvec3 d;
+};
+layout (push_constant, std430) uniform PC {
+ BlockB blockB;
+ BlockC blockC;
+ BlockD blockD;
+};
+
+bool compare_float (highp float a, highp float b) { return abs(a - b) < 0.05; }
+bool compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, b.x)&&compare_float(a.y, b.y)&&compare_float(a.z, b.z); }
+bool compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])&&compare_vec3(a[1], b[1]); }
+bool compare_ivec2 (highp ivec2 a, highp ivec2 b) { return a == b; }
+bool compare_uvec3 (highp uvec3 a, highp uvec3 b) { return a == b; }
+bool compare_float16_t(highp float a, highp float b) { return abs(a - b) < 0.05; }
+
+void main (void)
+{
+ bool allOk = true;
+ allOk = allOk && compare_mat2x3(blockC.c, mat2x3(-5.0, 1.0, -7.0, 1.0, 2.0, 8.0));
+ if (allOk)
+ ac_numPassed++;
+
+ blockD.d = (uvec3(8u, 1u, 5u));
+}
\ No newline at end of file
diff --git a/Test/spv.bufferhandle13.frag b/Test/spv.bufferhandle13.frag
new file mode 100644
index 0000000..1538d90
--- /dev/null
+++ b/Test/spv.bufferhandle13.frag
@@ -0,0 +1,30 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(set = 1, binding = 2, buffer_reference, std430) buffer t4 {
+ layout(offset = 0) int j;
+};
+
+layout(std430) buffer t5 {
+ t4 m;
+} s5;
+
+t4 f1(const t4 y) { return y; }
+t4 f2(t4 y) { return y; }
+t4 f3(const restrict t4 y) { return y; }
+t4 f4(restrict t4 y) { return y; }
+
+t4 g1;
+restrict t4 g2;
+
+void main()
+{
+ t4 a = s5.m;
+ restrict t4 b = s5.m;
+
+ f1(a);
+ f2(a);
+ f3(a);
+ f4(a);
+}
diff --git a/Test/spv.bufferhandle14.frag b/Test/spv.bufferhandle14.frag
new file mode 100644
index 0000000..132af69
--- /dev/null
+++ b/Test/spv.bufferhandle14.frag
@@ -0,0 +1,40 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430, buffer_reference_align = 4) buffer T1 {
+ int i;
+ int j;
+ int k;
+};
+
+layout(buffer_reference, std430, buffer_reference_align = 8) buffer T2 {
+ int i;
+ int j;
+ int k;
+};
+
+layout(buffer_reference, std430) buffer T3 {
+ int i;
+ int j;
+ int k;
+};
+
+layout(buffer_reference, std430, buffer_reference_align = 32) buffer T4 {
+ int i;
+ int j;
+ int k;
+};
+
+void main()
+{
+ T1 t1;
+ T2 t2;
+ T3 t3;
+ T4 t4;
+
+ t1.i = t1.k;
+ t2.i = t2.k;
+ t3.i = t3.k;
+ t4.i = t4.k;
+}
diff --git a/Test/spv.bufferhandle15.frag b/Test/spv.bufferhandle15.frag
new file mode 100644
index 0000000..ca64593
--- /dev/null
+++ b/Test/spv.bufferhandle15.frag
@@ -0,0 +1,38 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+#extension GL_EXT_scalar_block_layout : enable
+
+layout(buffer_reference, scalar) buffer T1 {
+ vec3 x[];
+};
+
+layout(buffer_reference, scalar) buffer T2 {
+ vec3 x[][4][2];
+};
+
+struct S
+{
+ highp ivec3 a;
+ mediump mat3 b[4];
+ highp vec4 c;
+};
+
+layout(buffer_reference, scalar) buffer T3 {
+ S s;
+};
+layout(std430) buffer T4 {
+ T1 t1;
+ T2 t2;
+ T3 t3;
+} t4;
+
+layout(location = 0) flat in int i;
+
+void main()
+{
+ vec3 y;
+ y = t4.t1.x[i];
+ y = t4.t2.x[i][i][i];
+ mat3 z = t4.t3.s.b[0];
+}
diff --git a/Test/spv.bufferhandle2.frag b/Test/spv.bufferhandle2.frag
new file mode 100644
index 0000000..497e550
--- /dev/null
+++ b/Test/spv.bufferhandle2.frag
@@ -0,0 +1,25 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer blockType {
+ layout(offset = 0) int a;
+ layout(offset = 4) int b;
+ layout(offset = 8) int c;
+ layout(offset = 12) int d;
+ layout(offset = 16) int e;
+};
+
+layout(std430) buffer t2 {
+ blockType f;
+ blockType g;
+} t;
+
+void main() {
+
+ blockType b1[2] = blockType[2](t.f, t.g);
+ b1[0].a = b1[1].b;
+ blockType b2 = t.f;
+ blockType b3 = t.g;
+ b2.a = b3.b;
+}
diff --git a/Test/spv.bufferhandle3.frag b/Test/spv.bufferhandle3.frag
new file mode 100644
index 0000000..6dddf20
--- /dev/null
+++ b/Test/spv.bufferhandle3.frag
@@ -0,0 +1,25 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer t3 {
+ int h;
+};
+
+layout(set = 1, binding = 2, buffer_reference, std430) buffer t4 {
+ layout(offset = 0) int j;
+ t3 k;
+} x;
+
+layout(std430) buffer t5 {
+ t4 m;
+} s5;
+
+flat in t4 k;
+
+t4 foo(t4 y) { return y; }
+
+void main() {
+ foo(s5.m).j = s5.m.k.h;
+ x.j = k.k.h;
+}
diff --git a/Test/spv.bufferhandle4.frag b/Test/spv.bufferhandle4.frag
new file mode 100644
index 0000000..16a02cb
--- /dev/null
+++ b/Test/spv.bufferhandle4.frag
@@ -0,0 +1,26 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference) buffer t4;
+
+layout(buffer_reference, std430) buffer t3 {
+ int h;
+ t4 i;
+};
+
+layout(set = 1, binding = 2, buffer_reference, std430) buffer t4 {
+ layout(offset = 0) int j;
+ t3 k;
+} x;
+
+layout(std430) buffer t5 {
+ t4 m;
+} s5;
+
+void main() {
+ x.k.h = s5.m.k.i.k.i.k.h;
+
+ bool b = true;
+ s5.m = b ? s5.m : s5.m.k.i;
+}
diff --git a/Test/spv.bufferhandle5.frag b/Test/spv.bufferhandle5.frag
new file mode 100644
index 0000000..6ad5188
--- /dev/null
+++ b/Test/spv.bufferhandle5.frag
@@ -0,0 +1,16 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std140) buffer t3 {
+ int h;
+};
+
+layout(set = 1, binding = 2, std140) uniform t4 {
+ layout(offset = 0) int j;
+ t3 k;
+} x;
+
+void main() {
+ x.k.h = x.j;
+}
diff --git a/Test/spv.bufferhandle6.frag b/Test/spv.bufferhandle6.frag
new file mode 100644
index 0000000..dcc30d0
--- /dev/null
+++ b/Test/spv.bufferhandle6.frag
@@ -0,0 +1,30 @@
+#version 450 core
+
+#extension GL_EXT_buffer_reference : enable
+layout (push_constant, std430) uniform Block { int identity[32]; } pc;
+layout(r32ui, set = 3, binding = 0) uniform uimage2D image0_0;
+layout(buffer_reference) buffer T1;
+layout(set = 3, binding = 1, buffer_reference) buffer T1 {
+ layout(offset = 0) int a[2]; // stride = 4 for std430, 16 for std140
+ layout(offset = 32) int b;
+ layout(offset = 48) T1 c[2]; // stride = 8 for std430, 16 for std140
+ layout(offset = 80) T1 d;
+} x;
+void main()
+{
+ int accum = 0, temp;
+ accum |= x.a[0] - 0;
+ accum |= x.a[pc.identity[1]] - 1;
+ accum |= x.b - 2;
+ accum |= x.c[0].a[0] - 3;
+ accum |= x.c[0].a[pc.identity[1]] - 4;
+ accum |= x.c[0].b - 5;
+ accum |= x.c[pc.identity[1]].a[0] - 6;
+ accum |= x.c[pc.identity[1]].a[pc.identity[1]] - 7;
+ accum |= x.c[pc.identity[1]].b - 8;
+ accum |= x.d.a[0] - 9;
+ accum |= x.d.a[pc.identity[1]] - 10;
+ accum |= x.d.b - 11;
+ uvec4 color = (accum != 0) ? uvec4(0,0,0,0) : uvec4(1,0,0,1);
+ imageStore(image0_0, ivec2(gl_FragCoord.x, gl_FragCoord.y), color);
+}
\ No newline at end of file
diff --git a/Test/spv.bufferhandle7.frag b/Test/spv.bufferhandle7.frag
new file mode 100644
index 0000000..dbc9b2f
--- /dev/null
+++ b/Test/spv.bufferhandle7.frag
@@ -0,0 +1,24 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer blockType {
+ layout(offset = 0) int a;
+ layout(offset = 4) int b;
+ layout(offset = 8) int c;
+ layout(offset = 12) int d;
+ layout(offset = 16) int e;
+};
+
+layout(std430, buffer_reference) buffer t2 {
+ blockType f;
+ blockType g;
+} t;
+
+layout(std430) buffer t3 {
+ t2 f;
+} u;
+
+void main() {
+ t.f = blockType(u.f);
+}
diff --git a/Test/spv.bufferhandle8.frag b/Test/spv.bufferhandle8.frag
new file mode 100644
index 0000000..1bc13c3
--- /dev/null
+++ b/Test/spv.bufferhandle8.frag
@@ -0,0 +1,32 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer blockType {
+ layout(offset = 0) int a;
+ layout(offset = 4) int b;
+ layout(offset = 8) int c;
+ layout(offset = 12) int d;
+ layout(offset = 16) int e;
+};
+
+layout(std430) buffer t2 {
+ blockType f;
+ blockType g;
+} t;
+
+layout(std430, buffer_reference) buffer T2 { int x; };
+layout(std430, buffer_reference) buffer T1 { int x; };
+
+struct Blah {
+ T1 t1;
+ T2 t2;
+};
+
+layout(set=0, binding=0) buffer T3 {
+ Blah Bindings[];
+} t3;
+
+void main() {
+ t3.Bindings[0] = t3.Bindings[1];
+}
diff --git a/Test/spv.bufferhandle9.frag b/Test/spv.bufferhandle9.frag
new file mode 100644
index 0000000..7c9f608
--- /dev/null
+++ b/Test/spv.bufferhandle9.frag
@@ -0,0 +1,30 @@
+#version 450
+
+#extension GL_ARB_gpu_shader_int64 : enable
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference, std430) buffer blockType {
+ layout(offset = 0) int a;
+ layout(offset = 4) int b;
+ layout(offset = 8) int c;
+ layout(offset = 12) int d;
+ layout(offset = 16) int e;
+};
+
+layout(std430) buffer t2 {
+ blockType f;
+ blockType g;
+} t;
+
+flat in uint64_t h, i;
+
+void main() {
+
+ blockType b1[2] = blockType[2](blockType(h), blockType(i));
+ b1[0].a = b1[1].b;
+ blockType b2 = blockType(h);
+ blockType b3 = blockType(i);
+ b2.a = b3.b;
+ uint64_t j = uint64_t(b2);
+ b2 = blockType(j+256);
+}
diff --git a/Test/spv.bufferhandle_Error.frag b/Test/spv.bufferhandle_Error.frag
new file mode 100644
index 0000000..98cbac8
--- /dev/null
+++ b/Test/spv.bufferhandle_Error.frag
@@ -0,0 +1,45 @@
+#version 450
+
+#extension GL_EXT_buffer_reference : enable
+
+layout(buffer_reference) buffer bufType1 { int x; };
+layout(buffer_reference) buffer bufType2 { int x; };
+layout(buffer_reference) uniform bufType3 { int x; };
+
+layout(buffer_reference) buffer;
+layout(buffer_reference) uniform;
+layout(buffer_reference) in;
+layout(buffer_reference) out;
+layout(buffer_reference) in badin { float x; } badin2;
+layout(buffer_reference) out badout { float x; } badout2;
+
+layout(buffer_reference) buffer bufType5;
+
+layout(buffer_reference) buffer bufType6 { int x[]; };
+
+buffer bufType4 {
+ bufType1 b1;
+ bufType2 b2;
+ bufType3 b3;
+ bufType6 b6;
+} b4;
+
+void f()
+{
+ bufType6 b;
+ b.x.length();
+ b4.b6.x.length();
+}
+
+void main() {
+ bufType2 x1 = b4.b1;
+ bufType2 x2 = bufType2(b4.b1);
+ bufType2 x3 = bufType2(b4.b2);
+ bufType2 x4 = bufType2(b4.b3);
+
+ b4.b1 = b4.b2;
+ b4.b1 = b4.b3;
+ b4.b3 = b4.b2;
+}
+
+layout(buffer_reference) uniform bufType5 { int x; };
diff --git a/glslang/Include/BaseTypes.h b/glslang/Include/BaseTypes.h
index fabd613..1827c49 100644
--- a/glslang/Include/BaseTypes.h
+++ b/glslang/Include/BaseTypes.h
@@ -66,6 +66,8 @@
EbtAccStructNV,
#endif
+ EbtReference,
+
// HLSL types that live only temporarily.
EbtString,
diff --git a/glslang/Include/Types.h b/glslang/Include/Types.h
index 30fc8ce..eb57c3a 100644
--- a/glslang/Include/Types.h
+++ b/glslang/Include/Types.h
@@ -721,6 +721,7 @@
clearUniformLayout();
layoutPushConstant = false;
+ layoutBufferReference = false;
#ifdef NV_EXTENSIONS
layoutPassthrough = false;
layoutViewportRelative = false;
@@ -729,6 +730,8 @@
layoutShaderRecordNV = false;
#endif
+ layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd;
+
clearInterstageLayout();
layoutSpecConstantId = layoutSpecConstantIdEnd;
@@ -763,7 +766,8 @@
#ifdef NV_EXTENSIONS
layoutShaderRecordNV ||
#endif
- layoutPushConstant;
+ layoutPushConstant ||
+ layoutBufferReference;
}
bool hasLayout() const
{
@@ -808,9 +812,14 @@
unsigned int layoutSpecConstantId : 11;
static const unsigned int layoutSpecConstantIdEnd = 0x7FF;
+ // stored as log2 of the actual alignment value
+ unsigned int layoutBufferReferenceAlign : 6;
+ static const unsigned int layoutBufferReferenceAlignEnd = 0x3F;
+
TLayoutFormat layoutFormat : 8;
bool layoutPushConstant;
+ bool layoutBufferReference;
#ifdef NV_EXTENSIONS
bool layoutPassthrough;
@@ -918,6 +927,10 @@
// is just whether or not it was declared with an ID.
return layoutSpecConstantId != layoutSpecConstantIdEnd;
}
+ bool hasBufferReferenceAlign() const
+ {
+ return layoutBufferReferenceAlign != layoutBufferReferenceAlignEnd;
+ }
bool isSpecConstant() const
{
// True if type is a specialization constant, whether or not it
@@ -1308,7 +1321,12 @@
sampler.clear();
qualifier = p.qualifier;
if (p.userDef) {
- structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
+ if (p.userDef->basicType == EbtReference) {
+ basicType = EbtReference;
+ referentType = p.userDef->referentType;
+ } else {
+ structure = p.userDef->getWritableStruct(); // public type is short-lived; there are no sharing issues
+ }
typeName = NewPoolTString(p.userDef->getTypeName().c_str());
}
}
@@ -1377,6 +1395,17 @@
sampler.clear();
typeName = NewPoolTString(n.c_str());
}
+ // for block reference (first parameter must be EbtReference)
+ explicit TType(TBasicType t, const TType &p, const TString& n) :
+ basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false),
+ arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr)
+ {
+ assert(t == EbtReference);
+ typeName = NewPoolTString(n.c_str());
+ qualifier.clear();
+ qualifier.storage = p.qualifier.storage;
+ referentType = p.clone();
+ }
virtual ~TType() {}
// Not for use across pool pops; it will cause multiple instances of TType to point to the same information.
@@ -1392,9 +1421,13 @@
matrixRows = copyOf.matrixRows;
vector1 = copyOf.vector1;
arraySizes = copyOf.arraySizes; // copying the pointer only, not the contents
- structure = copyOf.structure;
fieldName = copyOf.fieldName;
typeName = copyOf.typeName;
+ if (isStruct()) {
+ structure = copyOf.structure;
+ } else {
+ referentType = copyOf.referentType;
+ }
}
// Make complete copy of the whole type graph rooted at 'copyOf'.
@@ -1457,6 +1490,7 @@
virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); }
virtual const TArraySizes* getArraySizes() const { return arraySizes; }
virtual TArraySizes* getArraySizes() { return arraySizes; }
+ virtual TType* getReferentType() const { return referentType; }
virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); }
virtual bool isScalarOrVec1() const { return isScalar() || vector1; }
@@ -1468,7 +1502,7 @@
virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); }
virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); }
virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); }
- virtual bool isStruct() const { return structure != nullptr; }
+ virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; }
virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; }
virtual bool isIntegerDomain() const
{
@@ -1509,7 +1543,7 @@
const auto hasa = [predicate](const TTypeLoc& tl) { return tl.type->contains(predicate); };
- return structure && std::any_of(structure->begin(), structure->end(), hasa);
+ return isStruct() && std::any_of(structure->begin(), structure->end(), hasa);
}
// Recursively checks if the type contains the given basic type
@@ -1688,6 +1722,7 @@
#ifdef NV_EXTENSIONS
case EbtAccStructNV: return "accelerationStructureNV";
#endif
+ case EbtReference: return "reference";
default: return "unknown type";
}
}
@@ -1773,6 +1808,12 @@
}
if (qualifier.layoutPushConstant)
appendStr(" push_constant");
+ if (qualifier.layoutBufferReference)
+ appendStr(" buffer_reference");
+ if (qualifier.hasBufferReferenceAlign()) {
+ appendStr(" buffer_reference_align=");
+ appendUint(1u << qualifier.layoutBufferReferenceAlign);
+ }
#ifdef NV_EXTENSIONS
if (qualifier.layoutPassthrough)
@@ -1892,7 +1933,7 @@
}
// Add struct/block members
- if (structure) {
+ if (isStruct()) {
appendStr("{");
for (size_t i = 0; i < structure->size(); ++i) {
if (! (*structure)[i].type->hiddenMember()) {
@@ -1920,9 +1961,9 @@
const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); }
const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); }
const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); }
- const TTypeList* getStruct() const { return structure; }
- void setStruct(TTypeList* s) { structure = s; }
- TTypeList* getWritableStruct() const { return structure; } // This should only be used when known to not be sharing with other threads
+ const TTypeList* getStruct() const { assert(isStruct()); return structure; }
+ void setStruct(TTypeList* s) { assert(isStruct()); structure = s; }
+ TTypeList* getWritableStruct() const { assert(isStruct()); return structure; } // This should only be used when known to not be sharing with other threads
int computeNumComponents() const
{
@@ -1961,11 +2002,12 @@
bool sameStructType(const TType& right) const
{
// Most commonly, they are both nullptr, or the same pointer to the same actual structure
- if (structure == right.structure)
+ if ((!isStruct() && !right.isStruct()) ||
+ isStruct() && right.isStruct() && structure == right.structure)
return true;
// Both being nullptr was caught above, now they both have to be structures of the same number of elements
- if (structure == nullptr || right.structure == nullptr ||
+ if (!isStruct() || !right.isStruct() ||
structure->size() != right.structure->size())
return false;
@@ -1985,6 +2027,23 @@
return true;
}
+ bool sameReferenceType(const TType& right) const
+ {
+ if ((basicType == EbtReference) != (right.basicType == EbtReference))
+ return false;
+
+ if ((basicType != EbtReference) && (right.basicType != EbtReference))
+ return true;
+
+ assert(referentType != nullptr);
+ assert(right.referentType != nullptr);
+
+ if (referentType == right.referentType)
+ return true;
+
+ return *referentType == *right.referentType;
+ }
+
// See if two types match, in all aspects except arrayness
bool sameElementType(const TType& right) const
{
@@ -2013,7 +2072,8 @@
matrixCols == right.matrixCols &&
matrixRows == right.matrixRows &&
vector1 == right.vector1 &&
- sameStructType(right);
+ sameStructType(right) &&
+ sameReferenceType(right);
}
// See if two types match in all ways (just the actual type, not qualification)
@@ -2044,7 +2104,7 @@
*arraySizes = *copyOf.arraySizes;
}
- if (copyOf.structure) {
+ if (copyOf.isStruct() && copyOf.structure) {
auto prevCopy = copiedMap.find(copyOf.structure);
if (prevCopy != copiedMap.end())
structure = prevCopy->second;
@@ -2082,7 +2142,12 @@
TQualifier qualifier;
TArraySizes* arraySizes; // nullptr unless an array; can be shared across types
- TTypeList* structure; // nullptr unless this is a struct; can be shared across types
+ // A type can't be both a structure (EbtStruct/EbtBlock) and a reference (EbtReference), so
+ // conserve space by making these a union
+ union {
+ TTypeList* structure; // invalid unless this is a struct; can be shared across types
+ TType *referentType; // invalid unless this is an EbtReference
+ };
TString *fieldName; // for structure field names
TString *typeName; // for structure type name
TSampler sampler;
diff --git a/glslang/Include/intermediate.h b/glslang/Include/intermediate.h
index 2725007..4b6bcb7 100644
--- a/glslang/Include/intermediate.h
+++ b/glslang/Include/intermediate.h
@@ -269,6 +269,10 @@
EOpConvDoubleToFloat16,
EOpConvDoubleToFloat,
+ // uint64_t <-> pointer
+ EOpConvUint64ToPtr,
+ EOpConvPtrToUint64,
+
//
// binary operations
//
@@ -732,6 +736,7 @@
EOpConstructStruct,
EOpConstructTextureSampler,
EOpConstructNonuniform, // expected to be transformed away, not present in final AST
+ EOpConstructReference,
EOpConstructGuardEnd,
//
diff --git a/glslang/MachineIndependent/Intermediate.cpp b/glslang/MachineIndependent/Intermediate.cpp
index a3ca56c..32b38a0 100755
--- a/glslang/MachineIndependent/Intermediate.cpp
+++ b/glslang/MachineIndependent/Intermediate.cpp
@@ -984,6 +984,14 @@
case EOpSequence:
case EOpConstructStruct:
+ if (type.getBasicType() == EbtReference || node->getType().getBasicType() == EbtReference) {
+ // types must match to assign a reference
+ if (type == node->getType())
+ return node;
+ else
+ return nullptr;
+ }
+
if (type.getBasicType() == node->getType().getBasicType())
return node;
@@ -2131,6 +2139,9 @@
}
}
break;
+ case EbtReference:
+ op = EOpConstructReference;
+ break;
default:
break;
}
diff --git a/glslang/MachineIndependent/ParseHelper.cpp b/glslang/MachineIndependent/ParseHelper.cpp
index 7ddc27e..d16dc99 100755
--- a/glslang/MachineIndependent/ParseHelper.cpp
+++ b/glslang/MachineIndependent/ParseHelper.cpp
@@ -354,6 +354,11 @@
if (variable->getType().getQualifier().isIo())
intermediate.addIoAccessed(*string);
+ if (variable->getType().getBasicType() == EbtReference &&
+ variable->getType().getQualifier().isMemory()) {
+ intermediate.setUseVulkanMemoryModel();
+ }
+
return node;
}
@@ -811,8 +816,12 @@
if (base->getType().getQualifier().isSpecConstant())
result->getWritableType().getQualifier().makeSpecConstant();
}
- } else if (base->getBasicType() == EbtStruct || base->getBasicType() == EbtBlock) {
- const TTypeList* fields = base->getType().getStruct();
+ } else if (base->getBasicType() == EbtStruct ||
+ base->getBasicType() == EbtBlock ||
+ base->getBasicType() == EbtReference) {
+ const TTypeList* fields = base->getBasicType() == EbtReference ?
+ base->getType().getReferentType()->getStruct() :
+ base->getType().getStruct();
bool fieldFound = false;
int member;
for (member = 0; member < (int)fields->size(); ++member) {
@@ -2386,6 +2395,10 @@
}
}
+ if (binaryNode && binaryNode->getOp() == EOpIndexDirectStruct &&
+ binaryNode->getLeft()->getBasicType() == EbtReference)
+ return false;
+
// Let the base class check errors
if (TParseContextBase::lValueErrorCheck(loc, op, node))
return true;
@@ -3096,13 +3109,17 @@
if (! symbolTable.atGlobalLevel())
return;
- if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
- error(loc, "memory qualifiers cannot be used on this type", "", "");
- } else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
- error(loc, "memory qualifiers cannot be used on this type", "", "");
+ if (!(publicType.userDef && publicType.userDef->getBasicType() == EbtReference)) {
+ if (qualifier.isMemoryQualifierImageAndSSBOOnly() && ! publicType.isImage() && publicType.qualifier.storage != EvqBuffer) {
+ error(loc, "memory qualifiers cannot be used on this type", "", "");
+ } else if (qualifier.isMemory() && (publicType.basicType != EbtSampler) && !publicType.qualifier.isUniformOrBuffer()) {
+ error(loc, "memory qualifiers cannot be used on this type", "", "");
+ }
}
- if (qualifier.storage == EvqBuffer && publicType.basicType != EbtBlock)
+ if (qualifier.storage == EvqBuffer &&
+ publicType.basicType != EbtBlock &&
+ !qualifier.layoutBufferReference)
error(loc, "buffers can be declared only as blocks", "buffer", "");
if (qualifier.storage != EvqVaryingIn && qualifier.storage != EvqVaryingOut)
@@ -3760,6 +3777,21 @@
if (isRuntimeLength(base))
return;
+ // Check for last member of a bufferreference type, which is runtime sizeable
+ // but doesn't support runtime length
+ if (base.getType().getQualifier().storage == EvqBuffer) {
+ const TIntermBinary* binary = base.getAsBinaryNode();
+ if (binary != nullptr &&
+ binary->getOp() == EOpIndexDirectStruct &&
+ binary->getLeft()->getBasicType() == EbtReference) {
+
+ const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+ const int memberCount = (int)binary->getLeft()->getType().getReferentType()->getStruct()->size();
+ if (index == memberCount - 1)
+ return;
+ }
+ }
+
// check for additional things allowed by GL_EXT_nonuniform_qualifier
if (base.getBasicType() == EbtSampler ||
(base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer()))
@@ -3777,6 +3809,10 @@
if (binary != nullptr && binary->getOp() == EOpIndexDirectStruct) {
// is it the last member?
const int index = binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst();
+
+ if (binary->getLeft()->getBasicType() == EbtReference)
+ return false;
+
const int memberCount = (int)binary->getLeft()->getType().getStruct()->size();
if (index == memberCount - 1)
return true;
@@ -4655,6 +4691,14 @@
publicType.qualifier.layoutPushConstant = true;
return;
}
+ if (id == "buffer_reference") {
+ requireVulkan(loc, "buffer_reference");
+ requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference");
+ publicType.qualifier.layoutBufferReference = true;
+ intermediate.setUseStorageBuffer();
+ intermediate.setUsePhysicalStorageBuffer();
+ return;
+ }
if (language == EShLangGeometry || language == EShLangTessEvaluation
#ifdef NV_EXTENSIONS
|| language == EShLangMeshNV
@@ -5013,6 +5057,15 @@
}
#endif
+ if (id == "buffer_reference_align") {
+ requireExtensions(loc, 1, &E_GL_EXT_buffer_reference, "buffer_reference_align");
+ if (! IsPow2(value))
+ error(loc, "must be a power of 2", "buffer_reference_align", "");
+ else
+ publicType.qualifier.layoutBufferReferenceAlign = std::log2(value);
+ return;
+ }
+
switch (language) {
case EShLangVertex:
break;
@@ -5177,6 +5230,9 @@
if (src.hasAlign())
dst.layoutAlign = src.layoutAlign;
+ if (src.hasBufferReferenceAlign())
+ dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign;
+
if (! inheritOnly) {
if (src.hasLocation())
dst.layoutLocation = src.layoutLocation;
@@ -5205,6 +5261,9 @@
if (src.layoutPushConstant)
dst.layoutPushConstant = true;
+ if (src.layoutBufferReference)
+ dst.layoutBufferReference = true;
+
#ifdef NV_EXTENSIONS
if (src.layoutPassthrough)
dst.layoutPassthrough = true;
@@ -5452,7 +5511,8 @@
#ifdef NV_EXTENSIONS
!qualifier.layoutShaderRecordNV &&
#endif
- !qualifier.layoutAttachment)
+ !qualifier.layoutAttachment &&
+ !qualifier.layoutBufferReference)
error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", "");
else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler)
error(loc, "sampler/texture/image requires layout(binding=X)", "binding", "");
@@ -5504,6 +5564,9 @@
if (qualifier.layoutPushConstant && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "push_constant", "");
+ if (qualifier.layoutBufferReference && type.getBasicType() != EbtBlock)
+ error(loc, "can only be used with a block", "buffer_reference", "");
+
#ifdef NV_EXTENSIONS
if (qualifier.layoutShaderRecordNV && type.getBasicType() != EbtBlock)
error(loc, "can only be used with a block", "shaderRecordNV", "");
@@ -5644,6 +5707,10 @@
if (qualifier.hasSet())
error(loc, "cannot be used with push_constant", "set", "");
}
+ if (qualifier.layoutBufferReference) {
+ if (qualifier.storage != EvqBuffer)
+ error(loc, "can only be used with buffer", "buffer_reference", "");
+ }
#ifdef NV_EXTENSIONS
if (qualifier.layoutShaderRecordNV) {
if (qualifier.storage != EvqBuffer)
@@ -6051,7 +6118,7 @@
return;
}
- if (publicType.qualifier.hasLayout())
+ if (publicType.qualifier.hasLayout() && !publicType.qualifier.layoutBufferReference)
warn(loc, "useless application of layout qualifier", "layout", "");
}
@@ -6659,10 +6726,15 @@
basicOp = EOpConstructInt64;
break;
+ case EOpConstructUint64:
+ if (type.isScalar() && node->getType().getBasicType() == EbtReference) {
+ TIntermUnary* newNode = intermediate.addUnaryNode(EOpConvPtrToUint64, node, node->getLoc(), type);
+ return newNode;
+ }
+ // fall through
case EOpConstructU64Vec2:
case EOpConstructU64Vec3:
case EOpConstructU64Vec4:
- case EOpConstructUint64:
basicOp = EOpConstructUint64;
break;
@@ -6678,6 +6750,19 @@
return node;
break;
+ case EOpConstructReference:
+ // construct reference from reference
+ if (node->getType().getBasicType() == EbtReference) {
+ newNode = intermediate.addUnaryNode(EOpConstructReference, node, node->getLoc(), type);
+ return newNode;
+ // construct reference from uint64
+ } else if (node->getType().isScalar() && node->getType().getBasicType() == EbtUint64) {
+ TIntermUnary* newNode = intermediate.addUnaryNode(EOpConvUint64ToPtr, node, node->getLoc(), type);
+ return newNode;
+ } else {
+ return nullptr;
+ }
+
default:
error(loc, "unsupported construction", "", "");
@@ -6922,31 +7007,57 @@
else
ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName);
- //
- // Don't make a user-defined type out of block name; that will cause an error
- // if the same block name gets reused in a different interface.
- //
- // "Block names have no other use within a shader
- // beyond interface matching; it is a compile-time error to use a block name at global scope for anything
- // other than as a block name (e.g., use of a block name for a global variable name or function name is
- // currently reserved)."
- //
- // Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
- // whose type is EbtBlock, but without all the structure; that will come from the type
- // the instances point to.
- //
- TType blockNameType(EbtBlock, blockType.getQualifier().storage);
- TVariable* blockNameVar = new TVariable(blockName, blockNameType);
- if (! symbolTable.insert(*blockNameVar)) {
- TSymbol* existingName = symbolTable.find(*blockName);
- if (existingName->getType().getBasicType() == EbtBlock) {
- if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
- error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
+ if (currentBlockQualifier.layoutBufferReference) {
+
+ if (currentBlockQualifier.storage != EvqBuffer)
+ error(loc, "can only be used with buffer", "buffer_reference", "");
+
+ // Create the block reference type. If it was forward-declared, detect that
+ // as a referent struct type with no members. Replace the referent type with
+ // blockType.
+ TType blockNameType(EbtReference, blockType, *blockName);
+ TVariable* blockNameVar = new TVariable(blockName, blockNameType, true);
+ if (! symbolTable.insert(*blockNameVar)) {
+ TSymbol* existingName = symbolTable.find(*blockName);
+ if (existingName->getType().getBasicType() == EbtReference &&
+ existingName->getType().getReferentType()->getStruct() &&
+ existingName->getType().getReferentType()->getStruct()->size() == 0 &&
+ existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
+ existingName->getType().getReferentType()->deepCopy(blockType);
+ } else {
+ error(loc, "block name cannot be redefined", blockName->c_str(), "");
+ }
+ }
+ if (!instanceName) {
+ return;
+ }
+ } else {
+ //
+ // Don't make a user-defined type out of block name; that will cause an error
+ // if the same block name gets reused in a different interface.
+ //
+ // "Block names have no other use within a shader
+ // beyond interface matching; it is a compile-time error to use a block name at global scope for anything
+ // other than as a block name (e.g., use of a block name for a global variable name or function name is
+ // currently reserved)."
+ //
+ // Use the symbol table to prevent normal reuse of the block's name, as a variable entry,
+ // whose type is EbtBlock, but without all the structure; that will come from the type
+ // the instances point to.
+ //
+ TType blockNameType(EbtBlock, blockType.getQualifier().storage);
+ TVariable* blockNameVar = new TVariable(blockName, blockNameType);
+ if (! symbolTable.insert(*blockNameVar)) {
+ TSymbol* existingName = symbolTable.find(*blockName);
+ if (existingName->getType().getBasicType() == EbtBlock) {
+ if (existingName->getType().getQualifier().storage == blockType.getQualifier().storage) {
+ error(loc, "Cannot reuse block name within the same interface:", blockName->c_str(), blockType.getStorageQualifierString());
+ return;
+ }
+ } else {
+ error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
return;
}
- } else {
- error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
- return;
}
}
@@ -7246,6 +7357,22 @@
void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qualifier, const TString& identifier)
{
TSymbol* symbol = symbolTable.find(identifier);
+
+ // A forward declaration of a block reference looks to the grammar like adding
+ // a qualifier to an existing symbol. Detect this and create the block reference
+ // type with an empty type list, which will be filled in later in
+ // TParseContext::declareBlock.
+ if (!symbol && qualifier.layoutBufferReference) {
+ TTypeList typeList;
+ TType blockType(&typeList, identifier, qualifier);;
+ TType blockNameType(EbtReference, blockType, identifier);
+ TVariable* blockNameVar = new TVariable(&identifier, blockNameType, true);
+ if (! symbolTable.insert(*blockNameVar)) {
+ error(loc, "block name cannot redefine a non-block name", blockName->c_str(), "");
+ }
+ return;
+ }
+
if (! symbol) {
error(loc, "identifier not previously declared", identifier.c_str(), "");
return;
@@ -7580,6 +7707,8 @@
error(loc, "cannot declare a default, use a full declaration", "xfb_offset", "");
if (qualifier.layoutPushConstant)
error(loc, "cannot declare a default, can only be used on a block", "push_constant", "");
+ if (qualifier.layoutBufferReference)
+ error(loc, "cannot declare a default, can only be used on a block", "buffer_reference", "");
if (qualifier.hasSpecConstantId())
error(loc, "cannot declare a default, can only be used on a scalar", "constant_id", "");
#ifdef NV_EXTENSIONS
diff --git a/glslang/MachineIndependent/Scan.cpp b/glslang/MachineIndependent/Scan.cpp
index 2247250..2ec26c6 100644
--- a/glslang/MachineIndependent/Scan.cpp
+++ b/glslang/MachineIndependent/Scan.cpp
@@ -776,7 +776,7 @@
loc = ppToken.loc;
parserToken->sType.lex.loc = loc;
switch (token) {
- case ';': afterType = false; return SEMICOLON;
+ case ';': afterType = false; afterBuffer = false; return SEMICOLON;
case ',': afterType = false; return COMMA;
case ':': return COLON;
case '=': afterType = false; return EQUAL;
@@ -798,7 +798,7 @@
case '?': return QUESTION;
case '[': return LEFT_BRACKET;
case ']': return RIGHT_BRACKET;
- case '{': afterStruct = false; return LEFT_BRACE;
+ case '{': afterStruct = false; afterBuffer = false; return LEFT_BRACE;
case '}': return RIGHT_BRACE;
case '\\':
parseContext.error(loc, "illegal use of escape character", "\\", "");
@@ -945,6 +945,7 @@
return keyword;
case BUFFER:
+ afterBuffer = true;
if ((parseContext.profile == EEsProfile && parseContext.version < 310) ||
(parseContext.profile != EEsProfile && parseContext.version < 430))
return identifierOrType();
@@ -1617,7 +1618,9 @@
parserToken->sType.lex.symbol = parseContext.symbolTable.find(*parserToken->sType.lex.string);
if ((afterType == false && afterStruct == false) && parserToken->sType.lex.symbol != nullptr) {
if (const TVariable* variable = parserToken->sType.lex.symbol->getAsVariable()) {
- if (variable->isUserType()) {
+ if (variable->isUserType() &&
+ // treat redeclaration of forward-declared buffer/uniform reference as an identifier
+ !(variable->getType().getBasicType() == EbtReference && afterBuffer)) {
afterType = true;
return TYPE_NAME;
diff --git a/glslang/MachineIndependent/ScanContext.h b/glslang/MachineIndependent/ScanContext.h
index 0cc7ea0..74b2b3c 100644
--- a/glslang/MachineIndependent/ScanContext.h
+++ b/glslang/MachineIndependent/ScanContext.h
@@ -53,7 +53,7 @@
explicit TScanContext(TParseContextBase& pc) :
parseContext(pc),
afterType(false), afterStruct(false),
- field(false) { }
+ field(false), afterBuffer(false) { }
virtual ~TScanContext() { }
static void fillInKeywordMap();
@@ -81,6 +81,7 @@
bool afterType; // true if we've recognized a type, so can only be looking for an identifier
bool afterStruct; // true if we've recognized the STRUCT keyword, so can only be looking for an identifier
bool field; // true if we're on a field, right after a '.'
+ bool afterBuffer; // true if we've recognized the BUFFER keyword
TSourceLoc loc;
TParserToken* parserToken;
TPpToken* ppToken;
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 9b8347f..8088845 100755
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -207,6 +207,7 @@
extensionBehavior[E_GL_EXT_samplerless_texture_functions] = EBhDisable;
extensionBehavior[E_GL_EXT_scalar_block_layout] = EBhDisable;
extensionBehavior[E_GL_EXT_fragment_invocation_density] = EBhDisable;
+ extensionBehavior[E_GL_EXT_buffer_reference] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable;
extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable;
@@ -383,6 +384,7 @@
"#define GL_EXT_samplerless_texture_functions 1\n"
"#define GL_EXT_scalar_block_layout 1\n"
"#define GL_EXT_fragment_invocation_density 1\n"
+ "#define GL_EXT_buffer_reference 1\n"
// GL_KHR_shader_subgroup
"#define GL_KHR_shader_subgroup_basic 1\n"
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index 3207503..0606e8e 100755
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -169,6 +169,7 @@
const char* const E_GL_EXT_samplerless_texture_functions = "GL_EXT_samplerless_texture_functions";
const char* const E_GL_EXT_scalar_block_layout = "GL_EXT_scalar_block_layout";
const char* const E_GL_EXT_fragment_invocation_density = "GL_EXT_fragment_invocation_density";
+const char* const E_GL_EXT_buffer_reference = "GL_EXT_buffer_reference";
// Arrays of extensions for the above viewportEXTs duplications
diff --git a/glslang/MachineIndependent/intermOut.cpp b/glslang/MachineIndependent/intermOut.cpp
index 5ad6790..f74b90a 100644
--- a/glslang/MachineIndependent/intermOut.cpp
+++ b/glslang/MachineIndependent/intermOut.cpp
@@ -172,8 +172,12 @@
case EOpIndexDirect: out.debug << "direct index"; break;
case EOpIndexIndirect: out.debug << "indirect index"; break;
case EOpIndexDirectStruct:
- out.debug << (*node->getLeft()->getType().getStruct())[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
- out.debug << ": direct index for structure"; break;
+ {
+ bool reference = node->getLeft()->getType().getBasicType() == EbtReference;
+ const TTypeList *members = reference ? node->getLeft()->getType().getReferentType()->getStruct() : node->getLeft()->getType().getStruct();
+ out.debug << (*members)[node->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()].type->getFieldName();
+ out.debug << ": direct index for structure"; break;
+ }
case EOpVectorSwizzle: out.debug << "vector swizzle"; break;
case EOpMatrixSwizzle: out.debug << "matrix swizzle"; break;
@@ -419,6 +423,8 @@
case EOpConvDoubleToUint: out.debug << "Convert double to uint"; break;
case EOpConvDoubleToUint64: out.debug << "Convert double to uint64"; break;
+ case EOpConvUint64ToPtr: out.debug << "Convert uint64_t to pointer"; break;
+ case EOpConvPtrToUint64: out.debug << "Convert pointer to uint64_t"; break;
case EOpRadians: out.debug << "radians"; break;
case EOpDegrees: out.debug << "degrees"; break;
@@ -674,6 +680,8 @@
case EOpSubpassLoad: out.debug << "subpassLoad"; break;
case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break;
+ case EOpConstructReference: out.debug << "Construct reference type"; break;
+
default: out.debug.message(EPrefixError, "Bad unary op");
}
@@ -808,6 +816,7 @@
case EOpConstructF16Mat4x4: out.debug << "Construct f16mat4"; break;
case EOpConstructStruct: out.debug << "Construct structure"; break;
case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break;
+ case EOpConstructReference: out.debug << "Construct reference"; break;
case EOpLessThan: out.debug << "Compare Less Than"; break;
case EOpGreaterThan: out.debug << "Compare Greater Than"; break;
diff --git a/glslang/MachineIndependent/linkValidate.cpp b/glslang/MachineIndependent/linkValidate.cpp
index 79c8c02..977600b 100755
--- a/glslang/MachineIndependent/linkValidate.cpp
+++ b/glslang/MachineIndependent/linkValidate.cpp
@@ -261,6 +261,7 @@
MERGE_TRUE(needToLegalize);
MERGE_TRUE(binaryDoubleOutput);
+ MERGE_TRUE(usePhysicalStorageBuffer);
}
//
@@ -1355,6 +1356,7 @@
case EbtUint8: size = 1; return 1;
case EbtInt16:
case EbtUint16: size = 2; return 2;
+ case EbtReference: size = 8; return 8;
default: size = 4; return 4;
}
}
diff --git a/glslang/MachineIndependent/localintermediate.h b/glslang/MachineIndependent/localintermediate.h
index eb8fe0b..cd589d8 100755
--- a/glslang/MachineIndependent/localintermediate.h
+++ b/glslang/MachineIndependent/localintermediate.h
@@ -255,6 +255,7 @@
textureSamplerTransformMode(EShTexSampTransKeep),
needToLegalize(false),
binaryDoubleOutput(false),
+ usePhysicalStorageBuffer(false),
uniformLocationBase(0)
{
localSize[0] = 1;
@@ -390,6 +391,11 @@
processes.addProcess("use-vulkan-memory-model");
}
bool usingVulkanMemoryModel() const { return useVulkanMemoryModel; }
+ void setUsePhysicalStorageBuffer()
+ {
+ usePhysicalStorageBuffer = true;
+ }
+ bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; }
template<class T> T addCounterBufferName(const T& name) const { return name + implicitCounterName; }
bool hasCounterBufferName(const TString& name) const {
@@ -825,6 +831,7 @@
bool needToLegalize;
bool binaryDoubleOutput;
+ bool usePhysicalStorageBuffer;
std::unordered_map<std::string, int> uniformLocationOverrides;
int uniformLocationBase;
diff --git a/gtests/Spv.FromFile.cpp b/gtests/Spv.FromFile.cpp
index 565eddd..170f985 100644
--- a/gtests/Spv.FromFile.cpp
+++ b/gtests/Spv.FromFile.cpp
@@ -265,6 +265,22 @@
"spv.bool.vert",
"spv.boolInBlock.frag",
"spv.branch-return.vert",
+ "spv.bufferhandle1.frag",
+ "spv.bufferhandle10.frag",
+ "spv.bufferhandle11.frag",
+ "spv.bufferhandle12.frag",
+ "spv.bufferhandle13.frag",
+ "spv.bufferhandle14.frag",
+ "spv.bufferhandle15.frag",
+ "spv.bufferhandle2.frag",
+ "spv.bufferhandle3.frag",
+ "spv.bufferhandle4.frag",
+ "spv.bufferhandle5.frag",
+ "spv.bufferhandle6.frag",
+ "spv.bufferhandle7.frag",
+ "spv.bufferhandle8.frag",
+ "spv.bufferhandle9.frag",
+ "spv.bufferhandle_Error.frag",
"spv.builtInXFB.vert",
"spv.conditionalDiscard.frag",
"spv.constStruct.vert",
diff --git a/known_good.json b/known_good.json
index b5c668c..face836 100644
--- a/known_good.json
+++ b/known_good.json
@@ -5,14 +5,14 @@
"site" : "github",
"subrepo" : "KhronosGroup/SPIRV-Tools",
"subdir" : "External/spirv-tools",
- "commit" : "a87d3ce48e88a653e855c3245a6b68deeae58efc"
+ "commit" : "5eab6df648eace6eab69c44ccd17bd0f5e57406d"
},
{
"name" : "spirv-tools/external/spirv-headers",
"site" : "github",
"subrepo" : "KhronosGroup/SPIRV-Headers",
"subdir" : "External/spirv-tools/external/spirv-headers",
- "commit" : "4618b86e9e4b027a22040732dfee35e399cd2c47"
+ "commit" : "79b6681aadcb53c27d1052e5f8a0e82a981dbf2f"
}
]
}