SPV: only declare the pure 8/16-bit capabilities when needed.

Only when operations stray outside the 8/16-bit storage-capabilities
are the general (pure 8/16-bit) capabilities needed.
This commit is contained in:
John Kessenich 2018-08-15 13:54:09 -06:00
parent 149afc3930
commit 31aa3d6019
10 changed files with 125 additions and 29 deletions

View File

@ -2612,7 +2612,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
spvType = builder.makeFloatType(64);
break;
case glslang::EbtFloat16:
builder.addCapability(spv::CapabilityFloat16);
#if AMD_EXTENSIONS
if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float);
@ -2627,16 +2626,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
else
spvType = builder.makeBoolType();
break;
case glslang::EbtInt8:
builder.addCapability(spv::CapabilityInt8);
case glslang::EbtInt8:
spvType = builder.makeIntType(8);
break;
case glslang::EbtUint8:
builder.addCapability(spv::CapabilityInt8);
spvType = builder.makeUintType(8);
break;
case glslang::EbtInt16:
builder.addCapability(spv::CapabilityInt16);
case glslang::EbtInt16:
#ifdef AMD_EXTENSIONS
if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);
@ -2644,7 +2640,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty
spvType = builder.makeIntType(16);
break;
case glslang::EbtUint16:
builder.addCapability(spv::CapabilityInt16);
#ifdef AMD_EXTENSIONS
if (builder.getSpvVersion() < glslang::EShTargetSpv_1_3)
builder.addExtension(spv::E_SPV_AMD_gpu_shader_int16);

View File

@ -194,10 +194,8 @@ Id Builder::makeIntegerType(int width, bool hasSign)
// deal with capabilities
switch (width) {
case 8:
addCapability(CapabilityInt8);
break;
case 16:
addCapability(CapabilityInt16);
// these are currently handled by storage-type declarations and post processing
break;
case 64:
addCapability(CapabilityInt64);
@ -229,7 +227,7 @@ Id Builder::makeFloatType(int width)
// deal with capabilities
switch (width) {
case 16:
addCapability(CapabilityFloat16);
// currently handled by storage-type declarations and post processing
break;
case 64:
addCapability(CapabilityFloat64);
@ -520,12 +518,6 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
Op typeClass = instr->getOpCode();
switch (typeClass)
{
case OpTypeVoid:
case OpTypeBool:
case OpTypeInt:
case OpTypeFloat:
case OpTypeStruct:
return typeClass;
case OpTypeVector:
case OpTypeMatrix:
case OpTypeArray:
@ -534,8 +526,7 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
case OpTypePointer:
return getMostBasicTypeClass(instr->getIdOperand(1));
default:
assert(0);
return OpTypeFloat;
return typeClass;
}
}
@ -622,6 +613,36 @@ Id Builder::getContainedTypeId(Id typeId) const
return getContainedTypeId(typeId, 0);
}
// Returns true if 'typeId' is or contains a scalar type declared with 'typeOp'
// of width 'width'. The 'width' is only consumed for int and float types.
// Returns false otherwise.
bool Builder::containsType(Id typeId, spv::Op typeOp, 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 OpTypeVector:
case OpTypeMatrix:
case OpTypeArray:
case OpTypeRuntimeArray:
case OpTypePointer:
return containsType(getContainedTypeId(typeId), typeOp, width);
default:
return typeClass == typeOp;
}
}
// See if a scalar constant of this type has already been created, so it
// can be reused rather than duplicated. (Required by the specification).
Id Builder::findScalarConstant(Op typeClass, Op opcode, Id typeId, unsigned value)

View File

@ -167,6 +167,7 @@ public:
bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; }
bool isSamplerType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampler; }
bool isSampledImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeSampledImage; }
bool containsType(Id typeId, Op typeOp, int width) const;
bool isConstantOpCode(Op opcode) const;
bool isSpecConstantOpCode(Op opcode) const;
@ -569,9 +570,11 @@ public:
void postProcess();
// Hook to visit each instruction in a block in a function
void postProcess(Instruction& inst);
void postProcess(const Instruction&);
// Hook to visit each instruction in a reachable block in a function.
void postProcessReachable(Instruction& inst);
void postProcessReachable(const Instruction&);
// Hook to visit each non-32-bit sized float/int operation in a block.
void postProcessType(const Instruction&, spv::Id typeId);
void dump(std::vector<unsigned int>&) const;

View File

