diff --git a/SPIRV/GlslangToSpv.cpp b/SPIRV/GlslangToSpv.cpp index dd5afd4b..9622a775 100755 --- a/SPIRV/GlslangToSpv.cpp +++ b/SPIRV/GlslangToSpv.cpp @@ -130,7 +130,7 @@ protected: void addMemberDecoration(spv::Id id, int member, spv::Decoration dec, unsigned value); spv::Id createSpvConstant(const glslang::TIntermTyped&); spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); - spv::Id createSpvConstantFromConstSubTree(const glslang::TIntermTyped* subTree); + spv::Id createSpvConstantFromConstSubTree(glslang::TIntermTyped* subTree); bool isTrivialLeaf(const glslang::TIntermTyped* node); bool isTrivial(const glslang::TIntermTyped* node); spv::Id createShortCircuit(glslang::TOperator, glslang::TIntermTyped& left, glslang::TIntermTyped& right); @@ -3854,15 +3854,36 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla return builder.makeCompositeConstant(typeId, spvConsts); } +namespace { +class SpecConstantOpModeGuard { +public: + SpecConstantOpModeGuard(spv::Builder* builder) + : builder_(builder) { + previous_flag_ = builder->isInSpecConstCodeGenMode(); + builder->setToSpecConstCodeGenMode(); + } + ~SpecConstantOpModeGuard() { + previous_flag_ ? builder_->setToSpecConstCodeGenMode() + : builder_->setToNormalCodeGenMode(); + } + +private: + spv::Builder* builder_; + bool previous_flag_; +}; +} + // Create constant ID from const initializer sub tree. spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree( - const glslang::TIntermTyped* subTree) { + glslang::TIntermTyped* subTree) +{ const glslang::TType& glslangType = subTree->getType(); spv::Id typeId = convertGlslangToSpvType(glslangType); bool is_spec_const = subTree->getType().getQualifier().isSpecConstant(); if (const glslang::TIntermAggregate* an = subTree->getAsAggregate()) { // Aggregate node, we should generate OpConstantComposite or // OpSpecConstantComposite instruction. + std::vector const_constituents; for (auto NI = an->getSequence().begin(); NI != an->getSequence().end(); NI++) { @@ -3881,17 +3902,27 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstSubTree( return const_constituents.front(); } - } else if (const glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) { + } else if (glslang::TIntermBinary* bn = subTree->getAsBinaryNode()) { // Binary operation node, we should generate OpSpecConstantOp // This case should only happen when Specialization Constants are involved. - spv::MissingFunctionality("OpSpecConstantOp not implemented"); - return spv::NoResult; - } else if (const glslang::TIntermUnary* un = subTree->getAsUnaryNode()) { + // Spec constants defined with binary operations and other constants requires + // OpSpecConstantOp instruction. + SpecConstantOpModeGuard set_to_spec_const_mode(&builder); + + bn->traverse(this); + return accessChainLoad(bn->getType()); + + } else if (glslang::TIntermUnary* un = subTree->getAsUnaryNode()) { // Unary operation node, similar to binary operation node, should only // happen when specialization constants are involved. - spv::MissingFunctionality("OpSpecConstantOp not implemented"); - return spv::NoResult; + + // Spec constants defined with unary operations and other constants requires + // OpSpecConstantOp instruction. + SpecConstantOpModeGuard set_to_spec_const_mode(&builder); + + un->traverse(this); + return accessChainLoad(un->getType()); } else if (const glslang::TIntermConstantUnion* cn = subTree->getAsConstantUnion()) { // ConstantUnion node, should redirect to diff --git a/SPIRV/SpvBuilder.cpp b/SPIRV/SpvBuilder.cpp index 336d3de3..4235f273 100644 --- a/SPIRV/SpvBuilder.cpp +++ b/SPIRV/SpvBuilder.cpp @@ -64,7 +64,8 @@ Builder::Builder(unsigned int magicNumber) : builderNumber(magicNumber), buildPoint(0), uniqueId(0), - mainFunction(0) + mainFunction(0), + generatingOpCodeForSpecConst(false) { clearAccessChain(); } @@ -1063,6 +1064,11 @@ Id Builder::createArrayLength(Id base, unsigned int member) Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) { + // Generate code for spec constants if in spec constant operation + // generation mode. + if (generatingOpCodeForSpecConst) { + return createSpecConstantOp(OpCompositeExtract, typeId, {composite}, {index}); + } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); extract->addIdOperand(composite); extract->addImmediateOperand(index); @@ -1073,6 +1079,11 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) Id Builder::createCompositeExtract(Id composite, Id typeId, std::vector& indexes) { + // Generate code for spec constants if in spec constant operation + // generation mode. + if (generatingOpCodeForSpecConst) { + return createSpecConstantOp(OpCompositeExtract, typeId, {composite}, indexes); + } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); extract->addIdOperand(composite); for (int i = 0; i < (int)indexes.size(); ++i) @@ -1170,6 +1181,11 @@ void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemant // An opcode that has one operands, a result id, and a type Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand) { + // Generate code for spec constants if in spec constant operation + // generation mode. + if (generatingOpCodeForSpecConst) { + return createSpecConstantOp(opCode, typeId, {operand}, {}); + } Instruction* op = new Instruction(getUniqueId(), typeId, opCode); op->addIdOperand(operand); buildPoint->addInstruction(std::unique_ptr(op)); @@ -1179,6 +1195,11 @@ Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand) Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right) { + // Generate code for spec constants if in spec constant operation + // generation mode. + if (generatingOpCodeForSpecConst) { + return createSpecConstantOp(opCode, typeId, {left, right}, {}); + } Instruction* op = new Instruction(getUniqueId(), typeId, opCode); op->addIdOperand(left); op->addIdOperand(right); @@ -1208,6 +1229,20 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) return op->getResultId(); } +Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& operands, const std::vector& literals) +{ + Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); + op->addImmediateOperand((unsigned) opCode); + for (auto it = operands.cbegin(); it != operands.cend(); ++it) + op->addIdOperand(*it); + for (auto it = literals.cbegin(); it != literals.cend(); ++it) + op->addImmediateOperand(*it); + module.mapInstruction(op); + constantsTypesGlobals.push_back(std::unique_ptr(op)); + + return op->getResultId(); +} + Id Builder::createFunctionCall(spv::Function* function, std::vector& args) { Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); @@ -1225,6 +1260,9 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, std: if (channels.size() == 1) return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision); + if (generatingOpCodeForSpecConst) { + return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, {source, source}, channels), precision); + } Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); assert(isVector(source)); swizzle->addIdOperand(source); @@ -1290,10 +1328,23 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) if (numComponents == 1) return scalar; - Instruction* smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); - for (int c = 0; c < numComponents; ++c) - smear->addIdOperand(scalar); - buildPoint->addInstruction(std::unique_ptr(smear)); + Instruction* smear = nullptr; + if (generatingOpCodeForSpecConst) { + auto members = std::vector(numComponents, scalar); + // 'scalar' can not be spec constant here. All spec constant involved + // promotion is done in createSpvConstantFromConstUnionArray(). This + // 'if' branch is only accessed when 'scalar' is used in the def-chain + // of other vector type spec constants. In such cases, all the + // instructions needed to promote 'scalar' to a vector type constants + // should be added at module level. + auto result_id = makeCompositeConstant(vectorType, members, false); + smear = module.getInstruction(result_id); + } else { + smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); + for (int c = 0; c < numComponents; ++c) + smear->addIdOperand(scalar); + buildPoint->addInstruction(std::unique_ptr(smear)); + } return setPrecision(smear->getResultId(), precision); } diff --git a/SPIRV/SpvBuilder.h b/SPIRV/SpvBuilder.h index e16ba38c..46bdee84 100755 --- a/SPIRV/SpvBuilder.h +++ b/SPIRV/SpvBuilder.h @@ -262,6 +262,7 @@ public: Id createTriOp(Op, Id typeId, Id operand1, Id operand2, Id operand3); Id createOp(Op, Id typeId, const std::vector& operands); Id createFunctionCall(spv::Function*, std::vector&); + Id createSpecConstantOp(Op, Id typeId, const std::vector& operands, const std::vector& literals); // Take an rvalue (source) and a set of channels to extract from it to // make a new rvalue, which is returned. @@ -521,6 +522,13 @@ public: void createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock); void createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control); + // Sets to generate opcode for specialization constants. + void setToSpecConstCodeGenMode() { generatingOpCodeForSpecConst = true; } + // Sets to generate opcode for non-specialization constants (normal mode). + void setToNormalCodeGenMode() { generatingOpCodeForSpecConst = false; } + // Check if the builder is generating code for spec constants. + bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; } + protected: Id makeIntConstant(Id typeId, unsigned value, bool specConstant); Id findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) const; @@ -544,6 +552,7 @@ public: Block* buildPoint; Id uniqueId; Function* mainFunction; + bool generatingOpCodeForSpecConst; AccessChain accessChain; // special blocks of instructions for output diff --git a/Test/baseResults/spv.specConstantOperations.vert.out b/Test/baseResults/spv.specConstantOperations.vert.out new file mode 100644 index 00000000..476efc90 --- /dev/null +++ b/Test/baseResults/spv.specConstantOperations.vert.out @@ -0,0 +1,116 @@ +spv.specConstantOperations.vert +Warning, version 450 is not yet complete; most version-specific features are present, but some are missing. + + +Linked vertex stage: + + +// Module Version 10000 +// Generated by (magic number): 80001 +// Id's are bound by 94 + + Capability Shader + Capability Float64 + 1: ExtInstImport "GLSL.std.450" + MemoryModel Logical GLSL450 + EntryPoint Vertex 4 "main" + Source GLSL 450 + Name 4 "main" + Decorate 7 SpecId 200 + Decorate 9 SpecId 201 + Decorate 11 SpecId 202 + Decorate 12 SpecId 203 + 2: TypeVoid + 3: TypeFunction 2 + 6: TypeFloat 32 + 7: 6(float) SpecConstant 1078530010 + 8: TypeInt 32 1 + 9: 8(int) SpecConstant 10 + 10: TypeInt 32 0 + 11: 10(int) SpecConstant 100 + 12: 8(int) SpecConstant 4294967286 + 13: TypeFloat 64 + 14: 13(float) SpecConstantOp 115 7 + 15: 6(float) SpecConstantOp 115 14 + 16: 8(int) SpecConstantOp 126 9 + 17: 8(int) SpecConstantOp 200 9 + 18: 8(int) Constant 2 + 19: 8(int) SpecConstantOp 128 9 18 + 20: 8(int) SpecConstantOp 128 9 18 + 21: 8(int) Constant 3 + 22: 8(int) SpecConstantOp 130 20 21 + 23: 8(int) Constant 4 + 24: 8(int) SpecConstantOp 130 19 23 + 25: 8(int) SpecConstantOp 132 12 18 + 26: 10(int) Constant 2 + 27: 10(int) SpecConstantOp 132 11 26 + 28: 8(int) Constant 5 + 29: 8(int) SpecConstantOp 135 25 28 + 30: 10(int) Constant 5 + 31: 10(int) SpecConstantOp 134 27 30 + 32: 8(int) SpecConstantOp 139 12 23 + 33: 10(int) Constant 4 + 34: 10(int) SpecConstantOp 137 11 33 + 35: 8(int) SpecConstantOp 132 12 21 + 36: 8(int) SpecConstantOp 135 35 28 + 37: 8(int) Constant 10 + 38: 8(int) SpecConstantOp 195 12 37 + 39: 8(int) Constant 20 + 40: 10(int) SpecConstantOp 194 11 39 + 41: 8(int) Constant 1 + 42: 8(int) SpecConstantOp 196 12 41 + 43: 10(int) SpecConstantOp 196 11 18 + 44: 8(int) Constant 256 + 45: 8(int) SpecConstantOp 197 12 44 + 46: 10(int) Constant 512 + 47: 10(int) SpecConstantOp 198 11 46 + 48: TypeBool + 49: 48(bool) SpecConstantOp 177 9 12 + 50: 48(bool) SpecConstantOp 170 11 11 + 51: 48(bool) SpecConstantOp 173 9 12 + 52: TypeVector 8(int) 4 + 53: 8(int) Constant 30 + 54: 52(ivec4) SpecConstantComposite 39 53 9 9 + 55: TypeVector 10(int) 4 + 56: 10(int) Constant 4294967295 + 57: 10(int) Constant 4294967294 + 58: 55(ivec4) SpecConstantComposite 11 11 56 57 + 59: TypeVector 6(float) 4 + 60: 6(float) Constant 1067450368 + 61: 59(fvec4) SpecConstantComposite 7 60 7 60 + 62: TypeVector 13(float) 4 + 63: 62(fvec4) SpecConstantOp 115 61 + 64: 59(fvec4) SpecConstantOp 115 63 + 65: 52(ivec4) SpecConstantOp 200 54 + 66: 52(ivec4) SpecConstantOp 126 54 + 67: 52(ivec4) ConstantComposite 18 18 18 18 + 68: 52(ivec4) SpecConstantOp 128 54 67 + 69: 52(ivec4) SpecConstantOp 128 54 67 + 70: 52(ivec4) ConstantComposite 21 21 21 21 + 71: 52(ivec4) SpecConstantOp 130 69 70 + 72: 52(ivec4) ConstantComposite 23 23 23 23 + 73: 52(ivec4) SpecConstantOp 130 71 72 + 74: 52(ivec4) SpecConstantOp 132 54 67 + 75: 52(ivec4) ConstantComposite 28 28 28 28 + 76: 52(ivec4) SpecConstantOp 135 74 75 + 77: 52(ivec4) SpecConstantOp 139 54 72 + 78: 52(ivec4) ConstantComposite 37 37 37 37 + 79: 52(ivec4) SpecConstantOp 195 54 78 + 80: 52(ivec4) SpecConstantOp 196 54 67 + 81: 8(int) Constant 1024 + 82: 52(ivec4) ConstantComposite 81 81 81 81 + 83: 52(ivec4) SpecConstantOp 197 54 82 + 84: 10(int) Constant 2048 + 85: 55(ivec4) ConstantComposite 84 84 84 84 + 86: 55(ivec4) SpecConstantOp 198 58 85 + 87: 10(int) Constant 0 + 88: 8(int) SpecConstantOp 81 54 0 + 89: TypeVector 8(int) 2 + 90: 89(ivec2) SpecConstantOp 79 54 54 1(GLSL.std.450) 0 + 91: TypeVector 8(int) 3 + 92: 91(ivec3) SpecConstantOp 79 54 54 2 1(GLSL.std.450) 0 + 93: 52(ivec4) SpecConstantOp 79 54 54 1(GLSL.std.450) 2 0 3 + 4(main): 2 Function None 3 + 5: Label + Return + FunctionEnd diff --git a/Test/spv.specConstantOperations.vert b/Test/spv.specConstantOperations.vert new file mode 100644 index 00000000..9de96aee --- /dev/null +++ b/Test/spv.specConstantOperations.vert @@ -0,0 +1,90 @@ +#version 450 + +layout(constant_id = 200) const float sp_float = 3.1415926; +layout(constant_id = 201) const int sp_int = 10; +layout(constant_id = 202) const uint sp_uint = 100; +layout(constant_id = 203) const int sp_sint = -10; + + +// +// Scalars +// + +// Size convert +const double float_to_double = double(sp_float); +const float double_to_float = float(float_to_double); + +// Negate and Not +const int negate_int = -sp_int; +const int not_int = ~sp_int; + +// Add and Subtract +const int sp_int_add_two = sp_int + 2; +const int sp_int_add_two_sub_three = sp_int + 2 - 3; +const int sp_int_add_two_sub_four = sp_int_add_two - 4; + +// Mul, Div and Rem +const int sp_sint_mul_two = sp_sint * 2; +const uint sp_uint_mul_two = sp_uint * 2; +const int sp_sint_mul_two_div_five = sp_sint_mul_two / 5; +const uint sp_uint_mul_two_div_five = sp_uint_mul_two / 5; +const int sp_sint_rem_four = sp_sint % 4; +const uint sp_uint_rem_four = sp_uint % 4; +const int sp_sint_mul_three_div_five = sp_sint * 3 / 5; + +// Shift +const int sp_sint_shift_right_arithmetic = sp_sint >> 10; +const uint sp_uint_shift_right_arithmetic = sp_uint >> 20; +const int sp_sint_shift_left = sp_sint << 1; +const uint sp_uint_shift_left = sp_uint << 2; + +// Bitwise And, Or, Xor +const int sp_sint_or_256 = sp_sint | 0x100; +const uint sp_uint_xor_512 = sp_uint ^ 0x200; + +/* // Scalar comparison */ +const bool sp_int_lt_sp_sint = sp_int < sp_sint; +const bool sp_uint_equal_sp_uint = sp_uint == sp_uint; +const bool sp_int_gt_sp_sint = sp_int > sp_sint; + +// +// Vectors +// +const ivec4 iv = ivec4(20, 30, sp_int, sp_int); +const uvec4 uv = uvec4(sp_uint, sp_uint, -1, -2); +const vec4 fv = vec4(sp_float, 1.25, sp_float, 1.25); + +// Size convert +const dvec4 fv_to_dv = dvec4(fv); +const vec4 dv_to_fv = vec4(fv_to_dv); + +// Negate and Not +const ivec4 not_iv = ~iv; +const ivec4 negate_iv = -iv; + +// Add and Subtract +const ivec4 iv_add_two = iv + 2; +const ivec4 iv_add_two_sub_three = iv + 2 - 3; +const ivec4 iv_add_two_sub_four = iv_add_two_sub_three - 4; + +// Mul, Div and Rem +const ivec4 iv_mul_two = iv * 2; +const ivec4 iv_mul_two_div_five = iv_mul_two / 5; +const ivec4 iv_rem_four = iv % 4; + +// Shift +const ivec4 iv_shift_right_arithmetic = iv >> 10; +const ivec4 iv_shift_left = iv << 2; + +// Bitwise And, Or, Xor +const ivec4 iv_or_1024 = iv | 0x400; +const uvec4 uv_xor_2048 = uv ^ 0x800; + +// Swizzles +const int iv_x = iv.x; +const ivec2 iv_yx = iv.yx; +const ivec3 iv_zyx = iv.zyx; +const ivec4 iv_yzxw = iv.yzxw; + +void main() {} + diff --git a/Test/test-spirv-list b/Test/test-spirv-list index 4534132f..b7dfd537 100644 --- a/Test/test-spirv-list +++ b/Test/test-spirv-list @@ -103,6 +103,7 @@ spv.subpass.frag spv.specConstant.vert spv.specConstant.comp spv.specConstantComposite.vert +spv.specConstantOperations.vert # GLSL-level semantics vulkan.frag vulkan.vert