Skip to content

Commit 6761288

Browse files
authored
Validator: Support SPV_NV_raw_access_chains (KhronosGroup#5568)
1 parent 3983d15 commit 6761288

6 files changed

Lines changed: 644 additions & 4 deletions

File tree

source/opcode.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) {
295295
case spv::Op::OpPtrAccessChain:
296296
case spv::Op::OpLoad:
297297
case spv::Op::OpConstantNull:
298+
case spv::Op::OpRawAccessChainNV:
298299
return true;
299300
default:
300301
return false;
@@ -309,6 +310,7 @@ int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) {
309310
case spv::Op::OpFunctionParameter:
310311
case spv::Op::OpImageTexelPointer:
311312
case spv::Op::OpCopyObject:
313+
case spv::Op::OpRawAccessChainNV:
312314
return true;
313315
default:
314316
return false;
@@ -754,6 +756,7 @@ bool spvOpcodeIsAccessChain(spv::Op opcode) {
754756
case spv::Op::OpInBoundsAccessChain:
755757
case spv::Op::OpPtrAccessChain:
756758
case spv::Op::OpInBoundsPtrAccessChain:
759+
case spv::Op::OpRawAccessChainNV:
757760
return true;
758761
default:
759762
return false;

source/val/validate_annotation.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec,
161161
case spv::Decoration::RestrictPointer:
162162
case spv::Decoration::AliasedPointer:
163163
if (target->opcode() != spv::Op::OpVariable &&
164-
target->opcode() != spv::Op::OpFunctionParameter) {
164+
target->opcode() != spv::Op::OpFunctionParameter &&
165+
target->opcode() != spv::Op::OpRawAccessChainNV) {
165166
return fail(0) << "must be a memory object declaration";
166167
}
167168
if (_.GetIdOpcode(target->type_id()) != spv::Op::OpTypePointer) {

source/val/validate_decorations.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,7 +1556,8 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate,
15561556
const auto opcode = inst.opcode();
15571557
const auto type_id = inst.type_id();
15581558
if (opcode != spv::Op::OpVariable &&
1559-
opcode != spv::Op::OpFunctionParameter) {
1559+
opcode != spv::Op::OpFunctionParameter &&
1560+
opcode != spv::Op::OpRawAccessChainNV) {
15601561
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
15611562
<< "Target of NonWritable decoration must be a memory object "
15621563
"declaration (a variable or a function parameter)";
@@ -1569,10 +1570,11 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate,
15691570
vstate.features().nonwritable_var_in_function_or_private) {
15701571
// New permitted feature in SPIR-V 1.4.
15711572
} else if (
1572-
// It may point to a UBO, SSBO, or storage image.
1573+
// It may point to a UBO, SSBO, storage image, or raw access chain.
15731574
vstate.IsPointerToUniformBlock(type_id) ||
15741575
vstate.IsPointerToStorageBuffer(type_id) ||
1575-
vstate.IsPointerToStorageImage(type_id)) {
1576+
vstate.IsPointerToStorageImage(type_id) ||
1577+
opcode == spv::Op::OpRawAccessChainNV) {
15761578
} else {
15771579
return vstate.diag(SPV_ERROR_INVALID_ID, &inst)
15781580
<< "Target of NonWritable decoration is invalid: must point to a "

source/val/validate_memory.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1427,6 +1427,126 @@ spv_result_t ValidateAccessChain(ValidationState_t& _,
14271427
return SPV_SUCCESS;
14281428
}
14291429

1430+
spv_result_t ValidateRawAccessChain(ValidationState_t& _,
1431+
const Instruction* inst) {
1432+
std::string instr_name = "Op" + std::string(spvOpcodeString(inst->opcode()));
1433+
1434+
// The result type must be OpTypePointer.
1435+
const auto result_type = _.FindDef(inst->type_id());
1436+
if (spv::Op::OpTypePointer != result_type->opcode()) {
1437+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1438+
<< "The Result Type of " << instr_name << " <id> "
1439+
<< _.getIdName(inst->id()) << " must be OpTypePointer. Found Op"
1440+
<< spvOpcodeString(result_type->opcode()) << '.';
1441+
}
1442+
1443+
// The pointed storage class must be valid.
1444+
const auto storage_class = result_type->GetOperandAs<spv::StorageClass>(1);
1445+
if (storage_class != spv::StorageClass::StorageBuffer &&
1446+
storage_class != spv::StorageClass::PhysicalStorageBuffer &&
1447+
storage_class != spv::StorageClass::Uniform) {
1448+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1449+
<< "The Result Type of " << instr_name << " <id> "
1450+
<< _.getIdName(inst->id())
1451+
<< " must point to a storage class of "
1452+
"StorageBuffer, PhysicalStorageBuffer, or Uniform.";
1453+
}
1454+
1455+
// The pointed type must not be one in the list below.
1456+
const auto result_type_pointee =
1457+
_.FindDef(result_type->GetOperandAs<uint32_t>(2));
1458+
if (result_type_pointee->opcode() == spv::Op::OpTypeArray ||
1459+
result_type_pointee->opcode() == spv::Op::OpTypeMatrix ||
1460+
result_type_pointee->opcode() == spv::Op::OpTypeStruct) {
1461+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1462+
<< "The Result Type of " << instr_name << " <id> "
1463+
<< _.getIdName(inst->id())
1464+
<< " must not point to "
1465+
"OpTypeArray, OpTypeMatrix, or OpTypeStruct.";
1466+
}
1467+
1468+
// Validate Stride is a OpConstant.
1469+
const auto stride = _.FindDef(inst->GetOperandAs<uint32_t>(3));
1470+
if (stride->opcode() != spv::Op::OpConstant) {
1471+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1472+
<< "The Stride of " << instr_name << " <id> "
1473+
<< _.getIdName(inst->id()) << " must be OpConstant. Found Op"
1474+
<< spvOpcodeString(stride->opcode()) << '.';
1475+
}
1476+
// Stride type must be OpTypeInt
1477+
const auto stride_type = _.FindDef(stride->type_id());
1478+
if (stride_type->opcode() != spv::Op::OpTypeInt) {
1479+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1480+
<< "The type of Stride of " << instr_name << " <id> "
1481+
<< _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
1482+
<< spvOpcodeString(stride_type->opcode()) << '.';
1483+
}
1484+
1485+
// Index and Offset type must be OpTypeInt with a width of 32
1486+
const auto ValidateType = [&](const char* name,
1487+
int operandIndex) -> spv_result_t {
1488+
const auto value = _.FindDef(inst->GetOperandAs<uint32_t>(operandIndex));
1489+
const auto value_type = _.FindDef(value->type_id());
1490+
if (value_type->opcode() != spv::Op::OpTypeInt) {
1491+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1492+
<< "The type of " << name << " of " << instr_name << " <id> "
1493+
<< _.getIdName(inst->id()) << " must be OpTypeInt. Found Op"
1494+
<< spvOpcodeString(value_type->opcode()) << '.';
1495+
}
1496+
const auto width = value_type->GetOperandAs<uint32_t>(1);
1497+
if (width != 32) {
1498+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1499+
<< "The integer width of " << name << " of " << instr_name
1500+
<< " <id> " << _.getIdName(inst->id()) << " must be 32. Found "
1501+
<< width << '.';
1502+
}
1503+
return SPV_SUCCESS;
1504+
};
1505+
spv_result_t result;
1506+
result = ValidateType("Index", 4);
1507+
if (result != SPV_SUCCESS) {
1508+
return result;
1509+
}
1510+
result = ValidateType("Offset", 5);
1511+
if (result != SPV_SUCCESS) {
1512+
return result;
1513+
}
1514+
1515+
uint32_t access_operands = 0;
1516+
if (inst->operands().size() >= 7) {
1517+
access_operands = inst->GetOperandAs<uint32_t>(6);
1518+
}
1519+
if (access_operands &
1520+
uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
1521+
uint64_t stride_value = 0;
1522+
if (_.EvalConstantValUint64(stride->id(), &stride_value) &&
1523+
stride_value == 0) {
1524+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1525+
<< "Stride must not be zero when per-element robustness is used.";
1526+
}
1527+
}
1528+
if (access_operands &
1529+
uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) ||
1530+
access_operands &
1531+
uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
1532+
if (storage_class == spv::StorageClass::PhysicalStorageBuffer) {
1533+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1534+
<< "Storage class cannot be PhysicalStorageBuffer when "
1535+
"raw access chain robustness is used.";
1536+
}
1537+
}
1538+
if (access_operands &
1539+
uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) &&
1540+
access_operands &
1541+
uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) {
1542+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
1543+
<< "Per-component robustness and per-element robustness are "
1544+
"mutually exclusive.";
1545+
}
1546+
1547+
return SPV_SUCCESS;
1548+
}
1549+
14301550
spv_result_t ValidatePtrAccessChain(ValidationState_t& _,
14311551
const Instruction* inst) {
14321552
if (_.addressing_model() == spv::AddressingModel::Logical) {
@@ -1866,6 +1986,9 @@ spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) {
18661986
case spv::Op::OpInBoundsPtrAccessChain:
18671987
if (auto error = ValidateAccessChain(_, inst)) return error;
18681988
break;
1989+
case spv::Op::OpRawAccessChainNV:
1990+
if (auto error = ValidateRawAccessChain(_, inst)) return error;
1991+
break;
18691992
case spv::Op::OpArrayLength:
18701993
if (auto error = ValidateArrayLength(_, inst)) return error;
18711994
break;

test/val/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_spvtools_unittest(TARGET val_abcde
4646
val_extension_spv_khr_bit_instructions_test.cpp
4747
val_extension_spv_khr_terminate_invocation_test.cpp
4848
val_extension_spv_khr_subgroup_rotate_test.cpp
49+
val_extension_spv_nv_raw_access_chains.cpp
4950
val_ext_inst_test.cpp
5051
val_ext_inst_debug_test.cpp
5152
${VAL_TEST_COMMON_SRCS}

0 commit comments

Comments
 (0)