Skip to content

Commit

Permalink
SPV: only declare the pure 8/16-bit capabilities when needed.
Browse files Browse the repository at this point in the history
Only when operations stray outside the 8/16-bit storage-capabilities
are the general (pure 8/16-bit) capabilities needed.
  • Loading branch information
johnkslang committed Aug 16, 2018
1 parent 149afc3 commit 31aa3d6
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 29 deletions.
9 changes: 2 additions & 7 deletions SPIRV/GlslangToSpv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -2627,24 +2626,20 @@ 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);
#endif
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);
Expand Down
45 changes: 33 additions & 12 deletions SPIRV/SpvBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -534,8 +526,7 @@ Op Builder::getMostBasicTypeClass(Id typeId) const
case OpTypePointer:
return getMostBasicTypeClass(instr->getIdOperand(1));
default:
assert(0);
return OpTypeFloat;
return typeClass;
}
}

Expand Down Expand Up @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions SPIRV/SpvBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class Builder {
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;
Expand Down Expand Up @@ -569,9 +570,11 @@ class Builder {
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;

Expand Down
86 changes: 84 additions & 2 deletions SPIRV/SpvPostProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion SPIRV/spvIR.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class Instruction {
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; }
Expand Down
1 change: 0 additions & 1 deletion Test/baseResults/spv.16bitstorage-int.frag.out
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion Test/baseResults/spv.16bitstorage-uint.frag.out
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion Test/baseResults/spv.16bitstorage.frag.out
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion Test/baseResults/spv.8bitstorage-int.frag.out
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 0 additions & 1 deletion Test/baseResults/spv.8bitstorage-uint.frag.out
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 31aa3d6

Please sign in to comment.