Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support SPV_INTEL_maximum_registers extension #2344

Merged
merged 9 commits into from
Feb 26, 2024
1 change: 1 addition & 0 deletions include/LLVMSPIRVExtensions.inc
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,4 @@ EXT(SPV_INTEL_fpga_argument_interfaces)
EXT(SPV_INTEL_fpga_latency_control)
EXT(SPV_INTEL_fp_max_error)
EXT(SPV_INTEL_cache_controls)
EXT(SPV_INTEL_maximum_registers)
15 changes: 15 additions & 0 deletions lib/SPIRV/SPIRVReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4306,6 +4306,21 @@ bool SPIRVToLLVM::transMetadata() {
F->setMetadata(kSPIR2MD::IntelFPGAIPInterface,
MDNode::get(*Context, InterfaceMDVec));
}
// TODO: Also add support for ExecutionModeMaximumRegistersIdINTEL and
// ExecutionModeNamedMaximumRegistersINTEL
if (auto *EM = BF->getExecutionMode(
Copy link
Contributor

@LU-JOHN LU-JOHN Feb 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check to ensure that only one mode is chosen?

Consider refactoring common code among the three if statements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually no. Even so it seems to have no sense to enable several different maxregisters execution modes, neither SPIR-V core spec, nor extension prohibits usage of several execution modes at the same time. So, I believe this code should not be changed to else if.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From KhronosGroup/SPIRV-Registry#235, in extensions/INTEL/SPV_INTEL_maximum_registers.asciidoc

  • Each OpEntryPoint must contain at most one of the
    MaximumRegistersINTEL, MaximumRegistersIdINTEL, or
    NamedMaximumRegistersINTEL execution modes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in 84a3ead. Unfortunately I can't add meaningful tests for that, because llvm-spirv fails with an assertion in case we add more than one execution mode of the certain type.
Verified locally that this check both on forward and reverse translation in case of invalid IR/SPV.

internal::ExecutionModeMaximumRegistersINTEL)) {
NamedMDNode *ExecModeMD =
M->getOrInsertNamedMetadata(kSPIRVMD::ExecutionMode);

SmallVector<Metadata *, 4> ValueVec;
ValueVec.push_back(ConstantAsMetadata::get(F));
ValueVec.push_back(
ConstantAsMetadata::get(getUInt32(M, EM->getExecutionMode())));
ValueVec.push_back(
ConstantAsMetadata::get(getUInt32(M, EM->getLiterals()[0])));
ExecModeMD->addOperand(MDNode::get(*Context, ValueVec));
}
}
NamedMDNode *MemoryModelMD =
M->getOrInsertNamedMetadata(kSPIRVMD::MemoryModel);
Expand Down
29 changes: 28 additions & 1 deletion lib/SPIRV/SPIRVWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,10 @@ SPIRVFunction *LLVMToSPIRVBase::transFunctionDecl(Function *F) {

transFPGAFunctionMetadata(BF, F);

transFunctionMetadataAsUserSemanticDecoration(BF, F);
if (BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_maximum_registers))
transFunctionMetadataAsExecutionMode(BF, F);
else
transFunctionMetadataAsUserSemanticDecoration(BF, F);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to support the 'old' implementation or throw an error here? Sorry if this is ignorant question.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we do, because it takes time for the consumers to adapt the new change on their side.


transAuxDataInst(BF, F);

Expand Down Expand Up @@ -1118,6 +1121,30 @@ void LLVMToSPIRVBase::transFPGAFunctionMetadata(SPIRVFunction *BF,
transMetadataDecorations(FDecoMD, BF);
}

void LLVMToSPIRVBase::transFunctionMetadataAsExecutionMode(SPIRVFunction *BF,
Function *F) {
if (!BM->isAllowedToUseExtension(ExtensionID::SPV_INTEL_maximum_registers))
vmaksimo marked this conversation as resolved.
Show resolved Hide resolved
return;

// TODO: Also add support for ExecutionModeMaximumRegistersIdINTEL
if (auto *RegisterAllocModeMD = F->getMetadata("RegisterAllocMode")) {
auto *RegisterAllocMode = RegisterAllocModeMD->getOperand(0).get();
if (isa<MDString>(RegisterAllocMode)) {
StringRef Str = getMDOperandAsString(RegisterAllocModeMD, 0);
if (Str == "AutoINTEL")
BF->addExecutionMode(BM->add(new SPIRVExecutionMode(
OpExecutionMode, BF,
internal::ExecutionModeNamedMaximumRegistersINTEL, 0)));
} else {
int64_t RegisterAllocNodeMDOp =
vmaksimo marked this conversation as resolved.
Show resolved Hide resolved
mdconst::dyn_extract<ConstantInt>(RegisterAllocMode)->getZExtValue();
BF->addExecutionMode(BM->add(new SPIRVExecutionMode(
OpExecutionMode, BF, internal::ExecutionModeMaximumRegistersINTEL,
RegisterAllocNodeMDOp)));
}
}
}

