| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | #include <cassert> |
| | #include <cstdlib> |
| |
|
| | #include <unordered_set> |
| | #include <algorithm> |
| |
|
| | #include "SpvBuilder.h" |
| |
|
| | #ifndef GLSLANG_WEB |
| | #include "hex_float.h" |
| | #endif |
| |
|
| | #ifndef _WIN32 |
| | #include <cstdio> |
| | #endif |
| |
|
| | namespace spv { |
| |
|
| | Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) : |
| | spvVersion(spvVersion), |
| | sourceLang(SourceLanguageUnknown), |
| | sourceVersion(0), |
| | sourceFileStringId(NoResult), |
| | currentLine(0), |
| | currentFile(nullptr), |
| | currentFileId(NoResult), |
| | lastDebugScopeId(NoResult), |
| | emitOpLines(false), |
| | emitNonSemanticShaderDebugInfo(false), |
| | addressModel(AddressingModelLogical), |
| | memoryModel(MemoryModelGLSL450), |
| | builderNumber(magicNumber), |
| | buildPoint(nullptr), |
| | uniqueId(0), |
| | entryPointFunction(nullptr), |
| | generatingOpCodeForSpecConst(false), |
| | logger(buildLogger) |
| | { |
| | clearAccessChain(); |
| | } |
| |
|
| | Builder::~Builder() |
| | { |
| | } |
| |
|
| | Id Builder::import(const char* name) |
| | { |
| | Instruction* import = new Instruction(getUniqueId(), NoType, OpExtInstImport); |
| | import->addStringOperand(name); |
| | module.mapInstruction(import); |
| |
|
| | imports.push_back(std::unique_ptr<Instruction>(import)); |
| | return import->getResultId(); |
| | } |
| |
|
| | |
| | |
| | |
| | void Builder::setLine(int lineNum) |
| | { |
| | if (lineNum != 0 && lineNum != currentLine) { |
| | currentLine = lineNum; |
| | if (emitOpLines) { |
| | if (emitNonSemanticShaderDebugInfo) |
| | addDebugScopeAndLine(currentFileId, currentLine, 0); |
| | else |
| | addLine(sourceFileStringId, currentLine, 0); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void Builder::setLine(int lineNum, const char* filename) |
| | { |
| | if (filename == nullptr) { |
| | setLine(lineNum); |
| | return; |
| | } |
| | if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr || |
| | strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) { |
| | currentLine = lineNum; |
| | currentFile = filename; |
| | if (emitOpLines) { |
| | spv::Id strId = getStringId(filename); |
| | if (emitNonSemanticShaderDebugInfo) |
| | addDebugScopeAndLine(strId, currentLine, 0); |
| | else |
| | addLine(strId, currentLine, 0); |
| | } |
| | } |
| | } |
| |
|
| | void Builder::addLine(Id fileName, int lineNum, int column) |
| | { |
| | Instruction* line = new Instruction(OpLine); |
| | line->addIdOperand(fileName); |
| | line->addImmediateOperand(lineNum); |
| | line->addImmediateOperand(column); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(line)); |
| | } |
| |
|
| | void Builder::addDebugScopeAndLine(Id fileName, int lineNum, int column) |
| | { |
| | assert(!currentDebugScopeId.empty()); |
| | 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)); |
| | } |
| |
|
| | |
| | Id Builder::makeVoidType() |
| | { |
| | Instruction* type; |
| | if (groupedTypes[OpTypeVoid].size() == 0) { |
| | 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); |
| | |
| | if (emitNonSemanticShaderDebugInfo) |
| | debugId[typeId] = typeId; |
| | } else |
| | type = groupedTypes[OpTypeVoid].back(); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeBoolType(bool const compilerGenerated) |
| | { |
| | Instruction* type; |
| | if (groupedTypes[OpTypeBool].size() == 0) { |
| | type = new Instruction(getUniqueId(), NoType, OpTypeBool); |
| | groupedTypes[OpTypeBool].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| | } else |
| | type = groupedTypes[OpTypeBool].back(); |
| |
|
| | if (emitNonSemanticShaderDebugInfo && !compilerGenerated) |
| | { |
| | auto const debugResultId = makeBoolDebugType(32); |
| | debugId[type->getResultId()] = debugResultId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeSamplerType() |
| | { |
| | Instruction* type; |
| | if (groupedTypes[OpTypeSampler].size() == 0) { |
| | type = new Instruction(getUniqueId(), NoType, OpTypeSampler); |
| | groupedTypes[OpTypeSampler].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| | } else |
| | type = groupedTypes[OpTypeSampler].back(); |
| |
|
| | if (emitNonSemanticShaderDebugInfo) |
| | { |
| | auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true); |
| | debugId[type->getResultId()] = debugResultId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makePointer(StorageClass storageClass, Id pointee) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) { |
| | type = groupedTypes[OpTypePointer][t]; |
| | if (type->getImmediateOperand(0) == (unsigned)storageClass && |
| | type->getIdOperand(1) == pointee) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypePointer); |
| | type->addImmediateOperand(storageClass); |
| | type->addIdOperand(pointee); |
| | groupedTypes[OpTypePointer].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeForwardPointer(StorageClass storageClass) |
| | { |
| | |
| | |
| | |
| | Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeForwardPointer); |
| | type->addImmediateOperand(storageClass); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardPointerType, Id pointee) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypePointer].size(); ++t) { |
| | type = groupedTypes[OpTypePointer][t]; |
| | if (type->getImmediateOperand(0) == (unsigned)storageClass && |
| | type->getIdOperand(1) == pointee) |
| | return type->getResultId(); |
| | } |
| |
|
| | type = new Instruction(forwardPointerType, NoType, OpTypePointer); |
| | type->addImmediateOperand(storageClass); |
| | type->addIdOperand(pointee); |
| | groupedTypes[OpTypePointer].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeIntegerType(int width, bool hasSign) |
| | { |
| | #ifdef GLSLANG_WEB |
| | assert(width == 32); |
| | width = 32; |
| | #endif |
| |
|
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) { |
| | type = groupedTypes[OpTypeInt][t]; |
| | if (type->getImmediateOperand(0) == (unsigned)width && |
| | type->getImmediateOperand(1) == (hasSign ? 1u : 0u)) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeInt); |
| | type->addImmediateOperand(width); |
| | type->addImmediateOperand(hasSign ? 1 : 0); |
| | groupedTypes[OpTypeInt].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | |
| | switch (width) { |
| | case 8: |
| | case 16: |
| | |
| | break; |
| | case 64: |
| | addCapability(CapabilityInt64); |
| | break; |
| | default: |
| | break; |
| | } |
| |
|
| | if (emitNonSemanticShaderDebugInfo) |
| | { |
| | auto const debugResultId = makeIntegerDebugType(width, hasSign); |
| | debugId[type->getResultId()] = debugResultId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeFloatType(int width) |
| | { |
| | #ifdef GLSLANG_WEB |
| | assert(width == 32); |
| | width = 32; |
| | #endif |
| |
|
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) { |
| | type = groupedTypes[OpTypeFloat][t]; |
| | if (type->getImmediateOperand(0) == (unsigned)width) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeFloat); |
| | type->addImmediateOperand(width); |
| | groupedTypes[OpTypeFloat].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | |
| | switch (width) { |
| | case 16: |
| | |
| | break; |
| | case 64: |
| | addCapability(CapabilityFloat64); |
| | break; |
| | default: |
| | break; |
| | } |
| |
|
| | if (emitNonSemanticShaderDebugInfo) |
| | { |
| | auto const debugResultId = makeFloatDebugType(width); |
| | debugId[type->getResultId()] = debugResultId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | Id Builder::makeStructType(const std::vector<Id>& members, const char* name, bool const compilerGenerated) |
| | { |
| | |
| | |
| |
|
| | |
| | Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeStruct); |
| | for (int op = 0; op < (int)members.size(); ++op) |
| | type->addIdOperand(members[op]); |
| | groupedTypes[OpTypeStruct].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| | addName(type->getResultId(), name); |
| |
|
| | if (emitNonSemanticShaderDebugInfo && !compilerGenerated) |
| | { |
| | auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure); |
| | debugId[type->getResultId()] = debugResultId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | |
| | Id Builder::makeStructResultType(Id type0, Id type1) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeStruct].size(); ++t) { |
| | type = groupedTypes[OpTypeStruct][t]; |
| | if (type->getNumOperands() != 2) |
| | continue; |
| | if (type->getIdOperand(0) != type0 || |
| | type->getIdOperand(1) != type1) |
| | continue; |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | std::vector<spv::Id> members; |
| | members.push_back(type0); |
| | members.push_back(type1); |
| |
|
| | return makeStructType(members, "ResType"); |
| | } |
| |
|
| | Id Builder::makeVectorType(Id component, int size) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeVector].size(); ++t) { |
| | type = groupedTypes[OpTypeVector][t]; |
| | if (type->getIdOperand(0) == component && |
| | type->getImmediateOperand(1) == (unsigned)size) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeVector); |
| | type->addIdOperand(component); |
| | type->addImmediateOperand(size); |
| | groupedTypes[OpTypeVector].push_back(type); |
| | 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(); |
| | } |
| |
|
| | Id Builder::makeMatrixType(Id component, int cols, int rows) |
| | { |
| | assert(cols <= maxMatrixSize && rows <= maxMatrixSize); |
| |
|
| | Id column = makeVectorType(component, rows); |
| |
|
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeMatrix].size(); ++t) { |
| | type = groupedTypes[OpTypeMatrix][t]; |
| | if (type->getIdOperand(0) == column && |
| | type->getImmediateOperand(1) == (unsigned)cols) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeMatrix); |
| | type->addIdOperand(column); |
| | type->addImmediateOperand(cols); |
| | groupedTypes[OpTypeMatrix].push_back(type); |
| | 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(); |
| | } |
| |
|
| | Id Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixKHR].size(); ++t) { |
| | type = groupedTypes[OpTypeCooperativeMatrixKHR][t]; |
| | if (type->getIdOperand(0) == component && |
| | type->getIdOperand(1) == scope && |
| | type->getIdOperand(2) == rows && |
| | type->getIdOperand(3) == cols && |
| | type->getIdOperand(4) == use) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixKHR); |
| | type->addIdOperand(component); |
| | type->addIdOperand(scope); |
| | type->addIdOperand(rows); |
| | type->addIdOperand(cols); |
| | type->addIdOperand(use); |
| | groupedTypes[OpTypeCooperativeMatrixKHR].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixNV].size(); ++t) { |
| | type = groupedTypes[OpTypeCooperativeMatrixNV][t]; |
| | if (type->getIdOperand(0) == component && type->getIdOperand(1) == scope && type->getIdOperand(2) == rows && |
| | type->getIdOperand(3) == cols) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixNV); |
| | type->addIdOperand(component); |
| | type->addIdOperand(scope); |
| | type->addIdOperand(rows); |
| | type->addIdOperand(cols); |
| | groupedTypes[OpTypeCooperativeMatrixNV].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType) |
| | { |
| | Instruction* instr = module.getInstruction(otherType); |
| | if (instr->getOpCode() == OpTypeCooperativeMatrixNV) { |
| | return makeCooperativeMatrixTypeNV(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3)); |
| | } else { |
| | assert(instr->getOpCode() == OpTypeCooperativeMatrixKHR); |
| | return makeCooperativeMatrixTypeKHR(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3), instr->getIdOperand(4)); |
| | } |
| | } |
| |
|
| | Id Builder::makeGenericType(spv::Op opcode, std::vector<spv::IdImmediate>& operands) |
| | { |
| | |
| | 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; |
| |
|
| | 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(); |
| | } |
| |
|
| | |
| | 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(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | Id Builder::makeArrayType(Id element, Id sizeId, int stride) |
| | { |
| | Instruction* type; |
| | if (stride == 0) { |
| | |
| | for (int t = 0; t < (int)groupedTypes[OpTypeArray].size(); ++t) { |
| | type = groupedTypes[OpTypeArray][t]; |
| | if (type->getIdOperand(0) == element && |
| | type->getIdOperand(1) == sizeId) |
| | return type->getResultId(); |
| | } |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeArray); |
| | type->addIdOperand(element); |
| | type->addIdOperand(sizeId); |
| | groupedTypes[OpTypeArray].push_back(type); |
| | 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(); |
| | } |
| |
|
| | Id Builder::makeRuntimeArray(Id element) |
| | { |
| | Instruction* type = new Instruction(getUniqueId(), NoType, OpTypeRuntimeArray); |
| | type->addIdOperand(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(); |
| | } |
| |
|
| | Id Builder::makeFunctionType(Id returnType, const std::vector<Id>& paramTypes) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeFunction].size(); ++t) { |
| | type = groupedTypes[OpTypeFunction][t]; |
| | if (type->getIdOperand(0) != returnType || (int)paramTypes.size() != type->getNumOperands() - 1) |
| | continue; |
| | bool mismatch = false; |
| | for (int p = 0; p < (int)paramTypes.size(); ++p) { |
| | if (paramTypes[p] != type->getIdOperand(p + 1)) { |
| | mismatch = true; |
| | break; |
| | } |
| | } |
| | if (! mismatch) |
| | { |
| | |
| | |
| | |
| | |
| | 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(); |
| | } |
| | } |
| |
|
| | |
| | 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]); |
| | groupedTypes[OpTypeFunction].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | |
| | if (emitNonSemanticShaderDebugInfo) { |
| | Id debugTypeId = makeDebugFunctionType(returnType, paramTypes); |
| | debugId[typeId] = debugTypeId; |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | 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) { |
| | if (isPointerType(paramType) || isArrayType(paramType)) { |
| | type->addIdOperand(debugId[getContainedTypeId(paramType)]); |
| | } |
| | else { |
| | type->addIdOperand(debugId[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); |
| |
|
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeImage].size(); ++t) { |
| | type = groupedTypes[OpTypeImage][t]; |
| | if (type->getIdOperand(0) == sampledType && |
| | type->getImmediateOperand(1) == (unsigned int)dim && |
| | type->getImmediateOperand(2) == ( depth ? 1u : 0u) && |
| | type->getImmediateOperand(3) == (arrayed ? 1u : 0u) && |
| | type->getImmediateOperand(4) == ( ms ? 1u : 0u) && |
| | type->getImmediateOperand(5) == sampled && |
| | type->getImmediateOperand(6) == (unsigned int)format) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeImage); |
| | type->addIdOperand(sampledType); |
| | type->addImmediateOperand( dim); |
| | type->addImmediateOperand( depth ? 1 : 0); |
| | type->addImmediateOperand(arrayed ? 1 : 0); |
| | type->addImmediateOperand( ms ? 1 : 0); |
| | type->addImmediateOperand(sampled); |
| | type->addImmediateOperand((unsigned int)format); |
| |
|
| | groupedTypes[OpTypeImage].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | #ifndef GLSLANG_WEB |
| | |
| | switch (dim) { |
| | case DimBuffer: |
| | if (sampled == 1) |
| | addCapability(CapabilitySampledBuffer); |
| | else |
| | addCapability(CapabilityImageBuffer); |
| | break; |
| | case Dim1D: |
| | if (sampled == 1) |
| | addCapability(CapabilitySampled1D); |
| | else |
| | addCapability(CapabilityImage1D); |
| | break; |
| | case DimCube: |
| | if (arrayed) { |
| | if (sampled == 1) |
| | addCapability(CapabilitySampledCubeArray); |
| | else |
| | addCapability(CapabilityImageCubeArray); |
| | } |
| | break; |
| | case DimRect: |
| | if (sampled == 1) |
| | addCapability(CapabilitySampledRect); |
| | else |
| | addCapability(CapabilityImageRect); |
| | break; |
| | case DimSubpassData: |
| | addCapability(CapabilityInputAttachment); |
| | break; |
| | default: |
| | break; |
| | } |
| |
|
| | if (ms) { |
| | if (sampled == 2) { |
| | |
| | |
| | if (dim != Dim::DimSubpassData) |
| | addCapability(CapabilityStorageImageMultisample); |
| | if (arrayed) |
| | addCapability(CapabilityImageMSArray); |
| | } |
| | } |
| | #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(); |
| | } |
| |
|
| | Id Builder::makeSampledImageType(Id imageType) |
| | { |
| | |
| | Instruction* type; |
| | for (int t = 0; t < (int)groupedTypes[OpTypeSampledImage].size(); ++t) { |
| | type = groupedTypes[OpTypeSampledImage][t]; |
| | if (type->getIdOperand(0) == imageType) |
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), NoType, OpTypeSampledImage); |
| | type->addIdOperand(imageType); |
| |
|
| | groupedTypes[OpTypeSampledImage].push_back(type); |
| | 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) |
| | { |
| | |
| | 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")); |
| | type->addIdOperand(makeUintConstant(size)); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); |
| |
|
| | 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) |
| | { |
| | |
| | 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(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | type->addIdOperand(nonSemanticShaderDebugInfo); |
| | type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); |
| | if(hasSign == true) { |
| | type->addIdOperand(getStringId("int")); |
| | } else { |
| | type->addIdOperand(getStringId("uint")); |
| | } |
| | type->addIdOperand(makeUintConstant(width)); |
| | if(hasSign == true) { |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); |
| | } else { |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); |
| | } |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); |
| |
|
| | 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) |
| | { |
| | |
| | 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(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | type->addIdOperand(nonSemanticShaderDebugInfo); |
| | type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); |
| | type->addIdOperand(getStringId("float")); |
| | type->addIdOperand(makeUintConstant(width)); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); |
| |
|
| | 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); |
| |
|
| | |
| | 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(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | type->addIdOperand(nonSemanticShaderDebugInfo); |
| | type->addImmediateOperand(sequenceType); |
| | type->addIdOperand(debugId[baseType]); |
| | type->addIdOperand(componentCount); |
| |
|
| | 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) |
| | { |
| | |
| | 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(); |
| | } |
| |
|
| | |
| | type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | type->addIdOperand(nonSemanticShaderDebugInfo); |
| | type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix); |
| | type->addIdOperand(debugId[vectorType]); |
| | type->addIdOperand(makeUintConstant(vectorCount)); |
| | type->addIdOperand(makeBoolConstant(columnMajor)); |
| |
|
| | 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)); |
| | type->addIdOperand(debugId[memberType]); |
| | type->addIdOperand(makeDebugSource(sourceFileStringId)); |
| | type->addIdOperand(makeUintConstant(debugTypeLoc.line)); |
| | type->addIdOperand(makeUintConstant(debugTypeLoc.column)); |
| | type->addIdOperand(makeUintConstant(0)); |
| | type->addIdOperand(makeUintConstant(0)); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); |
| |
|
| | groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | |
| | |
| | Id Builder::makeCompositeDebugType(std::vector<Id> const& memberTypes, char const*const name, |
| | NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType) |
| | { |
| | |
| | std::vector<Id> memberDebugTypes; |
| | for(auto const memberType : memberTypes) { |
| | assert(debugTypeLocs.find(memberType) != debugTypeLocs.end()); |
| |
|
| | memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType])); |
| |
|
| | |
| | |
| | } |
| |
|
| | |
| | Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | type->addIdOperand(nonSemanticShaderDebugInfo); |
| | type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite); |
| | type->addIdOperand(getStringId(name)); |
| | type->addIdOperand(makeUintConstant(tag)); |
| | type->addIdOperand(makeDebugSource(sourceFileStringId)); |
| | type->addIdOperand(makeUintConstant(currentLine)); |
| | type->addIdOperand(makeUintConstant(0)); |
| | type->addIdOperand(makeDebugCompilationUnit()); |
| | if(isOpaqueType == true) { |
| | |
| | type->addIdOperand(getStringId('@' + std::string(name))); |
| | type->addIdOperand(makeDebugInfoNone()); |
| | } else { |
| | type->addIdOperand(getStringId(name)); |
| | type->addIdOperand(makeUintConstant(0)); |
| | } |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); |
| | 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)); |
| | sourceInst->addIdOperand(makeUintConstant(4)); |
| | sourceInst->addIdOperand(makeDebugSource(sourceFileStringId)); |
| | sourceInst->addIdOperand(makeUintConstant(sourceLang)); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(sourceInst)); |
| | module.mapInstruction(sourceInst); |
| | nonSemanticShaderCompilationUnitId = resultId; |
| |
|
| | |
| | |
| | assert(currentDebugScopeId.empty()); |
| | currentDebugScopeId.push(nonSemanticShaderCompilationUnitId); |
| |
|
| | 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)); |
| | inst->addIdOperand(type); |
| | inst->addIdOperand(makeDebugSource(sourceFileStringId)); |
| | inst->addIdOperand(makeUintConstant(currentLine)); |
| | inst->addIdOperand(makeUintConstant(0)); |
| | inst->addIdOperand(makeDebugCompilationUnit()); |
| | inst->addIdOperand(getStringId(name)); |
| | inst->addIdOperand(variable); |
| | inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); |
| |
|
| | 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); |
| | assert(!currentDebugScopeId.empty()); |
| |
|
| | Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); |
| | inst->addIdOperand(nonSemanticShaderDebugInfo); |
| | inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable); |
| | inst->addIdOperand(getStringId(name)); |
| | inst->addIdOperand(type); |
| | inst->addIdOperand(makeDebugSource(sourceFileStringId)); |
| | inst->addIdOperand(makeUintConstant(currentLine)); |
| | inst->addIdOperand(makeUintConstant(0)); |
| | inst->addIdOperand(currentDebugScopeId.top()); |
| | inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); |
| | 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); |
| | inst->addIdOperand(localVariable); |
| | inst->addIdOperand(makeDebugExpression()); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); |
| |
|
| | return inst->getResultId(); |
| | } |
| |
|
| | #ifndef GLSLANG_WEB |
| | 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[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[OpTypeRayQueryKHR].back(); |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| |
|
| | Id Builder::makeHitObjectNVType() |
| | { |
| | Instruction *type; |
| | if (groupedTypes[OpTypeHitObjectNV].size() == 0) { |
| | type = new Instruction(getUniqueId(), NoType, OpTypeHitObjectNV); |
| | groupedTypes[OpTypeHitObjectNV].push_back(type); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| | } else { |
| | type = groupedTypes[OpTypeHitObjectNV].back(); |
| | } |
| |
|
| | return type->getResultId(); |
| | } |
| | #endif |
| |
|
| | Id Builder::getDerefTypeId(Id resultId) const |
| | { |
| | Id typeId = getTypeId(resultId); |
| | assert(isPointerType(typeId)); |
| |
|
| | return module.getInstruction(typeId)->getIdOperand(1); |
| | } |
| |
|
| | Op Builder::getMostBasicTypeClass(Id typeId) const |
| | { |
| | Instruction* instr = module.getInstruction(typeId); |
| |
|
| | Op typeClass = instr->getOpCode(); |
| | switch (typeClass) |
| | { |
| | case OpTypeVector: |
| | case OpTypeMatrix: |
| | case OpTypeArray: |
| | case OpTypeRuntimeArray: |
| | return getMostBasicTypeClass(instr->getIdOperand(0)); |
| | case OpTypePointer: |
| | return getMostBasicTypeClass(instr->getIdOperand(1)); |
| | default: |
| | return typeClass; |
| | } |
| | } |
| |
|
| | int Builder::getNumTypeConstituents(Id typeId) const |
| | { |
| | Instruction* instr = module.getInstruction(typeId); |
| |
|
| | switch (instr->getOpCode()) |
| | { |
| | case OpTypeBool: |
| | case OpTypeInt: |
| | case OpTypeFloat: |
| | case OpTypePointer: |
| | return 1; |
| | case OpTypeVector: |
| | case OpTypeMatrix: |
| | return instr->getImmediateOperand(1); |
| | case OpTypeArray: |
| | { |
| | Id lengthId = instr->getIdOperand(1); |
| | return module.getInstruction(lengthId)->getImmediateOperand(0); |
| | } |
| | case OpTypeStruct: |
| | return instr->getNumOperands(); |
| | case OpTypeCooperativeMatrixKHR: |
| | case OpTypeCooperativeMatrixNV: |
| | |
| | return 1; |
| | default: |
| | assert(0); |
| | return 1; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | Id Builder::getScalarTypeId(Id typeId) const |
| | { |
| | Instruction* instr = module.getInstruction(typeId); |
| |
|
| | Op typeClass = instr->getOpCode(); |
| | switch (typeClass) |
| | { |
| | case OpTypeVoid: |
| | case OpTypeBool: |
| | case OpTypeInt: |
| | case OpTypeFloat: |
| | case OpTypeStruct: |
| | return instr->getResultId(); |
| | case OpTypeVector: |
| | case OpTypeMatrix: |
| | case OpTypeArray: |
| | case OpTypeRuntimeArray: |
| | case OpTypePointer: |
| | return getScalarTypeId(getContainedTypeId(typeId)); |
| | default: |
| | assert(0); |
| | return NoResult; |
| | } |
| | } |
| |
|
| | |
| | Id Builder::getContainedTypeId(Id typeId, int member) const |
| | { |
| | Instruction* instr = module.getInstruction(typeId); |
| |
|
| | Op typeClass = instr->getOpCode(); |
| | switch (typeClass) |
| | { |
| | case OpTypeVector: |
| | case OpTypeMatrix: |
| | case OpTypeArray: |
| | case OpTypeRuntimeArray: |
| | case OpTypeCooperativeMatrixKHR: |
| | case OpTypeCooperativeMatrixNV: |
| | return instr->getIdOperand(0); |
| | case OpTypePointer: |
| | return instr->getIdOperand(1); |
| | case OpTypeStruct: |
| | return instr->getIdOperand(member); |
| | default: |
| | assert(0); |
| | return NoResult; |
| | } |
| | } |
| |
|
| | |
| | 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; |
| | } |
| |
|
| | |
| | Id Builder::getContainedTypeId(Id typeId) const |
| | { |
| | return getContainedTypeId(typeId, 0); |
| | } |
| |
|
| | |
| | |
| | |
| | bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const |
| | { |
| | const Instruction& instr = *module.getInstruction(typeId); |
| |
|
| | Op typeClass = instr.getOpCode(); |
| | switch (typeClass) |
| | { |
| | case OpTypeInt: |
| | case OpTypeFloat: |
| | return typeClass == typeOp && instr.getImmediateOperand(0) == width; |
| | case OpTypeStruct: |
| | for (int m = 0; m < instr.getNumOperands(); ++m) { |
| | if (containsType(instr.getIdOperand(m), typeOp, width)) |
| | return true; |
| | } |
| | return false; |
| | case OpTypePointer: |
| | return false; |
| | case OpTypeVector: |
| | case OpTypeMatrix: |
| | case OpTypeArray: |
| | case OpTypeRuntimeArray: |
| | return containsType(getContainedTypeId(typeId), typeOp, width); |
| | default: |
| | return typeClass == typeOp; |
| | } |
| | } |
| |
|
| | |
| | |
| | bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const |
| | { |
| | const Instruction& instr = *module.getInstruction(typeId); |
| |
|
| | Op typeClass = instr.getOpCode(); |
| | switch (typeClass) |
| | { |
| | case OpTypePointer: |
| | return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT; |
| | case OpTypeArray: |
| | return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId)); |
| | case OpTypeStruct: |
| | for (int m = 0; m < instr.getNumOperands(); ++m) { |
| | if (containsPhysicalStorageBufferOrArray(instr.getIdOperand(m))) |
| | return true; |
| | } |
| | return false; |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | |
| | Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value) |
| | { |
| | Instruction* constant; |
| | for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { |
| | constant = groupedConstants[typeClass][i]; |
| | if (constant->getOpCode() == opcode && |
| | constant->getTypeId() == typeId && |
| | constant->getImmediateOperand(0) == value) |
| | return constant->getResultId(); |
| | } |
| |
|
| | return 0; |
| | } |
| |
|
| | |
| | Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned v1, unsigned v2) |
| | { |
| | Instruction* constant; |
| | for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { |
| | constant = groupedConstants[typeClass][i]; |
| | if (constant->getOpCode() == opcode && |
| | constant->getTypeId() == typeId && |
| | constant->getImmediateOperand(0) == v1 && |
| | constant->getImmediateOperand(1) == v2) |
| | return constant->getResultId(); |
| | } |
| |
|
| | return 0; |
| | } |
| |
|
| | |
| | |
| | |
| | bool Builder::isConstantOpCode(Op opcode) const |
| | { |
| | switch (opcode) { |
| | case OpUndef: |
| | case OpConstantTrue: |
| | case OpConstantFalse: |
| | case OpConstant: |
| | case OpConstantComposite: |
| | case OpConstantSampler: |
| | case OpConstantNull: |
| | case OpSpecConstantTrue: |
| | case OpSpecConstantFalse: |
| | case OpSpecConstant: |
| | case OpSpecConstantComposite: |
| | case OpSpecConstantOp: |
| | return true; |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | |
| | bool Builder::isSpecConstantOpCode(Op opcode) const |
| | { |
| | switch (opcode) { |
| | case OpSpecConstantTrue: |
| | case OpSpecConstantFalse: |
| | case OpSpecConstant: |
| | case OpSpecConstantComposite: |
| | case OpSpecConstantOp: |
| | return true; |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | bool Builder::isRayTracingOpCode(Op opcode) const |
| | { |
| | switch (opcode) { |
| | case OpTypeAccelerationStructureKHR: |
| | case OpTypeRayQueryKHR: |
| | return true; |
| | default: |
| | return false; |
| | } |
| | } |
| |
|
| | Id Builder::makeNullConstant(Id typeId) |
| | { |
| | Instruction* constant; |
| |
|
| | |
| | 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; |
| |
|
| | |
| | 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(); |
| | Instruction* constant; |
| | Op opcode = specConstant ? (b ? OpSpecConstantTrue : OpSpecConstantFalse) : (b ? OpConstantTrue : OpConstantFalse); |
| |
|
| | |
| | |
| | if (! specConstant) { |
| | Id existing = 0; |
| | for (int i = 0; i < (int)groupedConstants[OpTypeBool].size(); ++i) { |
| | constant = groupedConstants[OpTypeBool][i]; |
| | if (constant->getTypeId() == typeId && constant->getOpCode() == opcode) |
| | existing = constant->getResultId(); |
| | } |
| |
|
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | |
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeBool].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | } |
| |
|
| | Id Builder::makeIntConstant(Id typeId, unsigned value, bool specConstant) |
| | { |
| | Op opcode = specConstant ? OpSpecConstant : OpConstant; |
| |
|
| | |
| | |
| | if (! specConstant) { |
| | Id existing = findScalarConstant(OpTypeInt, opcode, typeId, value); |
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | c->addImmediateOperand(value); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeInt].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | } |
| |
|
| | Id Builder::makeInt64Constant(Id typeId, unsigned long long value, bool specConstant) |
| | { |
| | Op opcode = specConstant ? OpSpecConstant : OpConstant; |
| |
|
| | unsigned op1 = value & 0xFFFFFFFF; |
| | unsigned op2 = value >> 32; |
| |
|
| | |
| | |
| | if (! specConstant) { |
| | Id existing = findScalarConstant(OpTypeInt, opcode, typeId, op1, op2); |
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | c->addImmediateOperand(op1); |
| | c->addImmediateOperand(op2); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeInt].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | } |
| |
|
| | Id Builder::makeFloatConstant(float f, bool specConstant) |
| | { |
| | Op opcode = specConstant ? OpSpecConstant : OpConstant; |
| | Id typeId = makeFloatType(32); |
| | union { float fl; unsigned int ui; } u; |
| | u.fl = f; |
| | unsigned value = u.ui; |
| |
|
| | |
| | |
| | if (! specConstant) { |
| | Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value); |
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | c->addImmediateOperand(value); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeFloat].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | } |
| |
|
| | Id Builder::makeDoubleConstant(double d, bool specConstant) |
| | { |
| | #ifdef GLSLANG_WEB |
| | assert(0); |
| | return NoResult; |
| | #else |
| | Op opcode = specConstant ? OpSpecConstant : OpConstant; |
| | Id typeId = makeFloatType(64); |
| | union { double db; unsigned long long ull; } u; |
| | u.db = d; |
| | unsigned long long value = u.ull; |
| | unsigned op1 = value & 0xFFFFFFFF; |
| | unsigned op2 = value >> 32; |
| |
|
| | |
| | |
| | if (! specConstant) { |
| | Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, op1, op2); |
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | c->addImmediateOperand(op1); |
| | c->addImmediateOperand(op2); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeFloat].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | #endif |
| | } |
| |
|
| | Id Builder::makeFloat16Constant(float f16, bool specConstant) |
| | { |
| | #ifdef GLSLANG_WEB |
| | assert(0); |
| | return NoResult; |
| | #else |
| | Op opcode = specConstant ? OpSpecConstant : OpConstant; |
| | Id typeId = makeFloatType(16); |
| |
|
| | spvutils::HexFloat<spvutils::FloatProxy<float>> fVal(f16); |
| | spvutils::HexFloat<spvutils::FloatProxy<spvutils::Float16>> f16Val(0); |
| | fVal.castTo(f16Val, spvutils::kRoundToZero); |
| |
|
| | unsigned value = f16Val.value().getAsFloat().get_value(); |
| |
|
| | |
| | |
| | if (!specConstant) { |
| | Id existing = findScalarConstant(OpTypeFloat, opcode, typeId, value); |
| | if (existing) |
| | return existing; |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | c->addImmediateOperand(value); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | groupedConstants[OpTypeFloat].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | #endif |
| | } |
| |
|
| | Id Builder::makeFpConstant(Id type, double d, bool specConstant) |
| | { |
| | #ifdef GLSLANG_WEB |
| | const int width = 32; |
| | assert(width == getScalarTypeWidth(type)); |
| | #else |
| | const int width = getScalarTypeWidth(type); |
| | #endif |
| |
|
| | assert(isFloatType(type)); |
| |
|
| | switch (width) { |
| | case 16: |
| | return makeFloat16Constant((float)d, specConstant); |
| | case 32: |
| | return makeFloatConstant((float)d, specConstant); |
| | case 64: |
| | return makeDoubleConstant(d, specConstant); |
| | default: |
| | break; |
| | } |
| |
|
| | assert(false); |
| | 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 = nullptr; |
| | bool found = false; |
| | for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { |
| | constant = groupedConstants[typeClass][i]; |
| |
|
| | if (constant->getTypeId() != typeId) |
| | continue; |
| |
|
| | |
| | bool mismatch = false; |
| | for (int op = 0; op < constant->getNumOperands(); ++op) { |
| | if (constant->getIdOperand(op) != comps[op]) { |
| | mismatch = true; |
| | break; |
| | } |
| | } |
| | if (! mismatch) { |
| | found = true; |
| | break; |
| | } |
| | } |
| |
|
| | return found ? constant->getResultId() : NoResult; |
| | } |
| |
|
| | Id Builder::findStructConstant(Id typeId, const std::vector<Id>& comps) |
| | { |
| | Instruction* constant = nullptr; |
| | bool found = false; |
| | for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) { |
| | constant = groupedStructConstants[typeId][i]; |
| |
|
| | |
| | bool mismatch = false; |
| | for (int op = 0; op < constant->getNumOperands(); ++op) { |
| | if (constant->getIdOperand(op) != comps[op]) { |
| | mismatch = true; |
| | break; |
| | } |
| | } |
| | if (! mismatch) { |
| | found = true; |
| | break; |
| | } |
| | } |
| |
|
| | return found ? constant->getResultId() : NoResult; |
| | } |
| |
|
| | |
| | Id Builder::makeCompositeConstant(Id typeId, const std::vector<Id>& members, bool specConstant) |
| | { |
| | Op opcode = specConstant ? OpSpecConstantComposite : OpConstantComposite; |
| | assert(typeId); |
| | Op typeClass = getTypeClass(typeId); |
| |
|
| | switch (typeClass) { |
| | case OpTypeVector: |
| | case OpTypeArray: |
| | case OpTypeMatrix: |
| | case OpTypeCooperativeMatrixKHR: |
| | case OpTypeCooperativeMatrixNV: |
| | if (! specConstant) { |
| | Id existing = findCompositeConstant(typeClass, typeId, members); |
| | if (existing) |
| | return existing; |
| | } |
| | break; |
| | case OpTypeStruct: |
| | if (! specConstant) { |
| | Id existing = findStructConstant(typeId, members); |
| | if (existing) |
| | return existing; |
| | } |
| | break; |
| | default: |
| | assert(0); |
| | return makeFloatConstant(0.0); |
| | } |
| |
|
| | Instruction* c = new Instruction(getUniqueId(), typeId, opcode); |
| | for (int op = 0; op < (int)members.size(); ++op) |
| | c->addIdOperand(members[op]); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(c)); |
| | if (typeClass == OpTypeStruct) |
| | groupedStructConstants[typeId].push_back(c); |
| | else |
| | groupedConstants[typeClass].push_back(c); |
| | module.mapInstruction(c); |
| |
|
| | return c->getResultId(); |
| | } |
| |
|
| | Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, const char* name) |
| | { |
| | Instruction* entryPoint = new Instruction(OpEntryPoint); |
| | entryPoint->addImmediateOperand(model); |
| | entryPoint->addIdOperand(function->getId()); |
| | entryPoint->addStringOperand(name); |
| |
|
| | entryPoints.push_back(std::unique_ptr<Instruction>(entryPoint)); |
| |
|
| | return entryPoint; |
| | } |
| |
|
| | |
| | void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3) |
| | { |
| | Instruction* instr = new Instruction(OpExecutionMode); |
| | instr->addIdOperand(entryPoint->getId()); |
| | instr->addImmediateOperand(mode); |
| | if (value1 >= 0) |
| | instr->addImmediateOperand(value1); |
| | if (value2 >= 0) |
| | instr->addImmediateOperand(value2); |
| | if (value3 >= 0) |
| | instr->addImmediateOperand(value3); |
| |
|
| | 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); |
| | name->addIdOperand(id); |
| | name->addStringOperand(string); |
| |
|
| | names.push_back(std::unique_ptr<Instruction>(name)); |
| | } |
| |
|
| | void Builder::addMemberName(Id id, int memberNumber, const char* string) |
| | { |
| | Instruction* name = new Instruction(OpMemberName); |
| | name->addIdOperand(id); |
| | name->addImmediateOperand(memberNumber); |
| | name->addStringOperand(string); |
| |
|
| | names.push_back(std::unique_ptr<Instruction>(name)); |
| | } |
| |
|
| | void Builder::addDecoration(Id id, Decoration decoration, int num) |
| | { |
| | if (decoration == spv::DecorationMax) |
| | return; |
| |
|
| | Instruction* dec = new Instruction(OpDecorate); |
| | dec->addIdOperand(id); |
| | dec->addImmediateOperand(decoration); |
| | if (num >= 0) |
| | dec->addImmediateOperand(num); |
| |
|
| | decorations.push_back(std::unique_ptr<Instruction>(dec)); |
| | } |
| |
|
| | void Builder::addDecoration(Id id, Decoration decoration, const char* s) |
| | { |
| | if (decoration == spv::DecorationMax) |
| | return; |
| |
|
| | Instruction* dec = new Instruction(OpDecorateString); |
| | dec->addIdOperand(id); |
| | dec->addImmediateOperand(decoration); |
| | dec->addStringOperand(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) |
| | return; |
| |
|
| | Instruction* dec = new Instruction(OpDecorateId); |
| | dec->addIdOperand(id); |
| | dec->addImmediateOperand(decoration); |
| | dec->addIdOperand(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) |
| | return; |
| |
|
| | Instruction* dec = new Instruction(OpMemberDecorate); |
| | dec->addIdOperand(id); |
| | dec->addImmediateOperand(member); |
| | dec->addImmediateOperand(decoration); |
| | if (num >= 0) |
| | dec->addImmediateOperand(num); |
| |
|
| | decorations.push_back(std::unique_ptr<Instruction>(dec)); |
| | } |
| |
|
| | void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decoration, const char *s) |
| | { |
| | if (decoration == spv::DecorationMax) |
| | return; |
| |
|
| | Instruction* dec = new Instruction(OpMemberDecorateStringGOOGLE); |
| | dec->addIdOperand(id); |
| | dec->addImmediateOperand(member); |
| | dec->addImmediateOperand(decoration); |
| | dec->addStringOperand(s); |
| |
|
| | 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)); |
| | } |
| |
|
| | |
| | Function* Builder::makeEntryPoint(const char* entryPoint) |
| | { |
| | assert(! entryPointFunction); |
| |
|
| | Block* entry; |
| | std::vector<Id> paramsTypes; |
| | std::vector<char const*> paramNames; |
| | std::vector<std::vector<Decoration>> decorations; |
| |
|
| | 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; |
| | } |
| |
|
| | |
| | Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, |
| | const std::vector<Id>& paramTypes, const std::vector<char const*>& paramNames, |
| | const std::vector<std::vector<Decoration>>& decorations, Block **entry) |
| | { |
| | |
| | Id typeId = makeFunctionType(returnType, paramTypes); |
| | Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size()); |
| | Id funcId = getUniqueId(); |
| | Function* function = new Function(funcId, returnType, typeId, firstParamId, module); |
| |
|
| | |
| | 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) { |
| | addDecoration(firstParamId + p, decorations[p][d]); |
| | function->addParamPrecision(p, decorations[p][d]); |
| | } |
| | } |
| |
|
| | |
| | if (emitNonSemanticShaderDebugInfo) { |
| | Id nameId = getStringId(unmangleFunctionName(name)); |
| | Id debugFuncId = makeDebugFunction(function, nameId, typeId); |
| | debugId[funcId] = debugFuncId; |
| | currentDebugScopeId.push(debugFuncId); |
| | lastDebugScopeId = NoResult; |
| | } |
| |
|
| | |
| | assert(entry != nullptr); |
| | *entry = new Block(getUniqueId(), *function); |
| | function->addBlock(*entry); |
| | setBuildPoint(*entry); |
| |
|
| | |
| | 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 getParamTypeId = [this](Id const& typeId) { |
| | if (isPointerType(typeId) || isArrayType(typeId)) { |
| | return getContainedTypeId(typeId); |
| | } |
| | else { |
| | return typeId; |
| | } |
| | }; |
| | auto const& paramName = paramNames[p]; |
| | auto const debugLocalVariableId = createDebugLocalVariable(debugId[getParamTypeId(paramTypes[p])], paramName, p+1); |
| | debugId[firstParamId + p] = debugLocalVariableId; |
| |
|
| | makeDebugDeclare(debugLocalVariableId, firstParamId + p); |
| | } |
| | } |
| |
|
| | if (name) |
| | addName(function->getId(), name); |
| |
|
| | functions.push_back(std::unique_ptr<Function>(function)); |
| |
|
| | |
| | if (emitNonSemanticShaderDebugInfo) |
| | currentDebugScopeId.pop(); |
| |
|
| | return function; |
| | } |
| |
|
| | Id Builder::makeDebugFunction([[maybe_unused]] 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)); |
| | type->addIdOperand(makeUintConstant(currentLine)); |
| | type->addIdOperand(makeUintConstant(0)); |
| | type->addIdOperand(makeDebugCompilationUnit()); |
| | type->addIdOperand(nameId); |
| | type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); |
| | type->addIdOperand(makeUintConstant(currentLine)); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(type)); |
| | module.mapInstruction(type); |
| | return funcId; |
| | } |
| |
|
| | Id Builder::makeDebugLexicalBlock(uint32_t line) { |
| | assert(!currentDebugScopeId.empty()); |
| |
|
| | 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)); |
| | lex->addIdOperand(currentDebugScopeId.top()); |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | void Builder::makeReturn(bool implicit, Id retVal) |
| | { |
| | if (retVal) { |
| | Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue); |
| | inst->addIdOperand(retVal); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); |
| | } else |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(NoResult, NoType, OpReturn))); |
| |
|
| | if (! implicit) |
| | createAndSetNoPredecessorBlock("post-return"); |
| | } |
| |
|
| | |
| | void Builder::enterScope(uint32_t line) |
| | { |
| | |
| | Id lexId = makeDebugLexicalBlock(line); |
| | currentDebugScopeId.push(lexId); |
| | lastDebugScopeId = NoResult; |
| | } |
| |
|
| | |
| | void Builder::leaveScope() |
| | { |
| | |
| | currentDebugScopeId.pop(); |
| | lastDebugScopeId = NoResult; |
| | } |
| |
|
| | |
| | void Builder::enterFunction(Function const* function) |
| | { |
| | |
| | |
| | restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo; |
| | if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) { |
| | emitNonSemanticShaderDebugInfo = false; |
| | } |
| |
|
| | if (emitNonSemanticShaderDebugInfo) { |
| | |
| | Id funcId = function->getFuncId(); |
| | currentDebugScopeId.push(debugId[funcId]); |
| | |
| | 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)); |
| | } |
| | } |
| |
|
| | |
| | void Builder::leaveFunction() |
| | { |
| | Block* block = buildPoint; |
| | Function& function = buildPoint->getParent(); |
| | assert(block); |
| |
|
| | |
| | if (! block->isTerminated()) { |
| | if (function.getReturnType() == makeVoidType()) |
| | makeReturn(true); |
| | else { |
| | makeReturn(true, createUndefined(function.getReturnType())); |
| | } |
| | } |
| |
|
| | |
| | if (emitNonSemanticShaderDebugInfo) |
| | currentDebugScopeId.pop(); |
| |
|
| | emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo; |
| | } |
| |
|
| | |
| | void Builder::makeStatementTerminator(spv::Op opcode, const char *name) |
| | { |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(new Instruction(opcode))); |
| | createAndSetNoPredecessorBlock(name); |
| | } |
| |
|
| | |
| | void Builder::makeStatementTerminator(spv::Op opcode, const std::vector<Id>& operands, const char* name) |
| | { |
| | |
| | |
| | |
| | createNoResultOp(opcode, operands); |
| | createAndSetNoPredecessorBlock(name); |
| | } |
| |
|
| | |
| | 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); |
| | inst->addImmediateOperand(storageClass); |
| | if (initializer != NoResult) |
| | inst->addIdOperand(initializer); |
| |
|
| | switch (storageClass) { |
| | case StorageClassFunction: |
| | |
| | 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(); |
| | } |
| |
|
| | |
| | Id Builder::createUndefined(Id type) |
| | { |
| | Instruction* inst = new Instruction(getUniqueId(), type, OpUndef); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); |
| | return inst->getResultId(); |
| | } |
| |
|
| | |
| | spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAccessMask memoryAccess, StorageClass sc) |
| | const |
| | { |
| | switch (sc) { |
| | case spv::StorageClassUniform: |
| | case spv::StorageClassWorkgroup: |
| | case spv::StorageClassStorageBuffer: |
| | case spv::StorageClassPhysicalStorageBufferEXT: |
| | break; |
| | default: |
| | memoryAccess = spv::MemoryAccessMask(memoryAccess & |
| | ~(spv::MemoryAccessMakePointerAvailableKHRMask | |
| | spv::MemoryAccessMakePointerVisibleKHRMask | |
| | spv::MemoryAccessNonPrivatePointerKHRMask)); |
| | break; |
| | } |
| | return memoryAccess; |
| | } |
| |
|
| | |
| | void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAccess, spv::Scope scope, |
| | unsigned int alignment) |
| | { |
| | Instruction* store = new Instruction(OpStore); |
| | store->addIdOperand(lValue); |
| | store->addIdOperand(rValue); |
| |
|
| | memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue)); |
| |
|
| | if (memoryAccess != MemoryAccessMaskNone) { |
| | store->addImmediateOperand(memoryAccess); |
| | if (memoryAccess & spv::MemoryAccessAlignedMask) { |
| | store->addImmediateOperand(alignment); |
| | } |
| | if (memoryAccess & spv::MemoryAccessMakePointerAvailableKHRMask) { |
| | store->addIdOperand(makeUintConstant(scope)); |
| | } |
| | } |
| |
|
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(store)); |
| | } |
| |
|
| | |
| | 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); |
| |
|
| | memoryAccess = sanitizeMemoryAccessForStorageClass(memoryAccess, getStorageClass(lValue)); |
| |
|
| | if (memoryAccess != MemoryAccessMaskNone) { |
| | load->addImmediateOperand(memoryAccess); |
| | if (memoryAccess & spv::MemoryAccessAlignedMask) { |
| | load->addImmediateOperand(alignment); |
| | } |
| | if (memoryAccess & spv::MemoryAccessMakePointerVisibleKHRMask) { |
| | load->addIdOperand(makeUintConstant(scope)); |
| | } |
| | } |
| |
|
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(load)); |
| | setPrecision(load->getResultId(), precision); |
| |
|
| | return load->getResultId(); |
| | } |
| |
|
| | |
| | Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vector<Id>& offsets) |
| | { |
| | |
| | Id typeId = getResultingAccessChainType(); |
| | typeId = makePointer(storageClass, typeId); |
| |
|
| | |
| | Instruction* chain = new Instruction(getUniqueId(), typeId, OpAccessChain); |
| | chain->addIdOperand(base); |
| | for (int i = 0; i < (int)offsets.size(); ++i) |
| | chain->addIdOperand(offsets[i]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(chain)); |
| |
|
| | return chain->getResultId(); |
| | } |
| |
|
| | Id Builder::createArrayLength(Id base, unsigned int member) |
| | { |
| | spv::Id intType = makeUintType(32); |
| | Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength); |
| | length->addIdOperand(base); |
| | length->addImmediateOperand(member); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(length)); |
| |
|
| | return length->getResultId(); |
| | } |
| |
|
| | Id Builder::createCooperativeMatrixLengthKHR(Id type) |
| | { |
| | spv::Id intType = makeUintType(32); |
| |
|
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | return createSpecConstantOp(OpCooperativeMatrixLengthKHR, intType, std::vector<Id>(1, type), std::vector<Id>()); |
| | } |
| |
|
| | Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthKHR); |
| | length->addIdOperand(type); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(length)); |
| |
|
| | return length->getResultId(); |
| | } |
| |
|
| | Id Builder::createCooperativeMatrixLengthNV(Id type) |
| | { |
| | spv::Id intType = makeUintType(32); |
| |
|
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | return createSpecConstantOp(OpCooperativeMatrixLengthNV, intType, std::vector<Id>(1, type), std::vector<Id>()); |
| | } |
| |
|
| | Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthNV); |
| | length->addIdOperand(type); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(length)); |
| |
|
| | return length->getResultId(); |
| | } |
| |
|
| | Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) |
| | { |
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), |
| | std::vector<Id>(1, index)); |
| | } |
| | Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); |
| | extract->addIdOperand(composite); |
| | extract->addImmediateOperand(index); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); |
| |
|
| | return extract->getResultId(); |
| | } |
| |
|
| | Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vector<unsigned>& indexes) |
| | { |
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | return createSpecConstantOp(OpCompositeExtract, typeId, std::vector<Id>(1, composite), indexes); |
| | } |
| | Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); |
| | extract->addIdOperand(composite); |
| | for (int i = 0; i < (int)indexes.size(); ++i) |
| | extract->addImmediateOperand(indexes[i]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); |
| |
|
| | return extract->getResultId(); |
| | } |
| |
|
| | Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned index) |
| | { |
| | Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); |
| | insert->addIdOperand(object); |
| | insert->addIdOperand(composite); |
| | insert->addImmediateOperand(index); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); |
| |
|
| | return insert->getResultId(); |
| | } |
| |
|
| | Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std::vector<unsigned>& indexes) |
| | { |
| | Instruction* insert = new Instruction(getUniqueId(), typeId, OpCompositeInsert); |
| | insert->addIdOperand(object); |
| | insert->addIdOperand(composite); |
| | for (int i = 0; i < (int)indexes.size(); ++i) |
| | insert->addImmediateOperand(indexes[i]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); |
| |
|
| | return insert->getResultId(); |
| | } |
| |
|
| | Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex) |
| | { |
| | Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic); |
| | extract->addIdOperand(vector); |
| | extract->addIdOperand(componentIndex); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(extract)); |
| |
|
| | return extract->getResultId(); |
| | } |
| |
|
| | Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id componentIndex) |
| | { |
| | Instruction* insert = new Instruction(getUniqueId(), typeId, OpVectorInsertDynamic); |
| | insert->addIdOperand(vector); |
| | insert->addIdOperand(component); |
| | insert->addIdOperand(componentIndex); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(insert)); |
| |
|
| | return insert->getResultId(); |
| | } |
| |
|
| | |
| | void Builder::createNoResultOp(Op opCode) |
| | { |
| | Instruction* op = new Instruction(opCode); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | |
| | void Builder::createNoResultOp(Op opCode, Id operand) |
| | { |
| | Instruction* op = new Instruction(opCode); |
| | op->addIdOperand(operand); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | |
| | void Builder::createNoResultOp(Op opCode, const std::vector<Id>& operands) |
| | { |
| | Instruction* op = new Instruction(opCode); |
| | for (auto it = operands.cbegin(); it != operands.cend(); ++it) { |
| | op->addIdOperand(*it); |
| | } |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | |
| | void Builder::createNoResultOp(Op opCode, const std::vector<IdImmediate>& operands) |
| | { |
| | Instruction* op = new Instruction(opCode); |
| | for (auto it = operands.cbegin(); it != operands.cend(); ++it) { |
| | if (it->isId) |
| | op->addIdOperand(it->word); |
| | else |
| | op->addImmediateOperand(it->word); |
| | } |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics) |
| | { |
| | Instruction* op = new Instruction(OpControlBarrier); |
| | op->addIdOperand(makeUintConstant(execution)); |
| | op->addIdOperand(makeUintConstant(memory)); |
| | op->addIdOperand(makeUintConstant(semantics)); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics) |
| | { |
| | Instruction* op = new Instruction(OpMemoryBarrier); |
| | op->addIdOperand(makeUintConstant(executionScope)); |
| | op->addIdOperand(makeUintConstant(memorySemantics)); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| | } |
| |
|
| | |
| | Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand) |
| | { |
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | return createSpecConstantOp(opCode, typeId, std::vector<Id>(1, operand), std::vector<Id>()); |
| | } |
| | Instruction* op = new Instruction(getUniqueId(), typeId, opCode); |
| | op->addIdOperand(operand); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right) |
| | { |
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | std::vector<Id> operands(2); |
| | operands[0] = left; operands[1] = right; |
| | return createSpecConstantOp(opCode, typeId, operands, std::vector<Id>()); |
| | } |
| | Instruction* op = new Instruction(getUniqueId(), typeId, opCode); |
| | op->addIdOperand(left); |
| | op->addIdOperand(right); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) |
| | { |
| | |
| | |
| | if (generatingOpCodeForSpecConst) { |
| | std::vector<Id> operands(3); |
| | operands[0] = op1; |
| | operands[1] = op2; |
| | operands[2] = op3; |
| | return createSpecConstantOp( |
| | opCode, typeId, operands, std::vector<Id>()); |
| | } |
| | Instruction* op = new Instruction(getUniqueId(), typeId, opCode); |
| | op->addIdOperand(op1); |
| | op->addIdOperand(op2); |
| | op->addIdOperand(op3); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | Id Builder::createOp(Op opCode, Id typeId, const std::vector<Id>& operands) |
| | { |
| | Instruction* op = new Instruction(getUniqueId(), typeId, opCode); |
| | for (auto it = operands.cbegin(); it != operands.cend(); ++it) |
| | op->addIdOperand(*it); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | Id Builder::createOp(Op opCode, Id typeId, const std::vector<IdImmediate>& operands) |
| | { |
| | Instruction* op = new Instruction(getUniqueId(), typeId, opCode); |
| | for (auto it = operands.cbegin(); it != operands.cend(); ++it) { |
| | if (it->isId) |
| | op->addIdOperand(it->word); |
| | else |
| | op->addImmediateOperand(it->word); |
| | } |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | 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); |
| | for (auto it = operands.cbegin(); it != operands.cend(); ++it) |
| | op->addIdOperand(*it); |
| | for (auto it = literals.cbegin(); it != literals.cend(); ++it) |
| | op->addImmediateOperand(*it); |
| | module.mapInstruction(op); |
| | constantsTypesGlobals.push_back(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | Id Builder::createFunctionCall(spv::Function* function, const std::vector<spv::Id>& args) |
| | { |
| | Instruction* op = new Instruction(getUniqueId(), function->getReturnType(), OpFunctionCall); |
| | op->addIdOperand(function->getId()); |
| | for (int a = 0; a < (int)args.size(); ++a) |
| | op->addIdOperand(args[a]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | |
| | Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, const std::vector<unsigned>& channels) |
| | { |
| | if (channels.size() == 1) |
| | return setPrecision(createCompositeExtract(source, typeId, channels.front()), precision); |
| |
|
| | if (generatingOpCodeForSpecConst) { |
| | std::vector<Id> operands(2); |
| | operands[0] = operands[1] = source; |
| | return setPrecision(createSpecConstantOp(OpVectorShuffle, typeId, operands, channels), precision); |
| | } |
| | Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); |
| | assert(isVector(source)); |
| | swizzle->addIdOperand(source); |
| | swizzle->addIdOperand(source); |
| | for (int i = 0; i < (int)channels.size(); ++i) |
| | swizzle->addImmediateOperand(channels[i]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle)); |
| |
|
| | return setPrecision(swizzle->getResultId(), precision); |
| | } |
| |
|
| | |
| | Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vector<unsigned>& channels) |
| | { |
| | if (channels.size() == 1 && getNumComponents(source) == 1) |
| | return createCompositeInsert(source, target, typeId, channels.front()); |
| |
|
| | Instruction* swizzle = new Instruction(getUniqueId(), typeId, OpVectorShuffle); |
| |
|
| | assert(isVector(target)); |
| | swizzle->addIdOperand(target); |
| |
|
| | assert(getNumComponents(source) == (int)channels.size()); |
| | assert(isVector(source)); |
| | swizzle->addIdOperand(source); |
| |
|
| | |
| | unsigned int components[4]; |
| | int numTargetComponents = getNumComponents(target); |
| | for (int i = 0; i < numTargetComponents; ++i) |
| | components[i] = i; |
| |
|
| | |
| | for (int i = 0; i < (int)channels.size(); ++i) |
| | components[channels[i]] = numTargetComponents + i; |
| |
|
| | |
| | for (int i = 0; i < numTargetComponents; ++i) |
| | swizzle->addImmediateOperand(components[i]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(swizzle)); |
| |
|
| | return swizzle->getResultId(); |
| | } |
| |
|
| | |
| | void Builder::promoteScalar(Decoration precision, Id& left, Id& right) |
| | { |
| | int direction = getNumComponents(right) - getNumComponents(left); |
| |
|
| | if (direction > 0) |
| | left = smearScalar(precision, left, makeVectorType(getTypeId(left), getNumComponents(right))); |
| | else if (direction < 0) |
| | right = smearScalar(precision, right, makeVectorType(getTypeId(right), getNumComponents(left))); |
| |
|
| | return; |
| | } |
| |
|
| | |
| | Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) |
| | { |
| | assert(getNumComponents(scalar) == 1); |
| | assert(getTypeId(scalar) == getScalarTypeId(vectorType)); |
| |
|
| | int numComponents = getNumTypeComponents(vectorType); |
| | if (numComponents == 1) |
| | return scalar; |
| |
|
| | Instruction* smear = nullptr; |
| | if (generatingOpCodeForSpecConst) { |
| | auto members = std::vector<spv::Id>(numComponents, scalar); |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | auto result_id = makeCompositeConstant(vectorType, members, isSpecConstant(scalar)); |
| | smear = module.getInstruction(result_id); |
| | } else { |
| | smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); |
| | for (int c = 0; c < numComponents; ++c) |
| | smear->addIdOperand(scalar); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(smear)); |
| | } |
| |
|
| | return setPrecision(smear->getResultId(), precision); |
| | } |
| |
|
| | |
| | Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const std::vector<Id>& args) |
| | { |
| | Instruction* inst = new Instruction(getUniqueId(), resultType, OpExtInst); |
| | inst->addIdOperand(builtins); |
| | inst->addImmediateOperand(entryPoint); |
| | for (int arg = 0; arg < (int)args.size(); ++arg) |
| | inst->addIdOperand(args[arg]); |
| |
|
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(inst)); |
| |
|
| | return inst->getResultId(); |
| | } |
| |
|
| | |
| | |
| | Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, |
| | bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask) |
| | { |
| | std::vector<Id> texArgs; |
| |
|
| | |
| | |
| | |
| | bool explicitLod = false; |
| | texArgs.push_back(parameters.sampler); |
| | texArgs.push_back(parameters.coords); |
| | if (parameters.Dref != NoResult) |
| | texArgs.push_back(parameters.Dref); |
| | if (parameters.component != NoResult) |
| | texArgs.push_back(parameters.component); |
| |
|
| | #ifndef GLSLANG_WEB |
| | if (parameters.granularity != NoResult) |
| | texArgs.push_back(parameters.granularity); |
| | if (parameters.coarse != NoResult) |
| | texArgs.push_back(parameters.coarse); |
| | #endif |
| |
|
| | |
| | |
| | |
| | size_t optArgNum = texArgs.size(); |
| | ImageOperandsMask mask = ImageOperandsMaskNone; |
| | if (parameters.bias) { |
| | mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask); |
| | texArgs.push_back(parameters.bias); |
| | } |
| | if (parameters.lod) { |
| | mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); |
| | texArgs.push_back(parameters.lod); |
| | explicitLod = true; |
| | } else if (parameters.gradX) { |
| | mask = (ImageOperandsMask)(mask | ImageOperandsGradMask); |
| | texArgs.push_back(parameters.gradX); |
| | texArgs.push_back(parameters.gradY); |
| | explicitLod = true; |
| | } else if (noImplicitLod && ! fetch && ! gather) { |
| | |
| | |
| | mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); |
| | texArgs.push_back(makeFloatConstant(0.0)); |
| | explicitLod = true; |
| | } |
| | if (parameters.offset) { |
| | if (isConstant(parameters.offset)) |
| | mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetMask); |
| | else { |
| | addCapability(CapabilityImageGatherExtended); |
| | mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask); |
| | } |
| | texArgs.push_back(parameters.offset); |
| | } |
| | if (parameters.offsets) { |
| | addCapability(CapabilityImageGatherExtended); |
| | mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask); |
| | texArgs.push_back(parameters.offsets); |
| | } |
| | #ifndef GLSLANG_WEB |
| | if (parameters.sample) { |
| | mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask); |
| | texArgs.push_back(parameters.sample); |
| | } |
| | if (parameters.lodClamp) { |
| | |
| | addCapability(CapabilityMinLod); |
| |
|
| | mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask); |
| | texArgs.push_back(parameters.lodClamp); |
| | } |
| | if (parameters.nonprivate) { |
| | mask = mask | ImageOperandsNonPrivateTexelKHRMask; |
| | } |
| | if (parameters.volatil) { |
| | mask = mask | ImageOperandsVolatileTexelKHRMask; |
| | } |
| | #endif |
| | mask = mask | signExtensionMask; |
| | |
| | if (mask != ImageOperandsMaskNone) |
| | texArgs.insert(texArgs.begin() + optArgNum, mask); |
| |
|
| | |
| | |
| | |
| | Op opCode = OpNop; |
| | if (fetch) { |
| | if (sparse) |
| | opCode = OpImageSparseFetch; |
| | else |
| | opCode = OpImageFetch; |
| | #ifndef GLSLANG_WEB |
| | } else if (parameters.granularity && parameters.coarse) { |
| | opCode = OpImageSampleFootprintNV; |
| | } else if (gather) { |
| | if (parameters.Dref) |
| | if (sparse) |
| | opCode = OpImageSparseDrefGather; |
| | else |
| | opCode = OpImageDrefGather; |
| | else |
| | if (sparse) |
| | opCode = OpImageSparseGather; |
| | else |
| | opCode = OpImageGather; |
| | #endif |
| | } else if (explicitLod) { |
| | if (parameters.Dref) { |
| | if (proj) |
| | if (sparse) |
| | opCode = OpImageSparseSampleProjDrefExplicitLod; |
| | else |
| | opCode = OpImageSampleProjDrefExplicitLod; |
| | else |
| | if (sparse) |
| | opCode = OpImageSparseSampleDrefExplicitLod; |
| | else |
| | opCode = OpImageSampleDrefExplicitLod; |
| | } else { |
| | if (proj) |
| | if (sparse) |
| | opCode = OpImageSparseSampleProjExplicitLod; |
| | else |
| | opCode = OpImageSampleProjExplicitLod; |
| | else |
| | if (sparse) |
| | opCode = OpImageSparseSampleExplicitLod; |
| | else |
| | opCode = OpImageSampleExplicitLod; |
| | } |
| | } else { |
| | if (parameters.Dref) { |
| | if (proj) |
| | if (sparse) |
| | opCode = OpImageSparseSampleProjDrefImplicitLod; |
| | else |
| | opCode = OpImageSampleProjDrefImplicitLod; |
| | else |
| | if (sparse) |
| | opCode = OpImageSparseSampleDrefImplicitLod; |
| | else |
| | opCode = OpImageSampleDrefImplicitLod; |
| | } else { |
| | if (proj) |
| | if (sparse) |
| | opCode = OpImageSparseSampleProjImplicitLod; |
| | else |
| | opCode = OpImageSampleProjImplicitLod; |
| | else |
| | if (sparse) |
| | opCode = OpImageSparseSampleImplicitLod; |
| | else |
| | opCode = OpImageSampleImplicitLod; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | Id smearedType = resultType; |
| | if (! isScalarType(resultType)) { |
| | switch (opCode) { |
| | case OpImageSampleDrefImplicitLod: |
| | case OpImageSampleDrefExplicitLod: |
| | case OpImageSampleProjDrefImplicitLod: |
| | case OpImageSampleProjDrefExplicitLod: |
| | resultType = getScalarTypeId(resultType); |
| | break; |
| | default: |
| | break; |
| | } |
| | } |
| |
|
| | Id typeId0 = 0; |
| | Id typeId1 = 0; |
| |
|
| | if (sparse) { |
| | typeId0 = resultType; |
| | typeId1 = getDerefTypeId(parameters.texelOut); |
| | resultType = makeStructResultType(typeId0, typeId1); |
| | } |
| |
|
| | |
| | Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode); |
| | for (size_t op = 0; op < optArgNum; ++op) |
| | textureInst->addIdOperand(texArgs[op]); |
| | if (optArgNum < texArgs.size()) |
| | textureInst->addImmediateOperand(texArgs[optArgNum]); |
| | for (size_t op = optArgNum + 1; op < texArgs.size(); ++op) |
| | textureInst->addIdOperand(texArgs[op]); |
| | setPrecision(textureInst->getResultId(), precision); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(textureInst)); |
| |
|
| | Id resultId = textureInst->getResultId(); |
| |
|
| | if (sparse) { |
| | |
| | addCapability(CapabilitySparseResidency); |
| |
|
| | |
| | createStore(createCompositeExtract(resultId, typeId1, 1), parameters.texelOut); |
| | resultId = createCompositeExtract(resultId, typeId0, 0); |
| | setPrecision(resultId, precision); |
| | } else { |
| | |
| | |
| | if (resultType != smearedType) |
| | resultId = smearScalar(precision, resultId, smearedType); |
| | } |
| |
|
| | return resultId; |
| | } |
| |
|
| | |
| | Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameters, bool isUnsignedResult) |
| | { |
| | |
| | Id resultType = 0; |
| | switch (opCode) { |
| | case OpImageQuerySize: |
| | case OpImageQuerySizeLod: |
| | { |
| | int numComponents = 0; |
| | switch (getTypeDimensionality(getImageType(parameters.sampler))) { |
| | case Dim1D: |
| | case DimBuffer: |
| | numComponents = 1; |
| | break; |
| | case Dim2D: |
| | case DimCube: |
| | case DimRect: |
| | case DimSubpassData: |
| | numComponents = 2; |
| | break; |
| | case Dim3D: |
| | numComponents = 3; |
| | break; |
| |
|
| | default: |
| | assert(0); |
| | break; |
| | } |
| | if (isArrayedImageType(getImageType(parameters.sampler))) |
| | ++numComponents; |
| |
|
| | Id intType = isUnsignedResult ? makeUintType(32) : makeIntType(32); |
| | if (numComponents == 1) |
| | resultType = intType; |
| | else |
| | resultType = makeVectorType(intType, numComponents); |
| |
|
| | break; |
| | } |
| | case OpImageQueryLod: |
| | resultType = makeVectorType(getScalarTypeId(getTypeId(parameters.coords)), 2); |
| | break; |
| | case OpImageQueryLevels: |
| | case OpImageQuerySamples: |
| | resultType = isUnsignedResult ? makeUintType(32) : makeIntType(32); |
| | break; |
| | default: |
| | assert(0); |
| | break; |
| | } |
| |
|
| | Instruction* query = new Instruction(getUniqueId(), resultType, opCode); |
| | query->addIdOperand(parameters.sampler); |
| | if (parameters.coords) |
| | query->addIdOperand(parameters.coords); |
| | if (parameters.lod) |
| | query->addIdOperand(parameters.lod); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(query)); |
| | addCapability(CapabilityImageQuery); |
| |
|
| | return query->getResultId(); |
| | } |
| |
|
| | |
| | |
| | Id Builder::createCompositeCompare(Decoration precision, Id value1, Id value2, bool equal) |
| | { |
| | Id boolType = makeBoolType(); |
| | Id valueType = getTypeId(value1); |
| |
|
| | Id resultId = NoResult; |
| |
|
| | int numConstituents = getNumTypeConstituents(valueType); |
| |
|
| | |
| |
|
| | if (isScalarType(valueType) || isVectorType(valueType)) { |
| | assert(valueType == getTypeId(value2)); |
| | |
| | |
| | Op op; |
| | switch (getMostBasicTypeClass(valueType)) { |
| | case OpTypeFloat: |
| | op = equal ? OpFOrdEqual : OpFUnordNotEqual; |
| | break; |
| | case OpTypeInt: |
| | default: |
| | op = equal ? OpIEqual : OpINotEqual; |
| | break; |
| | case OpTypeBool: |
| | op = equal ? OpLogicalEqual : OpLogicalNotEqual; |
| | precision = NoPrecision; |
| | break; |
| | } |
| |
|
| | if (isScalarType(valueType)) { |
| | |
| | resultId = createBinOp(op, boolType, value1, value2); |
| | } else { |
| | |
| | resultId = createBinOp(op, makeVectorType(boolType, numConstituents), value1, value2); |
| | setPrecision(resultId, precision); |
| | |
| | resultId = createUnaryOp(equal ? OpAll : OpAny, boolType, resultId); |
| | } |
| |
|
| | return setPrecision(resultId, precision); |
| | } |
| |
|
| | |
| | |
| | assert(isAggregateType(valueType) || isMatrixType(valueType)); |
| |
|
| | |
| | for (int constituent = 0; constituent < numConstituents; ++constituent) { |
| | std::vector<unsigned> indexes(1, constituent); |
| | Id constituentType1 = getContainedTypeId(getTypeId(value1), constituent); |
| | Id constituentType2 = getContainedTypeId(getTypeId(value2), constituent); |
| | Id constituent1 = createCompositeExtract(value1, constituentType1, indexes); |
| | Id constituent2 = createCompositeExtract(value2, constituentType2, indexes); |
| |
|
| | Id subResultId = createCompositeCompare(precision, constituent1, constituent2, equal); |
| |
|
| | if (constituent == 0) |
| | resultId = subResultId; |
| | else |
| | resultId = setPrecision(createBinOp(equal ? OpLogicalAnd : OpLogicalOr, boolType, resultId, subResultId), |
| | precision); |
| | } |
| |
|
| | return resultId; |
| | } |
| |
|
| | |
| | Id Builder::createCompositeConstruct(Id typeId, const std::vector<Id>& constituents) |
| | { |
| | assert(isAggregateType(typeId) || (getNumTypeConstituents(typeId) > 1 && |
| | getNumTypeConstituents(typeId) == (int)constituents.size())); |
| |
|
| | if (generatingOpCodeForSpecConst) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | return makeCompositeConstant(typeId, constituents, |
| | std::any_of(constituents.begin(), constituents.end(), |
| | [&](spv::Id id) { return isSpecConstant(id); })); |
| | } |
| |
|
| | Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct); |
| | for (int c = 0; c < (int)constituents.size(); ++c) |
| | op->addIdOperand(constituents[c]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(op)); |
| |
|
| | return op->getResultId(); |
| | } |
| |
|
| | |
| | Id Builder::createConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId) |
| | { |
| | Id result = NoResult; |
| | unsigned int numTargetComponents = getNumTypeComponents(resultTypeId); |
| | unsigned int targetComponent = 0; |
| |
|
| | |
| | |
| | if (sources.size() == 1 && isScalar(sources[0]) && numTargetComponents > 1) |
| | return smearScalar(precision, sources[0], resultTypeId); |
| |
|
| | |
| | std::vector<Id> constituents; |
| | Id scalarTypeId = getScalarTypeId(resultTypeId); |
| |
|
| | |
| | const auto latchResult = [&](Id comp) { |
| | if (numTargetComponents > 1) |
| | constituents.push_back(comp); |
| | else |
| | result = comp; |
| | ++targetComponent; |
| | }; |
| |
|
| | |
| | const auto accumulateVectorConstituents = [&](Id sourceArg) { |
| | unsigned int sourceSize = getNumComponents(sourceArg); |
| | unsigned int sourcesToUse = sourceSize; |
| | if (sourcesToUse + targetComponent > numTargetComponents) |
| | sourcesToUse = numTargetComponents - targetComponent; |
| |
|
| | for (unsigned int s = 0; s < sourcesToUse; ++s) { |
| | std::vector<unsigned> swiz; |
| | swiz.push_back(s); |
| | latchResult(createRvalueSwizzle(precision, scalarTypeId, sourceArg, swiz)); |
| | } |
| | }; |
| |
|
| | |
| | const auto accumulateMatrixConstituents = [&](Id sourceArg) { |
| | unsigned int sourceSize = getNumColumns(sourceArg) * getNumRows(sourceArg); |
| | unsigned int sourcesToUse = sourceSize; |
| | if (sourcesToUse + targetComponent > numTargetComponents) |
| | sourcesToUse = numTargetComponents - targetComponent; |
| |
|
| | int col = 0; |
| | int row = 0; |
| | for (unsigned int s = 0; s < sourcesToUse; ++s) { |
| | if (row >= getNumRows(sourceArg)) { |
| | row = 0; |
| | col++; |
| | } |
| | std::vector<Id> indexes; |
| | indexes.push_back(col); |
| | indexes.push_back(row); |
| | latchResult(createCompositeExtract(sourceArg, scalarTypeId, indexes)); |
| | row++; |
| | } |
| | }; |
| |
|
| | |
| | |
| | for (unsigned int i = 0; i < sources.size(); ++i) { |
| |
|
| | if (isScalar(sources[i]) || isPointer(sources[i])) |
| | latchResult(sources[i]); |
| | else if (isVector(sources[i])) |
| | accumulateVectorConstituents(sources[i]); |
| | else if (isMatrix(sources[i])) |
| | accumulateMatrixConstituents(sources[i]); |
| | else |
| | assert(0); |
| |
|
| | if (targetComponent >= numTargetComponents) |
| | break; |
| | } |
| |
|
| | |
| | if (constituents.size() > 0) |
| | result = createCompositeConstruct(resultTypeId, constituents); |
| |
|
| | return setPrecision(result, precision); |
| | } |
| |
|
| | |
| | Id Builder::createMatrixConstructor(Decoration precision, const std::vector<Id>& sources, Id resultTypeId) |
| | { |
| | Id componentTypeId = getScalarTypeId(resultTypeId); |
| | int numCols = getTypeNumColumns(resultTypeId); |
| | int numRows = getTypeNumRows(resultTypeId); |
| |
|
| | Instruction* instr = module.getInstruction(componentTypeId); |
| | #ifdef GLSLANG_WEB |
| | const unsigned bitCount = 32; |
| | assert(bitCount == instr->getImmediateOperand(0)); |
| | #else |
| | const unsigned bitCount = instr->getImmediateOperand(0); |
| | #endif |
| |
|
| | |
| | if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) { |
| | |
| | |
| | |
| | Id matrix = sources[0]; |
| | Id columnTypeId = getContainedTypeId(resultTypeId); |
| | Id sourceColumnTypeId = getContainedTypeId(getTypeId(matrix)); |
| |
|
| | std::vector<unsigned> channels; |
| | for (int row = 0; row < numRows; ++row) |
| | channels.push_back(row); |
| |
|
| | std::vector<Id> matrixColumns; |
| | for (int col = 0; col < numCols; ++col) { |
| | std::vector<unsigned> indexes; |
| | indexes.push_back(col); |
| | Id colv = createCompositeExtract(matrix, sourceColumnTypeId, indexes); |
| | setPrecision(colv, precision); |
| |
|
| | if (numRows != getNumRows(matrix)) { |
| | matrixColumns.push_back(createRvalueSwizzle(precision, columnTypeId, colv, channels)); |
| | } else { |
| | matrixColumns.push_back(colv); |
| | } |
| | } |
| |
|
| | return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision); |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| | Id ids[maxMatrixSize][maxMatrixSize]; |
| | Id one = (bitCount == 64 ? makeDoubleConstant(1.0) : makeFloatConstant(1.0)); |
| | Id zero = (bitCount == 64 ? makeDoubleConstant(0.0) : makeFloatConstant(0.0)); |
| | for (int col = 0; col < 4; ++col) { |
| | for (int row = 0; row < 4; ++row) { |
| | if (col == row) |
| | ids[col][row] = one; |
| | else |
| | ids[col][row] = zero; |
| | } |
| | } |
| |
|
| | |
| | if (sources.size() == 1 && isScalar(sources[0])) { |
| | |
| | for (int col = 0; col < 4; ++col) |
| | ids[col][col] = sources[0]; |
| | } else if (isMatrix(sources[0])) { |
| | |
| | Id matrix = sources[0]; |
| | int minCols = std::min(numCols, getNumColumns(matrix)); |
| | int minRows = std::min(numRows, getNumRows(matrix)); |
| | for (int col = 0; col < minCols; ++col) { |
| | std::vector<unsigned> indexes; |
| | indexes.push_back(col); |
| | for (int row = 0; row < minRows; ++row) { |
| | indexes.push_back(row); |
| | ids[col][row] = createCompositeExtract(matrix, componentTypeId, indexes); |
| | indexes.pop_back(); |
| | setPrecision(ids[col][row], precision); |
| | } |
| | } |
| | } else { |
| | |
| | int row = 0; |
| | int col = 0; |
| |
|
| | 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) { |
| | argComp = createCompositeExtract(sources[arg], componentTypeId, comp); |
| | setPrecision(argComp, precision); |
| | } |
| | ids[col][row++] = argComp; |
| | if (row == numRows) { |
| | row = 0; |
| | col++; |
| | } |
| | if (col == numCols) { |
| | |
| | break; |
| | } |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| |
|
| | |
| | Id columnTypeId = getContainedTypeId(resultTypeId); |
| | std::vector<Id> matrixColumns; |
| | for (int col = 0; col < numCols; ++col) { |
| | std::vector<Id> vectorComponents; |
| | for (int row = 0; row < numRows; ++row) |
| | vectorComponents.push_back(ids[col][row]); |
| | Id column = createCompositeConstruct(columnTypeId, vectorComponents); |
| | setPrecision(column, precision); |
| | matrixColumns.push_back(column); |
| | } |
| |
|
| | |
| | return setPrecision(createCompositeConstruct(resultTypeId, matrixColumns), precision); |
| | } |
| |
|
| | |
| | Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) : |
| | builder(gb), |
| | condition(cond), |
| | control(ctrl), |
| | elseBlock(nullptr) |
| | { |
| | function = &builder.getBuildPoint()->getParent(); |
| |
|
| | |
| | |
| | |
| | thenBlock = new Block(builder.getUniqueId(), *function); |
| | mergeBlock = new Block(builder.getUniqueId(), *function); |
| |
|
| | |
| | |
| | headerBlock = builder.getBuildPoint(); |
| |
|
| | function->addBlock(thenBlock); |
| | builder.setBuildPoint(thenBlock); |
| | } |
| |
|
| | |
| | void Builder::If::makeBeginElse() |
| | { |
| | |
| | builder.createBranch(mergeBlock); |
| |
|
| | |
| | elseBlock = new Block(builder.getUniqueId(), *function); |
| | function->addBlock(elseBlock); |
| |
|
| | |
| | builder.setBuildPoint(elseBlock); |
| | } |
| |
|
| | |
| | void Builder::If::makeEndIf() |
| | { |
| | |
| | builder.createBranch(mergeBlock); |
| |
|
| | |
| | builder.setBuildPoint(headerBlock); |
| | builder.createSelectionMerge(mergeBlock, control); |
| | if (elseBlock) |
| | builder.createConditionalBranch(condition, thenBlock, elseBlock); |
| | else |
| | builder.createConditionalBranch(condition, thenBlock, mergeBlock); |
| |
|
| | |
| | function->addBlock(mergeBlock); |
| | builder.setBuildPoint(mergeBlock); |
| | } |
| |
|
| | |
| | void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, const std::vector<int>& caseValues, |
| | const std::vector<int>& valueIndexToSegment, int defaultSegment, |
| | std::vector<Block*>& segmentBlocks) |
| | { |
| | Function& function = buildPoint->getParent(); |
| |
|
| | |
| | for (int s = 0; s < numSegments; ++s) |
| | segmentBlocks.push_back(new Block(getUniqueId(), function)); |
| |
|
| | Block* mergeBlock = new Block(getUniqueId(), function); |
| |
|
| | |
| | createSelectionMerge(mergeBlock, control); |
| |
|
| | |
| | Instruction* switchInst = new Instruction(NoResult, NoType, OpSwitch); |
| | switchInst->addIdOperand(selector); |
| | auto defaultOrMerge = (defaultSegment >= 0) ? segmentBlocks[defaultSegment] : mergeBlock; |
| | switchInst->addIdOperand(defaultOrMerge->getId()); |
| | defaultOrMerge->addPredecessor(buildPoint); |
| | for (int i = 0; i < (int)caseValues.size(); ++i) { |
| | switchInst->addImmediateOperand(caseValues[i]); |
| | switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId()); |
| | segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint); |
| | } |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(switchInst)); |
| |
|
| | |
| | switchMerges.push(mergeBlock); |
| | } |
| |
|
| | |
| | void Builder::addSwitchBreak() |
| | { |
| | |
| | createBranch(switchMerges.top()); |
| | createAndSetNoPredecessorBlock("post-switch-break"); |
| | } |
| |
|
| | |
| | void Builder::nextSwitchSegment(std::vector<Block*>& segmentBlock, int nextSegment) |
| | { |
| | int lastSegment = nextSegment - 1; |
| | if (lastSegment >= 0) { |
| | |
| | if (! buildPoint->isTerminated()) |
| | createBranch(segmentBlock[nextSegment]); |
| | } |
| | Block* block = segmentBlock[nextSegment]; |
| | block->getParent().addBlock(block); |
| | setBuildPoint(block); |
| | } |
| |
|
| | |
| | void Builder::endSwitch(std::vector<Block*>& ) |
| | { |
| | |
| | if (! buildPoint->isTerminated()) |
| | addSwitchBreak(); |
| |
|
| | switchMerges.top()->getParent().addBlock(switchMerges.top()); |
| | setBuildPoint(switchMerges.top()); |
| |
|
| | switchMerges.pop(); |
| | } |
| |
|
| | Block& Builder::makeNewBlock() |
| | { |
| | Function& function = buildPoint->getParent(); |
| | auto block = new Block(getUniqueId(), function); |
| | function.addBlock(block); |
| | return *block; |
| | } |
| |
|
| | Builder::LoopBlocks& Builder::makeNewLoop() |
| | { |
| | |
| | |
| | |
| | |
| | Block& head = makeNewBlock(); |
| | Block& body = makeNewBlock(); |
| | Block& merge = makeNewBlock(); |
| | Block& continue_target = makeNewBlock(); |
| | LoopBlocks blocks(head, body, merge, continue_target); |
| | loops.push(blocks); |
| | return loops.top(); |
| | } |
| |
|
| | void Builder::createLoopContinue() |
| | { |
| | createBranch(&loops.top().continue_target); |
| | |
| | createAndSetNoPredecessorBlock("post-loop-continue"); |
| | } |
| |
|
| | void Builder::createLoopExit() |
| | { |
| | createBranch(&loops.top().merge); |
| | |
| | createAndSetNoPredecessorBlock("post-loop-break"); |
| | } |
| |
|
| | void Builder::closeLoop() |
| | { |
| | loops.pop(); |
| | } |
| |
|
| | void Builder::clearAccessChain() |
| | { |
| | accessChain.base = NoResult; |
| | accessChain.indexChain.clear(); |
| | accessChain.instr = NoResult; |
| | accessChain.swizzle.clear(); |
| | accessChain.component = NoResult; |
| | accessChain.preSwizzleBaseType = NoType; |
| | accessChain.isRValue = false; |
| | accessChain.coherentFlags.clear(); |
| | accessChain.alignment = 0; |
| | } |
| |
|
| | |
| | void Builder::accessChainPushSwizzle(std::vector<unsigned>& swizzle, Id preSwizzleBaseType, |
| | AccessChain::CoherentFlags coherentFlags, unsigned int alignment) |
| | { |
| | accessChain.coherentFlags |= coherentFlags; |
| | accessChain.alignment |= alignment; |
| |
|
| | |
| | |
| | if (accessChain.preSwizzleBaseType == NoType) |
| | accessChain.preSwizzleBaseType = preSwizzleBaseType; |
| |
|
| | |
| | if (accessChain.swizzle.size() > 0) { |
| | std::vector<unsigned> oldSwizzle = accessChain.swizzle; |
| | accessChain.swizzle.resize(0); |
| | for (unsigned int i = 0; i < swizzle.size(); ++i) { |
| | assert(swizzle[i] < oldSwizzle.size()); |
| | accessChain.swizzle.push_back(oldSwizzle[swizzle[i]]); |
| | } |
| | } else |
| | accessChain.swizzle = swizzle; |
| |
|
| | |
| | simplifyAccessChainSwizzle(); |
| | } |
| |
|
| | |
| | void Builder::accessChainStore(Id rvalue, Decoration nonUniform, spv::MemoryAccessMask memoryAccess, spv::Scope scope, unsigned int alignment) |
| | { |
| | assert(accessChain.isRValue == false); |
| |
|
| | transferAccessChainSwizzle(true); |
| |
|
| | |
| | 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; |
| |
|
| | Id base = collapseAccessChain(); |
| | addDecoration(base, nonUniform); |
| |
|
| | accessChain.indexChain.pop_back(); |
| | accessChain.instr = NoResult; |
| |
|
| | |
| | assert(accessChain.component == NoResult); |
| |
|
| | Id source = createCompositeExtract(rvalue, getContainedTypeId(getTypeId(rvalue)), i); |
| |
|
| | |
| | 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; |
| |
|
| | |
| | assert(accessChain.component == NoResult); |
| |
|
| | |
| | |
| | if (accessChain.swizzle.size() > 0) { |
| | Id tempBaseId = createLoad(base, spv::NoPrecision); |
| | source = createLvalueSwizzle(getTypeId(tempBaseId), tempBaseId, source, accessChain.swizzle); |
| | } |
| |
|
| | |
| | alignment = alignment & ~(alignment & (alignment-1)); |
| | if (getStorageClass(base) == StorageClassPhysicalStorageBufferEXT) { |
| | memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); |
| | } |
| |
|
| | createStore(source, base, memoryAccess, scope, 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; |
| |
|
| | if (accessChain.isRValue) { |
| | |
| | transferAccessChainSwizzle(false); |
| | if (accessChain.indexChain.size() > 0) { |
| | Id swizzleBase = accessChain.preSwizzleBaseType != NoType ? accessChain.preSwizzleBaseType : resultType; |
| |
|
| | |
| | std::vector<unsigned> indexes; |
| | bool constant = true; |
| | for (int i = 0; i < (int)accessChain.indexChain.size(); ++i) { |
| | if (isConstantScalar(accessChain.indexChain[i])) |
| | indexes.push_back(getConstantScalar(accessChain.indexChain[i])); |
| | else { |
| | constant = false; |
| | break; |
| | } |
| | } |
| |
|
| | if (constant) { |
| | id = createCompositeExtract(accessChain.base, swizzleBase, indexes); |
| | setPrecision(id, precision); |
| | } else { |
| | Id lValue = NoResult; |
| | if (spvVersion >= Spv_1_4 && isValidInitializer(accessChain.base)) { |
| | |
| | |
| | |
| | lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), |
| | "indexable", accessChain.base); |
| | addDecoration(lValue, DecorationNonWritable); |
| | } else { |
| | lValue = createVariable(NoPrecision, StorageClassFunction, getTypeId(accessChain.base), |
| | "indexable"); |
| | |
| | createStore(accessChain.base, lValue); |
| | } |
| | |
| | accessChain.base = lValue; |
| | accessChain.isRValue = false; |
| |
|
| | |
| | id = createLoad(collapseAccessChain(), precision); |
| | } |
| | } else |
| | id = accessChain.base; |
| | } else { |
| | transferAccessChainSwizzle(true); |
| |
|
| | |
| | alignment = alignment & ~(alignment & (alignment-1)); |
| | if (getStorageClass(accessChain.base) == StorageClassPhysicalStorageBufferEXT) { |
| | memoryAccess = (spv::MemoryAccessMask)(memoryAccess | spv::MemoryAccessAlignedMask); |
| | } |
| |
|
| | |
| | id = collapseAccessChain(); |
| | |
| | |
| | |
| | |
| | addDecoration(id, l_nonUniform); |
| | id = createLoad(id, precision, memoryAccess, scope, alignment); |
| | addDecoration(id, r_nonUniform); |
| | } |
| |
|
| | |
| | if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult) |
| | return id; |
| |
|
| | |
| |
|
| | |
| | if (accessChain.swizzle.size() > 0) { |
| | Id swizzledType = getScalarTypeId(getTypeId(id)); |
| | if (accessChain.swizzle.size() > 1) |
| | swizzledType = makeVectorType(swizzledType, (int)accessChain.swizzle.size()); |
| | id = createRvalueSwizzle(precision, swizzledType, id, accessChain.swizzle); |
| | } |
| |
|
| | |
| | if (accessChain.component != NoResult) |
| | id = setPrecision(createVectorExtractDynamic(id, resultType, accessChain.component), precision); |
| |
|
| | addDecoration(id, r_nonUniform); |
| | return id; |
| | } |
| |
|
| | Id Builder::accessChainGetLValue() |
| | { |
| | assert(accessChain.isRValue == false); |
| |
|
| | transferAccessChainSwizzle(true); |
| | Id lvalue = collapseAccessChain(); |
| |
|
| | |
| | |
| | |
| | assert(accessChain.swizzle.size() == 0); |
| | assert(accessChain.component == NoResult); |
| |
|
| | return lvalue; |
| | } |
| |
|
| | |
| | Id Builder::accessChainGetInferredType() |
| | { |
| | |
| | if (accessChain.base == NoResult) |
| | return NoType; |
| | Id type = getTypeId(accessChain.base); |
| |
|
| | |
| | if (! accessChain.isRValue) |
| | type = getContainedTypeId(type); |
| |
|
| | |
| | for (auto it = accessChain.indexChain.cbegin(); it != accessChain.indexChain.cend(); ++it) { |
| | if (isStructType(type)) |
| | type = getContainedTypeId(type, getConstantScalar(*it)); |
| | else |
| | type = getContainedTypeId(type); |
| | } |
| |
|
| | |
| | if (accessChain.swizzle.size() == 1) |
| | type = getContainedTypeId(type); |
| | else if (accessChain.swizzle.size() > 1) |
| | type = makeVectorType(getContainedTypeId(type), (int)accessChain.swizzle.size()); |
| |
|
| | |
| | if (accessChain.component) |
| | type = getContainedTypeId(type); |
| |
|
| | return type; |
| | } |
| |
|
| | void Builder::dump(std::vector<unsigned int>& out) const |
| | { |
| | |
| | out.push_back(MagicNumber); |
| | out.push_back(spvVersion); |
| | out.push_back(builderNumber); |
| | out.push_back(uniqueId + 1); |
| | out.push_back(0); |
| |
|
| | |
| | for (auto it = capabilities.cbegin(); it != capabilities.cend(); ++it) { |
| | Instruction capInst(0, 0, OpCapability); |
| | capInst.addImmediateOperand(*it); |
| | capInst.dump(out); |
| | } |
| |
|
| | for (auto it = extensions.cbegin(); it != extensions.cend(); ++it) { |
| | Instruction extInst(0, 0, OpExtension); |
| | extInst.addStringOperand(it->c_str()); |
| | extInst.dump(out); |
| | } |
| |
|
| | dumpInstructions(out, imports); |
| | Instruction memInst(0, 0, OpMemoryModel); |
| | memInst.addImmediateOperand(addressModel); |
| | memInst.addImmediateOperand(memoryModel); |
| | memInst.dump(out); |
| |
|
| | |
| | dumpInstructions(out, entryPoints); |
| | dumpInstructions(out, executionModes); |
| |
|
| | |
| | dumpInstructions(out, strings); |
| | dumpSourceInstructions(out); |
| | for (int e = 0; e < (int)sourceExtensions.size(); ++e) { |
| | Instruction sourceExtInst(0, 0, OpSourceExtension); |
| | sourceExtInst.addStringOperand(sourceExtensions[e]); |
| | sourceExtInst.dump(out); |
| | } |
| | dumpInstructions(out, names); |
| | dumpModuleProcesses(out); |
| |
|
| | |
| | dumpInstructions(out, decorations); |
| |
|
| | dumpInstructions(out, constantsTypesGlobals); |
| | dumpInstructions(out, externals); |
| |
|
| | |
| | module.dump(out); |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | Id Builder::collapseAccessChain() |
| | { |
| | assert(accessChain.isRValue == false); |
| |
|
| | |
| | if (accessChain.instr != NoResult) |
| | return accessChain.instr; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | remapDynamicSwizzle(); |
| | if (accessChain.component != NoResult) { |
| | |
| | accessChain.indexChain.push_back(accessChain.component); |
| | accessChain.component = NoResult; |
| | } |
| |
|
| | |
| |
|
| | |
| | if (accessChain.indexChain.size() == 0) |
| | return accessChain.base; |
| |
|
| | |
| | StorageClass storageClass = (StorageClass)module.getStorageClass(getTypeId(accessChain.base)); |
| | accessChain.instr = createAccessChain(storageClass, accessChain.base, accessChain.indexChain); |
| |
|
| | return accessChain.instr; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | void Builder::remapDynamicSwizzle() |
| | { |
| | |
| | if (accessChain.component != NoResult && accessChain.swizzle.size() > 1) { |
| | |
| | std::vector<Id> components; |
| | for (int c = 0; c < (int)accessChain.swizzle.size(); ++c) |
| | components.push_back(makeUintConstant(accessChain.swizzle[c])); |
| | Id mapType = makeVectorType(makeUintType(32), (int)accessChain.swizzle.size()); |
| | Id map = makeCompositeConstant(mapType, components); |
| |
|
| | |
| | accessChain.component = createVectorExtractDynamic(map, makeUintType(32), accessChain.component); |
| | accessChain.swizzle.clear(); |
| | } |
| | } |
| |
|
| | |
| | |
| | void Builder::simplifyAccessChainSwizzle() |
| | { |
| | |
| | |
| | if (getNumTypeComponents(accessChain.preSwizzleBaseType) > (int)accessChain.swizzle.size()) |
| | return; |
| |
|
| | |
| | for (unsigned int i = 0; i < accessChain.swizzle.size(); ++i) { |
| | if (i != accessChain.swizzle[i]) |
| | return; |
| | } |
| |
|
| | |
| | accessChain.swizzle.clear(); |
| | if (accessChain.component == NoResult) |
| | accessChain.preSwizzleBaseType = NoType; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | void Builder::transferAccessChainSwizzle(bool dynamic) |
| | { |
| | |
| | if (accessChain.swizzle.size() == 0 && accessChain.component == NoResult) |
| | return; |
| |
|
| | |
| | |
| | if (accessChain.swizzle.size() > 1) |
| | return; |
| |
|
| | |
| | if (accessChain.swizzle.size() == 1) { |
| | assert(accessChain.component == NoResult); |
| | |
| | accessChain.indexChain.push_back(makeUintConstant(accessChain.swizzle.front())); |
| | accessChain.swizzle.clear(); |
| | accessChain.preSwizzleBaseType = NoType; |
| | } else if (dynamic && accessChain.component != NoResult) { |
| | assert(accessChain.swizzle.size() == 0); |
| | |
| | accessChain.indexChain.push_back(accessChain.component); |
| | accessChain.preSwizzleBaseType = NoType; |
| | accessChain.component = NoResult; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | void Builder::createAndSetNoPredecessorBlock(const char* ) |
| | { |
| | Block* block = new Block(getUniqueId(), buildPoint->getParent()); |
| | block->setUnreachable(); |
| | buildPoint->getParent().addBlock(block); |
| | setBuildPoint(block); |
| |
|
| | |
| | |
| | } |
| |
|
| | |
| | void Builder::createBranch(Block* block) |
| | { |
| | Instruction* branch = new Instruction(OpBranch); |
| | branch->addIdOperand(block->getId()); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(branch)); |
| | block->addPredecessor(buildPoint); |
| | } |
| |
|
| | void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control) |
| | { |
| | Instruction* merge = new Instruction(OpSelectionMerge); |
| | merge->addIdOperand(mergeBlock->getId()); |
| | merge->addImmediateOperand(control); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(merge)); |
| | } |
| |
|
| | void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, |
| | const std::vector<unsigned int>& operands) |
| | { |
| | Instruction* merge = new Instruction(OpLoopMerge); |
| | merge->addIdOperand(mergeBlock->getId()); |
| | merge->addIdOperand(continueBlock->getId()); |
| | merge->addImmediateOperand(control); |
| | for (int op = 0; op < (int)operands.size(); ++op) |
| | merge->addImmediateOperand(operands[op]); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(merge)); |
| | } |
| |
|
| | void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock) |
| | { |
| | Instruction* branch = new Instruction(OpBranchConditional); |
| | branch->addIdOperand(condition); |
| | branch->addIdOperand(thenBlock->getId()); |
| | branch->addIdOperand(elseBlock->getId()); |
| | buildPoint->addInstruction(std::unique_ptr<Instruction>(branch)); |
| | thenBlock->addPredecessor(buildPoint); |
| | elseBlock->addPredecessor(buildPoint); |
| | } |
| |
|
| | |
| | |
| | |
| | void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& text, |
| | std::vector<unsigned int>& out) const |
| | { |
| | const int maxWordCount = 0xFFFF; |
| | const int opSourceWordCount = 4; |
| | const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1; |
| |
|
| | if (sourceLang != SourceLanguageUnknown) { |
| | |
| | Instruction sourceInst(NoResult, NoType, OpSource); |
| | sourceInst.addImmediateOperand(sourceLang); |
| | sourceInst.addImmediateOperand(sourceVersion); |
| | |
| | if (fileId != NoResult) { |
| | sourceInst.addIdOperand(fileId); |
| | |
| | if (text.size() > 0) { |
| | int nextByte = 0; |
| | std::string subString; |
| | while ((int)text.size() - nextByte > 0) { |
| | subString = text.substr(nextByte, nonNullBytesPerInstruction); |
| | if (nextByte == 0) { |
| | |
| | sourceInst.addStringOperand(subString.c_str()); |
| | sourceInst.dump(out); |
| | } else { |
| | |
| | Instruction sourceContinuedInst(OpSourceContinued); |
| | sourceContinuedInst.addStringOperand(subString.c_str()); |
| | sourceContinuedInst.dump(out); |
| | } |
| | nextByte += nonNullBytesPerInstruction; |
| | } |
| | } else |
| | sourceInst.dump(out); |
| | } else |
| | sourceInst.dump(out); |
| | } |
| | } |
| |
|
| | |
| | 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 |
| | { |
| | for (int i = 0; i < (int)instructions.size(); ++i) { |
| | instructions[i]->dump(out); |
| | } |
| | } |
| |
|
| | void Builder::dumpModuleProcesses(std::vector<unsigned int>& out) const |
| | { |
| | for (int i = 0; i < (int)moduleProcesses.size(); ++i) { |
| | Instruction moduleProcessed(OpModuleProcessed); |
| | moduleProcessed.addStringOperand(moduleProcesses[i]); |
| | moduleProcessed.dump(out); |
| | } |
| | } |
| |
|
| | } |
| |
|