summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp')
-rw-r--r--3rdparty/bgfx/3rdparty/glslang/SPIRV/SpvBuilder.cpp1102
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);