@ -61,8 +61,78 @@ namespace spv {
namespace spv {
// Hook to visit each operand type and result type of an instruction.
// Will be called multiple times for one instruction, once for each typed
// operand and the result.
void Builder::postProcessType(const Instruction& inst, Id typeId)
{
// Characterize the type being questioned
Id basicTypeOp = getMostBasicTypeClass(typeId);
int width = 0;
if (basicTypeOp == OpTypeFloat || basicTypeOp == OpTypeInt)
width = getScalarTypeWidth(typeId);
// Do opcode-specific checks
switch (inst.getOpCode()) {
case OpLoad:
case OpStore:
if (basicTypeOp == OpTypeStruct) {
if (containsType(typeId, OpTypeInt, 8))
addCapability(CapabilityInt8);
if (containsType(typeId, OpTypeInt, 16))
addCapability(CapabilityInt16);
if (containsType(typeId, OpTypeFloat, 16))
addCapability(CapabilityFloat16);
} else {
StorageClass storageClass = getStorageClass(inst.getIdOperand(0));
if (width == 8) {
switch (storageClass) {
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
break;
default:
addCapability(CapabilityInt8);
break;
}
} else if (width == 16) {
switch (storageClass) {
case StorageClassUniform:
case StorageClassStorageBuffer:
case StorageClassPushConstant:
case StorageClassInput:
case StorageClassOutput:
break;
default:
if (basicTypeOp == OpTypeInt)
addCapability(CapabilityInt16);
if (basicTypeOp == OpTypeFloat)
addCapability(CapabilityFloat16);
break;
}
}
}
break;
case OpAccessChain:
case OpPtrAccessChain:
case OpCopyObject:
case OpFConvert:
case OpSConvert:
case OpUConvert:
break;
default:
if (basicTypeOp == OpTypeFloat && width == 16)
addCapability(CapabilityFloat16);
if (basicTypeOp == OpTypeInt && width == 16)
addCapability(CapabilityInt16);
if (basicTypeOp == OpTypeInt && width == 8)
addCapability(CapabilityInt8);
break;
}
}
// Called for each instruction that resides in a block.
void Builder::postProcess(Instruction& inst)
void Builder::postProcess(const Instruction& inst)
{
// Add capabilities based simply on the opcode.
switch (inst.getOpCode()) {
@ -104,10 +174,22 @@ void Builder::postProcess(Instruction& inst)
default:
break;
}
// Checks based on type
if (inst.getTypeId() != NoType)
postProcessType(inst, inst.getTypeId());
for (int op = 0; op < inst.getNumOperands(); ++op) {
if (inst.isIdOperand(op)) {
// In blocks, these are always result ids, but we are relying on
// getTypeId() to return NoType for things like OpLabel.
if (getTypeId(inst.getIdOperand(op)) != NoType)
postProcessType(inst, getTypeId(inst.getIdOperand(op)));
}
}
}
// Called for each instruction in a reachable block.
void Builder::postProcessReachable(Instruction& inst)
void Builder::postProcessReachable(const Instruction& inst)
{
// did have code here, but questionable to do so without deleting the instructions
}

View File

@ -127,7 +127,7 @@ public:
addImmediateOperand(word);
}
}
bool isIdOperand(int op) { return idOperand[op]; }
bool isIdOperand(int op) const { return idOperand[op]; }
void setBlock(Block* b) { block = b; }
Block* getBlock() const { return block; }
Op getOpCode() const { return opCode; }

View File

@ -4,7 +4,6 @@ spv.16bitstorage-int.frag
// Id's are bound by 171
Capability Shader
Capability Int16
Capability StorageUniformBufferBlock16
Capability StorageUniform16
Extension "SPV_AMD_gpu_shader_int16"

View File

@ -4,7 +4,6 @@ spv.16bitstorage-uint.frag
// Id's are bound by 173
Capability Shader
Capability Int16
Capability StorageUniformBufferBlock16
Capability StorageUniform16
Extension "SPV_AMD_gpu_shader_int16"

View File

@ -4,7 +4,6 @@ spv.16bitstorage.frag
// Id's are bound by 173
Capability Shader
Capability Float16
Capability StorageUniformBufferBlock16
Capability StorageUniform16
Extension "SPV_AMD_gpu_shader_half_float"

View File

@ -4,7 +4,6 @@ spv.8bitstorage-int.frag
// Id's are bound by 171
Capability Shader
Capability Int8
Capability CapabilityStorageBuffer8BitAccess
Capability CapabilityUniformAndStorageBuffer8BitAccess
Extension "SPV_KHR_8bit_storage"

View File

@ -4,7 +4,6 @@ spv.8bitstorage-uint.frag
// Id's are bound by 173
Capability Shader
Capability Int8
Capability CapabilityStorageBuffer8BitAccess
Capability CapabilityUniformAndStorageBuffer8BitAccess
Extension "SPV_KHR_8bit_storage"