@@ -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+
14301550spv_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 ;
0 commit comments