[llvm-branch-commits] [llvm] bc15209 - [𝘀𝗽𝗿] initial version
Jon Roelofs via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Nov 28 10:39:49 PST 2023
Author: Jon Roelofs
Date: 2023-11-28T10:39:44-08:00
New Revision: bc152095691b32d1ad8539dfd60f5089df5eed8d
URL: https://github.com/llvm/llvm-project/commit/bc152095691b32d1ad8539dfd60f5089df5eed8d
DIFF: https://github.com/llvm/llvm-project/commit/bc152095691b32d1ad8539dfd60f5089df5eed8d.diff
LOG: [𝘀𝗽𝗿] initial version
Created using spr 1.3.4
Added:
llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll
llvm/test/CodeGen/AArch64/ifunc-asm.ll
llvm/test/Verifier/ifunc-macho.ll
Modified:
llvm/docs/LangRef.rst
llvm/include/llvm/CodeGen/AsmPrinter.h
llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
llvm/lib/Target/X86/X86AsmPrinter.cpp
llvm/lib/Target/X86/X86AsmPrinter.h
llvm/test/CodeGen/AArch64/addrsig-macho.ll
llvm/test/CodeGen/X86/ifunc-asm.ll
Removed:
################################################################################
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e448c5ed5c5d947..cb222e979db29d4 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -934,10 +934,11 @@ IFuncs
-------
IFuncs, like as aliases, don't create any new data or func. They are just a new
-symbol that dynamic linker resolves at runtime by calling a resolver function.
+symbol that is resolved at runtime by calling a resolver function.
-IFuncs have a name and a resolver that is a function called by dynamic linker
-that returns address of another function associated with the name.
+On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On
+MachO platforms, they are lowered in terms of ``.symbol_resolver``s, which
+lazily resolve the callee the first time they are called.
IFunc may have an optional :ref:`linkage type <linkage>` and an optional
:ref:`visibility style <visibility>`.
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 2731ef452c79cbb..48fa6c478464c73 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -882,7 +882,11 @@ class AsmPrinter : public MachineFunctionPass {
GCMetadataPrinter *getOrCreateGCPrinter(GCStrategy &S);
void emitGlobalAlias(Module &M, const GlobalAlias &GA);
- void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+
+protected:
+ virtual void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
+
+private:
/// This method decides whether the specified basic block requires a label.
bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const;
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index 2527b1431289677..e0080b145d4f995 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -144,7 +144,12 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB,
// Try looking through a bitcast from one function type to another.
// Commonly happens with calls to objc_msgSend().
const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts();
- if (const Function *F = dyn_cast<Function>(CalleeV))
+ if (const GlobalIFunc *IF = dyn_cast<GlobalIFunc>(CalleeV);
+ IF && MF.getTarget().getTargetTriple().isOSBinFormatMachO()) {
+ // ld64 requires that .symbol_resolvers to be called via a stub, so these
+ // must always be a diret call.
+ Info.Callee = MachineOperand::CreateGA(IF, 0);
+ } else if (const Function *F = dyn_cast<Function>(CalleeV))
Info.Callee = MachineOperand::CreateGA(F, 0);
else
Info.Callee = MachineOperand::CreateReg(GetCalleeReg(), false);
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 5560c037aa3ee6b..94e76a43bf38d6d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -959,6 +959,7 @@ void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) {
GlobalIFunc::getResolverFunctionType(GI.getValueType());
Check(ResolverTy == ResolverFuncTy->getPointerTo(GI.getAddressSpace()),
"IFunc resolver has incorrect type", &GI);
+
}
void Verifier::visitNamedMDNode(const NamedMDNode &NMD) {
@@ -2239,13 +2240,10 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
}
// Check EVEX512 feature.
- if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features")) {
- Triple T(M.getTargetTriple());
- if (T.isX86()) {
- StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
- Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
- "512-bit vector arguments require 'evex512' for AVX512", V);
- }
+ if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && TT.isX86()) {
+ StringRef TF = Attrs.getFnAttr("target-features").getValueAsString();
+ Check(!TF.contains("+avx512f") || !TF.contains("-evex512"),
+ "512-bit vector arguments require 'evex512' for AVX512", V);
}
checkUnsignedBaseTenFuncAttr(Attrs, "patchable-function-prefix", V);
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index f4d3a85f34c88da..2dab8e126c9abd0 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -30,6 +30,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/BinaryFormat/MachO.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/FaultMaps.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
@@ -47,10 +48,12 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
@@ -68,6 +71,22 @@ using namespace llvm;
namespace {
+enum class IFuncLowering { SymbolResolverIfSupported, SymbolResolverAlways, SymbolResolverNever };
+
+static cl::opt<IFuncLowering> PreferredIFuncLowering(
+ "arm64-darwin-ifunc-symbol_resolver", cl::init(IFuncLowering::SymbolResolverNever),
+ cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden,
+ cl::values(
+ clEnumValN(
+ IFuncLowering::SymbolResolverIfSupported, "if_supported",
+ "Use .symbol_resolver's when known to be supported by the linker."),
+ clEnumValN(IFuncLowering::SymbolResolverAlways, "always",
+ "Always use .symbol_resolvers. NOTE: this might not be "
+ "supported by the linker in all cases."),
+ clEnumValN(IFuncLowering::SymbolResolverNever, "never",
+ "Use a manual lowering, doing what the linker would have "
+ "done, but in the compiler.")));
+
class AArch64AsmPrinter : public AsmPrinter {
AArch64MCInstLower MCInstLowering;
FaultMaps FM;
@@ -198,6 +217,11 @@ class AArch64AsmPrinter : public AsmPrinter {
bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override {
return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags;
}
+
+ void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override;
+
+ void emitLinkerSymbolResolver(Module &M, const GlobalIFunc &GI);
+ void emitManualSymbolResolver(Module &M, const GlobalIFunc &GI);
};
} // end anonymous namespace
@@ -1809,6 +1833,290 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
}
+void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M,
+ const GlobalIFunc &GI) {
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+ MCSymbol *Name = getSymbol(&GI);
+
+ // NOTE: non-global .symbol_resolvers are not yet supported by Darwin linkers
+
+ if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
+ else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
+ else
+ assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+
+ OutStreamer->emitCodeAlignment(Align(4), STI);
+ OutStreamer->emitLabel(Name);
+ OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver);
+ emitVisibility(Name, GI.getVisibility());
+
+ // ld-prime does not seem to support aliases of symbol resolvers, so we have to
+ // tail call the resolver manually.
+ OutStreamer->emitInstruction(
+ MCInstBuilder(AArch64::B)
+ .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+ *STI);
+}
+
+/// \brief Emit a manually-constructed .symbol_resolver that implements the
+/// symbol resolution duties of the IFunc.
+///
+/// Normally, this would be handled by linker magic, but unfortunately there are
+/// a few limitations in ld64 and ld-prime's implementation of .symbol_resolver
+/// that mean we can't always use them:
+///
+/// * resolvers cannot be the target of an alias
+/// * resolvers cannot have private linkage
+/// * resolvers cannot have linkonce linkage
+/// * resolvers cannot appear in executables
+/// * resolvers cannot appear in bundles
+///
+/// This works around that by emitting a close approximation of what the linker
+/// would have done.
+void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
+ const GlobalIFunc &GI) {
+ auto EmitLinkage = [&](MCSymbol *Sym) {
+ if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_Global);
+ else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+ OutStreamer->emitSymbolAttribute(Sym, MCSA_WeakReference);
+ else
+ assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+ };
+
+ MCSymbol *LazyPointer = TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+ "_" + GI.getName() + ".lazy_pointer");
+ MCSymbol *StubHelper =
+ TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+ "_" + GI.getName() + ".stub_helper");
+
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection());
+
+ EmitLinkage(LazyPointer);
+ OutStreamer->emitLabel(LazyPointer);
+ emitVisibility(LazyPointer, GI.getVisibility());
+ OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+ MCSymbol *Stub = getSymbol(&GI);
+
+ EmitLinkage(Stub);
+ OutStreamer->emitCodeAlignment(Align(4), STI);
+ OutStreamer->emitLabel(Stub);
+ emitVisibility(Stub, GI.getVisibility());
+
+ // adrp x16, lazy_pointer at GOTPAGE
+ // ldr x16, [x16, lazy_pointer at GOTPAGEOFF]
+ // ldr x16, [x16]
+ // br x16
+
+ {
+ MCInst Adrp;
+ Adrp.setOpcode(AArch64::ADRP);
+ Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPage;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGE),
+ SymPage);
+ Adrp.addOperand(SymPage);
+ OutStreamer->emitInstruction(Adrp, *STI);
+ }
+
+ {
+ MCInst Ldr;
+ Ldr.setOpcode(AArch64::LDRXui);
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPageOff;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
+ SymPageOff);
+ Ldr.addOperand(SymPageOff);
+ Ldr.addOperand(MCOperand::createImm(0));
+ OutStreamer->emitInstruction(Ldr, *STI);
+ }
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X16)
+ .addImm(0), *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+ ? AArch64::BRAAZ
+ : AArch64::BR)
+ .addReg(AArch64::X16),
+ *STI);
+
+ EmitLinkage(StubHelper);
+ OutStreamer->emitCodeAlignment(Align(4), STI);
+ OutStreamer->emitLabel(StubHelper);
+ emitVisibility(StubHelper, GI.getVisibility());
+
+ // stp fp, lr, [sp, #-16]!
+ // mov fp, sp
+ // stp x1, x0, [sp, #-16]!
+ // stp x3, x2, [sp, #-16]!
+ // stp x5, x4, [sp, #-16]!
+ // stp x7, x6, [sp, #-16]!
+ // stp d1, d0, [sp, #-16]!
+ // stp d3, d2, [sp, #-16]!
+ // stp d5, d4, [sp, #-16]!
+ // stp d7, d6, [sp, #-16]!
+ // bl _resolver
+ // adrp x16, lazy_pointer at GOTPAGE
+ // ldr x16, [x16, lazy_pointer at GOTPAGEOFF]
+ // str x0, [x16]
+ // mov x16, x0
+ // ldp d7, d6, [sp], #16
+ // ldp d5, d4, [sp], #16
+ // ldp d3, d2, [sp], #16
+ // ldp d1, d0, [sp], #16
+ // ldp x7, x6, [sp], #16
+ // ldp x5, x4, [sp], #16
+ // ldp x3, x2, [sp], #16
+ // ldp x1, x0, [sp], #16
+ // ldp fp, lr, [sp], #16
+ // br x16
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::LR)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::SP)
+ .addImm(0)
+ .addImm(0),
+ *STI);
+
+ for (int I = 0; I != 4; ++I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::X1 + 2 * I)
+ .addReg(AArch64::X0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ for (int I = 0; I != 4; ++I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::D1 + 2 * I)
+ .addReg(AArch64::D0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(-2),
+ *STI);
+
+ OutStreamer->emitInstruction(
+ MCInstBuilder(AArch64::BL)
+ .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+ *STI);
+
+ {
+ MCInst Adrp;
+ Adrp.setOpcode(AArch64::ADRP);
+ Adrp.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPage;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGE),
+ SymPage);
+ Adrp.addOperand(SymPage);
+ OutStreamer->emitInstruction(Adrp, *STI);
+ }
+
+ {
+ MCInst Ldr;
+ Ldr.setOpcode(AArch64::LDRXui);
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ Ldr.addOperand(MCOperand::createReg(AArch64::X16));
+ MCOperand SymPageOff;
+ MCInstLowering.lowerOperand(
+ MachineOperand::CreateES(LazyPointer->getName().data() + 1,
+ AArch64II::MO_GOT | AArch64II::MO_PAGEOFF),
+ SymPageOff);
+ Ldr.addOperand(SymPageOff);
+ Ldr.addOperand(MCOperand::createImm(0));
+ OutStreamer->emitInstruction(Ldr, *STI);
+ }
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui)
+ .addReg(AArch64::X0)
+ .addReg(AArch64::X16)
+ .addImm(0),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X0)
+ .addImm(0)
+ .addImm(0),
+ *STI);
+
+ for (int I = 3; I != -1; --I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::D1 + 2 * I)
+ .addReg(AArch64::D0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ for (int I = 3; I != -1; --I)
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::X1 + 2 * I)
+ .addReg(AArch64::X0 + 2 * I)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
+ .addReg(AArch64::SP)
+ .addReg(AArch64::FP)
+ .addReg(AArch64::LR)
+ .addReg(AArch64::SP)
+ .addImm(2),
+ *STI);
+
+ OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
+ ? AArch64::BRAAZ
+ : AArch64::BR)
+ .addReg(AArch64::X16),
+ *STI);
+}
+
+void AArch64AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
+ if (!TM.getTargetTriple().isOSBinFormatMachO())
+ return AsmPrinter::emitGlobalIFunc(M, GI);
+
+ switch (PreferredIFuncLowering) {
+ case IFuncLowering::SymbolResolverAlways:
+ return emitLinkerSymbolResolver(M, GI);
+ case IFuncLowering::SymbolResolverNever:
+ return emitManualSymbolResolver(M, GI);
+ case IFuncLowering::SymbolResolverIfSupported:
+ if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ return emitLinkerSymbolResolver(M, GI);
+ else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+ // NOTE: non-global .symbol_resolvers are not yet supported by Darwin
+ // linkers
+ return emitManualSymbolResolver(M, GI);
+ else
+ assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+ }
+}
+
// Force static initialization.
extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() {
RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget());
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 73c7450620966cd..5241aa6e1c0eade 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -530,6 +530,34 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
O << ']';
}
+void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
+ if (!TM.getTargetTriple().isOSBinFormatMachO())
+ return AsmPrinter::emitGlobalIFunc(M, GI);
+
+ OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+ MCSymbol *Name = getSymbol(&GI);
+
+ if (GI.hasExternalLinkage() || !MAI->getWeakRefDirective())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_Global);
+ else if (GI.hasWeakLinkage() || GI.hasLinkOnceLinkage())
+ OutStreamer->emitSymbolAttribute(Name, MCSA_WeakReference);
+ else
+ assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
+
+ OutStreamer->emitCodeAlignment(Align(16), Subtarget);
+ OutStreamer->emitLabel(Name);
+ OutStreamer->emitSymbolAttribute(Name, MCSA_SymbolResolver);
+ emitVisibility(Name, GI.getVisibility());
+
+ // ld64 does not seem to support aliases of symbol resolvers, so we have to
+ // tail call the resolver manually.
+ MCInst JMP;
+ JMP.setOpcode(X86::JMP_4);
+ JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver())));
+ OutStreamer->emitInstruction(JMP, *Subtarget);
+}
+
static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,
char Mode, raw_ostream &O) {
Register Reg = MO.getReg();
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.h b/llvm/lib/Target/X86/X86AsmPrinter.h
index c81651cf7f2f0e6..47f3b7c00c99ddb 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.h
+++ b/llvm/lib/Target/X86/X86AsmPrinter.h
@@ -120,6 +120,7 @@ class LLVM_LIBRARY_VISIBILITY X86AsmPrinter : public AsmPrinter {
const char *Modifier);
void PrintIntelMemReference(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier);
+ void emitGlobalIFunc(Module &M, const GlobalIFunc &GI) override;
public:
X86AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll
new file mode 100644
index 000000000000000..8e51845c2faa9c0
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll
@@ -0,0 +1,37 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+; RUN: llc -mtriple=aarch64-macho -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=MACHO,CHECK
+; RUN: llc -mtriple=aarch64-elf -global-isel -stop-after=irtranslator -verify-machineinstrs -o - %s | FileCheck %s --check-prefixes=ELF,CHECK
+
+ at foo_ifunc = ifunc i32 (i32), ptr @foo_resolver
+
+define internal ptr @foo_resolver() {
+ ; CHECK-LABEL: name: foo_resolver
+ ; CHECK: bb.1.entry:
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
+ ; CHECK-NEXT: $x0 = COPY [[C]](p0)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+entry:
+ ret ptr null
+}
+
+define void @caller() {
+ ; MACHO-LABEL: name: caller
+ ; MACHO: bb.1.entry:
+ ; MACHO-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
+ ; MACHO-NEXT: BL @foo_ifunc, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0
+ ; MACHO-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
+ ; MACHO-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+ ; MACHO-NEXT: RET_ReallyLR
+ ;
+ ; ELF-LABEL: name: caller
+ ; ELF: bb.1.entry:
+ ; ELF-NEXT: [[GV:%[0-9]+]]:gpr64(p0) = G_GLOBAL_VALUE @foo_ifunc
+ ; ELF-NEXT: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
+ ; ELF-NEXT: BLR [[GV]](p0), csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $w0
+ ; ELF-NEXT: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
+ ; ELF-NEXT: [[COPY:%[0-9]+]]:_(s32) = COPY $w0
+ ; ELF-NEXT: RET_ReallyLR
+entry:
+ %0 = call i32 @foo_ifunc()
+ ret void
+}
diff --git a/llvm/test/CodeGen/AArch64/addrsig-macho.ll b/llvm/test/CodeGen/AArch64/addrsig-macho.ll
index 360876fccaad34e..980b0e7bc446695 100644
--- a/llvm/test/CodeGen/AArch64/addrsig-macho.ll
+++ b/llvm/test/CodeGen/AArch64/addrsig-macho.ll
@@ -118,8 +118,8 @@ declare void @f3() unnamed_addr
@a1 = alias i32, i32* @g1
@a2 = internal local_unnamed_addr alias i32, i32* @g2
- at i1 = ifunc void(), void()* ()* @f1
- at i2 = internal local_unnamed_addr ifunc void(), void()* ()* @f2
+ at i1 = external ifunc void(), void()* ()* @f1
+ at i2 = external local_unnamed_addr ifunc void(), void()* ()* @f2
declare void @llvm.dbg.value(metadata, metadata, metadata)
diff --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
new file mode 100644
index 000000000000000..fbc0f74cee46baa
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
@@ -0,0 +1,82 @@
+; RUN: llc -mtriple=arm64-unknown-linux-gnu %s -filetype=asm -o - | FileCheck %s --check-prefixes=ELF
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=always | FileCheck %s --check-prefixes=MACHO,MACHO-LINKER
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=if_supported | FileCheck %s --check-prefixes=MACHO,MACHO-DEFAULT
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -arm64-darwin-ifunc-symbol_resolver=never | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL
+
+define internal ptr @foo_resolver() {
+entry:
+ ret ptr null
+}
+; ELF: .type foo_resolver, at function
+; ELF-NEXT: foo_resolver:
+
+; MACHO: .p2align 2
+; MACHO-NEXT: _foo_resolver
+
+
+ at foo_ifunc = ifunc i32 (i32), ptr @foo_resolver
+; ELF: .globl foo_ifunc
+; ELF-NEXT: .type foo_ifunc, at gnu_indirect_function
+; ELF-NEXT: .set foo_ifunc, foo_resolver
+
+; MACHO-LINKER: .globl _foo_ifunc
+; MACHO-LINKER-NEXT: .p2align 2
+; MACHO-LINKER-NEXT: _foo_ifunc:
+; MACHO-LINKER-NEXT: .symbol_resolver _foo_ifunc
+; MACHO-LINKER-NEXT: b _foo_resolver
+
+; MACHO-DEFAULT: .globl _foo_ifunc
+; MACHO-DEFAULT-NEXT: .p2align 2
+; MACHO-DEFAULT-NEXT: _foo_ifunc:
+; MACHO-DEFAULT-NEXT: .symbol_resolver _foo_ifunc
+; MACHO-DEFAULT-NEXT: b _foo_resolver
+
+; MACHO-MANUAL: .section __DATA,__data
+; MACHO-MANUAL-NEXT: .globl _foo_ifunc.lazy_pointer
+; MACHO-MANUAL-NEXT: _foo_ifunc.lazy_pointer:
+; MACHO-MANUAL-NEXT: .quad _foo_ifunc.stub_helper
+
+; MACHO-MANUAL: .section __TEXT,__text,regular,pure_instructions
+; MACHO-MANUAL-NEXT: .globl _foo_ifunc
+; MACHO-MANUAL-NEXT: .p2align 2
+; MACHO-MANUAL-NEXT: _foo_ifunc:
+; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer at GOTPAGE
+; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer at GOTPAGEOFF]
+; MACHO-MANUAL-NEXT: ldr x16, [x16]
+; MACHO-MANUAL-NEXT: br x16
+; MACHO-MANUAL-NEXT: .globl _foo_ifunc.stub_helper
+; MACHO-MANUAL-NEXT: .p2align 2
+; MACHO-MANUAL-NEXT: _foo_ifunc.stub_helper:
+; MACHO-MANUAL-NEXT: stp x29, x30, [sp, #-16]!
+; MACHO-MANUAL-NEXT: mov x29, sp
+; MACHO-MANUAL-NEXT: stp x1, x0, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp x3, x2, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp x5, x4, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp x7, x6, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp d1, d0, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp d3, d2, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp d5, d4, [sp, #-16]!
+; MACHO-MANUAL-NEXT: stp d7, d6, [sp, #-16]!
+; MACHO-MANUAL-NEXT: bl _foo_resolver
+; MACHO-MANUAL-NEXT: adrp x16, _foo_ifunc.lazy_pointer at GOTPAGE
+; MACHO-MANUAL-NEXT: ldr x16, [x16, _foo_ifunc.lazy_pointer at GOTPAGEOFF]
+; MACHO-MANUAL-NEXT: str x0, [x16]
+; MACHO-MANUAL-NEXT: add x16, x0, #0
+; MACHO-MANUAL-NEXT: ldp d7, d6, [sp], #16
+; MACHO-MANUAL-NEXT: ldp d5, d4, [sp], #16
+; MACHO-MANUAL-NEXT: ldp d3, d2, [sp], #16
+; MACHO-MANUAL-NEXT: ldp d1, d0, [sp], #16
+; MACHO-MANUAL-NEXT: ldp x7, x6, [sp], #16
+; MACHO-MANUAL-NEXT: ldp x5, x4, [sp], #16
+; MACHO-MANUAL-NEXT: ldp x3, x2, [sp], #16
+; MACHO-MANUAL-NEXT: ldp x1, x0, [sp], #16
+; MACHO-MANUAL-NEXT: ldp x29, x30, [sp], #16
+; MACHO-MANUAL-NEXT: br x16
+
+
+ at weak_ifunc = weak ifunc i32 (i32), ptr @foo_resolver
+; ELF: .type weak_ifunc, at gnu_indirect_function
+; MACHO-LINKER: .symbol_resolver _weak_ifunc
+; MACHO-MANUAL: _weak_ifunc.stub_helper:
+; MACHO-DEFEAULT: _weak_ifunc.stub_helper:
\ No newline at end of file
diff --git a/llvm/test/CodeGen/X86/ifunc-asm.ll b/llvm/test/CodeGen/X86/ifunc-asm.ll
index 4b380c8ae330135..76efda71153207d 100644
--- a/llvm/test/CodeGen/X86/ifunc-asm.ll
+++ b/llvm/test/CodeGen/X86/ifunc-asm.ll
@@ -1,14 +1,24 @@
-; RUN: llvm-as < %s -o - | llc -filetype=asm | FileCheck %s
+; RUN: llc -filetype=asm -mtriple=x86_64-unknown-linux-gnu %s -o - | FileCheck %s --check-prefixes=ELF
+; RUN: llc -filetype=asm -mtriple=x86_64-apple-darwin %s -o - | FileCheck %s --check-prefixes=MACHO
-target triple = "x86_64-unknown-linux-gnu"
-
-define internal ptr @foo_ifunc() {
+define internal ptr @foo_resolver() {
entry:
ret ptr null
}
-; CHECK: .type foo_ifunc, at function
-; CHECK-NEXT: foo_ifunc:
+; ELF: .type foo_resolver, at function
+; ELF-NEXT: foo_resolver:
+
+; MACHO: .p2align 4, 0x90
+; MACHO-NEXT: _foo_resolver
+
+
+ at foo_ifunc = ifunc i32 (i32), ptr @foo_resolver
+; ELF: .globl foo_ifunc
+; ELF-NEXT: .type foo_ifunc, at gnu_indirect_function
+; ELF-NEXT: .set foo_ifunc, foo_resolver
- at foo = ifunc i32 (i32), ptr @foo_ifunc
-; CHECK: .type foo, at gnu_indirect_function
-; CHECK-NEXT: .set foo, foo_ifunc
+; MACHO: .globl _foo_ifunc
+; MACHO-NEXT: .p2align 4, 0x90
+; MACHO-NEXT: _foo_ifunc:
+; MACHO-NEXT: .symbol_resolver _foo_ifunc
+; MACHO-NEXT: jmp _foo_resolver
diff --git a/llvm/test/Verifier/ifunc-macho.ll b/llvm/test/Verifier/ifunc-macho.ll
new file mode 100644
index 000000000000000..2e2166645983ac3
--- /dev/null
+++ b/llvm/test/Verifier/ifunc-macho.ll
@@ -0,0 +1,42 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+target triple = "arm64-apple-ios"
+
+define ptr @resolver() {
+ ret ptr null
+}
+
+ at g = external global i32
+ at inval_objtype = ifunc void (), ptr @g
+; CHECK: IFunc must have a Function resolver
+
+declare ptr @resolver_decl()
+ at inval_resolver_decl = ifunc void (), ptr @resolver_decl
+; CHECK: IFunc resolver must be a definition
+; CHECK-NEXT: @inval_resolver_decl
+
+define available_externally ptr @resolver_linker_decl() {
+ ret ptr null
+}
+ at inval_resolver_decl2 = ifunc void (), ptr @resolver_linker_decl
+; CHECK: IFunc resolver must be a definition
+; CHECK-NEXT: @inval_resolver_decl2
+
+ at ifunc_nonpointer_return_type = ifunc i32 (), ptr @resolver_returns_nonpointer
+; CHECK: IFunc resolver must return a pointer
+; CHECK-NEXT: ptr @ifunc_nonpointer_return_type
+
+define i32 @resolver_returns_nonpointer() {
+ ret i32 0
+}
+
+ at valid_external = ifunc void (), ptr @resolver
+; CHECK-NOT: valid_external
+
+ at inval_linkonce = linkonce ifunc void (), ptr @resolver
+
+ at inval_weak = weak ifunc void (), ptr @resolver
+
+ at inval_weak_extern = extern_weak ifunc void (), ptr @resolver
+
+ at inval_private = private ifunc void (), ptr @resolver
More information about the llvm-branch-commits
mailing list