add support for the SPV_KHR_linkonce_odr extension (#81512)

This PR adds support for the SPV_KHR_linkonce_odr extension and modifies
existing negative test with a positive check for the extension and
proper linkage type in case when the extension is enabled.

SPV_KHR_linkonce_odr adds a "LinkOnceODR" linkage type, allowing proper
translation of, for example, C++ templates classes merging during
linking from different modules and supporting any other cases when a
global variable/function must be merged with equivalent global
variable(s)/function(s) from other modules during the linking process.
This commit is contained in:
Vyacheslav Levytskyy 2024-02-15 11:30:17 +01:00 committed by GitHub
parent dfb9bf35c4
commit 9552a396ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 56 additions and 7 deletions

View File

@ -332,6 +332,10 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
if (F.hasName())
buildOpName(FuncVReg, F.getName(), MIRBuilder);
// Get access to information about available extensions
const auto *ST =
static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
// Handle entry points and function linkage.
if (isEntryPoint(F)) {
const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>();
@ -342,15 +346,19 @@ bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
addStringImm(F.getName(), MIB);
} else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage ||
F.getLinkage() == GlobalValue::LinkOnceODRLinkage) {
auto LnkTy = F.isDeclaration() ? SPIRV::LinkageType::Import
: SPIRV::LinkageType::Export;
SPIRV::LinkageType::LinkageType LnkTy =
F.isDeclaration()
? SPIRV::LinkageType::Import
: (F.getLinkage() == GlobalValue::LinkOnceODRLinkage &&
ST->canUseExtension(
SPIRV::Extension::SPV_KHR_linkonce_odr)
? SPIRV::LinkageType::LinkOnceODR
: SPIRV::LinkageType::Export);
buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
{static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier());
}
// Handle function pointers decoration
const auto *ST =
static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget());
bool hasFunctionPointers =
ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
if (hasFunctionPointers) {
@ -393,7 +401,7 @@ void SPIRVCallLowering::produceIndirectPtrTypes(
// SPIR-V pointer to function type:
SPIRVType *IndirectFuncPtrTy = GR->getOrCreateSPIRVPointerType(
SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
// Correct the Calee type
// Correct the Callee type
GR->assignSPIRVTypeToVReg(IndirectFuncPtrTy, IC.Callee, MF);
}
}

View File

@ -1601,7 +1601,10 @@ bool SPIRVInstructionSelector::selectGlobalValue(
SPIRV::LinkageType::LinkageType LnkType =
(GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
? SPIRV::LinkageType::Import
: SPIRV::LinkageType::Export;
: (GV->getLinkage() == GlobalValue::LinkOnceODRLinkage &&
STI.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr)
? SPIRV::LinkageType::LinkOnceODR
: SPIRV::LinkageType::Export);
Register Reg = GR.buildGlobalVariable(ResVReg, ResType, GlobalIdent, GV,
Storage, Init, GlobalVar->isConstant(),

View File

@ -679,6 +679,12 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex,
auto BuiltIn = static_cast<SPIRV::BuiltIn::BuiltIn>(BuiltInOp);
Reqs.addRequirements(getSymbolicOperandRequirements(
SPIRV::OperandCategory::BuiltInOperand, BuiltIn, ST, Reqs));
} else if (Dec == SPIRV::Decoration::LinkageAttributes) {
int64_t LinkageOp = MI.getOperand(MI.getNumOperands() - 1).getImm();
SPIRV::LinkageType::LinkageType LnkType =
static_cast<SPIRV::LinkageType::LinkageType>(LinkageOp);
if (LnkType == SPIRV::LinkageType::LinkOnceODR)
Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr);
}
}

View File

@ -54,6 +54,11 @@ cl::list<SPIRV::Extension::Extension> Extensions(
"SPV_KHR_bit_instructions",
"This enables bit instructions to be used by SPIR-V modules "
"without requiring the Shader capability"),
clEnumValN(
SPIRV::Extension::SPV_KHR_linkonce_odr, "SPV_KHR_linkonce_odr",
"Allows to use the LinkOnceODR linkage type that is to let "
"a function or global variable to be merged with other functions "
"or global variables of the same name when linkage occurs."),
clEnumValN(SPIRV::Extension::SPV_INTEL_function_pointers,
"SPV_INTEL_function_pointers",
"Allows translation of function pointers")));

View File

@ -1040,6 +1040,7 @@ multiclass LinkageTypeOperand<bits<32> value, list<Capability> reqCapabilities>
defm Export : LinkageTypeOperand<0, [Linkage]>;
defm Import : LinkageTypeOperand<1, [Linkage]>;
defm LinkOnceODR : LinkageTypeOperand<2, [Linkage]>;
//===----------------------------------------------------------------------===//
// Multiclass used to define AccessQualifier enum values and at the same time

View File

@ -1,5 +1,14 @@
;; No extension -> no LinkOnceODR
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-extensions=SPV_KHR_linkonce_odr %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV-EXT
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-extensions=SPV_KHR_linkonce_odr %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV-EXT: Capability Linkage
; CHECK-SPIRV-EXT: Extension "SPV_KHR_linkonce_odr"
; CHECK-SPIRV-EXT-DAG: OpDecorate %[[#]] LinkageAttributes "GV" LinkOnceODR
; CHECK-SPIRV-EXT-DAG: OpDecorate %[[#]] LinkageAttributes "square" LinkOnceODR
; No extension -> no LinkOnceODR
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV-NOT: OpExtension "SPV_KHR_linkonce_odr"
; CHECK-SPIRV-NOT: OpDecorate %[[#]] LinkageAttributes "GV" LinkOnceODR

View File

@ -0,0 +1,17 @@
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown --spirv-extensions=SPV_KHR_linkonce_odr %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV-EXT
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown --spirv-extensions=SPV_KHR_linkonce_odr %s -o - -filetype=obj | spirv-val %}
; CHECK-SPIRV-EXT: Capability Linkage
; CHECK-SPIRV-EXT: Extension "SPV_KHR_linkonce_odr"
; CHECK-SPIRV-EXT-DAG: OpDecorate %[[#]] LinkageAttributes "square" LinkOnceODR
define spir_kernel void @k() {
entry:
%call = call spir_func i32 @square(i32 2)
ret void
}
define linkonce_odr dso_local spir_func i32 @square(i32 %in) {
entry:
ret i32 %in
}