mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-14 02:10:17 +00:00
Make IsTypeNullable a transitive check.
This commit is contained in:
parent
4038195d81
commit
7ef6da7b7f
@ -489,22 +489,6 @@ int32_t spvOpcodeIsPointer(const SpvOp opcode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t spvOpcodeIsBasicTypeNullable(SpvOp opcode) {
|
|
||||||
switch (opcode) {
|
|
||||||
case SpvOpTypeBool:
|
|
||||||
case SpvOpTypeInt:
|
|
||||||
case SpvOpTypeFloat:
|
|
||||||
case SpvOpTypePointer:
|
|
||||||
case SpvOpTypeEvent:
|
|
||||||
case SpvOpTypeDeviceEvent:
|
|
||||||
case SpvOpTypeReserveId:
|
|
||||||
case SpvOpTypeQueue:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t spvInstructionIsInBasicBlock(const spv_instruction_t* pFirstInst,
|
int32_t spvInstructionIsInBasicBlock(const spv_instruction_t* pFirstInst,
|
||||||
const spv_instruction_t* pInst) {
|
const spv_instruction_t* pInst) {
|
||||||
while (pFirstInst != pInst) {
|
while (pFirstInst != pInst) {
|
||||||
|
@ -92,10 +92,6 @@ int32_t spvOpcodeAreTypesEqual(const spv_instruction_t* type_inst0,
|
|||||||
// non-zero otherwise.
|
// non-zero otherwise.
|
||||||
int32_t spvOpcodeIsPointer(const SpvOp opcode);
|
int32_t spvOpcodeIsPointer(const SpvOp opcode);
|
||||||
|
|
||||||
// Determines if the scalar type opcode is nullable. Returns zero if false,
|
|
||||||
// non-zero otherwise.
|
|
||||||
int32_t spvOpcodeIsBasicTypeNullable(SpvOp opcode);
|
|
||||||
|
|
||||||
// Determines if an instruction is in a basic block. The first_inst parameter
|
// Determines if an instruction is in a basic block. The first_inst parameter
|
||||||
// specifies the first instruction in the stream, while the inst parameter
|
// specifies the first instruction in the stream, while the inst parameter
|
||||||
// specifies the current instruction. Returns zero if false, non-zero otherwise.
|
// specifies the current instruction. Returns zero if false, non-zero otherwise.
|
||||||
|
@ -609,64 +609,54 @@ bool idUsage::isValid<SpvOpConstantSampler>(const spv_instruction_t* inst,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// True if instruction defines a type that can have a null value, as defined by
|
||||||
|
// the SPIR-V spec. Tracks composite-type components through usedefs to check
|
||||||
|
// nullability transitively.
|
||||||
|
bool IsTypeNullable(const std::vector<uint32_t>& instruction,
|
||||||
|
const UseDefTracker& usedefs) {
|
||||||
|
SpvOp opcode;
|
||||||
|
uint16_t word_count;
|
||||||
|
spvOpcodeSplit(instruction[0], &word_count, &opcode);
|
||||||
|
switch (opcode) {
|
||||||
|
case SpvOpTypeBool:
|
||||||
|
case SpvOpTypeInt:
|
||||||
|
case SpvOpTypeFloat:
|
||||||
|
case SpvOpTypePointer:
|
||||||
|
case SpvOpTypeEvent:
|
||||||
|
case SpvOpTypeDeviceEvent:
|
||||||
|
case SpvOpTypeReserveId:
|
||||||
|
case SpvOpTypeQueue:
|
||||||
|
return true;
|
||||||
|
case SpvOpTypeArray:
|
||||||
|
case SpvOpTypeMatrix:
|
||||||
|
case SpvOpTypeVector: {
|
||||||
|
auto base_type = usedefs.FindDef(instruction[2]);
|
||||||
|
return base_type.first && IsTypeNullable(base_type.second.words, usedefs);
|
||||||
|
}
|
||||||
|
case SpvOpTypeStruct: {
|
||||||
|
for (size_t elementIndex = 2; elementIndex < instruction.size();
|
||||||
|
++elementIndex) {
|
||||||
|
auto element = usedefs.FindDef(instruction[elementIndex]);
|
||||||
|
if (!element.first || !IsTypeNullable(element.second.words, usedefs))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
bool idUsage::isValid<SpvOpConstantNull>(const spv_instruction_t* inst,
|
bool idUsage::isValid<SpvOpConstantNull>(const spv_instruction_t* inst,
|
||||||
const spv_opcode_desc) {
|
const spv_opcode_desc) {
|
||||||
auto resultTypeIndex = 1;
|
auto resultTypeIndex = 1;
|
||||||
auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
|
auto resultType = usedefs_.FindDef(inst->words[resultTypeIndex]);
|
||||||
if (!resultType.first) return false;
|
if (!resultType.first || !IsTypeNullable(resultType.second.words, usedefs_)) {
|
||||||
switch (resultType.second.opcode) {
|
DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
|
||||||
default: {
|
<< inst->words[resultTypeIndex]
|
||||||
spvCheck(!spvOpcodeIsBasicTypeNullable(resultType.second.opcode),
|
<< "' cannot have a null value.";
|
||||||
DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
|
return false;
|
||||||
<< inst->words[resultTypeIndex]
|
|
||||||
<< "' cannot be null.";
|
|
||||||
return false);
|
|
||||||
} break;
|
|
||||||
case SpvOpTypeVector: {
|
|
||||||
auto type = usedefs_.FindDef(resultType.second.words[2]);
|
|
||||||
assert(type.first);
|
|
||||||
spvCheck(!spvOpcodeIsBasicTypeNullable(type.second.opcode),
|
|
||||||
DIAG(resultTypeIndex)
|
|
||||||
<< "OpConstantNull Result Type <id> '"
|
|
||||||
<< inst->words[resultTypeIndex]
|
|
||||||
<< "'s vector component type cannot be null.";
|
|
||||||
return false);
|
|
||||||
} break;
|
|
||||||
case SpvOpTypeArray: {
|
|
||||||
auto type = usedefs_.FindDef(resultType.second.words[2]);
|
|
||||||
assert(type.first);
|
|
||||||
spvCheck(!spvOpcodeIsBasicTypeNullable(type.second.opcode),
|
|
||||||
DIAG(resultTypeIndex) << "OpConstantNull Result Type <id> '"
|
|
||||||
<< inst->words[resultTypeIndex]
|
|
||||||
<< "'s array element type cannot be null.";
|
|
||||||
return false);
|
|
||||||
} break;
|
|
||||||
case SpvOpTypeMatrix: {
|
|
||||||
auto columnType = usedefs_.FindDef(resultType.second.words[2]);
|
|
||||||
assert(columnType.first);
|
|
||||||
auto type = usedefs_.FindDef(columnType.second.words[2]);
|
|
||||||
assert(type.first);
|
|
||||||
spvCheck(!spvOpcodeIsBasicTypeNullable(type.second.opcode),
|
|
||||||
DIAG(resultTypeIndex)
|
|
||||||
<< "OpConstantNull Result Type <id> '"
|
|
||||||
<< inst->words[resultTypeIndex]
|
|
||||||
<< "'s matrix component type cna not be null.";
|
|
||||||
return false);
|
|
||||||
} break;
|
|
||||||
case SpvOpTypeStruct: {
|
|
||||||
for (size_t elementIndex = 2;
|
|
||||||
elementIndex < resultType.second.words.size(); ++elementIndex) {
|
|
||||||
auto element = usedefs_.FindDef(resultType.second.words[elementIndex]);
|
|
||||||
assert(element.first);
|
|
||||||
spvCheck(!spvOpcodeIsBasicTypeNullable(element.second.opcode),
|
|
||||||
DIAG(resultTypeIndex)
|
|
||||||
<< "OpConstantNull Result Type <id> '"
|
|
||||||
<< inst->words[resultTypeIndex]
|
|
||||||
<< "'s struct element type cannot be null.";
|
|
||||||
return false);
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -612,15 +612,21 @@ TEST_F(ValidateID, OpConstantNullGood) {
|
|||||||
%22 = OpConstantNull %21
|
%22 = OpConstantNull %21
|
||||||
%23 = OpTypeStruct %3 %5 %1
|
%23 = OpTypeStruct %3 %5 %1
|
||||||
%24 = OpConstantNull %23
|
%24 = OpConstantNull %23
|
||||||
|
%26 = OpTypeArray %17 %25
|
||||||
|
%27 = OpConstantNull %26
|
||||||
|
%28 = OpTypeStruct %7 %26 %26 %1
|
||||||
|
%29 = OpConstantNull %28
|
||||||
)";
|
)";
|
||||||
CHECK(spirv, SPV_SUCCESS);
|
CHECK(spirv, SPV_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateID, OpConstantNullBasicBad) {
|
TEST_F(ValidateID, OpConstantNullBasicBad) {
|
||||||
const char* spirv = R"(
|
const char* spirv = R"(
|
||||||
%1 = OpTypeVoid
|
%1 = OpTypeVoid
|
||||||
%2 = OpConstantNull %1)";
|
%2 = OpConstantNull %1)";
|
||||||
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateID, OpConstantNullArrayBad) {
|
TEST_F(ValidateID, OpConstantNullArrayBad) {
|
||||||
const char* spirv = R"(
|
const char* spirv = R"(
|
||||||
%2 = OpTypeInt 32 0
|
%2 = OpTypeInt 32 0
|
||||||
@ -630,6 +636,7 @@ TEST_F(ValidateID, OpConstantNullArrayBad) {
|
|||||||
%6 = OpConstantNull %5)";
|
%6 = OpConstantNull %5)";
|
||||||
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ValidateID, OpConstantNullStructBad) {
|
TEST_F(ValidateID, OpConstantNullStructBad) {
|
||||||
const char* spirv = R"(
|
const char* spirv = R"(
|
||||||
%2 = OpTypeSampler
|
%2 = OpTypeSampler
|
||||||
@ -638,6 +645,14 @@ TEST_F(ValidateID, OpConstantNullStructBad) {
|
|||||||
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ValidateID, OpConstantNullRuntimeArrayBad) {
|
||||||
|
const char* spirv = R"(
|
||||||
|
%bool = OpTypeBool
|
||||||
|
%array = OpTypeRuntimeArray %bool
|
||||||
|
%null = OpConstantNull %array)";
|
||||||
|
CHECK(spirv, SPV_ERROR_INVALID_ID);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ValidateID, OpSpecConstantTrueGood) {
|
TEST_F(ValidateID, OpSpecConstantTrueGood) {
|
||||||
const char* spirv = R"(
|
const char* spirv = R"(
|
||||||
%1 = OpTypeBool
|
%1 = OpTypeBool
|
||||||
|
Loading…
Reference in New Issue
Block a user