diff options
Diffstat (limited to '3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp')
-rw-r--r-- | 3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp | 1102 |
1 files changed, 1022 insertions, 80 deletions
diff --git a/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp b/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp index bd208952e02..7c5ea874ba2 100644 --- a/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp +++ b/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp @@ -1,6 +1,7 @@ // // Copyright (C) 2014-2015 LunarG, Inc. // Copyright (C) 2015-2018 Google, Inc. +// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. // @@ -58,12 +59,15 @@ namespace spv { Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) : spvVersion(spvVersion), - source(SourceLanguageUnknown), + sourceLang(SourceLanguageUnknown), sourceVersion(0), sourceFileStringId(NoResult), currentLine(0), currentFile(nullptr), + currentFileId(NoResult), + lastDebugScopeId(NoResult), emitOpLines(false), + emitNonSemanticShaderDebugInfo(false), addressModel(AddressingModelLogical), memoryModel(MemoryModelGLSL450), builderNumber(magicNumber), @@ -97,8 +101,12 @@ void Builder::setLine(int lineNum) { if (lineNum != 0 && lineNum != currentLine) { currentLine = lineNum; - if (emitOpLines) - addLine(sourceFileStringId, currentLine, 0); + if (emitOpLines) { + if (emitNonSemanticShaderDebugInfo) + addDebugScopeAndLine(currentFileId, currentLine, 0); + else + addLine(sourceFileStringId, currentLine, 0); + } } } @@ -117,7 +125,10 @@ void Builder::setLine(int lineNum, const char* filename) currentFile = filename; if (emitOpLines) { spv::Id strId = getStringId(filename); - addLine(strId, currentLine, 0); + if (emitNonSemanticShaderDebugInfo) + addDebugScopeAndLine(strId, currentLine, 0); + else + addLine(strId, currentLine, 0); } } } @@ -131,22 +142,49 @@ void Builder::addLine(Id fileName, int lineNum, int column) buildPoint->addInstruction(std::unique_ptr<Instruction>(line)); } +void Builder::addDebugScopeAndLine(Id fileName, int lineNum, int column) +{ + if (currentDebugScopeId.top() != lastDebugScopeId) { + spv::Id resultId = getUniqueId(); + Instruction* scopeInst = new Instruction(resultId, makeVoidType(), OpExtInst); + scopeInst->addIdOperand(nonSemanticShaderDebugInfo); + scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope); + scopeInst->addIdOperand(currentDebugScopeId.top()); + buildPoint->addInstruction(std::unique_ptr<Instruction>(scopeInst)); + lastDebugScopeId = currentDebugScopeId.top(); + } + spv::Id resultId = getUniqueId(); + Instruction* lineInst = new Instruction(resultId, makeVoidType(), OpExtInst); + lineInst->addIdOperand(nonSemanticShaderDebugInfo); + lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine); + lineInst->addIdOperand(makeDebugSource(fileName)); + lineInst->addIdOperand(makeUintConstant(lineNum)); + lineInst->addIdOperand(makeUintConstant(lineNum)); + lineInst->addIdOperand(makeUintConstant(column)); + lineInst->addIdOperand(makeUintConstant(column)); + buildPoint->addInstruction(std::unique_ptr<Instruction>(lineInst)); +} + // For creating new groupedTypes (will return old type if the requested one was already made). Id Builder::makeVoidType() { Instruction* type; if (groupedTypes[OpTypeVoid].size() == 0) { - type = new Instruction(getUniqueId(), NoType, OpTypeVoid); + Id typeId = getUniqueId(); + type = new Instruction(typeId, NoType, OpTypeVoid); groupedTypes[OpTypeVoid].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + // Core OpTypeVoid used for debug void type + if (emitNonSemanticShaderDebugInfo) + debugId[typeId] = typeId; } else type = groupedTypes[OpTypeVoid].back(); return type->getResultId(); } -Id Builder::makeBoolType() +Id Builder::makeBoolType(bool const compilerGenerated) { Instruction* type; if (groupedTypes[OpTypeBool].size() == 0) { @@ -157,6 +195,12 @@ Id Builder::makeBoolType() } else type = groupedTypes[OpTypeBool].back(); + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) + { + auto const debugResultId = makeBoolDebugType(32); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -171,6 +215,12 @@ Id Builder::makeSamplerType() } else type = groupedTypes[OpTypeSampler].back(); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -267,6 +317,12 @@ Id Builder::makeIntegerType(int width, bool hasSign) break; } + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeIntegerDebugType(width, hasSign); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -304,6 +360,12 @@ Id Builder::makeFloatType(int width) break; } + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeFloatDebugType(width); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -311,7 +373,7 @@ Id Builder::makeFloatType(int width) // See makeStructResultType() for non-decorated structs // needed as the result of some instructions, which does // check for duplicates. -Id Builder::makeStructType(const std::vector<Id>& members, const char* name) +Id Builder::makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated) { // Don't look for previous one, because in the general case, // structs can be duplicated except for decorations. @@ -325,6 +387,12 @@ Id Builder::makeStructType(const std::vector<Id>& members, const char* name) module.mapInstruction(type); addName(type->getResultId(), name); + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) + { + auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -371,6 +439,12 @@ Id Builder::makeVectorType(Id component, int size) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeVectorDebugType(component, size); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -397,6 +471,12 @@ Id Builder::makeMatrixType(Id component, int cols, int rows) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeMatrixDebugType(column, cols); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -426,6 +506,37 @@ Id Builder::makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols) return type->getResultId(); } +Id Builder::makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedTypes[opcode].size(); ++t) { + type = groupedTypes[opcode][t]; + if (static_cast<size_t>(type->getNumOperands()) != operands.size()) + continue; // Number mismatch, find next + + bool match = true; + for (int op = 0; match && op < (int)operands.size(); ++op) { + match = (operands[op].isId ? type->getIdOperand(op) : type->getImmediateOperand(op)) == operands[op].word; + } + if (match) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), NoType, opcode); + for (size_t op = 0; op < operands.size(); ++op) { + if (operands[op].isId) + type->addIdOperand(operands[op].word); + else + type->addImmediateOperand(operands[op].word); + } + groupedTypes[opcode].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} // TODO: performance: track arrays per stride // If a stride is supplied (non-zero) make an array. @@ -452,6 +563,12 @@ Id Builder::makeArrayType(Id element, Id sizeId, int stride) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeArrayDebugType(element, sizeId); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -462,6 +579,12 @@ Id Builder::makeRuntimeArray(Id element) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0)); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -481,11 +604,25 @@ Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes) } } if (! mismatch) + { + // If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void) + // function type is created for the wrapper function. However, nonsemantic shader debug information is disabled + // while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create + // the associated debug function type if it hasn't been created yet. + if(emitNonSemanticShaderDebugInfo && debugId[type->getResultId()] == 0) { + assert(sourceLang == spv::SourceLanguageHLSL); + assert(getTypeClass(returnType) == OpTypeVoid && paramTypes.size() == 0); + + Id debugTypeId = makeDebugFunctionType(returnType, {}); + debugId[type->getResultId()] = debugTypeId; + } return type->getResultId(); + } } // not found, make it - type = new Instruction(getUniqueId(), NoType, OpTypeFunction); + Id typeId = getUniqueId(); + type = new Instruction(typeId, NoType, OpTypeFunction); type->addIdOperand(returnType); for (int p = 0; p < (int)paramTypes.size(); ++p) type->addIdOperand(paramTypes[p]); @@ -493,10 +630,36 @@ Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + // make debug type and map it + if (emitNonSemanticShaderDebugInfo) { + Id debugTypeId = makeDebugFunctionType(returnType, paramTypes); + debugId[typeId] = debugTypeId; + } + return type->getResultId(); } -Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) +Id Builder::makeDebugFunctionType(Id returnType, const std::vector<Id>& paramTypes) +{ + assert(debugId[returnType] != 0); + + Id typeId = getUniqueId(); + auto type = new Instruction(typeId, makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction); + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); + type->addIdOperand(debugId[returnType]); + for (auto const paramType : paramTypes) { + assert(isPointerType(paramType) || isArrayType(paramType)); + type->addIdOperand(debugId[getContainedTypeId(paramType)]); + } + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + return typeId; +} + +Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, + ImageFormat format) { assert(sampled == 1 || sampled == 2); @@ -576,6 +739,22 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo } #endif + if (emitNonSemanticShaderDebugInfo) + { + auto TypeName = [&dim]() -> char const* { + switch (dim) { + case Dim1D: return "type.1d.image"; + case Dim2D: return "type.2d.image"; + case Dim3D: return "type.3d.image"; + case DimCube: return "type.cube.image"; + default: return "type.image"; + } + }; + + auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -597,20 +776,402 @@ Id Builder::makeSampledImageType(Id imageType) constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true); + debugId[type->getResultId()] = debugResultId; + } + + return type->getResultId(); +} + +Id Builder::makeDebugInfoNone() +{ + if (debugInfoNone != 0) + return debugInfoNone; + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone); + + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); + module.mapInstruction(inst); + + debugInfoNone = inst->getResultId(); + + return debugInfoNone; +} + +Id Builder::makeBoolDebugType(int const size) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == getStringId("bool") && + type->getIdOperand(1) == static_cast<unsigned int>(size) && + type->getIdOperand(2) == NonSemanticShaderDebugInfo100Boolean) + return type->getResultId(); + } + + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + + type->addIdOperand(getStringId("bool")); // name id + type->addIdOperand(makeUintConstant(size)); // size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); // encoding id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeIntegerDebugType(int const width, bool const hasSign) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == (hasSign ? getStringId("int") : getStringId("uint")) && + type->getIdOperand(1) == static_cast<unsigned int>(width) && + type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfo100Signed : NonSemanticShaderDebugInfo100Unsigned)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + if(hasSign == true) { + type->addIdOperand(getStringId("int")); // name id + } else { + type->addIdOperand(getStringId("uint")); // name id + } + type->addIdOperand(makeUintConstant(width)); // size id + if(hasSign == true) { + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); // encoding id + } else { + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); // encoding id + } + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeFloatDebugType(int const width) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == getStringId("float") && + type->getIdOperand(1) == static_cast<unsigned int>(width) && + type->getIdOperand(2) == NonSemanticShaderDebugInfo100Float) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + type->addIdOperand(getStringId("float")); // name id + type->addIdOperand(makeUintConstant(width)); // size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); // encoding id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + return type->getResultId(); } +Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType) +{ + assert(sequenceType == NonSemanticShaderDebugInfo100DebugTypeArray || + sequenceType == NonSemanticShaderDebugInfo100DebugTypeVector); + + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) { + type = groupedDebugTypes[sequenceType][t]; + if (type->getIdOperand(0) == baseType && + type->getIdOperand(1) == makeUintConstant(componentCount)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(sequenceType); + type->addIdOperand(debugId[baseType]); // base type + type->addIdOperand(componentCount); // component count + + groupedDebugTypes[sequenceType].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeArrayDebugType(Id const baseType, Id const componentCount) +{ + return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfo100DebugTypeArray); +} + +Id Builder::makeVectorDebugType(Id const baseType, int const componentCount) +{ + return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfo100DebugTypeVector);; +} + +Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix][t]; + if (type->getIdOperand(0) == vectorType && + type->getIdOperand(1) == makeUintConstant(vectorCount)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix); + type->addIdOperand(debugId[vectorType]); // vector type id + type->addIdOperand(makeUintConstant(vectorCount)); // component count id + type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc) +{ + assert(debugId[memberType] != 0); + + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember); + type->addIdOperand(getStringId(debugTypeLoc.name)); // name id + type->addIdOperand(debugId[memberType]); // type id + type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives + type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero + type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id + type->addIdOperand(makeUintConstant(0)); // TODO: offset id + type->addIdOperand(makeUintConstant(0)); // TODO: size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +// Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be +// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names. +Id Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name, + NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType) +{ + // Create the debug member types. + std::vector<Id> memberDebugTypes; + for(auto const memberType : memberTypes) { + assert(debugTypeLocs.find(memberType) != debugTypeLocs.end()); + + memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType])); + + // TODO: Need to rethink this method of passing location information. + // debugTypeLocs.erase(memberType); + } + + // Create The structure debug type. + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite); + type->addIdOperand(getStringId(name)); // name id + type->addIdOperand(makeUintConstant(tag)); // tag id + type->addIdOperand(makeDebugSource(sourceFileStringId)); // source id TODO: verify this works across include directives + type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? + type->addIdOperand(makeUintConstant(0)); // TODO: column id + type->addIdOperand(makeDebugCompilationUnit()); // scope id + if(isOpaqueType == true) { + // Prepend '@' to opaque types. + type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id + type->addIdOperand(makeDebugInfoNone()); // size id + } else { + type->addIdOperand(getStringId(name)); // linkage name id + type->addIdOperand(makeUintConstant(0)); // TODO: size id + } + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id + assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty())); + for(auto const memberDebugType : memberDebugTypes) { + type->addIdOperand(memberDebugType); + } + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(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->addIdOperand(nonSemanticShaderDebugInfo); + sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource); + sourceInst->addIdOperand(fileName); + if (emitNonSemanticShaderDebugSource) { + spv::Id sourceId = 0; + if (fileName == sourceFileStringId) { + sourceId = getStringId(sourceText); + } else { + auto incItr = includeFiles.find(fileName); + assert(incItr != includeFiles.end()); + sourceId = getStringId(*incItr->second); + } + sourceInst->addIdOperand(sourceId); + } + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst)); + module.mapInstruction(sourceInst); + debugSourceId[fileName] = resultId; + return resultId; +} + +Id Builder::makeDebugCompilationUnit() { + if (nonSemanticShaderCompilationUnitId != 0) + return nonSemanticShaderCompilationUnitId; + spv::Id resultId = getUniqueId(); + Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst); + sourceInst->addIdOperand(nonSemanticShaderDebugInfo); + sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit); + sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number + sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number + sourceInst->addIdOperand(makeDebugSource(sourceFileStringId)); + sourceInst->addIdOperand(makeUintConstant(sourceLang)); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst)); + module.mapInstruction(sourceInst); + nonSemanticShaderCompilationUnitId = resultId; + return resultId; +} + +Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable) +{ + assert(type != 0); + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable); + inst->addIdOperand(getStringId(name)); // name id + inst->addIdOperand(type); // type id + inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id + inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? + inst->addIdOperand(makeUintConstant(0)); // TODO: column id + inst->addIdOperand(makeDebugCompilationUnit()); // scope id + inst->addIdOperand(getStringId(name)); // linkage name id + inst->addIdOperand(variable); // variable id + inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); // flags id + + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); + module.mapInstruction(inst); + + return inst->getResultId(); +} + +Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber) +{ + assert(name != nullptr); + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable); + inst->addIdOperand(getStringId(name)); // name id + inst->addIdOperand(type); // type id + inst->addIdOperand(makeDebugSource(sourceFileStringId)); // source id + inst->addIdOperand(makeUintConstant(currentLine)); // line id + inst->addIdOperand(makeUintConstant(0)); // TODO: column id + inst->addIdOperand(currentDebugScopeId.top()); // scope id + inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id + if(argNumber != 0) { + inst->addIdOperand(makeUintConstant(argNumber)); + } + + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); + module.mapInstruction(inst); + + return inst->getResultId(); +} + +Id Builder::makeDebugExpression() +{ + if (debugExpression != 0) + return debugExpression; + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression); + + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); + module.mapInstruction(inst); + + debugExpression = inst->getResultId(); + + return debugExpression; +} + +Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const localVariable) +{ + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare); + inst->addIdOperand(debugLocalVariable); // debug local variable id + inst->addIdOperand(localVariable); // local variable id + inst->addIdOperand(makeDebugExpression()); // expression id + buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); + + return inst->getResultId(); +} + #ifndef GLSLANG_WEB -Id Builder::makeAccelerationStructureNVType() +Id Builder::makeAccelerationStructureType() +{ + Instruction *type; + if (groupedTypes[OpTypeAccelerationStructureKHR].size() == 0) { + type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureKHR); + groupedTypes[OpTypeAccelerationStructureKHR].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + } else { + type = groupedTypes[OpTypeAccelerationStructureKHR].back(); + } + + return type->getResultId(); +} + +Id Builder::makeRayQueryType() { Instruction *type; - if (groupedTypes[OpTypeAccelerationStructureNV].size() == 0) { - type = new Instruction(getUniqueId(), NoType, OpTypeAccelerationStructureNV); - groupedTypes[OpTypeAccelerationStructureNV].push_back(type); + if (groupedTypes[OpTypeRayQueryKHR].size() == 0) { + type = new Instruction(getUniqueId(), NoType, OpTypeRayQueryKHR); + groupedTypes[OpTypeRayQueryKHR].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); module.mapInstruction(type); } else { - type = groupedTypes[OpTypeAccelerationStructureNV].back(); + type = groupedTypes[OpTypeRayQueryKHR].back(); } return type->getResultId(); @@ -726,6 +1287,26 @@ Id Builder::getContainedTypeId(Id typeId, int member) const } } +// Figure out the final resulting type of the access chain. +Id Builder::getResultingAccessChainType() const +{ + assert(accessChain.base != NoResult); + Id typeId = getTypeId(accessChain.base); + + assert(isPointerType(typeId)); + typeId = getContainedTypeId(typeId); + + for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) { + if (isStructType(typeId)) { + assert(isConstantScalar(accessChain.indexChain[i])); + typeId = getContainedTypeId(typeId, getConstantScalar(accessChain.indexChain[i])); + } else + typeId = getContainedTypeId(typeId, accessChain.indexChain[i]); + } + + return typeId; +} + // Return the immediately contained type of a given composite type. Id Builder::getContainedTypeId(Id typeId) const { @@ -852,6 +1433,41 @@ bool Builder::isSpecConstantOpCode(Op opcode) const } } +bool Builder::isRayTracingOpCode(Op opcode) const +{ + switch (opcode) { + case OpTypeAccelerationStructureKHR: + case OpTypeRayQueryKHR: + return true; + default: + return false; + } +} + +Id Builder::makeNullConstant(Id typeId) +{ + Instruction* constant; + + // See if we already made it. + Id existing = NoResult; + for (int i = 0; i < (int)nullConstants.size(); ++i) { + constant = nullConstants[i]; + if (constant->getTypeId() == typeId) + existing = constant->getResultId(); + } + + if (existing != NoResult) + return existing; + + // Make it + Instruction* c = new Instruction(getUniqueId(), typeId, OpConstantNull); + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); + nullConstants.push_back(c); + module.mapInstruction(c); + + return c->getResultId(); +} + Id Builder::makeBoolConstant(bool b, bool specConstant) { Id typeId = makeBoolType(); @@ -1044,6 +1660,19 @@ Id Builder::makeFpConstant(Id type, double d, bool specConstant) return NoResult; } +Id Builder::importNonSemanticShaderDebugInfoInstructions() +{ + assert(emitNonSemanticShaderDebugInfo == true); + + if(nonSemanticShaderDebugInfo == 0) + { + this->addExtension(spv::E_SPV_KHR_non_semantic_info); + nonSemanticShaderDebugInfo = this->import("NonSemantic.Shader.DebugInfo.100"); + } + + return nonSemanticShaderDebugInfo; +} + Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector<Id>& comps) { Instruction* constant = 0; @@ -1166,6 +1795,28 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int val executionModes.push_back(std::unique_ptr<Instruction>(instr)); } +void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector<unsigned>& literals) +{ + Instruction* instr = new Instruction(OpExecutionMode); + instr->addIdOperand(entryPoint->getId()); + instr->addImmediateOperand(mode); + for (auto literal : literals) + instr->addImmediateOperand(literal); + + executionModes.push_back(std::unique_ptr<Instruction>(instr)); +} + +void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector<Id>& operandIds) +{ + Instruction* instr = new Instruction(OpExecutionModeId); + instr->addIdOperand(entryPoint->getId()); + instr->addImmediateOperand(mode); + for (auto operandId : operandIds) + instr->addIdOperand(operandId); + + executionModes.push_back(std::unique_ptr<Instruction>(instr)); +} + void Builder::addName(Id id, const char* string) { Instruction* name = new Instruction(OpName); @@ -1204,7 +1855,7 @@ void Builder::addDecoration(Id id, Decoration decoration, const char* s) if (decoration == spv::DecorationMax) return; - Instruction* dec = new Instruction(OpDecorateStringGOOGLE); + Instruction* dec = new Instruction(OpDecorateString); dec->addIdOperand(id); dec->addImmediateOperand(decoration); dec->addStringOperand(s); @@ -1212,6 +1863,34 @@ void Builder::addDecoration(Id id, Decoration decoration, const char* s) decorations.push_back(std::unique_ptr<Instruction>(dec)); } +void Builder::addDecoration(Id id, Decoration decoration, const std::vector<unsigned>& literals) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorate); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + for (auto literal : literals) + dec->addImmediateOperand(literal); + + decorations.push_back(std::unique_ptr<Instruction>(dec)); +} + +void Builder::addDecoration(Id id, Decoration decoration, const std::vector<const char*>& strings) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateString); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + for (auto string : strings) + dec->addStringOperand(string); + + decorations.push_back(std::unique_ptr<Instruction>(dec)); +} + void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) { if (decoration == spv::DecorationMax) @@ -1225,6 +1904,21 @@ void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) decorations.push_back(std::unique_ptr<Instruction>(dec)); } +void Builder::addDecorationId(Id id, Decoration decoration, const std::vector<Id>& operandIds) +{ + if(decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpDecorateId); + dec->addIdOperand(id); + dec->addImmediateOperand(decoration); + + for (auto operandId : operandIds) + dec->addIdOperand(operandId); + + decorations.push_back(std::unique_ptr<Instruction>(dec)); +} + void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, int num) { if (decoration == spv::DecorationMax) @@ -1254,41 +1948,114 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat decorations.push_back(std::unique_ptr<Instruction>(dec)); } +void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<unsigned>& literals) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpMemberDecorate); + dec->addIdOperand(id); + dec->addImmediateOperand(member); + dec->addImmediateOperand(decoration); + for (auto literal : literals) + dec->addImmediateOperand(literal); + + decorations.push_back(std::unique_ptr<Instruction>(dec)); +} + +void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const std::vector<const char*>& strings) +{ + if (decoration == spv::DecorationMax) + return; + + Instruction* dec = new Instruction(OpMemberDecorateString); + dec->addIdOperand(id); + dec->addImmediateOperand(member); + dec->addImmediateOperand(decoration); + for (auto string : strings) + dec->addStringOperand(string); + + decorations.push_back(std::unique_ptr<Instruction>(dec)); +} + // Comments in header Function* Builder::makeEntryPoint(const char* entryPoint) { assert(! entryPointFunction); Block* entry; - std::vector<Id> params; + std::vector<Id> paramsTypes; + std::vector<char const*> paramNames; std::vector<std::vector<Decoration>> decorations; - entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry); + auto const returnType = makeVoidType(); + + restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo; + if(sourceLang == spv::SourceLanguageHLSL) { + emitNonSemanticShaderDebugInfo = false; + } + + entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, paramsTypes, paramNames, decorations, &entry); + + emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo; return entryPointFunction; } // Comments in header Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, - const std::vector<Id>& paramTypes, const std::vector<std::vector<Decoration>>& decorations, Block **entry) + const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames, + const std::vector<std::vector<Decoration>>& decorations, Block **entry) { // Make the function and initial instructions in it Id typeId = makeFunctionType(returnType, paramTypes); Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size()); - Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module); + Id funcId = getUniqueId(); + Function* function = new Function(funcId, returnType, typeId, firstParamId, module); // Set up the precisions setPrecision(function->getId(), precision); + function->setReturnPrecision(precision); for (unsigned p = 0; p < (unsigned)decorations.size(); ++p) { - for (int d = 0; d < (int)decorations[p].size(); ++d) + for (int d = 0; d < (int)decorations[p].size(); ++d) { addDecoration(firstParamId + p, decorations[p][d]); + function->addParamPrecision(p, decorations[p][d]); + } + } + + // Make the debug function instruction + if (emitNonSemanticShaderDebugInfo) { + Id nameId = getStringId(unmangleFunctionName(name)); + Id debugFuncId = makeDebugFunction(function, nameId, typeId); + debugId[funcId] = debugFuncId; + currentDebugScopeId.push(debugFuncId); + lastDebugScopeId = NoResult; } // CFG - if (entry) { - *entry = new Block(getUniqueId(), *function); - function->addBlock(*entry); - setBuildPoint(*entry); + assert(entry != nullptr); + *entry = new Block(getUniqueId(), *function); + function->addBlock(*entry); + setBuildPoint(*entry); + + // DebugScope and DebugLine for parameter DebugDeclares + if (emitNonSemanticShaderDebugInfo && (int)paramTypes.size() > 0) { + addDebugScopeAndLine(currentFileId, currentLine, 0); + } + + if (emitNonSemanticShaderDebugInfo) { + assert(paramTypes.size() == paramNames.size()); + for(size_t p = 0; p < paramTypes.size(); ++p) + { + auto const& paramType = paramTypes[p]; + assert(isPointerType(paramType) || isArrayType(paramType)); + assert(debugId[getContainedTypeId(paramType)] != 0); + auto const& paramName = paramNames[p]; + auto const debugLocalVariableId = createDebugLocalVariable(debugId[getContainedTypeId(paramType)], paramName, p+1); + debugId[firstParamId + p] = debugLocalVariableId; + + makeDebugDeclare(debugLocalVariableId, firstParamId + p); + } } if (name) @@ -1296,9 +2063,62 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const functions.push_back(std::unique_ptr<Function>(function)); + // Clear debug scope stack + if (emitNonSemanticShaderDebugInfo) + currentDebugScopeId.pop(); + return function; } +Id Builder::makeDebugFunction(Function* function, Id nameId, Id funcTypeId) { + assert(function != nullptr); + assert(nameId != 0); + assert(funcTypeId != 0); + assert(debugId[funcTypeId] != 0); + + Id funcId = getUniqueId(); + auto type = new Instruction(funcId, makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction); + type->addIdOperand(nameId); + type->addIdOperand(debugId[funcTypeId]); + type->addIdOperand(makeDebugSource(currentFileId)); // Will be fixed later when true filename available + type->addIdOperand(makeUintConstant(currentLine)); // Will be fixed later when true line available + type->addIdOperand(makeUintConstant(0)); // column + type->addIdOperand(makeDebugCompilationUnit()); // scope + type->addIdOperand(nameId); // linkage name + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); + type->addIdOperand(makeUintConstant(currentLine)); // TODO(greg-lunarg): correct scope line + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); + module.mapInstruction(type); + return funcId; +} + +Id Builder::makeDebugLexicalBlock(uint32_t line) { + Id lexId = getUniqueId(); + auto lex = new Instruction(lexId, makeVoidType(), OpExtInst); + lex->addIdOperand(nonSemanticShaderDebugInfo); + lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock); + lex->addIdOperand(makeDebugSource(currentFileId)); + lex->addIdOperand(makeUintConstant(line)); + lex->addIdOperand(makeUintConstant(0)); // column + lex->addIdOperand(currentDebugScopeId.top()); // scope + constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(lex)); + module.mapInstruction(lex); + return lexId; +} + +std::string Builder::unmangleFunctionName(std::string const& name) const +{ + assert(name.length() > 0); + + if(name.rfind('(') != std::string::npos) { + return name.substr(0, name.rfind('(')); + } else { + return name; + } +} + // Comments in header void Builder::makeReturn(bool implicit, Id retVal) { @@ -1314,6 +2134,48 @@ void Builder::makeReturn(bool implicit, Id retVal) } // Comments in header +void Builder::enterScope(uint32_t line) +{ + // Generate new lexical scope debug instruction + Id lexId = makeDebugLexicalBlock(line); + currentDebugScopeId.push(lexId); + lastDebugScopeId = NoResult; +} + +// Comments in header +void Builder::leaveScope() +{ + // Pop current scope from stack and clear current scope + currentDebugScopeId.pop(); + lastDebugScopeId = NoResult; +} + +// Comments in header +void Builder::enterFunction(Function const* function) +{ + // Save and disable debugInfo for HLSL entry point function. It is a wrapper + // function with no user code in it. + restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo; + if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) { + emitNonSemanticShaderDebugInfo = false; + } + + if (emitNonSemanticShaderDebugInfo) { + // Initialize scope state + Id funcId = function->getFuncId(); + currentDebugScopeId.push(debugId[funcId]); + // Create DebugFunctionDefinition + spv::Id resultId = getUniqueId(); + Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst); + defInst->addIdOperand(nonSemanticShaderDebugInfo); + defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition); + defInst->addIdOperand(debugId[funcId]); + defInst->addIdOperand(funcId); + buildPoint->addInstruction(std::unique_ptr<Instruction>(defInst)); + } +} + +// Comments in header void Builder::leaveFunction() { Block* block = buildPoint; @@ -1328,17 +2190,34 @@ void Builder::leaveFunction() makeReturn(true, createUndefined(function.getReturnType())); } } + + // Clear function scope from debug scope stack + if (emitNonSemanticShaderDebugInfo) + currentDebugScopeId.pop(); + + emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo; } // Comments in header -void Builder::makeDiscard() +void Builder::makeStatementTerminator(spv::Op opcode, const char *name) { - buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(OpKill))); - createAndSetNoPredecessorBlock("post-discard"); + buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(opcode))); + createAndSetNoPredecessorBlock(name); } // Comments in header -Id Builder::createVariable(StorageClass storageClass, Id type, const char* name, Id initializer) +void Builder::makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name) +{ + // It's assumed that the terminator instruction is always of void return type + // However in future if there is a need for non void return type, new helper + // methods can be created. + createNoResultOp(opcode, operands); + createAndSetNoPredecessorBlock(name); +} + +// Comments in header +Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer, + bool const compilerGenerated) { Id pointerType = makePointer(storageClass, type); Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable); @@ -1350,16 +2229,32 @@ Id Builder::createVariable(StorageClass storageClass, Id type, const char* name, case StorageClassFunction: // Validation rules require the declaration in the entry block buildPoint->getParent().addLocalVariable(std::unique_ptr<Instruction>(inst)); + + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) + { + auto const debugLocalVariableId = createDebugLocalVariable(debugId[type], name); + debugId[inst->getResultId()] = debugLocalVariableId; + + makeDebugDeclare(debugLocalVariableId, inst->getResultId()); + } + break; default: constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(inst)); module.mapInstruction(inst); + + if (emitNonSemanticShaderDebugInfo && !isRayTracingOpCode(getOpCode(type))) + { + auto const debugResultId = createDebugGlobalVariable(debugId[type], name, inst->getResultId()); + debugId[inst->getResultId()] = debugResultId; + } break; } if (name) addName(inst->getResultId(), name); + setPrecision(inst->getResultId(), precision); return inst->getResultId(); } @@ -1373,7 +2268,8 @@ Id Builder::createUndefined(Id type) } // av/vis/nonprivate are unnecessary and illegal for some storage classes. -spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) const +spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) + const { switch (sc) { case spv::StorageClassUniform: @@ -1382,7 +2278,7 @@ spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAc case spv::StorageClassPhysicalStorageBufferEXT: break; default: - memoryAccess = spv::MemoryAccessMask(memoryAccess & + memoryAccess = spv::MemoryAccessMask(memoryAccess & ~(spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask | spv::MemoryAccessNonPrivatePointerKHRMask)); @@ -1392,7 +2288,8 @@ spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAc } // Comments in header -void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, + unsigned int alignment) { Instruction* store = new Instruction(OpStore); store->addIdOperand(lValue); @@ -1414,7 +2311,8 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce } // Comments in header -Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMask memoryAccess, + spv::Scope scope, unsigned int alignment) { Instruction* load = new Instruction(getUniqueId(), getDerefTypeId(lValue), OpLoad); load->addIdOperand(lValue); @@ -1432,6 +2330,7 @@ Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope } buildPoint->addInstruction(std::unique_ptr<Instruction>(load)); + setPrecision(load->getResultId(), precision); return load->getResultId(); } @@ -1440,16 +2339,7 @@ Id Builder::createLoad(Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets) { // Figure out the final resulting type. - spv::Id typeId = getTypeId(base); - assert(isPointerType(typeId) && offsets.size() > 0); - typeId = getContainedTypeId(typeId); - for (int i = 0; i < (int)offsets.size(); ++i) { - if (isStructType(typeId)) { - assert(isConstantScalar(offsets[i])); - typeId = getContainedTypeId(typeId, getConstantScalar(offsets[i])); - } else - typeId = getContainedTypeId(typeId, offsets[i]); - } + Id typeId = getResultingAccessChainType(); typeId = makePointer(storageClass, typeId); // Make the instruction @@ -1495,7 +2385,8 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) // Generate code for spec constants if in spec constant operation // generation mode. if (generatingOpCodeForSpecConst) { - return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), std::vector<Id>(1, index)); + return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), + std::vector<Id>(1, index)); } Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); extract->addIdOperand(composite); @@ -1697,7 +2588,8 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& opera return op->getResultId(); } -Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, const std::vector<unsigned>& literals) +Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector<Id>& operands, + const std::vector<unsigned>& literals) { Instruction* op = new Instruction(getUniqueId(), typeId, OpSpecConstantOp); op->addImmediateOperand((unsigned) opCode); @@ -1862,7 +2754,7 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, texArgs[numArgs++] = parameters.granularity; if (parameters.coarse != NoResult) texArgs[numArgs++] = parameters.coarse; -#endif +#endif // // Set up the optional arguments @@ -2144,7 +3036,7 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b Op op; switch (getMostBasicTypeClass(valueType)) { case OpTypeFloat: - op = equal ? OpFOrdEqual : OpFOrdNotEqual; + op = equal ? OpFOrdEqual : OpFUnordNotEqual; break; case OpTypeInt: default: @@ -2187,7 +3079,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b if (constituent == 0) resultId = subResultId; else - resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), precision); + resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), + precision); } return resultId; @@ -2196,7 +3089,8 @@ Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, b // OpCompositeConstruct Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents) { - assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && getNumTypeConstituents(typeId) == (int)constituents.size())); + assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && + getNumTypeConstituents(typeId) == (int)constituents.size())); if (generatingOpCodeForSpecConst) { // Sometime, even in spec-constant-op mode, the constant composite to be @@ -2394,7 +3288,7 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& int row = 0; int col = 0; - for (int arg = 0; arg < (int)sources.size(); ++arg) { + for (int arg = 0; arg < (int)sources.size() && col < numCols; ++arg) { Id argComp = sources[arg]; for (int comp = 0; comp < getNumComponents(sources[arg]); ++comp) { if (getNumComponents(sources[arg]) > 1) { @@ -2406,6 +3300,10 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& row = 0; col++; } + if (col == numCols) { + // If more components are provided than fit the matrix, discard the rest. + break; + } } } } @@ -2609,7 +3507,8 @@ void Builder::clearAccessChain() } // Comments in header -void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, AccessChain::CoherentFlags coherentFlags, unsigned int alignment) +void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, + AccessChain::CoherentFlags coherentFlags, unsigned int alignment) { accessChain.coherentFlags |= coherentFlags; accessChain.alignment |= alignment; @@ -2635,35 +3534,70 @@ void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizz } // Comments in header -void Builder::accessChainStore(Id rvalue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) { assert(accessChain.isRValue == false); transferAccessChainSwizzle(true); - Id base = collapseAccessChain(); - Id source = rvalue; - // dynamic component should be gone - assert(accessChain.component == NoResult); + // 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() && + accessChain.component == NoResult) { + for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { + accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle[i])); + accessChain.instr = NoResult; - // If swizzle still exists, it is out-of-order or not full, we must load the target vector, - // extract and insert elements to perform writeMask and/or swizzle. - if (accessChain.swizzle.size() > 0) { - Id tempBaseId = createLoad(base); - source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); - } + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); + + accessChain.indexChain.pop_back(); + accessChain.instr = NoResult; + + // dynamic component should be gone + assert(accessChain.component == NoResult); + + Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i); + + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } - // take LSB of alignment - alignment = alignment & ~(alignment & (alignment-1)); - if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { - memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + createStore(source, base, memoryAccess, scope, alignment); + } } + else { + Id base = collapseAccessChain(); + addDecoration(base, nonUniform); + + Id source = rvalue; + + // dynamic component should be gone + assert(accessChain.component == NoResult); + + // If swizzle still exists, it may be out-of-order, we must load the target vector, + // extract and insert elements to perform writeMask and/or swizzle. + if (accessChain.swizzle.size() > 0) { + Id tempBaseId = createLoad(base, spv::NoPrecision); + source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); + } - createStore(source, base, memoryAccess, scope, alignment); + // take LSB of alignment + alignment = alignment & ~(alignment & (alignment-1)); + if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { + memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); + } + + createStore(source, base, memoryAccess, scope, alignment); + } } // Comments in header -Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) +Id Builder::accessChainLoad(Decoration precision, Decoration l_nonUniform, + Decoration r_nonUniform, Id resultType, spv::MemoryAccessMask memoryAccess, + spv::Scope scope, unsigned int alignment) { Id id; @@ -2687,17 +3621,19 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu if (constant) { id = createCompositeExtract(accessChain.base, swizzleBase, indexes); + setPrecision(id, precision); } else { Id lValue = NoResult; - if (spvVersion >= Spv_1_4) { + if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) { // make a new function variable for this r-value, using an initializer, // and mark it as NonWritable so that downstream it can be detected as a lookup // table - lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable", - accessChain.base); + lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), + "indexable", accessChain.base); addDecoration(lValue, DecorationNonWritable); } else { - lValue = createVariable(StorageClassFunction, getTypeId(accessChain.base), "indexable"); + lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), + "indexable"); // store into it createStore(accessChain.base, lValue); } @@ -2706,9 +3642,8 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu accessChain.isRValue = false; // load through the access chain - id = createLoad(collapseAccessChain()); + id = createLoad(collapseAccessChain(), precision); } - setPrecision(id, precision); } else id = accessChain.base; // no precision, it was set when this was defined } else { @@ -2721,9 +3656,14 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu } // load through the access chain - id = createLoad(collapseAccessChain(), memoryAccess, scope, alignment); - setPrecision(id, precision); - addDecoration(id, nonUniform); + id = collapseAccessChain(); + // Apply nonuniform both to the access chain and the loaded value. + // Buffer accesses need the access chain decorated, and this is where + // loaded image types get decorated. TODO: This should maybe move to + // createImageTextureFunctionCall. + addDecoration(id, l_nonUniform); + id = createLoad(id, precision, memoryAccess, scope, alignment); + addDecoration(id, r_nonUniform); } // Done, unless there are swizzles to do @@ -2744,7 +3684,7 @@ Id Builder::accessChainLoad(Decoration precision, Decoration nonUniform, Id resu if (accessChain.component != NoResult) id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision); - addDecoration(id, nonUniform); + addDecoration(id, r_nonUniform); return id; } @@ -3034,10 +3974,10 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te const int opSourceWordCount = 4; const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1; - if (source != SourceLanguageUnknown) { + if (sourceLang != SourceLanguageUnknown) { // OpSource Language Version File Source Instruction sourceInst(NoResult, NoType, OpSource); - sourceInst.addImmediateOperand(source); + sourceInst.addImmediateOperand(sourceLang); sourceInst.addImmediateOperand(sourceVersion); // File operand if (fileId != NoResult) { @@ -3070,12 +4010,14 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te // Dump an OpSource[Continued] sequence for the source and every include file void Builder::dumpSourceInstructions(std::vector<unsigned int>& out) const { + if (emitNonSemanticShaderDebugInfo) return; dumpSourceInstructions(sourceFileStringId, sourceText, out); for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr) dumpSourceInstructions(iItr->first, *iItr->second, out); } -void Builder::dumpInstructions(std::vector<unsigned int>& out, const std::vector<std::unique_ptr<Instruction> >& instructions) const +void Builder::dumpInstructions(std::vector<unsigned int>& out, + const std::vector<std::unique_ptr<Instruction> >& instructions) const { for (int i = 0; i < (int)instructions.size(); ++i) { instructions[i]->dump(out); |