Skip to content

Commit 26fb01b

Browse files
authored
Add validation support for Intel SPIR-V extensions (KhronosGroup#6232)
This PR adds validation support for three Intel SPIR-V extensions: OpConstantFunctionPointerINTEL: Added validation logic and test coverage ArbitraryPrecisionIntegersINTEL: Added type validation support and tests OpAliasScopeDeclINTEL/OpAliasScopeListDeclINTEL: Added ID validation support and tests Fixes KhronosGroup#6034
1 parent 8d00442 commit 26fb01b

12 files changed

Lines changed: 380 additions & 4 deletions

source/operand.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,11 @@ std::function<bool(unsigned)> spvOperandCanBeForwardDeclaredFunction(
546546
out = [](unsigned index) { return index == 2; };
547547
break;
548548

549+
case spv::Op::OpConstantFunctionPointerINTEL:
550+
// The Function parameter.
551+
out = [](unsigned index) { return index == 2; };
552+
break;
553+
549554
case spv::Op::OpPhi:
550555
out = [](unsigned index) { return index > 1; };
551556
break;

source/val/validate_annotation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ bool DecorationTakesIdParameters(spv::Decoration type) {
3939
case spv::Decoration::PayloadNodeBaseIndexAMDX:
4040
case spv::Decoration::ArrayStrideIdEXT:
4141
case spv::Decoration::OffsetIdEXT:
42+
case spv::Decoration::AliasScopeINTEL:
43+
case spv::Decoration::NoAliasINTEL:
4244
return true;
4345
default:
4446
break;

source/val/validate_constants.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,52 @@ spv_result_t ValidateSpecConstantOp(ValidationState_t& _,
647647
return SPV_SUCCESS;
648648
}
649649

650+
spv_result_t ValidateConstantFunctionPointerINTEL(ValidationState_t& _,
651+
const Instruction* inst) {
652+
const auto result_type = _.FindDef(inst->type_id());
653+
// Result Type must be a pointer type
654+
if (result_type->opcode() != spv::Op::OpTypePointer &&
655+
result_type->opcode() != spv::Op::OpTypeUntypedPointerKHR) {
656+
return _.diag(SPV_ERROR_INVALID_ID, inst)
657+
<< "OpConstantFunctionPointerINTEL Result Type <id> "
658+
<< _.getIdName(inst->type_id()) << " is not a pointer type";
659+
}
660+
661+
// For typed pointers, check that pointee is a function type
662+
const Instruction* pointee_type = nullptr;
663+
if (result_type->opcode() == spv::Op::OpTypePointer) {
664+
pointee_type = _.FindDef(result_type->GetOperandAs<uint32_t>(2));
665+
if (pointee_type->opcode() != spv::Op::OpTypeFunction) {
666+
return _.diag(SPV_ERROR_INVALID_ID, inst)
667+
<< "OpConstantFunctionPointerINTEL Result Type <id> "
668+
<< _.getIdName(inst->type_id())
669+
<< " must be a pointer to function type";
670+
}
671+
}
672+
673+
// Validate that the function operand refers to an OpFunction
674+
const uint32_t function_id = inst->GetOperandAs<uint32_t>(2);
675+
const auto function_inst = _.FindDef(function_id);
676+
if (function_inst->opcode() != spv::Op::OpFunction) {
677+
return _.diag(SPV_ERROR_INVALID_ID, inst)
678+
<< "OpConstantFunctionPointerINTEL Function operand <id> "
679+
<< _.getIdName(function_id) << " is not an OpFunction";
680+
}
681+
682+
// For typed pointers, validate that function type matches pointee type
683+
if (pointee_type) {
684+
const uint32_t function_type_id = function_inst->GetOperandAs<uint32_t>(3);
685+
if (function_type_id != pointee_type->id()) {
686+
return _.diag(SPV_ERROR_INVALID_ID, inst)
687+
<< "OpConstantFunctionPointerINTEL Function operand <id> "
688+
<< _.getIdName(function_id)
689+
<< " type does not match the pointer's function type";
690+
}
691+
}
692+
693+
return SPV_SUCCESS;
694+
}
695+
650696
} // namespace
651697

652698
spv_result_t ConstantPass(ValidationState_t& _, const Instruction* inst) {
@@ -681,6 +727,10 @@ spv_result_t ConstantPass(ValidationState_t& _, const Instruction* inst) {
681727
case spv::Op::OpConstantSizeOfEXT:
682728
if (auto error = ValidateConstantSizeOfEXT(_, inst)) return error;
683729
break;
730+
case spv::Op::OpConstantFunctionPointerINTEL:
731+
if (auto error = ValidateConstantFunctionPointerINTEL(_, inst))
732+
return error;
733+
break;
684734
default:
685735
break;
686736
}

source/val/validate_function.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
9191
spv::Op::OpCooperativeMatrixReduceNV,
9292
spv::Op::OpCooperativeMatrixLoadTensorNV,
9393
spv::Op::OpConditionalEntryPointINTEL,
94-
};
95-
94+
spv::Op::OpConstantFunctionPointerINTEL};
9695
for (auto& pair : inst->uses()) {
9796
const auto* use = pair.first;
9897
if (std::find(acceptable.begin(), acceptable.end(), use->opcode()) ==
9998
acceptable.end() &&
100-
!use->IsNonSemantic() && !use->IsDebugInfo()) {
99+
!use->IsNonSemantic() && !use->IsDebugInfo() &&
100+
!spvOpcodeIsDecoration(use->opcode())) {
101101
return _.diag(SPV_ERROR_INVALID_ID, use)
102102
<< "Invalid use of function result id " << _.getIdName(inst->id())
103103
<< ".";

source/val/validate_id.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ bool InstructionRequiresTypeOperand(const Instruction* inst) {
154154
spv::Op::OpPhi,
155155
spv::Op::OpUntypedArrayLengthKHR,
156156
spv::Op::OpAsmINTEL,
157+
spv::Op::OpAliasScopeDeclINTEL,
158+
spv::Op::OpAliasScopeListDeclINTEL,
157159
};
158160
const auto opcode = inst->opcode();
159161
bool debug_instruction = spvOpcodeIsDebug(opcode) || inst->IsDebugInfo();

source/val/validate_logical_pointers.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,8 @@ spv_result_t ValidateLogicalPointerReturns(ValidationState_t& _,
366366
case spv::Op::OpCopyObject:
367367
// Core spec bugs
368368
case spv::Op::OpUndef:
369+
// SPV_INTEL_function_pointers
370+
case spv::Op::OpConstantFunctionPointerINTEL:
369371
// SPV_KHR_untyped_pointers
370372
case spv::Op::OpUntypedAccessChainKHR:
371373
case spv::Op::OpUntypedInBoundsAccessChainKHR:

source/val/validate_type.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ spv_result_t ValidateTypeInt(ValidationState_t& _, const Instruction* inst) {
8181
return _.diag(SPV_ERROR_INVALID_DATA, inst)
8282
<< "Using a 64-bit integer type requires the Int64 capability.";
8383
} else {
84+
// Check for SPV_INTEL_arbitrary_precision_integers extension
85+
if (_.HasCapability(spv::Capability::ArbitraryPrecisionIntegersINTEL)) {
86+
if (num_bits == 0) {
87+
return _.diag(SPV_ERROR_INVALID_DATA, inst)
88+
<< "OpTypeInt has 0 bits, which is not allowed even with "
89+
"ArbitraryPrecisionIntegersINTEL.";
90+
}
91+
return SPV_SUCCESS;
92+
}
8493
return _.diag(SPV_ERROR_INVALID_DATA, inst)
8594
<< "Invalid number of bits (" << num_bits
8695
<< ") used for OpTypeInt.";
@@ -639,13 +648,20 @@ spv_result_t ValidateTypeFunction(ValidationState_t& _,
639648
}
640649

641650
// The only valid uses of OpTypeFunction are in an OpFunction, debugging, or
642-
// decoration instruction.
651+
// decoration instruction, or in OpTypePointer when FunctionPointersINTEL
652+
// capability is enabled.
643653
for (auto& pair : inst->uses()) {
644654
const auto* use = pair.first;
645655
if (use->opcode() != spv::Op::OpFunction &&
646656
use->opcode() != spv::Op::OpAsmINTEL &&
647657
!spvOpcodeIsDebug(use->opcode()) && !use->IsNonSemantic() &&
648658
!spvOpcodeIsDecoration(use->opcode())) {
659+
// Check if this is OpTypePointer with FunctionPointersINTEL capability
660+
if (use->opcode() == spv::Op::OpTypePointer &&
661+
_.HasCapability(spv::Capability::FunctionPointersINTEL)) {
662+
// Allow OpTypePointer to use function types with this capability
663+
continue;
664+
}
649665
return _.diag(SPV_ERROR_INVALID_ID, use)
650666
<< "Invalid use of function type result id "
651667
<< _.getIdName(inst->id()) << ".";

source/val/validation_state.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ ModuleLayoutSection InstructionLayoutSection(
7777
case spv::Op::OpDecorateId:
7878
case spv::Op::OpDecorateStringGOOGLE:
7979
case spv::Op::OpMemberDecorateStringGOOGLE:
80+
// SPV_INTEL_memory_access_aliasing: alias scope instructions go in the
81+
// annotations section so that OpDecorateId can reference them without
82+
// requiring a forward reference across layout sections.
83+
case spv::Op::OpAliasDomainDeclINTEL:
84+
case spv::Op::OpAliasScopeDeclINTEL:
85+
case spv::Op::OpAliasScopeListDeclINTEL:
8086
return kLayoutAnnotations;
8187
case spv::Op::OpTypeForwardPointer:
8288
case spv::Op::OpTypeTaskSequenceINTEL:

test/val/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_spvtools_unittest(TARGET val_abcde
4949
val_extension_spv_khr_terminate_invocation_test.cpp
5050
val_extension_spv_khr_subgroup_rotate_test.cpp
5151
val_extension_spv_nv_raw_access_chains.cpp
52+
val_extension_spv_intel_arbitrary_precision_integers_test.cpp
5253
val_extension_spv_intel_function_variants.cpp
5354
val_extension_spv_intel_inline_assembly.cpp
5455
val_extension_spv_ext_descriptor_heap.cpp

test/val/val_constants_test.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,28 @@ INSTANTIATE_TEST_SUITE_P(
11351135
// "InBoundsPtrAccessChain"),
11361136
}));
11371137

1138+
TEST_F(ValidateConstant, ForwardConstantFunctionPointerINTEL) {
1139+
const std::string spirv = R"(
1140+
OpCapability Linkage
1141+
OpCapability Shader
1142+
OpCapability FunctionPointersINTEL
1143+
OpExtension "SPV_INTEL_function_pointers"
1144+
OpMemoryModel Logical Simple
1145+
%void = OpTypeVoid
1146+
%functype = OpTypeFunction %void
1147+
; UniformConstant avoids logical pointer validation conflicts in Function sc
1148+
%ptr_fun = OpTypePointer UniformConstant %functype
1149+
%const_ptr = OpConstantFunctionPointerINTEL %ptr_fun %target_func
1150+
%target_func = OpFunction %void None %functype
1151+
%lbl = OpLabel
1152+
OpReturn
1153+
OpFunctionEnd
1154+
)";
1155+
1156+
CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3);
1157+
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
1158+
}
1159+
11381160
} // namespace
11391161
} // namespace val
11401162
} // namespace spvtools

0 commit comments

Comments
 (0)