diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp index 8ac498e1556be..baeed2ad895a4 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -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(&MIRBuilder.getMF().getSubtarget()); + // Handle entry points and function linkage. if (isEntryPoint(F)) { const auto &STI = MIRBuilder.getMF().getSubtarget(); @@ -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(LnkTy)}, F.getGlobalIdentifier()); } // Handle function pointers decoration - const auto *ST = - static_cast(&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); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index 52eeb8a523e6f..ed2c9ab4d4362 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -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(), diff --git a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp index a18aae1761c83..0412d98345524 100644 --- a/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp @@ -647,6 +647,12 @@ static void addOpDecorateReqs(const MachineInstr &MI, unsigned DecIndex, auto BuiltIn = static_cast(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(LinkageOp); + if (LnkType == SPIRV::LinkageType::LinkOnceODR) + Reqs.addExtension(SPIRV::Extension::SPV_KHR_linkonce_odr); } } diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp index effedc2f17d35..354cd5d9b297e 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -54,6 +54,11 @@ cl::list 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"))); diff --git a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td index 5d252275ac709..ed05013642ac2 100644 --- a/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td +++ b/llvm/lib/Target/SPIRV/SPIRVSymbolicOperands.td @@ -1040,6 +1040,7 @@ multiclass LinkageTypeOperand value, list 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 diff --git a/llvm/test/CodeGen/SPIRV/LinkOnceODR.ll b/llvm/test/CodeGen/SPIRV/LinkOnceODR.ll index 3fb49ac241c6e..3dfdeac7adaa5 100644 --- a/llvm/test/CodeGen/SPIRV/LinkOnceODR.ll +++ b/llvm/test/CodeGen/SPIRV/LinkOnceODR.ll @@ -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 diff --git a/llvm/test/CodeGen/SPIRV/LinkOnceODRFun.ll b/llvm/test/CodeGen/SPIRV/LinkOnceODRFun.ll new file mode 100644 index 0000000000000..7505c3fc277e9 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/LinkOnceODRFun.ll @@ -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 +}