From 42f85b8a5c1ae59f3e97f95485e274d2115d65f2 Mon Sep 17 00:00:00 2001 From: Sasha Szpakowski Date: Wed, 31 Jul 2024 19:42:06 -0300 Subject: [PATCH] update glslang --- src/libraries/glslang/SPIRV/GLSL.ext.EXT.h | 1 + src/libraries/glslang/SPIRV/GLSL.ext.KHR.h | 2 + src/libraries/glslang/SPIRV/GlslangToSpv.cpp | 127 +++++-- src/libraries/glslang/SPIRV/GlslangToSpv.h | 1 + src/libraries/glslang/SPIRV/SpvBuilder.cpp | 325 +++++++++++++++--- src/libraries/glslang/SPIRV/SpvBuilder.h | 36 +- .../glslang/SPIRV/SpvPostProcess.cpp | 67 +++- src/libraries/glslang/SPIRV/SpvTools.cpp | 12 + src/libraries/glslang/SPIRV/SpvTools.h | 5 +- src/libraries/glslang/SPIRV/doc.cpp | 18 + src/libraries/glslang/SPIRV/spirv.hpp | 34 +- src/libraries/glslang/SPIRV/spvIR.h | 16 +- .../glslang/glslang/Include/BaseTypes.h | 2 - .../glslang/glslang/Include/Common.h | 5 + .../glslang/glslang/Include/InfoSink.h | 14 +- .../glslang/MachineIndependent/Constant.cpp | 12 +- .../glslang/MachineIndependent/Initialize.cpp | 21 +- .../MachineIndependent/ParseContextBase.cpp | 2 +- .../MachineIndependent/ParseHelper.cpp | 73 +++- .../glslang/MachineIndependent/PoolAlloc.cpp | 11 +- .../glslang/MachineIndependent/Scan.cpp | 2 +- .../glslang/MachineIndependent/ShaderLang.cpp | 22 +- .../glslang/MachineIndependent/Versions.cpp | 15 +- .../glslang/MachineIndependent/Versions.h | 1 + .../MachineIndependent/linkValidate.cpp | 118 +++++-- .../MachineIndependent/localintermediate.h | 26 +- .../MachineIndependent/preprocessor/Pp.cpp | 2 +- .../preprocessor/PpScanner.cpp | 4 +- .../glslang/glslang/Public/ShaderLang.h | 4 + 29 files changed, 778 insertions(+), 200 deletions(-) diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h b/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h index caab27938..07f3c3026 100644 --- a/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h +++ b/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h @@ -41,5 +41,6 @@ static const char* const E_SPV_EXT_shader_atomic_float_min_max = "SPV_EXT_shader static const char* const E_SPV_EXT_shader_image_int64 = "SPV_EXT_shader_image_int64"; static const char* const E_SPV_EXT_shader_tile_image = "SPV_EXT_shader_tile_image"; static const char* const E_SPV_EXT_mesh_shader = "SPV_EXT_mesh_shader"; +static const char* const E_SPV_ARM_cooperative_matrix_layouts = "SPV_ARM_cooperative_matrix_layouts"; #endif // #ifndef GLSLextEXT_H diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h b/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h index 1d3af1403..38d3b974b 100644 --- a/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h +++ b/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h @@ -61,5 +61,7 @@ static const char* const E_SPV_KHR_cooperative_matrix = "SPV_KHR_coope static const char* const E_SPV_KHR_maximal_reconvergence = "SPV_KHR_maximal_reconvergence"; static const char* const E_SPV_KHR_subgroup_rotate = "SPV_KHR_subgroup_rotate"; static const char* const E_SPV_KHR_expect_assume = "SPV_KHR_expect_assume"; +static const char* const E_SPV_EXT_replicated_composites = "SPV_EXT_replicated_composites"; +static const char* const E_SPV_KHR_relaxed_extended_instruction = "SPV_KHR_relaxed_extended_instruction"; #endif // #ifndef GLSLextKHR_H diff --git a/src/libraries/glslang/SPIRV/GlslangToSpv.cpp b/src/libraries/glslang/SPIRV/GlslangToSpv.cpp index 740a831ed..02ecb6f1f 100755 --- a/src/libraries/glslang/SPIRV/GlslangToSpv.cpp +++ b/src/libraries/glslang/SPIRV/GlslangToSpv.cpp @@ -227,6 +227,7 @@ protected: spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId); spv::Id getSymbolId(const glslang::TIntermSymbol* node); void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier); + bool hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor); void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor); void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather); spv::Id createSpvConstant(const glslang::TIntermTyped&); @@ -283,6 +284,7 @@ protected: spv::Id taskPayloadID; // Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData std::unordered_map locationToSymbol[4]; + std::unordered_map > idToQCOMDecorations; }; // @@ -398,11 +400,11 @@ void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector bool useVulkanMemoryModel) { if (!useVulkanMemoryModel) { - if (qualifier.isCoherent()) - memory.push_back(spv::DecorationCoherent); if (qualifier.isVolatile()) { memory.push_back(spv::DecorationVolatile); memory.push_back(spv::DecorationCoherent); + } else if (qualifier.isCoherent()) { + memory.push_back(spv::DecorationCoherent); } } if (qualifier.isRestrict()) @@ -987,18 +989,6 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInHitTriangleVertexPositionsKHR; case glslang::EbvInstanceCustomIndex: return spv::BuiltInInstanceCustomIndexKHR; - case glslang::EbvHitT: - { - // this is a GLSL alias of RayTmax - // in SPV_NV_ray_tracing it has a dedicated builtin - // but in SPV_KHR_ray_tracing it gets mapped to RayTmax - auto& extensions = glslangIntermediate->getRequestedExtensions(); - if (extensions.find("GL_NV_ray_tracing") != extensions.end()) { - return spv::BuiltInHitTNV; - } else { - return spv::BuiltInRayTmaxKHR; - } - } case glslang::EbvHitKind: return spv::BuiltInHitKindKHR; case glslang::EbvObjectToWorld: @@ -1593,6 +1583,8 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addInclude(iItr->first, iItr->second); } + builder.setUseReplicatedComposites(glslangIntermediate->usingReplicatedComposites()); + stdBuiltins = builder.import("GLSL.std.450"); spv::AddressingModel addressingModel = spv::AddressingModelLogical; @@ -2007,8 +1999,9 @@ void TGlslangToSpvTraverser::finishSpv(bool compileOnly) } // finish off the entry-point SPV instruction by adding the Input/Output - for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it) - entryPoint->addIdOperand(*it); + entryPoint->reserveOperands(iOSet.size()); + for (auto id : iOSet) + entryPoint->addIdOperand(id); } // Add capabilities, extensions, remove unneeded decorations, etc., @@ -3381,6 +3374,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpImageBlockMatchGatherSSDQCOM: case glslang::EOpImageBlockMatchGatherSADQCOM: + builder.addCapability(spv::CapabilityTextureBlockMatchQCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing); builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM); builder.addExtension(spv::E_SPV_QCOM_image_processing2); break; @@ -3710,6 +3705,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf if (node->getOp() == glslang::EOpCooperativeMatrixLoad) { idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout + auto layout = builder.getConstantScalar(operands[3]); + if (layout == spv::CooperativeMatrixLayoutRowBlockedInterleavedARM || + layout == spv::CooperativeMatrixLayoutColumnBlockedInterleavedARM) { + builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts); + builder.addCapability(spv::CapabilityCooperativeMatrixLayoutsARM); + } idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride } else { idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride @@ -3734,6 +3735,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object if (node->getOp() == glslang::EOpCooperativeMatrixStore) { idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout + auto layout = builder.getConstantScalar(operands[3]); + if (layout == spv::CooperativeMatrixLayoutRowBlockedInterleavedARM || + layout == spv::CooperativeMatrixLayoutColumnBlockedInterleavedARM) { + builder.addExtension(spv::E_SPV_ARM_cooperative_matrix_layouts); + builder.addCapability(spv::CapabilityCooperativeMatrixLayoutsARM); + } idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride } else { idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride @@ -5376,17 +5383,37 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType int memberAlignment = glslangIntermediate->getMemberAlignment(memberType, memberSize, dummyStride, explicitLayout, matrixLayout == glslang::ElmRowMajor); + bool isVectorLike = memberType.isVector(); + if (memberType.isMatrix()) { + if (matrixLayout == glslang::ElmRowMajor) + isVectorLike = memberType.getMatrixRows() == 1; + else + isVectorLike = memberType.getMatrixCols() == 1; + } + // Adjust alignment for HLSL rules // TODO: make this consistent in early phases of code: // adjusting this late means inconsistencies with earlier code, which for reflection is an issue // Until reflection is brought in sync with these adjustments, don't apply to $Global, // which is the most likely to rely on reflection, and least likely to rely implicit layouts if (glslangIntermediate->usingHlslOffsets() && - ! memberType.isArray() && memberType.isVector() && structType.getTypeName().compare("$Global") != 0) { - int dummySize; - int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, dummySize); - if (componentAlignment <= 4) + ! memberType.isStruct() && structType.getTypeName().compare("$Global") != 0) { + int componentSize; + int componentAlignment = glslangIntermediate->getBaseAlignmentScalar(memberType, componentSize); + if (! memberType.isArray() && isVectorLike && componentAlignment <= 4) memberAlignment = componentAlignment; + + // Don't add unnecessary padding after this member + // (undo std140 bumping size to a mutliple of vec4) + if (explicitLayout == glslang::ElpStd140) { + if (memberType.isMatrix()) { + if (matrixLayout == glslang::ElmRowMajor) + memberSize -= componentSize * (4 - memberType.getMatrixCols()); + else + memberSize -= componentSize * (4 - memberType.getMatrixRows()); + } else if (memberType.isArray()) + memberSize -= componentSize * (4 - memberType.getVectorSize()); + } } // Bump up to member alignment @@ -5394,7 +5421,7 @@ void TGlslangToSpvTraverser::updateMemberOffset(const glslang::TType& structType // Bump up to vec4 if there is a bad straddle if (explicitLayout != glslang::ElpScalar && glslangIntermediate->improperStraddle(memberType, memberSize, - currentOffset)) + currentOffset, isVectorLike)) glslang::RoundToPow2(currentOffset, 16); nextOffset = currentOffset + memberSize; @@ -5479,8 +5506,10 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF // memory and use RestrictPointer/AliasedPointer. if (originalParam(type.getQualifier().storage, type, false) || !writableParam(type.getQualifier().storage)) { - decorations.push_back(type.getQualifier().isRestrict() ? spv::DecorationRestrict : - spv::DecorationAliased); + // TranslateMemoryDecoration added Restrict decoration already. + if (!type.getQualifier().isRestrict()) { + decorations.push_back(spv::DecorationAliased); + } } else { decorations.push_back(type.getQualifier().isRestrict() ? spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); @@ -5492,12 +5521,16 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate(); if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction) continue; + + builder.setDebugSourceLocation(glslFunction->getLoc().line, glslFunction->getLoc().getFilename()); + if (isShaderEntryPoint(glslFunction)) { + // For HLSL, the entry function is actually a compiler generated function to resolve the difference of + // entry function signature between HLSL and SPIR-V. So we don't emit debug information for that. if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) { - builder.setupDebugFunctionEntry(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(), - glslFunction->getLoc().line, - std::vector(), // main function has no param - std::vector()); + builder.setupFunctionDebugInfo(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(), + std::vector(), // main function has no param + std::vector()); } continue; } @@ -5550,8 +5583,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()), glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes, paramDecorations, &functionBlock); - builder.setupDebugFunctionEntry(function, glslFunction->getName().c_str(), glslFunction->getLoc().line, - paramTypes, paramNames); + builder.setupFunctionDebugInfo(function, glslFunction->getName().c_str(), paramTypes, paramNames); if (implicitThis) function->setImplicitThis(); @@ -5775,8 +5807,16 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& lvalueCoherentFlags = builder.getAccessChain().coherentFlags; builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags)); lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType()); - } else - arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType())); + } else { + if (i > 0 && + glslangArguments[i]->getAsSymbolNode() && glslangArguments[i-1]->getAsSymbolNode() && + glslangArguments[i]->getAsSymbolNode()->getId() == glslangArguments[i-1]->getAsSymbolNode()->getId()) { + // Reuse the id if possible + arguments.push_back(arguments[i-1]); + } else { + arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType())); + } + } } } @@ -6407,6 +6447,9 @@ spv::Id TGlslangToSpvTraverser::handleUserFunctionCall(const glslang::TIntermAgg } } + // Reset source location to the function call location after argument evaluation + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); + // 2. Allocate space for anything needing a copy, and if it's "in" or "inout" // copy the original into that space. // @@ -8055,6 +8098,7 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv } std::vector spvAtomicOperands; // hold the spv operands + spvAtomicOperands.reserve(6); spvAtomicOperands.push_back(pointerId); spvAtomicOperands.push_back(scopeId); spvAtomicOperands.push_back(semanticsId); @@ -9813,6 +9857,16 @@ void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const g } } +bool TGlslangToSpvTraverser::hasQCOMImageProceessingDecoration(spv::Id id, spv::Decoration decor) +{ + std::vector &decoVec = idToQCOMDecorations[id]; + for ( auto d : decoVec ) { + if ( d == decor ) + return true; + } + return false; +} + void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor) { spv::Op opc = builder.getOpCode(id); @@ -9823,7 +9877,10 @@ void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::D if (opc == spv::OpLoad) { spv::Id texid = builder.getIdOperand(id, 0); - builder.addDecoration(texid, decor); + if (!hasQCOMImageProceessingDecoration(texid, decor)) {// + builder.addDecoration(texid, decor); + idToQCOMDecorations[texid].push_back(decor); + } } } @@ -9841,7 +9898,10 @@ void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) { assert(iOSet.count(tsid) > 0); } - this->builder.addDecoration(tsid, decor); + if (!hasQCOMImageProceessingDecoration(tsid, decor)) { + this->builder.addDecoration(tsid, decor); + idToQCOMDecorations[tsid].push_back(decor); + } } }; @@ -10183,6 +10243,7 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan // Operands to accumulate OpPhi operands std::vector phiOperands; + phiOperands.reserve(4); // accumulate left operand's phi information phiOperands.push_back(leftId); phiOperands.push_back(builder.getBuildPoint()->getId()); diff --git a/src/libraries/glslang/SPIRV/GlslangToSpv.h b/src/libraries/glslang/SPIRV/GlslangToSpv.h index 1b9ef3c51..95ea891bf 100644 --- a/src/libraries/glslang/SPIRV/GlslangToSpv.h +++ b/src/libraries/glslang/SPIRV/GlslangToSpv.h @@ -53,6 +53,7 @@ struct SpvOptions { bool emitNonSemanticShaderDebugInfo {false}; bool emitNonSemanticShaderDebugSource{ false }; bool compileOnly{false}; + bool optimizerAllowExpandedIDBound{false}; }; void GetSpirvVersion(std::string&); diff --git a/src/libraries/glslang/SPIRV/SpvBuilder.cpp b/src/libraries/glslang/SPIRV/SpvBuilder.cpp index 062a7c79b..caff5c114 100644 --- a/src/libraries/glslang/SPIRV/SpvBuilder.cpp +++ b/src/libraries/glslang/SPIRV/SpvBuilder.cpp @@ -157,6 +157,7 @@ Id Builder::makePointer(StorageClass storageClass, Id pointee) // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypePointer); + type->reserveOperands(2); type->addImmediateOperand(storageClass); type->addIdOperand(pointee); groupedTypes[OpTypePointer].push_back(type); @@ -181,6 +182,10 @@ Id Builder::makeForwardPointer(StorageClass storageClass) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) { + const Id debugResultId = makeForwardPointerDebugType(storageClass); + debugId[type->getResultId()] = debugResultId; + } return type->getResultId(); } @@ -196,12 +201,22 @@ Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardP } type = new Instruction(forwardPointerType, NoType, OpTypePointer); + type->reserveOperands(2); type->addImmediateOperand(storageClass); type->addIdOperand(pointee); groupedTypes[OpTypePointer].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + // If we are emitting nonsemantic debuginfo, we need to patch the debug pointer type + // that was emitted alongside the forward pointer, now that we have a pointee debug + // type for it to point to. + if (emitNonSemanticShaderDebugInfo) { + Instruction *debugForwardPointer = module.getInstruction(debugId[forwardPointerType]); + assert(debugId[pointee]); + debugForwardPointer->setIdOperand(2, debugId[pointee]); + } + return type->getResultId(); } @@ -218,6 +233,7 @@ Id Builder::makeIntegerType(int width, bool hasSign) // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeInt); + type->reserveOperands(2); type->addImmediateOperand(width); type->addImmediateOperand(hasSign ? 1 : 0); groupedTypes[OpTypeInt].push_back(type); @@ -348,6 +364,7 @@ Id Builder::makeVectorType(Id component, int size) // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeVector); + type->reserveOperands(2); type->addIdOperand(component); type->addImmediateOperand(size); groupedTypes[OpTypeVector].push_back(type); @@ -380,6 +397,7 @@ Id Builder::makeMatrixType(Id component, int cols, int rows) // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeMatrix); + type->reserveOperands(2); type->addIdOperand(column); type->addImmediateOperand(cols); groupedTypes[OpTypeMatrix].push_back(type); @@ -411,6 +429,7 @@ Id Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id col // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixKHR); + type->reserveOperands(5); type->addIdOperand(component); type->addIdOperand(scope); type->addIdOperand(rows); @@ -436,6 +455,7 @@ Id Builder::makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixNV); + type->reserveOperands(4); type->addIdOperand(component); type->addIdOperand(scope); type->addIdOperand(rows); @@ -477,6 +497,7 @@ Id Builder::makeGenericType(spv::Op opcode, std::vector& opera // not found, make it type = new Instruction(getUniqueId(), NoType, opcode); + type->reserveOperands(operands.size()); for (size_t op = 0; op < operands.size(); ++op) { if (operands[op].isId) type->addIdOperand(operands[op].word); @@ -509,6 +530,7 @@ Id Builder::makeArrayType(Id element, Id sizeId, int stride) // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeArray); + type->reserveOperands(2); type->addIdOperand(element); type->addIdOperand(sizeId); groupedTypes[OpTypeArray].push_back(type); @@ -575,6 +597,7 @@ Id Builder::makeFunctionType(Id returnType, const std::vector& paramTypes) // not found, make it Id typeId = getUniqueId(); type = new Instruction(typeId, NoType, OpTypeFunction); + type->reserveOperands(paramTypes.size() + 1); type->addIdOperand(returnType); for (int p = 0; p < (int)paramTypes.size(); ++p) type->addIdOperand(paramTypes[p]); @@ -597,6 +620,7 @@ Id Builder::makeDebugFunctionType(Id returnType, const std::vector& paramTyp Id typeId = getUniqueId(); auto type = new Instruction(typeId, makeVoidType(), OpExtInst); + type->reserveOperands(paramTypes.size() + 4); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction); type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); @@ -635,6 +659,7 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo // not found, make it type = new Instruction(getUniqueId(), NoType, OpTypeImage); + type->reserveOperands(7); type->addIdOperand(sampledType); type->addImmediateOperand( dim); type->addImmediateOperand( depth ? 1 : 0); @@ -745,6 +770,7 @@ Id Builder::makeDebugInfoNone() return debugInfoNone; Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(2); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone); @@ -769,6 +795,7 @@ Id Builder::makeBoolDebugType(int const size) } type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(6); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); @@ -806,6 +833,7 @@ Id Builder::makeIntegerDebugType(int const width, bool const hasSign) // not found, make it type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(6); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); type->addIdOperand(nameId); // name id @@ -845,6 +873,7 @@ Id Builder::makeFloatDebugType(int const width) // not found, make it type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(6); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); type->addIdOperand(nameId); // name id @@ -875,6 +904,7 @@ Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, // not found, make it type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(4); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(sequenceType); type->addIdOperand(debugId[baseType]); // base type @@ -910,6 +940,7 @@ Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool // not found, make it type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(5); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix); type->addIdOperand(debugId[vectorType]); // vector type id @@ -928,6 +959,7 @@ Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTy assert(debugId[memberType] != 0); Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(10); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember); type->addIdOperand(getStringId(debugTypeLoc.name)); // name id @@ -967,6 +999,7 @@ Id Builder::makeCompositeDebugType(std::vector const& memberTypes, char cons // Create The structure debug type. Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(memberDebugTypes.size() + 11); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite); type->addIdOperand(getStringId(name)); // name id @@ -1011,6 +1044,7 @@ Id Builder::makePointerDebugType(StorageClass storageClass, Id const baseType) } Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->reserveOperands(5); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypePointer); type->addIdOperand(debugBaseType); @@ -1024,11 +1058,35 @@ Id Builder::makePointerDebugType(StorageClass storageClass, Id const baseType) return type->getResultId(); } +// Emit a OpExtInstWithForwardRefsKHR nonsemantic instruction for a pointer debug type +// where we don't have the pointee yet. Since we don't have the pointee yet, it just +// points to itself and we rely on patching it later. +Id Builder::makeForwardPointerDebugType(StorageClass storageClass) +{ + const Id scID = makeUintConstant(storageClass); + + this->addExtension(spv::E_SPV_KHR_relaxed_extended_instruction); + + Instruction *type = new Instruction(getUniqueId(), makeVoidType(), OpExtInstWithForwardRefsKHR); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypePointer); + type->addIdOperand(type->getResultId()); + type->addIdOperand(scID); + type->addIdOperand(makeUintConstant(0)); + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypePointer].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + Id Builder::makeDebugSource(const Id fileName) { if (debugSourceId.find(fileName) != debugSourceId.end()) return debugSourceId[fileName]; spv::Id resultId = getUniqueId(); Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst); + sourceInst->reserveOperands(3); sourceInst->addIdOperand(nonSemanticShaderDebugInfo); sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource); sourceInst->addIdOperand(fileName); @@ -1059,6 +1117,7 @@ Id Builder::makeDebugCompilationUnit() { return nonSemanticShaderCompilationUnitId; spv::Id resultId = getUniqueId(); Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst); + sourceInst->reserveOperands(6); sourceInst->addIdOperand(nonSemanticShaderDebugInfo); sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit); sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number @@ -1082,6 +1141,7 @@ Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id c assert(type != 0); Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(11); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable); inst->addIdOperand(getStringId(name)); // name id @@ -1106,6 +1166,7 @@ Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t cons assert(!currentDebugScopeId.empty()); Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(9); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable); inst->addIdOperand(getStringId(name)); // name id @@ -1131,6 +1192,7 @@ Id Builder::makeDebugExpression() return debugExpression; Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(2); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression); @@ -1145,6 +1207,7 @@ Id Builder::makeDebugExpression() Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const pointer) { Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(5); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare); inst->addIdOperand(debugLocalVariable); // debug local variable id @@ -1158,6 +1221,7 @@ Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const pointer) Id Builder::makeDebugValue(Id const debugLocalVariable, Id const value) { Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->reserveOperands(5); inst->addIdOperand(nonSemanticShaderDebugInfo); inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugValue); inst->addIdOperand(debugLocalVariable); // debug local variable id @@ -1248,7 +1312,7 @@ Op Builder::getMostBasicTypeClass(Id typeId) const } } -int Builder::getNumTypeConstituents(Id typeId) const +unsigned int Builder::getNumTypeConstituents(Id typeId) const { Instruction* instr = module.getInstruction(typeId); @@ -1456,12 +1520,14 @@ bool Builder::isConstantOpCode(Op opcode) const case OpConstantFalse: case OpConstant: case OpConstantComposite: + case OpConstantCompositeReplicateEXT: case OpConstantSampler: case OpConstantNull: case OpSpecConstantTrue: case OpSpecConstantFalse: case OpSpecConstant: case OpSpecConstantComposite: + case OpSpecConstantCompositeReplicateEXT: case OpSpecConstantOp: return true; default: @@ -1478,6 +1544,7 @@ bool Builder::isSpecConstantOpCode(Op opcode) const case OpSpecConstant: case OpSpecConstantComposite: case OpSpecConstantOp: + case OpSpecConstantCompositeReplicateEXT: return true; default: return false; @@ -1574,6 +1641,7 @@ Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specCons } Instruction* c = new Instruction(getUniqueId(), typeId, opcode); + c->reserveOperands(2); c->addImmediateOperand(op1); c->addImmediateOperand(op2); constantsTypesGlobals.push_back(std::unique_ptr(c)); @@ -1627,6 +1695,7 @@ Id Builder::makeDoubleConstant(double d, bool specConstant) } Instruction* c = new Instruction(getUniqueId(), typeId, opcode); + c->reserveOperands(2); c->addImmediateOperand(op1); c->addImmediateOperand(op2); constantsTypesGlobals.push_back(std::unique_ptr(c)); @@ -1752,10 +1821,27 @@ Id Builder::findStructConstant(Id typeId, const std::vector& comps) // Comments in header Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, bool specConstant) { - Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite; assert(typeId); Op typeClass = getTypeClass(typeId); + bool replicate = false; + size_t numMembers = members.size(); + if (useReplicatedComposites) { + // use replicate if all members are the same + replicate = numMembers > 0 && + std::equal(members.begin() + 1, members.end(), members.begin()); + + if (replicate) { + numMembers = 1; + addCapability(spv::CapabilityReplicatedCompositesEXT); + addExtension(spv::E_SPV_EXT_replicated_composites); + } + } + + Op opcode = replicate ? + (specConstant ? OpSpecConstantCompositeReplicateEXT : OpConstantCompositeReplicateEXT) : + (specConstant ? OpSpecConstantComposite : OpConstantComposite); + switch (typeClass) { case OpTypeVector: case OpTypeArray: @@ -1781,7 +1867,8 @@ Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, boo } Instruction* c = new Instruction(getUniqueId(), typeId, opcode); - for (int op = 0; op < (int)members.size(); ++op) + c->reserveOperands(members.size()); + for (size_t op = 0; op < numMembers; ++op) c->addIdOperand(members[op]); constantsTypesGlobals.push_back(std::unique_ptr(c)); if (typeClass == OpTypeStruct) @@ -1796,6 +1883,7 @@ Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, boo Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name) { Instruction* entryPoint = new Instruction(OpEntryPoint); + entryPoint->reserveOperands(3); entryPoint->addImmediateOperand(model); entryPoint->addIdOperand(function->getId()); entryPoint->addStringOperand(name); @@ -1813,6 +1901,7 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int val return; Instruction* instr = new Instruction(OpExecutionMode); + instr->reserveOperands(3); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); if (value1 >= 0) @@ -1832,6 +1921,7 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const s return; Instruction* instr = new Instruction(OpExecutionMode); + instr->reserveOperands(literals.size() + 2); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); for (auto literal : literals) @@ -1847,6 +1937,7 @@ void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const return; Instruction* instr = new Instruction(OpExecutionModeId); + instr->reserveOperands(operandIds.size() + 2); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); for (auto operandId : operandIds) @@ -1858,6 +1949,7 @@ void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const void Builder::addName(Id id, const char* string) { Instruction* name = new Instruction(OpName); + name->reserveOperands(2); name->addIdOperand(id); name->addStringOperand(string); @@ -1867,6 +1959,7 @@ void Builder::addName(Id id, const char* string) void Builder::addMemberName(Id id, int memberNumber, const char* string) { Instruction* name = new Instruction(OpMemberName); + name->reserveOperands(3); name->addIdOperand(id); name->addImmediateOperand(memberNumber); name->addStringOperand(string); @@ -1880,12 +1973,13 @@ void Builder::addDecoration(Id id, Decoration decoration, int num) return; Instruction* dec = new Instruction(OpDecorate); + dec->reserveOperands(2); dec->addIdOperand(id); dec->addImmediateOperand(decoration); if (num >= 0) dec->addImmediateOperand(num); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addDecoration(Id id, Decoration decoration, const char* s) @@ -1894,11 +1988,12 @@ void Builder::addDecoration(Id id, Decoration decoration, const char* s) return; Instruction* dec = new Instruction(OpDecorateString); + dec->reserveOperands(3); dec->addIdOperand(id); dec->addImmediateOperand(decoration); dec->addStringOperand(s); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addDecoration(Id id, Decoration decoration, const std::vector& literals) @@ -1907,12 +2002,13 @@ void Builder::addDecoration(Id id, Decoration decoration, const std::vectorreserveOperands(literals.size() + 2); dec->addIdOperand(id); dec->addImmediateOperand(decoration); for (auto literal : literals) dec->addImmediateOperand(literal); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addDecoration(Id id, Decoration decoration, const std::vector& strings) @@ -1921,22 +2017,24 @@ void Builder::addDecoration(Id id, Decoration decoration, const std::vectorreserveOperands(strings.size() + 2); dec->addIdOperand(id); dec->addImmediateOperand(decoration); for (auto string : strings) dec->addStringOperand(string); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType) { Instruction* dec = new Instruction(OpDecorate); + dec->reserveOperands(4); dec->addIdOperand(id); dec->addImmediateOperand(spv::DecorationLinkageAttributes); dec->addStringOperand(name); dec->addImmediateOperand(linkType); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) @@ -1945,11 +2043,12 @@ void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) return; Instruction* dec = new Instruction(OpDecorateId); + dec->reserveOperands(3); dec->addIdOperand(id); dec->addImmediateOperand(decoration); dec->addIdOperand(idDecoration); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addDecorationId(Id id, Decoration decoration, const std::vector& operandIds) @@ -1958,13 +2057,14 @@ void Builder::addDecorationId(Id id, Decoration decoration, const std::vectorreserveOperands(operandIds.size() + 2); dec->addIdOperand(id); dec->addImmediateOperand(decoration); for (auto operandId : operandIds) dec->addIdOperand(operandId); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num) @@ -1973,13 +2073,14 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat return; Instruction* dec = new Instruction(OpMemberDecorate); + dec->reserveOperands(3); dec->addIdOperand(id); dec->addImmediateOperand(member); dec->addImmediateOperand(decoration); if (num >= 0) dec->addImmediateOperand(num); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s) @@ -1988,12 +2089,13 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat return; Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE); + dec->reserveOperands(4); dec->addIdOperand(id); dec->addImmediateOperand(member); dec->addImmediateOperand(decoration); dec->addStringOperand(s); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector& literals) @@ -2002,13 +2104,14 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat return; Instruction* dec = new Instruction(OpMemberDecorate); + dec->reserveOperands(literals.size() + 3); dec->addIdOperand(id); dec->addImmediateOperand(member); dec->addImmediateOperand(decoration); for (auto literal : literals) dec->addImmediateOperand(literal); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector& strings) @@ -2017,20 +2120,28 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat return; Instruction* dec = new Instruction(OpMemberDecorateString); + dec->reserveOperands(strings.size() + 3); dec->addIdOperand(id); dec->addImmediateOperand(member); dec->addImmediateOperand(decoration); for (auto string : strings) dec->addStringOperand(string); - decorations.push_back(std::unique_ptr(dec)); + decorations.insert(std::unique_ptr(dec)); } void Builder::addInstruction(std::unique_ptr inst) { + // Phis must appear first in their block, don't insert line tracking instructions + // in front of them, just add the OpPhi and return. + if (inst->getOpCode() == OpPhi) { + buildPoint->addInstruction(std::move(inst)); + return; + } // Optionally insert OpDebugScope if (emitNonSemanticShaderDebugInfo && dirtyScopeTracker) { if (buildPoint->updateDebugScope(currentDebugScopeId.top())) { auto scopeInst = std::make_unique(getUniqueId(), makeVoidType(), OpExtInst); + scopeInst->reserveOperands(3); scopeInst->addIdOperand(nonSemanticShaderDebugInfo); scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope); scopeInst->addIdOperand(currentDebugScopeId.top()); @@ -2045,6 +2156,7 @@ void Builder::addInstruction(std::unique_ptr inst) { if (buildPoint->updateDebugSourceLocation(currentLine, 0, currentFileId)) { if (emitSpirvDebugInfo) { auto lineInst = std::make_unique(OpLine); + lineInst->reserveOperands(3); lineInst->addIdOperand(currentFileId); lineInst->addImmediateOperand(currentLine); lineInst->addImmediateOperand(0); @@ -2052,6 +2164,7 @@ void Builder::addInstruction(std::unique_ptr inst) { } if (emitNonSemanticShaderDebugInfo) { auto lineInst = std::make_unique(getUniqueId(), makeVoidType(), OpExtInst); + lineInst->reserveOperands(7); lineInst->addIdOperand(nonSemanticShaderDebugInfo); lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine); lineInst->addIdOperand(makeDebugSource(currentFileId)); @@ -2129,14 +2242,13 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const return function; } -void Builder::setupDebugFunctionEntry(Function* function, const char* name, int line, const std::vector& paramTypes, - const std::vector& paramNames) +void Builder::setupFunctionDebugInfo(Function* function, const char* name, const std::vector& paramTypes, + const std::vector& paramNames) { if (!emitNonSemanticShaderDebugInfo) return; - currentLine = line; Id nameId = getStringId(unmangleFunctionName(name)); Id funcTypeId = function->getFuncTypeId(); assert(debugId[funcTypeId] != 0); @@ -2191,6 +2303,7 @@ Id Builder::makeDebugFunction([[maybe_unused]] Function* function, Id nameId, Id Id funcId = getUniqueId(); auto type = new Instruction(funcId, makeVoidType(), OpExtInst); + type->reserveOperands(11); type->addIdOperand(nonSemanticShaderDebugInfo); type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction); type->addIdOperand(nameId); @@ -2212,6 +2325,7 @@ Id Builder::makeDebugLexicalBlock(uint32_t line) { Id lexId = getUniqueId(); auto lex = new Instruction(lexId, makeVoidType(), OpExtInst); + lex->reserveOperands(6); lex->addIdOperand(nonSemanticShaderDebugInfo); lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock); lex->addIdOperand(makeDebugSource(currentFileId)); @@ -2282,6 +2396,7 @@ void Builder::enterFunction(Function const* function) // Create DebugFunctionDefinition spv::Id resultId = getUniqueId(); Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst); + defInst->reserveOperands(4); defInst->addIdOperand(nonSemanticShaderDebugInfo); defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition); defInst->addIdOperand(debugId[funcId]); @@ -2413,6 +2528,7 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce unsigned int alignment) { Instruction* store = new Instruction(OpStore); + store->reserveOperands(2); store->addIdOperand(lValue); store->addIdOperand(rValue); @@ -2465,6 +2581,7 @@ Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vec // Make the instruction Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain); + chain->reserveOperands(offsets.size() + 1); chain->addIdOperand(base); for (int i = 0; i < (int)offsets.size(); ++i) chain->addIdOperand(offsets[i]); @@ -2477,6 +2594,7 @@ Id Builder::createArrayLength(Id base, unsigned int member) { spv::Id intType = makeUintType(32); Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength); + length->reserveOperands(2); length->addIdOperand(base); length->addImmediateOperand(member); addInstruction(std::unique_ptr(length)); @@ -2527,6 +2645,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) std::vector(1, index)); } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); + extract->reserveOperands(2); extract->addIdOperand(composite); extract->addImmediateOperand(index); addInstruction(std::unique_ptr(extract)); @@ -2542,6 +2661,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector(1, composite), indexes); } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); + extract->reserveOperands(indexes.size() + 1); extract->addIdOperand(composite); for (int i = 0; i < (int)indexes.size(); ++i) extract->addImmediateOperand(indexes[i]); @@ -2553,6 +2673,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vectorreserveOperands(3); insert->addIdOperand(object); insert->addIdOperand(composite); insert->addImmediateOperand(index); @@ -2564,6 +2685,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned i Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector& indexes) { Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); + insert->reserveOperands(indexes.size() + 2); insert->addIdOperand(object); insert->addIdOperand(composite); for (int i = 0; i < (int)indexes.size(); ++i) @@ -2576,6 +2698,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std: Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex) { Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic); + extract->reserveOperands(2); extract->addIdOperand(vector); extract->addIdOperand(componentIndex); addInstruction(std::unique_ptr(extract)); @@ -2586,6 +2709,7 @@ Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex) Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex) { Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic); + insert->reserveOperands(3); insert->addIdOperand(vector); insert->addIdOperand(component); insert->addIdOperand(componentIndex); @@ -2613,8 +2737,9 @@ void Builder::createNoResultOp(Op opCode, Id operand) void Builder::createNoResultOp(Op opCode, const std::vector& operands) { Instruction* op = new Instruction(opCode); - for (auto it = operands.cbegin(); it != operands.cend(); ++it) { - op->addIdOperand(*it); + op->reserveOperands(operands.size()); + for (auto id : operands) { + op->addIdOperand(id); } addInstruction(std::unique_ptr(op)); } @@ -2623,6 +2748,7 @@ void Builder::createNoResultOp(Op opCode, const std::vector& operands) void Builder::createNoResultOp(Op opCode, const std::vector& operands) { Instruction* op = new Instruction(opCode); + op->reserveOperands(operands.size()); for (auto it = operands.cbegin(); it != operands.cend(); ++it) { if (it->isId) op->addIdOperand(it->word); @@ -2635,6 +2761,7 @@ void Builder::createNoResultOp(Op opCode, const std::vector& operan void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics) { Instruction* op = new Instruction(OpControlBarrier); + op->reserveOperands(3); op->addIdOperand(makeUintConstant(execution)); op->addIdOperand(makeUintConstant(memory)); op->addIdOperand(makeUintConstant(semantics)); @@ -2644,6 +2771,7 @@ void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemantic void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics) { Instruction* op = new Instruction(OpMemoryBarrier); + op->reserveOperands(2); op->addIdOperand(makeUintConstant(executionScope)); op->addIdOperand(makeUintConstant(memorySemantics)); addInstruction(std::unique_ptr(op)); @@ -2674,6 +2802,7 @@ Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right) return createSpecConstantOp(opCode, typeId, operands, std::vector()); } Instruction* op = new Instruction(getUniqueId(), typeId, opCode); + op->reserveOperands(2); op->addIdOperand(left); op->addIdOperand(right); addInstruction(std::unique_ptr(op)); @@ -2694,6 +2823,7 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) opCode, typeId, operands, std::vector()); } Instruction* op = new Instruction(getUniqueId(), typeId, opCode); + op->reserveOperands(3); op->addIdOperand(op1); op->addIdOperand(op2); op->addIdOperand(op3); @@ -2705,8 +2835,9 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) { Instruction* op = new Instruction(getUniqueId(), typeId, opCode); - for (auto it = operands.cbegin(); it != operands.cend(); ++it) - op->addIdOperand(*it); + op->reserveOperands(operands.size()); + for (auto id : operands) + op->addIdOperand(id); addInstruction(std::unique_ptr(op)); return op->getResultId(); @@ -2715,6 +2846,7 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) { Instruction* op = new Instruction(getUniqueId(), typeId, opCode); + op->reserveOperands(operands.size()); for (auto it = operands.cbegin(); it != operands.cend(); ++it) { if (it->isId) op->addIdOperand(it->word); @@ -2730,6 +2862,7 @@ Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& op const std::vector& literals) { Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); + op->reserveOperands(operands.size() + literals.size() + 1); op->addImmediateOperand((unsigned) opCode); for (auto it = operands.cbegin(); it != operands.cend(); ++it) op->addIdOperand(*it); @@ -2752,6 +2885,7 @@ Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& op Id Builder::createFunctionCall(spv::Function* function, const std::vector& args) { Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); + op->reserveOperands(args.size() + 1); op->addIdOperand(function->getId()); for (int a = 0; a < (int)args.size(); ++a) op->addIdOperand(args[a]); @@ -2773,6 +2907,7 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, cons } Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); assert(isVector(source)); + swizzle->reserveOperands(channels.size() + 2); swizzle->addIdOperand(source); swizzle->addIdOperand(source); for (int i = 0; i < (int)channels.size(); ++i) @@ -2791,9 +2926,10 @@ Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vect Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); assert(isVector(target)); + swizzle->reserveOperands(2); swizzle->addIdOperand(target); - assert(getNumComponents(source) == (int)channels.size()); + assert(getNumComponents(source) == channels.size()); assert(isVector(source)); swizzle->addIdOperand(source); @@ -2808,6 +2944,7 @@ Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vect components[channels[i]] = numTargetComponents + i; // finish the instruction with these components selectors + swizzle->reserveOperands(numTargetComponents); for (int i = 0; i < numTargetComponents; ++i) swizzle->addImmediateOperand(components[i]); addInstruction(std::unique_ptr(swizzle)); @@ -2852,7 +2989,18 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar)); smear = module.getInstruction(result_id); } else { - smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); + bool replicate = useReplicatedComposites && (numComponents > 0); + + if (replicate) { + numComponents = 1; + addCapability(spv::CapabilityReplicatedCompositesEXT); + addExtension(spv::E_SPV_EXT_replicated_composites); + } + + Op opcode = replicate ? OpCompositeConstructReplicateEXT : OpCompositeConstruct; + + smear = new Instruction(getUniqueId(), vectorType, opcode); + smear->reserveOperands(numComponents); for (int c = 0; c < numComponents; ++c) smear->addIdOperand(scalar); addInstruction(std::unique_ptr(smear)); @@ -2865,6 +3013,7 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector& args) { Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst); + inst->reserveOperands(args.size() + 2); inst->addIdOperand(builtins); inst->addImmediateOperand(entryPoint); for (int arg = 0; arg < (int)args.size(); ++arg) @@ -3059,6 +3208,7 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, // Build the SPIR-V instruction Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode); + textureInst->reserveOperands(optArgNum + (texArgs.size() - (optArgNum + 1))); for (size_t op = 0; op < optArgNum; ++op) textureInst->addIdOperand(texArgs[op]); if (optArgNum < texArgs.size()) @@ -3226,7 +3376,7 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b Id Builder::createCompositeConstruct(Id typeId, const std::vector& constituents) { assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && - getNumTypeConstituents(typeId) == (int)constituents.size())); + getNumTypeConstituents(typeId) == constituents.size())); if (generatingOpCodeForSpecConst) { // Sometime, even in spec-constant-op mode, the constant composite to be @@ -3242,8 +3392,25 @@ Id Builder::createCompositeConstruct(Id typeId, const std::vector& constitue [&](spv::Id id) { return isSpecConstant(id); })); } - Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct); - for (int c = 0; c < (int)constituents.size(); ++c) + bool replicate = false; + size_t numConstituents = constituents.size(); + + if (useReplicatedComposites) { + replicate = numConstituents > 0 && + std::equal(constituents.begin() + 1, constituents.end(), constituents.begin()); + } + + if (replicate) { + numConstituents = 1; + addCapability(spv::CapabilityReplicatedCompositesEXT); + addExtension(spv::E_SPV_EXT_replicated_composites); + } + + Op opcode = replicate ? OpCompositeConstructReplicateEXT : OpCompositeConstruct; + + Instruction* op = new Instruction(getUniqueId(), typeId, opcode); + op->reserveOperands(constituents.size()); + for (size_t c = 0; c < numConstituents; ++c) op->addIdOperand(constituents[c]); addInstruction(std::unique_ptr(op)); @@ -3262,6 +3429,12 @@ Id Builder::createConstructor(Decoration precision, const std::vector& sourc if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1) return smearScalar(precision, sources[0], resultTypeId); + // Special case: 2 vectors of equal size + if (sources.size() == 1 && isVector(sources[0]) && numTargetComponents == getNumComponents(sources[0])) { + assert(resultTypeId == getTypeId(sources[0])); + return sources[0]; + } + // accumulate the arguments for OpCompositeConstruct std::vector constituents; Id scalarTypeId = getScalarTypeId(resultTypeId); @@ -3296,8 +3469,8 @@ Id Builder::createConstructor(Decoration precision, const std::vector& sourc if (sourcesToUse + targetComponent > numTargetComponents) sourcesToUse = numTargetComponents - targetComponent; - int col = 0; - int row = 0; + unsigned int col = 0; + unsigned int row = 0; for (unsigned int s = 0; s < sourcesToUse; ++s) { if (row >= getNumRows(sourceArg)) { row = 0; @@ -3329,18 +3502,21 @@ Id Builder::createConstructor(Decoration precision, const std::vector& sourc } // If the result is a vector, make it from the gathered constituents. - if (constituents.size() > 0) + if (constituents.size() > 0) { result = createCompositeConstruct(resultTypeId, constituents); - - return setPrecision(result, precision); + return setPrecision(result, precision); + } else { + // Precision was set when generating this component. + return result; + } } // Comments in header Id Builder::createMatrixConstructor(Decoration precision, const std::vector& sources, Id resultTypeId) { Id componentTypeId = getScalarTypeId(resultTypeId); - int numCols = getTypeNumColumns(resultTypeId); - int numRows = getTypeNumRows(resultTypeId); + unsigned int numCols = getTypeNumColumns(resultTypeId); + unsigned int numRows = getTypeNumRows(resultTypeId); Instruction* instr = module.getInstruction(componentTypeId); const unsigned bitCount = instr->getImmediateOperand(0); @@ -3355,11 +3531,11 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix)); std::vector channels; - for (int row = 0; row < numRows; ++row) + for (unsigned int row = 0; row < numRows; ++row) channels.push_back(row); std::vector matrixColumns; - for (int col = 0; col < numCols; ++col) { + for (unsigned int col = 0; col < numCols; ++col) { std::vector indexes; indexes.push_back(col); Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes); @@ -3375,6 +3551,13 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision); } + // Detect a matrix being constructed from a repeated vector of the correct size. + // Create the composite directly from it. + if (sources.size() == numCols && isVector(sources[0]) && getNumComponents(sources[0]) == numRows && + std::equal(sources.begin() + 1, sources.end(), sources.begin())) { + return setPrecision(createCompositeConstruct(resultTypeId, sources), precision); + } + // Otherwise, will use a two step process // 1. make a compile-time 2D array of values // 2. construct a matrix from that array @@ -3402,12 +3585,12 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& } else if (isMatrix(sources[0])) { // constructing from another matrix; copy over the parts that exist in both the argument and constructee Id matrix = sources[0]; - int minCols = std::min(numCols, getNumColumns(matrix)); - int minRows = std::min(numRows, getNumRows(matrix)); - for (int col = 0; col < minCols; ++col) { + unsigned int minCols = std::min(numCols, getNumColumns(matrix)); + unsigned int minRows = std::min(numRows, getNumRows(matrix)); + for (unsigned int col = 0; col < minCols; ++col) { std::vector indexes; indexes.push_back(col); - for (int row = 0; row < minRows; ++row) { + for (unsigned int row = 0; row < minRows; ++row) { indexes.push_back(row); ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes); indexes.pop_back(); @@ -3416,12 +3599,12 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& } } else { // fill in the matrix in column-major order with whatever argument components are available - int row = 0; - int col = 0; + unsigned int row = 0; + unsigned int col = 0; - for (int arg = 0; arg < (int)sources.size() && col < numCols; ++arg) { + for (unsigned int arg = 0; arg < sources.size() && col < numCols; ++arg) { Id argComp = sources[arg]; - for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) { + for (unsigned int comp = 0; comp < getNumComponents(sources[arg]); ++comp) { if (getNumComponents(sources[arg]) > 1) { argComp = createCompositeExtract(sources[arg], componentTypeId, comp); setPrecision(argComp, precision); @@ -3445,9 +3628,9 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& // make the column vectors Id columnTypeId = getContainedTypeId(resultTypeId); std::vector matrixColumns; - for (int col = 0; col < numCols; ++col) { + for (unsigned int col = 0; col < numCols; ++col) { std::vector vectorComponents; - for (int row = 0; row < numRows; ++row) + for (unsigned int row = 0; row < numRows; ++row) vectorComponents.push_back(ids[col][row]); Id column = createCompositeConstruct(columnTypeId, vectorComponents); setPrecision(column, precision); @@ -3532,6 +3715,7 @@ void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, con // make the switch instruction Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch); + switchInst->reserveOperands((caseValues.size() * 2) + 2); switchInst->addIdOperand(selector); auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock; switchInst->addIdOperand(defaultOrMerge->getId()); @@ -3673,7 +3857,7 @@ void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAcce // If a swizzle exists and is not full and is not dynamic, then the swizzle will be broken into individual stores. if (accessChain.swizzle.size() > 0 && - getNumTypeComponents(getResultingAccessChainType()) != (int)accessChain.swizzle.size() && + getNumTypeComponents(getResultingAccessChainType()) != accessChain.swizzle.size() && accessChain.component == NoResult) { for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i])); @@ -3993,7 +4177,7 @@ void Builder::simplifyAccessChainSwizzle() { // If the swizzle has fewer components than the vector, it is subsetting, and must stay // to preserve that fact. - if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size()) + if (getNumTypeComponents(accessChain.preSwizzleBaseType) > accessChain.swizzle.size()) return; // if components are out of order, it is a swizzle @@ -4067,6 +4251,7 @@ void Builder::createBranch(Block* block) void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control) { Instruction* merge = new Instruction(OpSelectionMerge); + merge->reserveOperands(2); merge->addIdOperand(mergeBlock->getId()); merge->addImmediateOperand(control); addInstruction(std::unique_ptr(merge)); @@ -4076,6 +4261,7 @@ void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned const std::vector& operands) { Instruction* merge = new Instruction(OpLoopMerge); + merge->reserveOperands(operands.size() + 3); merge->addIdOperand(mergeBlock->getId()); merge->addIdOperand(continueBlock->getId()); merge->addImmediateOperand(control); @@ -4087,6 +4273,7 @@ void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock) { Instruction* branch = new Instruction(OpBranchConditional); + branch->reserveOperands(3); branch->addIdOperand(condition); branch->addIdOperand(thenBlock->getId()); branch->addIdOperand(elseBlock->getId()); @@ -4108,6 +4295,7 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te if (sourceLang != SourceLanguageUnknown) { // OpSource Language Version File Source Instruction sourceInst(NoResult, NoType, OpSource); + sourceInst.reserveOperands(3); sourceInst.addImmediateOperand(sourceLang); sourceInst.addImmediateOperand(sourceVersion); // File operand @@ -4147,11 +4335,10 @@ void Builder::dumpSourceInstructions(std::vector& out) const dumpSourceInstructions(iItr->first, *iItr->second, out); } -void Builder::dumpInstructions(std::vector& out, - const std::vector >& instructions) const +template void Builder::dumpInstructions(std::vector& out, const Range& instructions) const { - for (int i = 0; i < (int)instructions.size(); ++i) { - instructions[i]->dump(out); + for (const auto& inst : instructions) { + inst->dump(out); } } @@ -4164,4 +4351,40 @@ void Builder::dumpModuleProcesses(std::vector& out) const } } +bool Builder::DecorationInstructionLessThan::operator()(const std::unique_ptr& lhs, + const std::unique_ptr& rhs) const +{ + // Order by the id to which the decoration applies first. This is more intuitive. + assert(lhs->isIdOperand(0) && rhs->isIdOperand(0)); + if (lhs->getIdOperand(0) != rhs->getIdOperand(0)) { + return lhs->getIdOperand(0) < rhs->getIdOperand(0); + } + + if (lhs->getOpCode() != rhs->getOpCode()) + return lhs->getOpCode() < rhs->getOpCode(); + + // Now compare the operands. + int minSize = std::min(lhs->getNumOperands(), rhs->getNumOperands()); + for (int i = 1; i < minSize; ++i) { + if (lhs->isIdOperand(i) != rhs->isIdOperand(i)) { + return lhs->isIdOperand(i) < rhs->isIdOperand(i); + } + + if (lhs->isIdOperand(i)) { + if (lhs->getIdOperand(i) != rhs->getIdOperand(i)) { + return lhs->getIdOperand(i) < rhs->getIdOperand(i); + } + } else { + if (lhs->getImmediateOperand(i) != rhs->getImmediateOperand(i)) { + return lhs->getImmediateOperand(i) < rhs->getImmediateOperand(i); + } + } + } + + if (lhs->getNumOperands() != rhs->getNumOperands()) + return lhs->getNumOperands() < rhs->getNumOperands(); + + // In this case they are equal. + return false; +} } // end spv namespace diff --git a/src/libraries/glslang/SPIRV/SpvBuilder.h b/src/libraries/glslang/SPIRV/SpvBuilder.h index a65a98e33..f86dd81b3 100644 --- a/src/libraries/glslang/SPIRV/SpvBuilder.h +++ b/src/libraries/glslang/SPIRV/SpvBuilder.h @@ -235,6 +235,7 @@ public: Id makeCompositeDebugType(std::vector const& memberTypes, char const*const name, NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false); Id makePointerDebugType(StorageClass storageClass, Id const baseType); + Id makeForwardPointerDebugType(StorageClass storageClass); Id makeDebugSource(const Id fileName); Id makeDebugCompilationUnit(); Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable); @@ -246,9 +247,12 @@ public: Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId); Id makeDebugLexicalBlock(uint32_t line); std::string unmangleFunctionName(std::string const& name) const; - void setupDebugFunctionEntry(Function* function, const char* name, int line, - const std::vector& paramTypes, - const std::vector& paramNames); + + // Initialize non-semantic debug information for a function, including those of: + // - The function definition + // - The function parameters + void setupFunctionDebugInfo(Function* function, const char* name, const std::vector& paramTypes, + const std::vector& paramNames); // accelerationStructureNV type Id makeAccelerationStructureType(); @@ -263,9 +267,9 @@ public: Op getOpCode(Id id) const { return module.getInstruction(id)->getOpCode(); } Op getTypeClass(Id typeId) const { return getOpCode(typeId); } Op getMostBasicTypeClass(Id typeId) const; - int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); } - int getNumTypeConstituents(Id typeId) const; - int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); } + unsigned int getNumComponents(Id resultId) const { return getNumTypeComponents(getTypeId(resultId)); } + unsigned int getNumTypeConstituents(Id typeId) const; + unsigned int getNumTypeComponents(Id typeId) const { return getNumTypeConstituents(typeId); } Id getScalarTypeId(Id typeId) const; Id getContainedTypeId(Id typeId) const; Id getContainedTypeId(Id typeId, int) const; @@ -333,18 +337,18 @@ public: return module.getInstruction(scalarTypeId)->getImmediateOperand(0); } - int getTypeNumColumns(Id typeId) const + unsigned int getTypeNumColumns(Id typeId) const { assert(isMatrixType(typeId)); return getNumTypeConstituents(typeId); } - int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); } - int getTypeNumRows(Id typeId) const + unsigned int getNumColumns(Id resultId) const { return getTypeNumColumns(getTypeId(resultId)); } + unsigned int getTypeNumRows(Id typeId) const { assert(isMatrixType(typeId)); return getNumTypeComponents(getContainedTypeId(typeId)); } - int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); } + unsigned int getNumRows(Id resultId) const { return getTypeNumRows(getTypeId(resultId)); } Dim getTypeDimensionality(Id typeId) const { @@ -855,6 +859,8 @@ public: void postProcess(Instruction&); // Hook to visit each non-32-bit sized float/int operation in a block. void postProcessType(const Instruction&, spv::Id typeId); + // move OpSampledImage instructions to be next to their users. + void postProcessSamplers(); void dump(std::vector&) const; @@ -870,6 +876,8 @@ public: // Check if the builder is generating code for spec constants. bool isInSpecConstCodeGenMode() { return generatingOpCodeForSpecConst; } + void setUseReplicatedComposites(bool use) { useReplicatedComposites = use; } + protected: Id makeIntConstant(Id typeId, unsigned value, bool specConstant); Id makeInt64Constant(Id typeId, unsigned long long value, bool specConstant); @@ -885,10 +893,13 @@ public: void createSelectionMerge(Block* mergeBlock, unsigned int control); void dumpSourceInstructions(std::vector&) const; void dumpSourceInstructions(const spv::Id fileId, const std::string& text, std::vector&) const; - void dumpInstructions(std::vector&, const std::vector >&) const; + template void dumpInstructions(std::vector& out, const Range& instructions) const; void dumpModuleProcesses(std::vector&) const; spv::MemoryAccessMask sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const; + struct DecorationInstructionLessThan { + bool operator()(const std::unique_ptr& lhs, const std::unique_ptr& rhs) const; + }; unsigned int spvVersion; // the version of SPIR-V to emit in the header SourceLanguage sourceLang; @@ -936,6 +947,7 @@ public: Id uniqueId; Function* entryPointFunction; bool generatingOpCodeForSpecConst; + bool useReplicatedComposites { false }; AccessChain accessChain; // special blocks of instructions for output @@ -944,7 +956,7 @@ public: std::vector > entryPoints; std::vector > executionModes; std::vector > names; - std::vector > decorations; + std::set, DecorationInstructionLessThan> decorations; std::vector > constantsTypesGlobals; std::vector > externals; std::vector > functions; diff --git a/src/libraries/glslang/SPIRV/SpvPostProcess.cpp b/src/libraries/glslang/SPIRV/SpvPostProcess.cpp index ebc69124e..e35ab71fe 100644 --- a/src/libraries/glslang/SPIRV/SpvPostProcess.cpp +++ b/src/libraries/glslang/SPIRV/SpvPostProcess.cpp @@ -387,12 +387,14 @@ void Builder::postProcessCFG() } // Remove unneeded decorations, for unreachable instructions - decorations.erase(std::remove_if(decorations.begin(), decorations.end(), - [&unreachableDefinitions](std::unique_ptr& I) -> bool { - Id decoration_id = I.get()->getIdOperand(0); - return unreachableDefinitions.count(decoration_id) != 0; - }), - decorations.end()); + for (auto decorationIter = decorations.begin(); decorationIter != decorations.end();) { + Id decorationId = (*decorationIter)->getIdOperand(0); + if (unreachableDefinitions.count(decorationId) != 0) { + decorationIter = decorations.erase(decorationIter); + } else { + ++decorationIter; + } + } } // comment in header @@ -483,6 +485,58 @@ void Builder::postProcessFeatures() { } } +// SPIR-V requires that any instruction consuming the result of an OpSampledImage +// be in the same block as the OpSampledImage instruction. This pass goes finds +// uses of OpSampledImage where that is not the case and duplicates the +// OpSampledImage to be immediately before the instruction that consumes it. +// The old OpSampledImage is left in place, potentially with no users. +void Builder::postProcessSamplers() +{ + // first, find all OpSampledImage instructions and store them in a map. + std::map sampledImageInstrs; + for (auto f: module.getFunctions()) { + for (auto b: f->getBlocks()) { + for (auto &i: b->getInstructions()) { + if (i->getOpCode() == spv::OpSampledImage) { + sampledImageInstrs[i->getResultId()] = i.get(); + } + } + } + } + // next find all uses of the given ids and rewrite them if needed. + for (auto f: module.getFunctions()) { + for (auto b: f->getBlocks()) { + auto &instrs = b->getInstructions(); + for (size_t idx = 0; idx < instrs.size(); idx++) { + Instruction *i = instrs[idx].get(); + for (int opnum = 0; opnum < i->getNumOperands(); opnum++) { + // Is this operand of the current instruction the result of an OpSampledImage? + if (i->isIdOperand(opnum) && + sampledImageInstrs.count(i->getIdOperand(opnum))) + { + Instruction *opSampImg = sampledImageInstrs[i->getIdOperand(opnum)]; + if (i->getBlock() != opSampImg->getBlock()) { + Instruction *newInstr = new Instruction(getUniqueId(), + opSampImg->getTypeId(), + spv::OpSampledImage); + newInstr->addIdOperand(opSampImg->getIdOperand(0)); + newInstr->addIdOperand(opSampImg->getIdOperand(1)); + newInstr->setBlock(b); + + // rewrite the user of the OpSampledImage to use the new instruction. + i->setIdOperand(opnum, newInstr->getResultId()); + // insert the new OpSampledImage right before the current instruction. + instrs.insert(instrs.begin() + idx, + std::unique_ptr(newInstr)); + idx++; + } + } + } + } + } + } +} + // comment in header void Builder::postProcess(bool compileOnly) { @@ -491,6 +545,7 @@ void Builder::postProcess(bool compileOnly) postProcessCFG(); postProcessFeatures(); + postProcessSamplers(); } }; // end spv namespace diff --git a/src/libraries/glslang/SPIRV/SpvTools.cpp b/src/libraries/glslang/SPIRV/SpvTools.cpp index ff04f4f96..5a3755aca 100644 --- a/src/libraries/glslang/SPIRV/SpvTools.cpp +++ b/src/libraries/glslang/SPIRV/SpvTools.cpp @@ -44,6 +44,7 @@ #include "SpvTools.h" #include "spirv-tools/optimizer.hpp" +#include "../glslang/MachineIndependent/localintermediate.h" namespace glslang { @@ -218,9 +219,20 @@ void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector optimizer.RegisterPass(spvtools::CreateCFGCleanupPass()); spvtools::OptimizerOptions spvOptOptions; + if (options->optimizerAllowExpandedIDBound) + spvOptOptions.set_max_id_bound(0x3FFFFFFF); optimizer.SetTargetEnv(MapToSpirvToolsEnv(intermediate.getSpv(), logger)); spvOptOptions.set_run_validator(false); // The validator may run as a separate step later on optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); + + if (options->optimizerAllowExpandedIDBound) { + if (spirv.size() > 3 && spirv[3] > kDefaultMaxIdBound) { + spvtools::Optimizer optimizer2(target_env); + optimizer2.SetMessageConsumer(OptimizerMesssageConsumer); + optimizer2.RegisterPass(spvtools::CreateCompactIdsPass()); + optimizer2.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); + } + } } bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector& spirv, diff --git a/src/libraries/glslang/SPIRV/SpvTools.h b/src/libraries/glslang/SPIRV/SpvTools.h index 3ef053d73..2575e7938 100644 --- a/src/libraries/glslang/SPIRV/SpvTools.h +++ b/src/libraries/glslang/SPIRV/SpvTools.h @@ -44,10 +44,11 @@ #if ENABLE_OPT #include #include +#include #include "spirv-tools/libspirv.h" #endif -#include "../glslang/MachineIndependent/localintermediate.h" +#include "../glslang/MachineIndependent/Versions.h" #include "GlslangToSpv.h" #include "Logger.h" @@ -55,6 +56,8 @@ namespace glslang { #if ENABLE_OPT +class TIntermediate; + // Translate glslang's view of target versioning to what SPIRV-Tools uses. spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger); diff --git a/src/libraries/glslang/SPIRV/doc.cpp b/src/libraries/glslang/SPIRV/doc.cpp index 26e4b1018..0105caa2e 100755 --- a/src/libraries/glslang/SPIRV/doc.cpp +++ b/src/libraries/glslang/SPIRV/doc.cpp @@ -1035,6 +1035,8 @@ const char* CapabilityString(int info) case CapabilityTileImageDepthReadAccessEXT: return "TileImageDepthReadAccessEXT"; case CapabilityTileImageStencilReadAccessEXT: return "TileImageStencilReadAccessEXT"; + case CapabilityCooperativeMatrixLayoutsARM: return "CooperativeMatrixLayoutsARM"; + case CapabilityFragmentShadingRateKHR: return "FragmentShadingRateKHR"; case CapabilityDemoteToHelperInvocationEXT: return "DemoteToHelperInvocationEXT"; @@ -1064,6 +1066,9 @@ const char* CapabilityString(int info) case CapabilityTextureSampleWeightedQCOM: return "TextureSampleWeightedQCOM"; case CapabilityTextureBoxFilterQCOM: return "TextureBoxFilterQCOM"; case CapabilityTextureBlockMatchQCOM: return "TextureBlockMatchQCOM"; + case CapabilityTextureBlockMatch2QCOM: return "TextureBlockMatch2QCOM"; + + case CapabilityReplicatedCompositesEXT: return "CapabilityReplicatedCompositesEXT"; default: return "Bad"; } @@ -1442,6 +1447,7 @@ const char* OpcodeString(int op) case 4429: return "OpSubgroupAnyKHR"; case 4430: return "OpSubgroupAllEqualKHR"; case 4432: return "OpSubgroupReadInvocationKHR"; + case 4433: return "OpExtInstWithForwardRefsKHR"; case OpGroupNonUniformQuadAllKHR: return "OpGroupNonUniformQuadAllKHR"; case OpGroupNonUniformQuadAnyKHR: return "OpGroupNonUniformQuadAnyKHR"; @@ -1583,6 +1589,10 @@ const char* OpcodeString(int op) case OpImageBlockMatchGatherSSDQCOM: return "OpImageBlockMatchGatherSSDQCOM"; case OpImageBlockMatchGatherSADQCOM: return "OpImageBlockMatchGatherSADQCOM"; + case OpConstantCompositeReplicateEXT: return "OpConstantCompositeReplicateEXT"; + case OpSpecConstantCompositeReplicateEXT: return "OpSpecConstantCompositeReplicateEXT"; + case OpCompositeConstructReplicateEXT: return "OpCompositeConstructReplicateEXT"; + default: return "Bad"; } @@ -1889,6 +1899,10 @@ void Parameterize() InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'"); InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n..."); + InstructionDesc[OpExtInstWithForwardRefsKHR].operands.push(OperandId, "'Set'"); + InstructionDesc[OpExtInstWithForwardRefsKHR].operands.push(OperandLiteralNumber, "'Instruction'"); + InstructionDesc[OpExtInstWithForwardRefsKHR].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n..."); + InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'"); InstructionDesc[OpLoad].operands.push(OperandMemoryAccess, "", true); InstructionDesc[OpLoad].operands.push(OperandLiteralNumber, "", true); @@ -3470,6 +3484,10 @@ void Parameterize() InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'block size'"); InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandImageOperands, "", true); InstructionDesc[OpImageBlockMatchGatherSADQCOM].setResultAndType(true, true); + + InstructionDesc[OpConstantCompositeReplicateEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpSpecConstantCompositeReplicateEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpCompositeConstructReplicateEXT].operands.push(OperandId, "'Value'"); }); } diff --git a/src/libraries/glslang/SPIRV/spirv.hpp b/src/libraries/glslang/SPIRV/spirv.hpp index 6eceabe67..b09d99bee 100644 --- a/src/libraries/glslang/SPIRV/spirv.hpp +++ b/src/libraries/glslang/SPIRV/spirv.hpp @@ -385,7 +385,7 @@ enum ImageOperandsShift { ImageOperandsMax = 0x7fffffff, }; -enum ImageOperandsMask { +enum ImageOperandsMask : unsigned { ImageOperandsMaskNone = 0, ImageOperandsBiasMask = 0x00000001, ImageOperandsLodMask = 0x00000002, @@ -420,7 +420,7 @@ enum FPFastMathModeShift { FPFastMathModeMax = 0x7fffffff, }; -enum FPFastMathModeMask { +enum FPFastMathModeMask : unsigned { FPFastMathModeMaskNone = 0, FPFastMathModeNotNaNMask = 0x00000001, FPFastMathModeNotInfMask = 0x00000002, @@ -745,7 +745,7 @@ enum SelectionControlShift { SelectionControlMax = 0x7fffffff, }; -enum SelectionControlMask { +enum SelectionControlMask : unsigned { SelectionControlMaskNone = 0, SelectionControlFlattenMask = 0x00000001, SelectionControlDontFlattenMask = 0x00000002, @@ -774,7 +774,7 @@ enum LoopControlShift { LoopControlMax = 0x7fffffff, }; -enum LoopControlMask { +enum LoopControlMask : unsigned { LoopControlMaskNone = 0, LoopControlUnrollMask = 0x00000001, LoopControlDontUnrollMask = 0x00000002, @@ -806,7 +806,7 @@ enum FunctionControlShift { FunctionControlMax = 0x7fffffff, }; -enum FunctionControlMask { +enum FunctionControlMask : unsigned { FunctionControlMaskNone = 0, FunctionControlInlineMask = 0x00000001, FunctionControlDontInlineMask = 0x00000002, @@ -836,7 +836,7 @@ enum MemorySemanticsShift { MemorySemanticsMax = 0x7fffffff, }; -enum MemorySemanticsMask { +enum MemorySemanticsMask : unsigned { MemorySemanticsMaskNone = 0, MemorySemanticsAcquireMask = 0x00000002, MemorySemanticsReleaseMask = 0x00000004, @@ -872,7 +872,7 @@ enum MemoryAccessShift { MemoryAccessMax = 0x7fffffff, }; -enum MemoryAccessMask { +enum MemoryAccessMask : unsigned { MemoryAccessMaskNone = 0, MemoryAccessVolatileMask = 0x00000001, MemoryAccessAlignedMask = 0x00000002, @@ -922,7 +922,7 @@ enum KernelProfilingInfoShift { KernelProfilingInfoMax = 0x7fffffff, }; -enum KernelProfilingInfoMask { +enum KernelProfilingInfoMask : unsigned { KernelProfilingInfoMaskNone = 0, KernelProfilingInfoCmdExecTimeMask = 0x00000001, }; @@ -1002,6 +1002,7 @@ enum Capability { CapabilityTileImageColorReadAccessEXT = 4166, CapabilityTileImageDepthReadAccessEXT = 4167, CapabilityTileImageStencilReadAccessEXT = 4168, + CapabilityCooperativeMatrixLayoutsARM = 4201, CapabilityFragmentShadingRateKHR = 4422, CapabilitySubgroupBallotKHR = 4423, CapabilityDrawParameters = 4427, @@ -1163,6 +1164,7 @@ enum Capability { CapabilityDotProductKHR = 6019, CapabilityRayCullMaskKHR = 6020, CapabilityCooperativeMatrixKHR = 6022, + CapabilityReplicatedCompositesEXT = 6024, CapabilityBitInstructions = 6025, CapabilityGroupNonUniformRotateKHR = 6026, CapabilityAtomicFloat32AddEXT = 6033, @@ -1192,7 +1194,7 @@ enum RayFlagsShift { RayFlagsMax = 0x7fffffff, }; -enum RayFlagsMask { +enum RayFlagsMask : unsigned { RayFlagsMaskNone = 0, RayFlagsOpaqueKHRMask = 0x00000001, RayFlagsNoOpaqueKHRMask = 0x00000002, @@ -1234,7 +1236,7 @@ enum FragmentShadingRateShift { FragmentShadingRateMax = 0x7fffffff, }; -enum FragmentShadingRateMask { +enum FragmentShadingRateMask : unsigned { FragmentShadingRateMaskNone = 0, FragmentShadingRateVertical2PixelsMask = 0x00000001, FragmentShadingRateVertical4PixelsMask = 0x00000002, @@ -1289,7 +1291,7 @@ enum CooperativeMatrixOperandsShift { CooperativeMatrixOperandsMax = 0x7fffffff, }; -enum CooperativeMatrixOperandsMask { +enum CooperativeMatrixOperandsMask : unsigned { CooperativeMatrixOperandsMaskNone = 0, CooperativeMatrixOperandsMatrixASignedComponentsKHRMask = 0x00000001, CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask = 0x00000002, @@ -1301,6 +1303,8 @@ enum CooperativeMatrixOperandsMask { enum CooperativeMatrixLayout { CooperativeMatrixLayoutRowMajorKHR = 0, CooperativeMatrixLayoutColumnMajorKHR = 1, + CooperativeMatrixLayoutRowBlockedInterleavedARM = 4202, + CooperativeMatrixLayoutColumnBlockedInterleavedARM = 4203, CooperativeMatrixLayoutMax = 0x7fffffff, }; @@ -1667,6 +1671,7 @@ enum Op { OpSubgroupAllEqualKHR = 4430, OpGroupNonUniformRotateKHR = 4431, OpSubgroupReadInvocationKHR = 4432, + OpExtInstWithForwardRefsKHR = 4433, OpTraceRayKHR = 4445, OpExecuteCallableKHR = 4446, OpConvertUToAccelerationStructureKHR = 4447, @@ -1689,6 +1694,9 @@ enum Op { OpCooperativeMatrixStoreKHR = 4458, OpCooperativeMatrixMulAddKHR = 4459, OpCooperativeMatrixLengthKHR = 4460, + OpConstantCompositeReplicateEXT = 4461, + OpSpecConstantCompositeReplicateEXT = 4462, + OpCompositeConstructReplicateEXT = 4463, OpTypeRayQueryKHR = 4472, OpRayQueryInitializeKHR = 4473, OpRayQueryTerminateKHR = 4474, @@ -2391,6 +2399,7 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpPtrEqual: *hasResult = true; *hasResultType = true; break; case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; case OpPtrDiff: *hasResult = true; *hasResultType = true; break; + case OpExtInstWithForwardRefsKHR: *hasResult = true; *hasResultType = true; break; case OpColorAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; case OpDepthAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; case OpStencilAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; @@ -2418,6 +2427,9 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpCooperativeMatrixStoreKHR: *hasResult = false; *hasResultType = false; break; case OpCooperativeMatrixMulAddKHR: *hasResult = true; *hasResultType = true; break; case OpCooperativeMatrixLengthKHR: *hasResult = true; *hasResultType = true; break; + case OpConstantCompositeReplicateEXT: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantCompositeReplicateEXT: *hasResult = true; *hasResultType = true; break; + case OpCompositeConstructReplicateEXT: *hasResult = true; *hasResultType = true; break; case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; diff --git a/src/libraries/glslang/SPIRV/spvIR.h b/src/libraries/glslang/SPIRV/spvIR.h index 6f3124f8d..bd639d8f7 100644 --- a/src/libraries/glslang/SPIRV/spvIR.h +++ b/src/libraries/glslang/SPIRV/spvIR.h @@ -97,12 +97,24 @@ public: Instruction(Id resultId, Id typeId, Op opCode) : resultId(resultId), typeId(typeId), opCode(opCode), block(nullptr) { } explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { } virtual ~Instruction() {} + void reserveOperands(size_t count) { + operands.reserve(count); + idOperand.reserve(count); + } void addIdOperand(Id id) { // ids can't be 0 assert(id); operands.push_back(id); idOperand.push_back(true); } + // This method is potentially dangerous as it can break assumptions + // about SSA and lack of forward references. + void setIdOperand(unsigned idx, Id id) { + assert(id); + assert(idOperand[idx]); + operands[idx] = id; + } + void addImmediateOperand(unsigned int immediate) { operands.push_back(immediate); idOperand.push_back(false); @@ -234,7 +246,7 @@ public: void addLocalVariable(std::unique_ptr inst) { localVariables.push_back(std::move(inst)); } const std::vector& getPredecessors() const { return predecessors; } const std::vector& getSuccessors() const { return successors; } - const std::vector >& getInstructions() const { + std::vector >& getInstructions() { return instructions; } const std::vector >& getLocalVariables() const { return localVariables; } @@ -398,6 +410,7 @@ public: void setDebugLineInfo(Id fileName, int line, int column) { lineInstruction = std::unique_ptr{new Instruction(OpLine)}; + lineInstruction->reserveOperands(3); lineInstruction->addIdOperand(fileName); lineInstruction->addImmediateOperand(line); lineInstruction->addImmediateOperand(column); @@ -521,6 +534,7 @@ __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParam linkType(linkage) { // OpFunction + functionInstruction.reserveOperands(2); functionInstruction.addImmediateOperand(FunctionControlMaskNone); functionInstruction.addIdOperand(functionType); parent.mapInstruction(&functionInstruction); diff --git a/src/libraries/glslang/glslang/Include/BaseTypes.h b/src/libraries/glslang/glslang/Include/BaseTypes.h index 64bffa892..0ac526bfb 100755 --- a/src/libraries/glslang/glslang/Include/BaseTypes.h +++ b/src/libraries/glslang/glslang/Include/BaseTypes.h @@ -268,7 +268,6 @@ enum TBuiltInVariable { EbvRayTmin, EbvRayTmax, EbvCullMask, - EbvHitT, EbvHitKind, EbvObjectToWorld, EbvObjectToWorld3x4, @@ -495,7 +494,6 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvObjectRayDirection: return "ObjectRayDirectionNV"; case EbvRayTmin: return "ObjectRayTminNV"; case EbvRayTmax: return "ObjectRayTmaxNV"; - case EbvHitT: return "HitTNV"; case EbvHitKind: return "HitKindNV"; case EbvIncomingRayFlags: return "IncomingRayFlagsNV"; case EbvObjectToWorld: return "ObjectToWorldNV"; diff --git a/src/libraries/glslang/glslang/Include/Common.h b/src/libraries/glslang/glslang/Include/Common.h index d1bd13b57..0c1426053 100644 --- a/src/libraries/glslang/glslang/Include/Common.h +++ b/src/libraries/glslang/glslang/Include/Common.h @@ -94,6 +94,11 @@ std::string to_string(const T& val) { #pragma warning(disable : 4201) // nameless union #endif +// Allow compilation to WASI which does not support threads yet. +#ifdef __wasi__ +#define DISABLE_THREAD_SUPPORT +#endif + #include "PoolAlloc.h" // diff --git a/src/libraries/glslang/glslang/Include/InfoSink.h b/src/libraries/glslang/glslang/Include/InfoSink.h index 23f495dcb..262933941 100644 --- a/src/libraries/glslang/glslang/Include/InfoSink.h +++ b/src/libraries/glslang/glslang/Include/InfoSink.h @@ -95,10 +95,14 @@ public: default: append("UNKNOWN ERROR: "); break; } } - void location(const TSourceLoc& loc, bool absolute = false) { + void location(const TSourceLoc& loc, bool absolute = false, bool displayColumn = false) { const int maxSize = 24; char locText[maxSize]; - snprintf(locText, maxSize, ":%d", loc.line); + if (displayColumn) { + snprintf(locText, maxSize, ":%d:%d", loc.line, loc.column); + } else { + snprintf(locText, maxSize, ":%d", loc.line); + } if(loc.getFilename() == nullptr && shaderFileName != nullptr && absolute) { append(std::filesystem::absolute(shaderFileName).string()); @@ -119,9 +123,11 @@ public: append(s); append("\n"); } - void message(TPrefixType message, const char* s, const TSourceLoc& loc) { + void message(TPrefixType message, const char* s, const TSourceLoc& loc, bool absolute = false, + bool displayColumn = false) + { prefix(message); - location(loc); + location(loc, absolute, displayColumn); append(s); append("\n"); } diff --git a/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp b/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp index ac7fc8cd1..7a9fb2ed6 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp @@ -507,7 +507,11 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EbtUint8: newConstArray[i].setU8Const(static_cast(-static_cast(unionArray[i].getU8Const()))); break; case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break; case EbtUint16:newConstArray[i].setU16Const(static_cast(-static_cast(unionArray[i].getU16Const()))); break; - case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break; + case EbtInt64: { + int64_t i64val = unionArray[i].getI64Const(); + newConstArray[i].setI64Const(i64val == INT64_MIN ? INT64_MIN : -i64val); + break; + } case EbtUint64: newConstArray[i].setU64Const(static_cast(-static_cast(unionArray[i].getU64Const()))); break; default: return nullptr; @@ -1009,6 +1013,12 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) objectSize = std::max(children[0]->getAsTyped()->getType().getVectorSize(), children[2]->getAsTyped()->getType().getVectorSize()); break; + case EOpMul: + { + TIntermConstantUnion* left = children[0]->getAsConstantUnion(); + TIntermConstantUnion* right = children[1]->getAsConstantUnion(); + return left->fold(EOpMul, right); + } default: return aggrNode; } diff --git a/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp b/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp index daaab38c3..06e5ff9b6 100755 --- a/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp @@ -1707,9 +1707,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 textureCube(samplerCube, vec3);" - "vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array - "vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array - "\n"); } } @@ -1736,9 +1733,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 shadow2DRectProj(sampler2DRectShadow, vec4);" // GL_ARB_texture_rectangle, caught by keyword check "vec4 texture1DArray(sampler1DArray, vec2);" // GL_EXT_texture_array + "vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array "vec4 shadow1DArray(sampler1DArrayShadow, vec3);" // GL_EXT_texture_array "vec4 shadow2DArray(sampler2DArrayShadow, vec4);" // GL_EXT_texture_array "vec4 texture1DArray(sampler1DArray, vec2, float);" // GL_EXT_texture_array + "vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array "vec4 shadow1DArray(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array "vec4 texture1DArrayLod(sampler1DArray, vec2, float);" // GL_EXT_texture_array "vec4 texture2DArrayLod(sampler2DArray, vec3, float);" // GL_EXT_texture_array @@ -4559,6 +4558,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "const int gl_MatrixOperandsSaturatingAccumulation = 0x10;\n" "const int gl_CooperativeMatrixLayoutRowMajor = 0;\n" "const int gl_CooperativeMatrixLayoutColumnMajor = 1;\n" + "const int gl_CooperativeMatrixLayoutRowBlockedInterleavedARM = 4202;\n" + "const int gl_CooperativeMatrixLayoutColumnBlockedInterleavedARM = 4203;\n" "\n" ); } @@ -8122,11 +8123,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion } // E_GL_EXT_texture_array - if (spvVersion.spv == 0) { - symbolTable.setFunctionExtensions("texture2DArray", 1, &E_GL_EXT_texture_array); - } if (profile != EEsProfile && spvVersion.spv == 0) { symbolTable.setFunctionExtensions("texture1DArray", 1, &E_GL_EXT_texture_array); + symbolTable.setFunctionExtensions("texture2DArray", 1, &E_GL_EXT_texture_array); symbolTable.setFunctionExtensions("shadow1DArray", 1, &E_GL_EXT_texture_array); symbolTable.setFunctionExtensions("shadow2DArray", 1, &E_GL_EXT_texture_array); @@ -9212,8 +9211,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_RayTmaxNV", EbvRayTmax, symbolTable); BuiltInVariable("gl_RayTmaxEXT", EbvRayTmax, symbolTable); BuiltInVariable("gl_CullMaskEXT", EbvCullMask, symbolTable); - BuiltInVariable("gl_HitTNV", EbvHitT, symbolTable); - BuiltInVariable("gl_HitTEXT", EbvHitT, symbolTable); BuiltInVariable("gl_HitKindNV", EbvHitKind, symbolTable); BuiltInVariable("gl_HitKindEXT", EbvHitKind, symbolTable); BuiltInVariable("gl_ObjectToWorldNV", EbvObjectToWorld, symbolTable); @@ -9232,6 +9229,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_HitKindFrontFacingMicroTriangleNV", EbvHitKindFrontFacingMicroTriangleNV, symbolTable); BuiltInVariable("gl_HitKindBackFacingMicroTriangleNV", EbvHitKindBackFacingMicroTriangleNV, symbolTable); + // gl_HitT variables are aliases of their gl_RayTmax counterparts. + RetargetVariable("gl_HitTNV", "gl_RayTmaxNV", symbolTable); + RetargetVariable("gl_HitTEXT", "gl_RayTmaxEXT", symbolTable); + // GL_ARB_shader_ballot symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); symbolTable.setVariableExtensions("gl_SubGroupInvocationARB", 1, &E_GL_ARB_shader_ballot); @@ -10138,11 +10139,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("textureBlockMatchGatherSADQCOM", EOpImageBlockMatchGatherSADQCOM); } - if (spvVersion.spv == 0) { - symbolTable.relateToOperator("texture2DArray", EOpTexture); - } if (profile != EEsProfile && spvVersion.spv == 0) { symbolTable.relateToOperator("texture1DArray", EOpTexture); + symbolTable.relateToOperator("texture2DArray", EOpTexture); symbolTable.relateToOperator("shadow1DArray", EOpTexture); symbolTable.relateToOperator("shadow2DArray", EOpTexture); diff --git a/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp b/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp index 591dfc718..f7895d979 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp @@ -59,7 +59,7 @@ void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReaso safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); infoSink.info.prefix(prefix); - infoSink.info.location(loc, messages & EShMsgAbsolutePath); + infoSink.info.location(loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; if (prefix == EPrefixError) { diff --git a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp index ff4e90397..6351997a7 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -4,6 +4,7 @@ // Copyright (C) 2015-2018 Google, Inc. // Copyright (C) 2017, 2019 ARM Limited. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. +// Modifications Copyright (C) 2024 Ravi Prakash Singh. // // All rights reserved. // @@ -399,6 +400,10 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& if (spvVersion.spv < glslang::EShTargetSpv_1_3) error(loc, "requires SPIR-V 1.3", "#pragma use_variable_pointers", ""); intermediate.setUseVariablePointers(); + } else if (spvVersion.spv > 0 && tokens[0].compare("use_replicated_composites") == 0) { + if (tokens.size() != 1) + error(loc, "extra tokens", "#pragma", ""); + intermediate.setReplicatedComposites(); } else if (tokens[0].compare("once") == 0) { warn(loc, "not implemented", "#pragma once", ""); } else if (tokens[0].compare("glslang_binary_double_output") == 0) { @@ -492,7 +497,7 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb if ((variable->getMangledName() == "gl_PrimitiveTriangleIndicesEXT" && primitiveType != ElgTriangles) || (variable->getMangledName() == "gl_PrimitiveLineIndicesEXT" && primitiveType != ElgLines) || (variable->getMangledName() == "gl_PrimitivePointIndicesEXT" && primitiveType != ElgPoints)) { - error(loc, "cannot be used (ouput primitive type mismatch)", string->c_str(), ""); + error(loc, "cannot be used (output primitive type mismatch)", string->c_str(), ""); variable = nullptr; } } @@ -598,6 +603,10 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn indexValue >= resources.maxCullDistances) { error(loc, "gl_CullDistance", "[", "array index out of range '%d'", indexValue); } + else if (base->getQualifier().builtIn == EbvSampleMask && + indexValue >= (resources.maxSamples + 31) / 32) { + error(loc, "gl_SampleMask", "[", "array index out of range '%d'", indexValue); + } // For 2D per-view builtin arrays, update the inner dimension size in parent type if (base->getQualifier().isPerView() && base->getQualifier().builtIn != EbvNone) { TIntermBinary* binaryNode = base->getAsBinaryNode(); @@ -2700,7 +2709,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan case EOpEmitStreamVertex: case EOpEndStreamPrimitive: if (version == 150) - requireExtensions(loc, 1, &E_GL_ARB_gpu_shader5, "if the verison is 150 , the EmitStreamVertex and EndStreamPrimitive only support at extension GL_ARB_gpu_shader5"); + requireExtensions(loc, 1, &E_GL_ARB_gpu_shader5, "if the version is 150 , the EmitStreamVertex and EndStreamPrimitive only support at extension GL_ARB_gpu_shader5"); intermediate.setMultiStream(); break; @@ -3609,6 +3618,19 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T makeSpecConst = ! intArgument && !type.isArray(); break; + case EOpConstructCooperativeMatrixNV: + case EOpConstructCooperativeMatrixKHR: + case EOpConstructStruct: + { + const char *specConstantCompositeExt[] = { E_GL_EXT_spec_constant_composites }; + if (checkExtensionsRequested(loc, 1, specConstantCompositeExt, "spec constant aggregate constructor")) { + makeSpecConst = true; + } else { + makeSpecConst = false; + } + } + break; + default: // anything else wasn't white-listed in the spec as a conversion makeSpecConst = false; @@ -6564,10 +6586,10 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision); if (repeated >= 0 && ! typeCollision) error(loc, "overlapping use of location", "location", "%d", repeated); - // "fragment-shader outputs/tileImageEXT ... if two variables are placed within the same - // location, they must have the same underlying type (floating-point or integer)" - if (typeCollision && language == EShLangFragment && (qualifier.isPipeOutput() || qualifier.storage == EvqTileImageEXT)) - error(loc, "fragment outputs or tileImageEXTs sharing the same location", "location", "%d must be the same basic type", repeated); + // When location aliasing, the aliases sharing the location must have the same underlying numerical type and bit width( + // floating - point or integer, 32 - bit versus 64 - bit,etc.) + if (typeCollision && (qualifier.isPipeInput() || qualifier.isPipeOutput() || qualifier.storage == EvqTileImageEXT)) + error(loc, "the aliases sharing the location", "location", "%d must be the same basic type and interpolation qualification", repeated); } if (qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()) { @@ -7365,7 +7387,7 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T } } else if (function->getName() == "atomicCounter") { // change atomicCounter into a direct read of the variable - if (arguments->getAsTyped()) { + if (arguments && arguments->getAsTyped()) { result = arguments->getAsTyped(); } } @@ -8351,6 +8373,11 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* int paramCount = 0; // keeps track of the constructor parameter number being checked + // We don't know "top down" whether type is a specialization constant, + // but a const becomes a specialization constant if any of its children are. + bool hasSpecConst = false; + bool isConstConstructor = true; + // for each parameter to the constructor call, check to see if the right type is passed or convert them // to the right type if possible (and allowed). // for structure constructors, just check if the right type is passed, no conversion is allowed. @@ -8363,13 +8390,24 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* else newNode = constructBuiltIn(type, op, (*p)->getAsTyped(), node->getLoc(), true); - if (newNode) + if (newNode) { *p = newNode; - else + if (!newNode->getType().getQualifier().isConstant()) + isConstConstructor = false; + if (newNode->getType().getQualifier().isSpecConstant()) + hasSpecConst = true; + } else return nullptr; } - TIntermTyped *ret_node = intermediate.setAggregateOperator(aggrNode, op, type, loc); + TIntermTyped* ret_node = intermediate.setAggregateOperator(aggrNode, op, type, loc); + + const char *specConstantCompositeExt[] = { E_GL_EXT_spec_constant_composites }; + if (checkExtensionsRequested(loc, 1, specConstantCompositeExt, "spec constant aggregate constructor")) { + if (isConstConstructor && hasSpecConst) { + ret_node->getWritableType().getQualifier().makeSpecConstant(); + } + } TIntermAggregate *agg_node = ret_node->getAsAggregate(); if (agg_node && (agg_node->isVector() || agg_node->isArray() || agg_node->isMatrix())) @@ -8503,7 +8541,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructFloat16; // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types, // so construct a 32-bit type and convert - if (!intermediate.getArithemeticFloat16Enabled()) { + // and do not generate any conversion if it is an identity conversion, i.e. float16_t( var) + if (!intermediate.getArithemeticFloat16Enabled() && (node->getBasicType() != EbtFloat16)) { TType tempType(EbtFloat, EvqTemporary, type.getVectorSize()); newNode = node; if (tempType != newNode->getType()) { @@ -8526,7 +8565,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructInt8; // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types, // so construct a 32-bit type and convert - if (!intermediate.getArithemeticInt8Enabled()) { + // and do not generate any conversion if it is an identity conversion, i.e. int8_t( var) + if (!intermediate.getArithemeticInt8Enabled() && (node->getBasicType() != EbtInt8)) { TType tempType(EbtInt, EvqTemporary, type.getVectorSize()); newNode = node; if (tempType != newNode->getType()) { @@ -8549,7 +8589,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructUint8; // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types, // so construct a 32-bit type and convert - if (!intermediate.getArithemeticInt8Enabled()) { + // and do not generate any conversion if it is an identity conversion, i.e. uint8_t( var) + if (!intermediate.getArithemeticInt8Enabled() && (node->getBasicType() != EbtUint8)) { TType tempType(EbtUint, EvqTemporary, type.getVectorSize()); newNode = node; if (tempType != newNode->getType()) { @@ -8572,7 +8613,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructInt16; // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types, // so construct a 32-bit type and convert - if (!intermediate.getArithemeticInt16Enabled()) { + // and do not generate any conversion if it is an identity conversion, i.e. int16_t( var) + if (!intermediate.getArithemeticInt16Enabled() && (node->getBasicType() != EbtInt16)) { TType tempType(EbtInt, EvqTemporary, type.getVectorSize()); newNode = node; if (tempType != newNode->getType()) { @@ -8595,7 +8637,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T basicOp = EOpConstructUint16; // 8/16-bit storage extensions don't support constructing composites of 8/16-bit types, // so construct a 32-bit type and convert - if (!intermediate.getArithemeticInt16Enabled()) { + // and do not generate any conversion if it is an identity conversion, i.e. uint16_t( var) + if (!intermediate.getArithemeticInt16Enabled() && (node->getBasicType() != EbtUint16)) { TType tempType(EbtUint, EvqTemporary, type.getVectorSize()); newNode = node; if (tempType != newNode->getType()) { diff --git a/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp b/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp index 5d7173c9d..93a3b0d12 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp @@ -35,14 +35,21 @@ #include "../Include/Common.h" #include "../Include/PoolAlloc.h" +// Mostly here for target that do not support threads such as WASI. +#ifdef DISABLE_THREAD_SUPPORT +#define THREAD_LOCAL +#else +#define THREAD_LOCAL thread_local +#endif + namespace glslang { namespace { -thread_local TPoolAllocator* threadPoolAllocator = nullptr; +THREAD_LOCAL TPoolAllocator* threadPoolAllocator = nullptr; TPoolAllocator* GetDefaultThreadPoolAllocator() { - thread_local TPoolAllocator defaultAllocator; + THREAD_LOCAL TPoolAllocator defaultAllocator; return &defaultAllocator; } } // anonymous namespace diff --git a/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp b/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp index b3f3dc4d4..44546596e 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp @@ -1497,7 +1497,7 @@ int TScanContext::tokenizeIdentifier() case USAMPLER2DARRAY: afterType = true; if (keyword == SAMPLER2DARRAY || keyword == SAMPLER2DARRAYSHADOW) { - if ((keyword == SAMPLER2DARRAY || !parseContext.isEsProfile()) && + if (!parseContext.isEsProfile() && (parseContext.extensionTurnedOn(E_GL_EXT_texture_array) || parseContext.symbolTable.atBuiltInLevel())) { return keyword; } diff --git a/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp b/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp index 740ddd648..bc5d0c208 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp @@ -82,7 +82,10 @@ namespace { // anonymous namespace for file-local functions and symbols int NumberOfClients = 0; // global initialization lock +#ifndef DISABLE_THREAD_SUPPORT std::mutex init_lock; +#endif + using namespace glslang; @@ -420,7 +423,9 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp TInfoSink infoSink; // Make sure only one thread tries to do this at a time +#ifndef DISABLE_THREAD_SUPPORT const std::lock_guard lock(init_lock); +#endif // See if it's already been done for this version/profile combination int versionIndex = MapVersionToIndex(version); @@ -788,7 +793,7 @@ bool ProcessDeferred( // set version/profile to defaultVersion/defaultProfile regardless of the #version // directive in the source code bool forceDefaultVersionAndProfile, - int overrideVersion, // overrides version specified by #verison or default version + int overrideVersion, // overrides version specified by #version or default version bool forwardCompatible, // give errors for use of deprecated features EShMessages messages, // warnings/errors/AST; things to print out TIntermediate& intermediate, // returned tree, etc. @@ -1311,7 +1316,9 @@ bool CompileDeferred( // int ShInitialize() { +#ifndef DISABLE_THREAD_SUPPORT const std::lock_guard lock(init_lock); +#endif ++NumberOfClients; if (PerProcessGPA == nullptr) @@ -1371,7 +1378,9 @@ void ShDestruct(ShHandle handle) // int ShFinalize() { +#ifndef DISABLE_THREAD_SUPPORT const std::lock_guard lock(init_lock); +#endif --NumberOfClients; assert(NumberOfClients >= 0); if (NumberOfClients > 0) @@ -2033,7 +2042,7 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) // // Return true if no errors. // -bool TProgram::crossStageCheck(EShMessages) { +bool TProgram::crossStageCheck(EShMessages messages) { // make temporary intermediates to hold the linkage symbols for each linking interface // while we do the checks @@ -2084,7 +2093,7 @@ bool TProgram::crossStageCheck(EShMessages) { // compare cross stage symbols for each stage boundary for (unsigned int i = 1; i < activeStages.size(); ++i) { - activeStages[i - 1]->checkStageIO(*infoSink, *activeStages[i]); + activeStages[i - 1]->checkStageIO(messages, *infoSink, *activeStages[i]); error |= (activeStages[i - 1]->getNumErrors() != 0); } @@ -2105,11 +2114,15 @@ const char* TProgram::getInfoDebugLog() // Reflection implementation. // +unsigned int TObjectReflection::layoutLocation() const { return type->getQualifier().layoutLocation; } + bool TProgram::buildReflection(int opts) { if (! linked || reflection != nullptr) return false; + SetThreadPoolAllocator(pool); + int firstStage = EShLangVertex, lastStage = EShLangFragment; if (opts & EShReflectionIntermediateIO) { @@ -2165,6 +2178,9 @@ bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper) { if (! linked) return false; + + SetThreadPoolAllocator(pool); + TIoMapper* ioMapper = nullptr; TIoMapper defaultIOMapper; if (pIoMapper == nullptr) diff --git a/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp b/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp index 0d13fafa1..0262c54dc 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp @@ -265,6 +265,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_expect_assume] = EBhDisable; extensionBehavior[E_GL_EXT_control_flow_attributes2] = EBhDisable; + extensionBehavior[E_GL_EXT_spec_constant_composites] = EBhDisable; extensionBehavior[E_GL_KHR_cooperative_matrix] = EBhDisable; @@ -414,7 +415,6 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_texture_lod 1\n" "#define GL_EXT_shadow_samplers 1\n" "#define GL_EXT_fragment_shading_rate 1\n" - "#define GL_EXT_texture_array 1\n" // AEP "#define GL_ANDROID_extension_pack_es31a 1\n" @@ -520,6 +520,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_fragment_shading_rate 1\n" "#define GL_EXT_shared_memory_block 1\n" "#define GL_EXT_shader_integer_mix 1\n" + "#define GL_EXT_spec_constant_composites 1\n" // GL_KHR_shader_subgroup "#define GL_KHR_shader_subgroup_basic 1\n" @@ -774,7 +775,7 @@ void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int for (int i = 0; i < numExtensions; ++i) { switch (getExtensionBehavior(extensions[i])) { case EBhWarn: - infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc); + infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); [[fallthrough]]; case EBhRequire: case EBhEnable: @@ -812,7 +813,8 @@ void TParseVersions::checkDeprecated(const TSourceLoc& loc, int profileMask, int error(loc, "deprecated, may be removed in future release", featureDesc, ""); else if (! suppressWarnings()) infoSink.info.message(EPrefixWarning, (TString(featureDesc) + " deprecated in version " + - String(depVersion) + "; may be removed in future release").c_str(), loc); + String(depVersion) + "; may be removed in future release").c_str(), + loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); } } } @@ -849,11 +851,14 @@ bool TParseVersions::checkExtensionsRequested(const TSourceLoc& loc, int numExte for (int i = 0; i < numExtensions; ++i) { TExtensionBehavior behavior = getExtensionBehavior(extensions[i]); if (behavior == EBhDisable && relaxedErrors()) { - infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc); + infoSink.info.message(EPrefixWarning, "The following extension must be enabled to use this feature:", loc, + messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); behavior = EBhWarn; } if (behavior == EBhWarn) { - infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc); + infoSink.info.message(EPrefixWarning, + ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), + loc, messages & EShMsgAbsolutePath, messages & EShMsgDisplayErrorColumn); warned = true; } } diff --git a/src/libraries/glslang/glslang/MachineIndependent/Versions.h b/src/libraries/glslang/glslang/MachineIndependent/Versions.h index cfaeb1ff1..75a823774 100755 --- a/src/libraries/glslang/glslang/MachineIndependent/Versions.h +++ b/src/libraries/glslang/glslang/MachineIndependent/Versions.h @@ -222,6 +222,7 @@ const char* const E_GL_EXT_texture_array = "GL_EXT_texture_ar const char* const E_GL_EXT_maximal_reconvergence = "GL_EXT_maximal_reconvergence"; const char* const E_GL_EXT_expect_assume = "GL_EXT_expect_assume"; const char* const E_GL_EXT_control_flow_attributes2 = "GL_EXT_control_flow_attributes2"; +const char* const E_GL_EXT_spec_constant_composites = "GL_EXT_spec_constant_composites"; // Arrays of extensions for the above viewportEXTs duplications diff --git a/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp b/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp index 1bd6678b1..2eeb88d08 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -113,10 +113,32 @@ void TIntermediate::mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); } +static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) { + return // 1) same stage and same shader interface + (stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) || + // 2) accross stages and both are uniform or buffer + (symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) || + (symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) || + // 3) in/out matched across stage boundary + (stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) || + (unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut); +} + +static bool isSameSymbol(TIntermSymbol* symbol1, EShLanguage stage1, TIntermSymbol* symbol2, EShLanguage stage2) { + // If they are both blocks in the same shader interface, + // match by the block-name, not the identifier name. + if (symbol1->getType().getBasicType() == EbtBlock && symbol2->getType().getBasicType() == EbtBlock) { + if (isSameInterface(symbol1, stage1, symbol2, stage2)) { + return symbol1->getType().getTypeName() == symbol2->getType().getTypeName(); + } + } else if (symbol1->getName() == symbol2->getName()) + return true; + return false; +} // // do error checking on the shader boundary in / out vars // -void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) { +void TIntermediate::checkStageIO(EShMessages messages, TInfoSink& infoSink, TIntermediate& unit) { if (unit.treeRoot == nullptr || treeRoot == nullptr) return; @@ -137,7 +159,32 @@ void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) { // do matching and error checking mergeLinkerObjects(infoSink, linkerObjects, unitLinkerObjects, unit.getStage()); - // TODO: final check; make sure that any statically used `in` have matching `out` written to + // Check that all of our inputs have matching outputs from the previous stage. + // Only do this for Vulkan, since GL_ARB_separate_shader_objects allows for + // the in/out to not match + if (spvVersion.vulkan > 0 || (messages & EshMsgCrossStageIO)) { + for (auto& nextStageInterm : unitLinkerObjects) { + auto* nextStageSymbol = nextStageInterm->getAsSymbolNode(); + bool found = false; + for (auto& curStageInterm : linkerObjects) { + if (isSameSymbol(curStageInterm->getAsSymbolNode(), getStage(), nextStageSymbol, unit.getStage())) { + found = true; + break; + } + } + if (!found) { + TString errmsg; + errmsg.append("Input '"); + if (nextStageSymbol->getType().getBasicType() == EbtBlock) + errmsg.append(nextStageSymbol->getType().getTypeName()); + else + errmsg.append(nextStageSymbol->getName()); + errmsg.append("' in ").append(StageName(unit.getStage())); + errmsg.append(" shader has no corresponding output in ").append(StageName(getStage())).append(" shader."); + error(infoSink, errmsg.c_str(), unit.getStage()); + } + } + } } void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit) @@ -511,17 +558,6 @@ void TIntermediate::mergeBodies(TInfoSink& infoSink, TIntermSequence& globals, c globals.insert(globals.end() - 1, unitGlobals.begin(), unitGlobals.end() - 1); } -static inline bool isSameInterface(TIntermSymbol* symbol, EShLanguage stage, TIntermSymbol* unitSymbol, EShLanguage unitStage) { - return // 1) same stage and same shader interface - (stage == unitStage && symbol->getType().getShaderInterface() == unitSymbol->getType().getShaderInterface()) || - // 2) accross stages and both are uniform or buffer - (symbol->getQualifier().storage == EvqUniform && unitSymbol->getQualifier().storage == EvqUniform) || - (symbol->getQualifier().storage == EvqBuffer && unitSymbol->getQualifier().storage == EvqBuffer) || - // 3) in/out matched across stage boundary - (stage < unitStage && symbol->getQualifier().storage == EvqVaryingOut && unitSymbol->getQualifier().storage == EvqVaryingIn) || - (unitStage < stage && symbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().storage == EvqVaryingOut); -} - // // Global Unfiform block stores any default uniforms (i.e. uniforms without a block) // If two linked stages declare the same member, they are meant to be the same uniform @@ -707,24 +743,18 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin // Error check and merge the linker objects (duplicates should not be created) std::size_t initialNumLinkerObjects = linkerObjects.size(); for (unsigned int unitLinkObj = 0; unitLinkObj < unitLinkerObjects.size(); ++unitLinkObj) { + TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); bool merge = true; + + // Don't merge inputs backwards into previous stages + if (getStage() != unitStage && unitSymbol->getQualifier().storage == EvqVaryingIn) + merge = false; + for (std::size_t linkObj = 0; linkObj < initialNumLinkerObjects; ++linkObj) { TIntermSymbol* symbol = linkerObjects[linkObj]->getAsSymbolNode(); - TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); assert(symbol && unitSymbol); - bool isSameSymbol = false; - // If they are both blocks in the same shader interface, - // match by the block-name, not the identifier name. - if (symbol->getType().getBasicType() == EbtBlock && unitSymbol->getType().getBasicType() == EbtBlock) { - if (isSameInterface(symbol, getStage(), unitSymbol, unitStage)) { - isSameSymbol = symbol->getType().getTypeName() == unitSymbol->getType().getTypeName(); - } - } - else if (symbol->getName() == unitSymbol->getName()) - isSameSymbol = true; - - if (isSameSymbol) { + if (isSameSymbol(symbol, getStage(), unitSymbol, unitStage)) { // filter out copy merge = false; @@ -1689,7 +1719,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ // First range: TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation); TRange componentRange(0, 3); - TIoRange range(locationRange, componentRange, type.getBasicType(), 0); + TIoRange range(locationRange, componentRange, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch); // check for collisions collision = checkLocationRange(set, range, type, typeCollision); @@ -1699,7 +1729,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ // Second range: TRange locationRange2(qualifier.layoutLocation + 1, qualifier.layoutLocation + 1); TRange componentRange2(0, 1); - TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0); + TIoRange range2(locationRange2, componentRange2, type.getBasicType(), 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch); // check for collisions collision = checkLocationRange(set, range2, type, typeCollision); @@ -1725,7 +1755,7 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ TBasicType basicTy = type.getBasicType(); if (basicTy == EbtSampler && type.getSampler().isAttachmentEXT()) basicTy = type.getSampler().type; - TIoRange range(locationRange, componentRange, basicTy, qualifier.hasIndex() ? qualifier.getIndex() : 0); + TIoRange range(locationRange, componentRange, basicTy, qualifier.hasIndex() ? qualifier.getIndex() : 0, qualifier.centroid, qualifier.smooth, qualifier.flat, qualifier.sample, qualifier.patch); // check for collisions, except for vertex inputs on desktop targeting OpenGL if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) @@ -1737,6 +1767,24 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ return collision; } +// Check that two types can be stored in different components in the same location. +// They must be the same type, except signed/unsigned integers are considered compatible. +static bool checkCompatibleTypes(TBasicType t1, TBasicType t2) { + if (t1 != t2) { + if ((t1 == EbtInt8 && t2 == EbtUint8) || + (t2 == EbtInt8 && t1 == EbtUint8) || + (t1 == EbtInt16 && t2 == EbtUint16) || + (t2 == EbtInt16 && t1 == EbtUint16)|| + (t1 == EbtInt && t2 == EbtUint) || + (t2 == EbtInt && t1 == EbtUint)|| + (t1 == EbtInt64 && t2 == EbtUint64) || + (t2 == EbtInt64 && t1 == EbtUint64)) { + return true; + } + } + return t1 == t2; +} + // Compare a new (the passed in) 'range' against the existing set, and see // if there are any collisions. // @@ -1748,7 +1796,13 @@ int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TTyp if (range.overlap(usedIo[set][r])) { // there is a collision; pick one return std::max(range.location.start, usedIo[set][r].location.start); - } else if (range.location.overlap(usedIo[set][r].location) && type.getBasicType() != usedIo[set][r].basicType) { + } else if (range.location.overlap(usedIo[set][r].location) && + (!checkCompatibleTypes(type.getBasicType(), usedIo[set][r].basicType) || + type.getQualifier().centroid != usedIo[set][r].centroid || + type.getQualifier().smooth != usedIo[set][r].smooth || + type.getQualifier().flat != usedIo[set][r].flat || + type.getQualifier().sample != usedIo[set][r].sample || + type.getQualifier().patch != usedIo[set][r].patch)) { // aliased-type mismatch typeCollision = true; return std::max(range.location.start, usedIo[set][r].location.start); @@ -2217,9 +2271,9 @@ int TIntermediate::getBaseAlignment(const TType& type, int& size, int& stride, T } // To aid the basic HLSL rule about crossing vec4 boundaries. -bool TIntermediate::improperStraddle(const TType& type, int size, int offset) +bool TIntermediate::improperStraddle(const TType& type, int size, int offset, bool vectorLike) { - if (! type.isVector() || type.isArray()) + if (! vectorLike || type.isArray()) return false; return size <= 16 ? offset / 16 != (offset + size - 1) / 16 diff --git a/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h b/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h index db0367f5a..4cf6256c8 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h +++ b/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h @@ -99,7 +99,8 @@ private: // A "call" is a pair: . // There can be duplicates. General assumption is the list is small. struct TCall { - TCall(const TString& pCaller, const TString& pCallee) : caller(pCaller), callee(pCallee) { } + TCall(const TString& pCaller, const TString& pCallee) + : caller(pCaller), callee(pCallee), visited(false), currentPath(false), errorGiven(false) { } TString caller; TString callee; bool visited; @@ -123,8 +124,10 @@ struct TRange { // within the same location range, component range, and index value. Locations don't alias unless // all other dimensions of their range overlap. struct TIoRange { - TIoRange(TRange location, TRange component, TBasicType basicType, int index) - : location(location), component(component), basicType(basicType), index(index) { } + TIoRange(TRange location, TRange component, TBasicType basicType, int index, bool centroid, bool smooth, bool flat, bool sample, bool patch) + : location(location), component(component), basicType(basicType), index(index), centroid(centroid), smooth(smooth), flat(flat), sample(sample), patch(patch) + { + } bool overlap(const TIoRange& rhs) const { return location.overlap(rhs.location) && component.overlap(rhs.component) && index == rhs.index; @@ -133,6 +136,11 @@ struct TIoRange { TRange component; TBasicType basicType; int index; + bool centroid; + bool smooth; + bool flat; + bool sample; + bool patch; }; // An offset range is a 2-D rectangle; the set of (binding, offset) pairs all lying @@ -724,6 +732,11 @@ public: usePhysicalStorageBuffer = true; } bool usingPhysicalStorageBuffer() const { return usePhysicalStorageBuffer; } + void setReplicatedComposites() + { + useReplicatedComposites = true; + } + bool usingReplicatedComposites() const { return useReplicatedComposites; } void setUseVariablePointers() { useVariablePointers = true; @@ -1037,7 +1050,7 @@ public: void mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& unit, bool mergeExistingOnly); void mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit); - void checkStageIO(TInfoSink&, TIntermediate&); + void checkStageIO(EShMessages, TInfoSink&, TIntermediate&); bool buildConvertOp(TBasicType dst, TBasicType src, TOperator& convertOp) const; TIntermTyped* createConversion(TBasicType convertTo, TIntermTyped* node) const; @@ -1057,7 +1070,7 @@ public: static int getBaseAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); static int getScalarAlignment(const TType&, int& size, int& stride, bool rowMajor); static int getMemberAlignment(const TType&, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor); - static bool improperStraddle(const TType& type, int size, int offset); + static bool improperStraddle(const TType& type, int size, int offset, bool vectorLike); static void updateOffset(const TType& parentType, const TType& memberType, int& offset, int& memberSize); static int getOffset(const TType& type, int index); static int getBlockSize(const TType& blockType); @@ -1237,6 +1250,7 @@ protected: bool subgroupUniformControlFlow; bool maximallyReconverges; bool usePhysicalStorageBuffer; + bool useReplicatedComposites { false }; TSpirvRequirement* spirvRequirement; TSpirvExecutionMode* spirvExecutionMode; @@ -1251,7 +1265,7 @@ protected: std::unordered_set usedConstantId; // specialization constant ids used std::vector usedAtomics; // sets of bindings used by atomic counters - std::vector usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers + std::vector usedIo[5]; // sets of used locations, one for each of in, out, uniform, and buffers std::vector usedIoRT[4]; // sets of used location, one for rayPayload/rayPayloadIN, // one for callableData/callableDataIn, one for hitObjectAttributeNV and // one for shaderrecordhitobjectNV diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp index 5f18c4e92..56f1f0b38 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -374,7 +374,7 @@ namespace { int op_div(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a / b; } int op_mod(int a, int b) { return a == INT_MIN && b == -1 ? 0 : a % b; } int op_pos(int a) { return a; } - int op_neg(int a) { return -a; } + int op_neg(int a) { return a == INT_MIN ? INT_MIN : -a; } int op_cmpl(int a) { return ~a; } int op_not(int a) { return !a; } diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp index 34dec2076..49dafa59a 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -220,7 +220,9 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) } if (ch >= '0' && ch <= '9') { while (ch >= '0' && ch <= '9') { - exponent = exponent * 10 + (ch - '0'); + if (exponent < 500) { + exponent = exponent * 10 + (ch - '0'); + } saveName(ch); ch = getChar(); } diff --git a/src/libraries/glslang/glslang/Public/ShaderLang.h b/src/libraries/glslang/glslang/Public/ShaderLang.h index a6eb53b20..282063d14 100644 --- a/src/libraries/glslang/glslang/Public/ShaderLang.h +++ b/src/libraries/glslang/glslang/Public/ShaderLang.h @@ -271,6 +271,8 @@ enum EShMessages : unsigned { EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table EShMsgEnhanced = (1 << 15), // enhanced message readability EShMsgAbsolutePath = (1 << 16), // Output Absolute path for messages + EShMsgDisplayErrorColumn = (1 << 17), // Display error message column aswell as line + EshMsgCrossStageIO = (1 << 30), // Always validate cross-stage IO LAST_ELEMENT_MARKER(EShMsgCount), }; @@ -747,6 +749,8 @@ public: GLSLANG_EXPORT void dump() const; static TObjectReflection badReflection() { return TObjectReflection(); } + GLSLANG_EXPORT unsigned int layoutLocation() const; + std::string name; int offset; int glDefineType;