void LLVMToSPIRVBase::transFunctionMetadataAsUserSemanticDecoration(
SPIRVFunction *BF, Function *F) {
if (auto *RegisterAllocModeMD = F->getMetadata("RegisterAllocMode")) {
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/SPIRVWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class LLVMToSPIRVBase : protected BuiltinCallHelper {
SPIRVFunction *transFunctionDecl(Function *F);
void transVectorComputeMetadata(Function *F);
void transFPGAFunctionMetadata(SPIRVFunction *BF, Function *F);
void transFunctionMetadataAsExecutionMode(SPIRVFunction *BF, Function *F);
void transFunctionMetadataAsUserSemanticDecoration(SPIRVFunction *BF,
Function *F);
void transAuxDataInst(SPIRVFunction *BF, Function *F);
Expand Down
3 changes: 3 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,9 @@ void SPIRVExecutionMode::decode(std::istream &I) {
case ExecutionModeSchedulerTargetFmaxMhzINTEL:
case ExecutionModeRegisterMapInterfaceINTEL:
case ExecutionModeStreamingInterfaceINTEL:
case internal::ExecutionModeMaximumRegistersINTEL:
case internal::ExecutionModeMaximumRegistersIdINTEL:
case internal::ExecutionModeNamedMaximumRegistersINTEL:
WordLiterals.resize(1);
break;
default:
Expand Down
6 changes: 6 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,12 @@ template <> inline void SPIRVMap<SPIRVExecutionModeKind, SPIRVCapVec>::init() {
{CapabilityFPGAKernelAttributesINTEL});
ADD_VEC_INIT(ExecutionModeNamedBarrierCountINTEL,
{CapabilityVectorComputeINTEL});
ADD_VEC_INIT(internal::ExecutionModeMaximumRegistersINTEL,
{internal::CapabilityRegisterLimitsINTEL});
ADD_VEC_INIT(internal::ExecutionModeMaximumRegistersIdINTEL,
{internal::CapabilityRegisterLimitsINTEL});
ADD_VEC_INIT(internal::ExecutionModeNamedMaximumRegistersINTEL,
{internal::CapabilityRegisterLimitsINTEL});
}

template <> inline void SPIRVMap<SPIRVMemoryModelKind, SPIRVCapVec>::init() {
Expand Down
3 changes: 3 additions & 0 deletions lib/SPIRV/libSPIRV/SPIRVIsValidEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ inline bool isValid(spv::ExecutionModel V) {
case ExecutionModelCallableKHR:
case ExecutionModeRegisterMapInterfaceINTEL:
case ExecutionModeStreamingInterfaceINTEL:
case internal::ExecutionModeMaximumRegistersINTEL:
case internal::ExecutionModeMaximumRegistersIdINTEL:
case internal::ExecutionModeNamedMaximumRegistersINTEL:
return true;
default:
return false;
Expand Down
1 change: 1 addition & 0 deletions lib/SPIRV/libSPIRV/SPIRVNameMapEnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,7 @@ template <> inline void SPIRVMap<Capability, std::string>::init() {
"CooperativeMatrixInvocationInstructionsINTEL");
add(internal::CapabilityCooperativeMatrixCheckedInstructionsINTEL,
"CooperativeMatrixCheckedInstructionsINTEL");
add(internal::CapabilityRegisterLimitsINTEL, "RegisterLimitsINTEL");
}
SPIRV_DEF_NAMEMAP(Capability, SPIRVCapabilityNameMap)

Expand Down
14 changes: 13 additions & 1 deletion lib/SPIRV/libSPIRV/spirv_internal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,17 @@ enum InternalCapability {
ICapabilityJointMatrixBF16ComponentTypeINTEL = 6437,
ICapabilityJointMatrixPackedInt2ComponentTypeINTEL = 6438,
ICapabilityJointMatrixPackedInt4ComponentTypeINTEL = 6439,
ICapabilityCacheControlsINTEL = 6441
ICapabilityCacheControlsINTEL = 6441,
ICapRegisterLimitsINTEL = 6460
};

enum InternalFunctionControlMask { IFunctionControlOptNoneINTELMask = 0x10000 };

enum InternalExecutionMode {
IExecModeFastCompositeKernelINTEL = 6088,
IExecModeMaximumRegistersINTEL = 6461,
IExecModeMaximumRegistersIdINTEL = 6462,
IExecModeNamedMaximumRegistersINTEL = 6463
};

constexpr LinkageType LinkageTypeInternal =
Expand Down Expand Up @@ -289,12 +293,20 @@ constexpr Capability CapabilityBfloat16ConversionINTEL =
static_cast<Capability>(ICapBfloat16ConversionINTEL);
constexpr Capability CapabilityGlobalVariableDecorationsINTEL =
static_cast<Capability>(ICapGlobalVariableDecorationsINTEL);
constexpr Capability CapabilityRegisterLimitsINTEL =
static_cast<Capability>(ICapRegisterLimitsINTEL);

constexpr FunctionControlMask FunctionControlOptNoneINTELMask =
static_cast<FunctionControlMask>(IFunctionControlOptNoneINTELMask);

constexpr ExecutionMode ExecutionModeFastCompositeKernelINTEL =
static_cast<ExecutionMode>(IExecModeFastCompositeKernelINTEL);
constexpr ExecutionMode ExecutionModeMaximumRegistersINTEL =
static_cast<ExecutionMode>(IExecModeMaximumRegistersINTEL);
constexpr ExecutionMode ExecutionModeMaximumRegistersIdINTEL =
static_cast<ExecutionMode>(IExecModeMaximumRegistersIdINTEL);
constexpr ExecutionMode ExecutionModeNamedMaximumRegistersINTEL =
static_cast<ExecutionMode>(IExecModeNamedMaximumRegistersINTEL);

} // namespace internal
} // namespace spv
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
; RUN: llvm-as %s -o %t.bc
; RUN: llvm-spirv -spirv-text --spirv-ext=+SPV_INTEL_maximum_registers %t.bc
; RUN: FileCheck < %t.spt %s --check-prefix=CHECK-SPIRV
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_maximum_registers -o %t.spv
; RUN: llvm-spirv -r %t.spv -spirv-target-env=SPV-IR -o - | llvm-dis -o %t.rev.ll
; RUN: FileCheck < %t.rev.ll %s --check-prefix=CHECK-LLVM

; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC0:]] "main_l3"
; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC1:]] "main_l6"
; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC2:]] "main_l9"
; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC3:]] "main_l13"
; CHECK-SPIRV: EntryPoint [[#]] [[#FUNC4:]] "main_l19"

; CHECK-SPIRV: ExecutionMode [[#FUNC0]] 6461 2
; CHECK-SPIRV: ExecutionMode [[#FUNC1]] 6461 1
; CHECK-SPIRV: ExecutionMode [[#FUNC2]] 6461 0
; CHECK-SPIRV: ExecutionMode [[#FUNC3]] 6461 3

; CHECK-SPIRV-NOT: ExecutionMode [[#FUNC4]]

; CHECK-LLVM: !spirv.ExecutionMode = !{![[#FLAG0:]], ![[#FLAG1:]], ![[#FLAG2:]], ![[#FLAG3:]]}
; CHECK-LLVM: ![[#FLAG0]] = !{ptr @main_l3, i32 6461, i32 2}
; CHECK-LLVM: ![[#FLAG1]] = !{ptr @main_l6, i32 6461, i32 1}
; CHECK-LLVM: ![[#FLAG2]] = !{ptr @main_l9, i32 6461, i32 0}
; CHECK-LLVM: ![[#FLAG3]] = !{ptr @main_l13, i32 6461, i32 3}

target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
target triple = "spir64"

; Function Attrs: noinline nounwind optnone
define weak dso_local spir_kernel void @main_l3() #0 !RegisterAllocMode !10 {
newFuncRoot:
ret void
}

; Function Attrs: noinline nounwind optnone
define weak dso_local spir_kernel void @main_l6() #0 !RegisterAllocMode !11 {
newFuncRoot:
ret void
}

; Function Attrs: noinline nounwind optnone
define weak dso_local spir_kernel void @main_l9() #0 !RegisterAllocMode !12 {
newFuncRoot:
ret void
}

; Function Attrs: noinline nounwind optnone
define weak dso_local spir_kernel void @main_l13() #0 !RegisterAllocMode !13 {
newFuncRoot:
ret void
}

; Function Attrs: noinline nounwind optnone
define weak dso_local spir_kernel void @main_l19() #0 {
newFuncRoot:
ret void
}

attributes #0 = { noinline nounwind optnone }


!opencl.compiler.options = !{!0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0, !0}
!spirv.Source = !{!2, !3, !3, !3, !3, !3, !2, !3, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2, !2}
!llvm.module.flags = !{!4, !5, !6, !7, !8}
!spirv.MemoryModel = !{!9, !9, !9, !9, !9, !9}
!spirv.ExecutionMode = !{}

!0 = !{}
!2 = !{i32 4, i32 200000}
!3 = !{i32 3, i32 200000}
!4 = !{i32 1, !"wchar_size", i32 4}
!5 = !{i32 7, !"openmp", i32 50}
!6 = !{i32 7, !"openmp-device", i32 50}
!7 = !{i32 8, !"PIC Level", i32 2}
!8 = !{i32 7, !"frame-pointer", i32 2}
!9 = !{i32 2, i32 2}
!10 = !{i32 2}
!11 = !{i32 1}
!12 = !{i32 0}
!13 = !{i32 3}
Loading