* ValidationState_t and idUsage now store the addressing model and memory model of the SPIR-V module (this is necessary for certain instructions that need different checks depending on if the logical or physical addressing model is used)
* removed SpvOpPtrAccessChain and SpvOpInBoundsPtrAccessChain from spvOpcodeIsPointer again as these are disallowed in logical addressing mode and only allowed in physical addressing mode (which doesn't use/need spvOpcodeIsPointer in the first place)
* added SpvOpImageTexelPointer and SpvOpCopyObject to spvOpcodeIsPointer
* OpLoad/OpStore now only check if the used pointer operand originated from a valid pointer producing opcode in logical addressing mode (as per 2.16.1)
* moved bitcast pointer tests to the kernel / physical addressing model part (+cleanup)
* renamed spvOpcodeIsPointer to spvOpcodeReturnsLogicalPointer to clarify this function is only meant to be used with the logical addressing model
}
}
-int32_t spvOpcodeIsPointer(const SpvOp opcode) {
+int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode) {
switch (opcode) {
case SpvOpVariable:
case SpvOpAccessChain:
- case SpvOpPtrAccessChain:
case SpvOpInBoundsAccessChain:
- case SpvOpInBoundsPtrAccessChain:
case SpvOpFunctionParameter:
+ case SpvOpImageTexelPointer:
+ case SpvOpCopyObject:
return true;
default:
return false;
// non-zero otherwise.
int32_t spvOpcodeIsComposite(const SpvOp opcode);
-// Determines if the given opcode results in a pointer. Returns zero if false,
-// non-zero otherwise.
-int32_t spvOpcodeIsPointer(const SpvOp opcode);
+// Determines if the given opcode results in a pointer when using the logical
+// addressing model. Returns zero if false, non-zero otherwise.
+int32_t spvOpcodeReturnsLogicalPointer(const SpvOp opcode);
// Determines if the given opcode generates a type. Returns zero if false,
// non-zero otherwise.
// capabilities==0.
bool HasAnyOf(spv_capability_mask_t capabilities) const;
+ // Sets the addressing model of this module (logical/physical).
+ void setAddressingModel(SpvAddressingModel am);
+
+ // Returns the addressing model of this module, or Logical if uninitialized.
+ SpvAddressingModel getAddressingModel() const;
+
+ // Sets the memory model of this module.
+ void setMemoryModel(SpvMemoryModel mm);
+
+ // Returns the memory model of this module, or Simple if uninitialized.
+ SpvMemoryModel getMemoryModel() const;
+
AssemblyGrammar& grammar() { return grammar_; }
private:
std::vector<uint32_t> entry_points_;
AssemblyGrammar grammar_;
+
+ SpvAddressingModel addressing_model_;
+ SpvMemoryModel memory_model_;
+
};
} // namespace libspirv
const spv_operand_table operandTableArg,
const spv_ext_inst_table extInstTableArg,
const spv_instruction_t* pInsts, const uint64_t instCountArg,
+ const SpvMemoryModel memoryModelArg,
+ const SpvAddressingModel addressingModelArg,
const UseDefTracker& usedefs,
const std::vector<uint32_t>& entry_points, spv_position positionArg,
spv_diagnostic* pDiagnosticArg)
extInstTable(extInstTableArg),
firstInst(pInsts),
instCount(instCountArg),
+ memoryModel(memoryModelArg),
+ addressingModel(addressingModelArg),
position(positionArg),
pDiagnostic(pDiagnosticArg),
usedefs_(usedefs),
const spv_ext_inst_table extInstTable;
const spv_instruction_t* const firstInst;
const uint64_t instCount;
+ const SpvMemoryModel memoryModel;
+ const SpvAddressingModel addressingModel;
spv_position position;
spv_diagnostic* pDiagnostic;
UseDefTracker usedefs_;
return false);
auto pointerIndex = 3;
auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
- if (!pointer.first || !spvOpcodeIsPointer(pointer.second.opcode)) {
+ if (!pointer.first ||
+ (addressingModel == SpvAddressingModelLogical &&
+ !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
DIAG(pointerIndex) << "OpLoad Pointer <id> '" << inst->words[pointerIndex]
<< "' is not a pointer.";
return false;
const spv_opcode_desc) {
auto pointerIndex = 1;
auto pointer = usedefs_.FindDef(inst->words[pointerIndex]);
- if (!pointer.first || !spvOpcodeIsPointer(pointer.second.opcode)) {
+ if (!pointer.first ||
+ (addressingModel == SpvAddressingModelLogical &&
+ !spvOpcodeReturnsLogicalPointer(pointer.second.opcode))) {
DIAG(pointerIndex) << "OpStore Pointer <id> '" << inst->words[pointerIndex]
<< "' is not a pointer.";
return false;
}
auto pointerType = usedefs_.FindDef(pointer.second.type_id);
- assert(pointerType.first);
+ if (!pointer.first || pointerType.second.opcode != SpvOpTypePointer) {
+ DIAG(pointerIndex) << "OpStore type for pointer <id> '"
+ << inst->words[pointerIndex]
+ << "' is not a pointer type.";
+ return false;
+ }
auto type = usedefs_.FindDef(pointerType.second.words[3]);
assert(type.first);
spvCheck(SpvOpTypeVoid == type.second.opcode, DIAG(pointerIndex)
spv_position position,
spv_diagnostic* pDiag) {
idUsage idUsage(opcodeTable, operandTable, extInstTable, pInsts, instCount,
+ state.getMemoryModel(), state.getAddressingModel(),
state.usedefs(), state.entry_points(), position, pDiag);
for (uint64_t instIndex = 0; instIndex < instCount; ++instIndex) {
spvCheck(!idUsage.isValid(&pInsts[instIndex]), return SPV_ERROR_INVALID_ID);
if (opcode == SpvOpCapability)
_.registerCapability(
static_cast<SpvCapability>(inst->words[inst->operands[0].offset]));
+ if (opcode == SpvOpMemoryModel) {
+ _.setAddressingModel(
+ static_cast<SpvAddressingModel>(inst->words[inst->operands[0].offset]));
+ _.setMemoryModel(
+ static_cast<SpvMemoryModel>(inst->words[inst->operands[1].offset]));
+ }
if (opcode == SpvOpVariable) {
const auto storage_class =
static_cast<SpvStorageClass>(inst->words[inst->operands[2].offset]);
current_layout_section_(kLayoutCapabilities),
module_functions_(*this),
module_capabilities_(0u),
- grammar_(context) {}
+ grammar_(context),
+ addressing_model_(SpvAddressingModelLogical),
+ memory_model_(SpvMemoryModelSimple) {}
spv_result_t ValidationState_t::forwardDeclareId(uint32_t id) {
unresolved_forward_ids_.insert(id);
});
return found;
}
+
+void ValidationState_t::setAddressingModel(SpvAddressingModel am) {
+ addressing_model_ = am;
+}
+
+SpvAddressingModel ValidationState_t::getAddressingModel() const {
+ return addressing_model_;
+}
+
+void ValidationState_t::setMemoryModel(SpvMemoryModel mm) {
+ memory_model_ = mm;
+}
+
+SpvMemoryModel ValidationState_t::getMemoryModel() const {
+ return memory_model_;
+}
Functions::Functions(ValidationState_t& module)
: module_(module), in_function_(false), in_block_(false) {}
CHECK_KERNEL(spirv, SPV_SUCCESS, 64);
}
+TEST_F(ValidateID, OpLoadBitcastPointerGood) {
+ const char* spirv = R"(
+%2 = OpTypeVoid
+%3 = OpTypeInt 32 1
+%4 = OpTypeFloat 32
+%5 = OpTypePointer UniformConstant %3
+%6 = OpTypePointer UniformConstant %4
+%7 = OpVariable %5 UniformConstant
+%8 = OpTypeFunction %2
+%9 = OpFunction %2 None %8
+%10 = OpLabel
+%11 = OpBitcast %6 %7
+%12 = OpLoad %4 %11
+ OpReturn
+ OpFunctionEnd)";
+ CHECK_KERNEL(spirv, SPV_SUCCESS, 64);
+}
+TEST_F(ValidateID, OpLoadBitcastNonPointerBad) {
+ const char* spirv = R"(
+%2 = OpTypeVoid
+%3 = OpTypeInt 32 1
+%4 = OpTypeFloat 32
+%5 = OpTypePointer UniformConstant %3
+%6 = OpTypeFunction %2
+%7 = OpVariable %5 UniformConstant
+%8 = OpFunction %2 None %6
+%9 = OpLabel
+%10 = OpLoad %3 %7
+%11 = OpBitcast %4 %10
+%12 = OpLoad %3 %11
+ OpReturn
+ OpFunctionEnd)";
+ CHECK_KERNEL(spirv, SPV_ERROR_INVALID_ID, 64);
+}
+TEST_F(ValidateID, OpStoreBitcastPointerGood) {
+ const char* spirv = R"(
+%2 = OpTypeVoid
+%3 = OpTypeInt 32 1
+%4 = OpTypeFloat 32
+%5 = OpTypePointer Function %3
+%6 = OpTypePointer Function %4
+%7 = OpTypeFunction %2
+%8 = OpConstant %3 42
+%9 = OpFunction %2 None %7
+%10 = OpLabel
+%11 = OpVariable %6 Function
+%12 = OpBitcast %5 %11
+ OpStore %12 %8
+ OpReturn
+ OpFunctionEnd)";
+ CHECK_KERNEL(spirv, SPV_SUCCESS, 64);
+}
+TEST_F(ValidateID, OpStoreBitcastNonPointerBad) {
+ const char* spirv = R"(
+%2 = OpTypeVoid
+%3 = OpTypeInt 32 1
+%4 = OpTypeFloat 32
+%5 = OpTypePointer Function %4
+%6 = OpTypeFunction %2
+%7 = OpConstant %4 42
+%8 = OpFunction %2 None %6
+%9 = OpLabel
+%10 = OpVariable %5 Function
+%11 = OpBitcast %3 %7
+ OpStore %11 %7
+ OpReturn
+ OpFunctionEnd)";
+ CHECK_KERNEL(spirv, SPV_ERROR_INVALID_ID, 64);
+}
+
// TODO: OpLifetimeStart
// TODO: OpLifetimeStop
// TODO: OpAtomicInit