SPV arrays: Add support for runtime-sized array types and arrays of arrays.
This includes run-time block.member.length() (OpArrayLength).
diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp
index cc02738..4c7c17c 100755
--- a/SPIRV/GlslangToSpv.cpp
+++ b/SPIRV/GlslangToSpv.cpp
@@ -680,6 +680,24 @@
}
// Non-texturing.
+
+ if (node->getOp() == glslang::EOpArrayLength) {
+ // Quite special; won't want to evaluate the operand.
+
+ // Normal .length() would have been constant folded by the front-end.
+ // So, this has to be block.lastMember.length().
+ // SPV wants "block" as the operand, go get it.
+ assert(node->getOperand()->getType().isRuntimeSizedArray());
+ glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft();
+ block->traverse(this);
+ spv::Id length = builder.createUnaryOp(spv::OpArrayLength, builder.makeIntType(32), builder.accessChainGetLValue());
+
+ builder.clearAccessChain();
+ builder.setAccessChainRValue(length);
+
+ return false;
+ }
+
// Start by evaluating the operand
builder.clearAccessChain();
@@ -967,17 +985,6 @@
// which can be emitted by the one in createBinaryOperation()
binOp = glslang::EOpMod;
break;
- case glslang::EOpArrayLength:
- {
- glslang::TIntermTyped* typedNode = node->getSequence()[0]->getAsTyped();
- assert(typedNode);
- spv::Id length = builder.makeIntConstant(typedNode->getType().getOuterArraySize());
-
- builder.clearAccessChain();
- builder.setAccessChainRValue(length);
-
- return false;
- }
case glslang::EOpEmitVertex:
case glslang::EOpEndPrimitive:
case glslang::EOpBarrier:
@@ -1468,14 +1475,23 @@
}
if (type.isArray()) {
- unsigned arraySize;
- if (! type.isExplicitlySizedArray()) {
- spv::MissingFunctionality("Unsized array");
- arraySize = 8;
- } else
- arraySize = type.getOuterArraySize();
- spvType = builder.makeArrayType(spvType, arraySize);
+ // Do all but the outer dimension
+ for (int dim = type.getArraySizes()->getNumDims() - 1; dim > 0; --dim) {
+ assert(type.getArraySizes()->getDimSize(dim) > 0);
+ spvType = builder.makeArrayType(spvType, type.getArraySizes()->getDimSize(dim));
+ }
+ // Do the outer dimension, which might not be known for a runtime-sized array
+ if (type.isRuntimeSizedArray()) {
+ spvType = builder.makeRuntimeArray(spvType);
+ } else {
+ assert(type.getOuterArraySize() > 0);
+ spvType = builder.makeArrayType(spvType, type.getOuterArraySize());
+ }
+
+ // TODO: layout still needs to be done hierarchically for arrays of arrays, which
+ // may still require additional "link time" support from the front-end
+ // for arrays of arrays
if (explicitLayout)
builder.addDecoration(spvType, spv::DecorationArrayStride, getArrayStride(type));
}
diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp
index f544f21..953b604 100755
--- a/SPIRV/SpvBuilder.cpp
+++ b/SPIRV/SpvBuilder.cpp
@@ -264,6 +264,16 @@
return type->getResultId();
}
+Id Builder::makeRuntimeArray(Id element)
+{
+ Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray);
+ type->addIdOperand(element);
+ constantsTypesGlobals.push_back(type);
+ module.mapInstruction(type);
+
+ return type->getResultId();
+}
+
Id Builder::makeFunctionType(Id returnType, std::vector<Id>& paramTypes)
{
// try to find it
@@ -280,7 +290,7 @@
}
}
if (! mismatch)
- return type->getResultId();
+ return type->getResultId();
}
// not found, make it
diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h
index de9686c..1ceb9c6 100755
--- a/SPIRV/SpvBuilder.h
+++ b/SPIRV/SpvBuilder.h
@@ -102,6 +102,7 @@
Id makeVectorType(Id component, int size);
Id makeMatrixType(Id component, int cols, int rows);
Id makeArrayType(Id element, unsigned size);
+ Id makeRuntimeArray(Id element);
Id makeFunctionType(Id returnType, std::vector<Id>& paramTypes);
Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format);
Id makeSampledImageType(Id imageType);