From c9a808319a60e935e8087bafae16cc07a4ed3a2b Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Sat, 12 Sep 2015 12:17:44 -0600 Subject: [PATCH] SPV arrays: Add support for runtime-sized array types and arrays of arrays. This includes run-time block.member.length() (OpArrayLength). --- SPIRV/GlslangToSpv.cpp | 52 ++++++++----- SPIRV/SpvBuilder.cpp | 12 ++- SPIRV/SpvBuilder.h | 1 + Test/baseResults/spv.310.comp.out | 119 +++++++++++++++++++++++++++- Test/baseResults/spv.AofA.frag.out | 154 +++++++++++++++++++++++++++++++++++++ Test/spv.310.comp | 10 +-- Test/spv.AofA.frag | 43 +++++++++++ Test/test-spirv-list | 1 + glslang/Include/revision.h | 4 +- 9 files changed, 369 insertions(+), 27 deletions(-) create mode 100644 Test/baseResults/spv.AofA.frag.out create mode 100644 Test/spv.AofA.frag 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 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI } // 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 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt // 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 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty } 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 @@ Id Builder::makeArrayType(Id element, unsigned size) 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& paramTypes) { // try to find it @@ -280,7 +290,7 @@ Id Builder::makeFunctionType(Id returnType, std::vector& paramTypes) } } 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 @@ public: 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& paramTypes); Id makeImageType(Id sampledType, Dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format); Id makeSampledImageType(Id imageType); diff --git a/Test/baseResults/spv.310.comp.out b/Test/baseResults/spv.310.comp.out index d1f8a9a..9fbb2d5 100644 --- a/Test/baseResults/spv.310.comp.out +++ b/Test/baseResults/spv.310.comp.out @@ -5,4 +5,121 @@ Warning, version 310 is not yet complete; most version-specific features are pre Linked compute stage: -Missing functionality: Unsized array +// Module Version 99 +// Generated by (magic number): 51a00bb +// Id's are bound by 72 + + Source ESSL 310 + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint GLCompute 4 "main" + Name 4 "main" + Name 14 "outb" + MemberName 14(outb) 0 "f" + MemberName 14(outb) 1 "g" + MemberName 14(outb) 2 "h" + MemberName 14(outb) 3 "uns" + Name 16 "outbname" + Name 20 "s" + Name 25 "outbna" + MemberName 25(outbna) 0 "k" + MemberName 25(outbna) 1 "na" + Name 27 "outbnamena" + Name 47 "i" + Name 53 "outs" + MemberName 53(outs) 0 "s" + MemberName 53(outs) 1 "va" + Name 55 "outnames" + Name 59 "gl_LocalInvocationID" + Decorate 14(outb) GLSLShared + Decorate 14(outb) BufferBlock + Decorate 25(outbna) GLSLShared + Decorate 25(outbna) BufferBlock + Decorate 53(outs) GLSLShared + Decorate 53(outs) BufferBlock + Decorate 59(gl_LocalInvocationID) BuiltIn LocalInvocationId + Decorate 71 BuiltIn WorkgroupSize + Decorate 71 NoStaticUse + 2: TypeVoid + 3: TypeFunction 2 + 7: TypeInt 32 0 + 8: 7(int) Constant 1 + 9: 7(int) Constant 1023 + 10: 7(int) Constant 0 + 11: TypeFloat 32 + 12: TypeVector 11(float) 3 + 13: TypeRuntimeArray 12(fvec3) + 14(outb): TypeStruct 11(float) 11(float) 11(float) 13 + 15: TypePointer Uniform 14(outb) + 16(outbname): 15(ptr) Variable Uniform + 17: TypeInt 32 1 + 18: 17(int) Constant 0 + 19: TypePointer WorkgroupLocal 11(float) + 20(s): 19(ptr) Variable WorkgroupLocal + 22: TypePointer Uniform 11(float) + 24: TypeVector 11(float) 4 + 25(outbna): TypeStruct 17(int) 24(fvec4) + 26: TypePointer Uniform 25(outbna) + 27(outbnamena): 26(ptr) Variable Uniform + 28: 17(int) Constant 1 + 31: TypePointer Uniform 24(fvec4) + 33: TypeRuntimeArray 12(fvec3) + 34: 17(int) Constant 3 + 35: 17(int) Constant 18 + 36: TypePointer Uniform 12(fvec3) + 40: TypeRuntimeArray 12(fvec3) + 41: 17(int) Constant 17 + 42: 11(float) Constant 1077936128 + 43: 12(fvec3) ConstantComposite 42 42 42 + 45: TypeRuntimeArray 12(fvec3) + 46: TypePointer WorkgroupLocal 17(int) + 47(i): 46(ptr) Variable WorkgroupLocal + 52: TypeRuntimeArray 24(fvec4) + 53(outs): TypeStruct 17(int) 52 + 54: TypePointer Uniform 53(outs) + 55(outnames): 54(ptr) Variable Uniform + 56: TypeRuntimeArray 24(fvec4) + 57: TypeVector 7(int) 3 + 58: TypePointer Input 57(ivec3) +59(gl_LocalInvocationID): 58(ptr) Variable Input + 66: TypePointer Uniform 17(int) + 68: 7(int) Constant 16 + 69: 7(int) Constant 32 + 70: 7(int) Constant 4 + 71: 57(ivec3) ConstantComposite 68 69 70 + 4(main): 2 Function None 3 + 5: Label + MemoryBarrier 8 9 + ControlBarrier 8 8 10 + 21: 11(float) Load 20(s) + 23: 22(ptr) AccessChain 16(outbname) 18 + Store 23 21 + 29: 11(float) Load 20(s) + 30: 24(fvec4) CompositeConstruct 29 29 29 29 + 32: 31(ptr) AccessChain 27(outbnamena) 28 + Store 32 30 + 37: 36(ptr) AccessChain 16(outbname) 34 35 + 38: 12(fvec3) Load 37 + 39: 11(float) CompositeExtract 38 0 + Store 20(s) 39 + 44: 36(ptr) AccessChain 16(outbname) 34 41 + Store 44 43 + 48: 17(int) Load 47(i) + 49: 11(float) Load 20(s) + 50: 12(fvec3) CompositeConstruct 49 49 49 + 51: 36(ptr) AccessChain 16(outbname) 34 48 + Store 51 50 + 60: 57(ivec3) Load 59(gl_LocalInvocationID) + 61: 7(int) CompositeExtract 60 0 + 62: 11(float) Load 20(s) + 63: 24(fvec4) CompositeConstruct 62 62 62 62 + 64: 31(ptr) AccessChain 55(outnames) 28 61 + Store 64 63 + 65: 17(int) ArrayLength 16(outbname) + 67: 66(ptr) AccessChain 55(outnames) 18 + Store 67 65 + Branch 6 + 6: Label + Return + FunctionEnd diff --git a/Test/baseResults/spv.AofA.frag.out b/Test/baseResults/spv.AofA.frag.out new file mode 100644 index 0000000..bda0df3 --- /dev/null +++ b/Test/baseResults/spv.AofA.frag.out @@ -0,0 +1,154 @@ +spv.AofA.frag +Warning, version 430 is not yet complete; most version-specific features are present, but some are missing. + + +Linked fragment stage: + + +// Module Version 99 +// Generated by (magic number): 51a00bb +// Id's are bound by 104 + + Source GLSL 430 + Capability Shader + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Fragment 4 "main" + ExecutionMode 4 OriginLowerLeft + Name 4 "main" + Name 18 "foo(f1[5][7];" + Name 17 "a" + Name 21 "r" + Name 39 "outfloat" + Name 42 "g4" + Name 44 "g5" + Name 45 "param" + Name 48 "u" + Name 52 "param" + Name 66 "many" + Name 68 "i" + Name 70 "j" + Name 72 "k" + Name 78 "infloat" + Name 94 "uAofA" + MemberName 94(uAofA) 0 "f" + Name 98 "nameAofA" + Decorate 44(g5) Smooth + Decorate 78(infloat) Smooth + Decorate 94(uAofA) GLSLShared + Decorate 94(uAofA) Block + 2: TypeVoid + 3: TypeFunction 2 + 7: TypeFloat 32 + 8: TypeInt 32 0 + 9: 8(int) Constant 7 + 10: TypeArray 7(float) 9 + 11: 8(int) Constant 5 + 12: TypeArray 10 11 + 13: TypePointer Function 12 + 14: 8(int) Constant 4 + 15: TypeArray 10 14 + 16: TypeFunction 15 13(ptr) + 20: TypePointer Function 10 + 22: TypeInt 32 1 + 23: 22(int) Constant 2 + 26: 22(int) Constant 0 + 29: 22(int) Constant 1 + 33: 22(int) Constant 3 + 38: TypePointer Output 7(float) + 39(outfloat): 38(ptr) Variable Output + 40: 7(float) Constant 0 + 41: TypePointer PrivateGlobal 15 + 42(g4): 41(ptr) Variable PrivateGlobal + 43: TypePointer Input 12 + 44(g5): 43(ptr) Variable Input + 49: 7(float) Constant 1077936128 + 50: TypePointer Function 7(float) + 55: 8(int) Constant 6 + 56: TypeArray 7(float) 55 + 57: TypeArray 56 11 + 58: TypeArray 57 14 + 59: 8(int) Constant 3 + 60: TypeArray 58 59 + 61: 8(int) Constant 2 + 62: TypeArray 60 61 + 63: 8(int) Constant 1 + 64: TypeArray 62 63 + 65: TypePointer PrivateGlobal 64 + 66(many): 65(ptr) Variable PrivateGlobal + 67: TypePointer UniformConstant 22(int) + 68(i): 67(ptr) Variable UniformConstant + 70(j): 67(ptr) Variable UniformConstant + 72(k): 67(ptr) Variable UniformConstant + 77: TypePointer Input 7(float) + 78(infloat): 77(ptr) Variable Input + 80: TypePointer PrivateGlobal 7(float) + 92: TypeArray 7(float) 14 + 93: TypeArray 92 61 + 94(uAofA): TypeStruct 93 + 95: TypeArray 94(uAofA) 11 + 96: TypeArray 95 59 + 97: TypePointer Uniform 96 + 98(nameAofA): 97(ptr) Variable Uniform + 99: TypePointer Uniform 7(float) + 4(main): 2 Function None 3 + 5: Label + 45(param): 13(ptr) Variable Function + 48(u): 13(ptr) Variable Function + 52(param): 13(ptr) Variable Function + Store 39(outfloat) 40 + 46: 12 Load 44(g5) + Store 45(param) 46 + 47: 15 FunctionCall 18(foo(f1[5][7];) 45(param) + Store 42(g4) 47 + 51: 50(ptr) AccessChain 48(u) 23 23 + Store 51 49 + 53: 12 Load 48(u) + Store 52(param) 53 + 54: 15 FunctionCall 18(foo(f1[5][7];) 52(param) + 69: 22(int) Load 68(i) + 71: 22(int) Load 70(j) + 73: 22(int) Load 72(k) + 74: 22(int) Load 68(i) + 75: 22(int) Load 70(j) + 76: 22(int) Load 72(k) + 79: 7(float) Load 78(infloat) + 81: 80(ptr) AccessChain 66(many) 69 71 73 74 75 76 + Store 81 79 + 82: 22(int) Load 70(j) + 83: 22(int) Load 70(j) + 84: 22(int) Load 70(j) + 85: 22(int) Load 70(j) + 86: 22(int) Load 70(j) + 87: 22(int) Load 70(j) + 88: 80(ptr) AccessChain 66(many) 82 83 84 85 86 87 + 89: 7(float) Load 88 + 90: 7(float) Load 39(outfloat) + 91: 7(float) FAdd 90 89 + Store 39(outfloat) 91 + 100: 99(ptr) AccessChain 98(nameAofA) 29 23 26 26 33 + 101: 7(float) Load 100 + 102: 7(float) Load 39(outfloat) + 103: 7(float) FAdd 102 101 + Store 39(outfloat) 103 + Branch 6 + 6: Label + Return + FunctionEnd +18(foo(f1[5][7];): 15 Function None 16 + 17(a): 13(ptr) FunctionParameter + 19: Label + 21(r): 20(ptr) Variable Function + 24: 20(ptr) AccessChain 17(a) 23 + 25: 10 Load 24 + Store 21(r) 25 + 27: 20(ptr) AccessChain 17(a) 26 + 28: 10 Load 27 + 30: 20(ptr) AccessChain 17(a) 29 + 31: 10 Load 30 + 32: 10 Load 21(r) + 34: 20(ptr) AccessChain 17(a) 33 + 35: 10 Load 34 + 36: 15 CompositeConstruct 28 31 32 35 + ReturnValue 36 + FunctionEnd diff --git a/Test/spv.310.comp b/Test/spv.310.comp index 4511636..bd183e0 100644 --- a/Test/spv.310.comp +++ b/Test/spv.310.comp @@ -11,9 +11,7 @@ buffer outb { float f; float g; float h; - vec3 uns[]; // this makes it look like the "second" set of 3 floats in a struct, which LLVM - // takes advantage of when optimizing, giving confusing results, like thinking - // &outbname.uns[18].x == &outbname[9].uns.x + vec3 uns[]; } outbname; buffer outbna { @@ -22,6 +20,7 @@ buffer outbna { } outbnamena; buffer outs { + int s; vec4 va[]; } outnames; @@ -30,8 +29,9 @@ void main() barrier(); outbname.f = s; outbnamena.na = vec4(s); - s = outbname.uns[18].x; // TODO: see note above - //outbname.uns[17] = vec3(3.0); // TODO: see note above, this one bitcasts, which isn't handled + s = outbname.uns[18].x; + outbname.uns[17] = vec3(3.0); outbname.uns[i] = vec3(s); outnames.va[gl_LocalInvocationID.x] = vec4(s); + outnames.s = outbname.uns.length(); } diff --git a/Test/spv.AofA.frag b/Test/spv.AofA.frag new file mode 100644 index 0000000..606d73b --- /dev/null +++ b/Test/spv.AofA.frag @@ -0,0 +1,43 @@ +#version 430 + +in float infloat; +out float outfloat; + +uniform uAofA { + float f[2][4]; +} nameAofA[3][5]; + +float[4][5][6] many[1][2][3]; + +float g4[4][7]; +in float g5[5][7]; + +uniform int i, j, k; + +float[4][7] foo(float a[5][7]) +{ + float r[7]; + r = a[2]; + + return float[4][7](a[0], a[1], r, a[3]); +} + +void main() +{ + outfloat = 0.0; + + g4 = foo(g5); + +// if (foo(g5) == g4) +// ++outfloat; + + float u[][7]; + u[2][2] = 3.0; + float u[5][7]; + + foo(u); + + many[i][j][k][i][j][k] = infloat; + outfloat += many[j][j][j][j][j][j]; + outfloat += nameAofA[1][2].f[0][3]; +} diff --git a/Test/test-spirv-list b/Test/test-spirv-list index ccfa068..a7d8c8d 100644 --- a/Test/test-spirv-list +++ b/Test/test-spirv-list @@ -79,3 +79,4 @@ spv.varyingArrayIndirect.frag spv.voidFunction.frag spv.whileLoop.frag spv.atomic.comp +spv.AofA.frag diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index abb7f13..cd2e547 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -2,5 +2,5 @@ // For the version, it uses the latest git tag followed by the number of commits. // For the date, it uses the current date (when then script is run). -#define GLSLANG_REVISION "3.0.748" -#define GLSLANG_DATE "11-Sep-2015" +#define GLSLANG_REVISION "3.0.750" +#define GLSLANG_DATE "13-Sep-2015" -- 2.7.4