[llvm] [llvm] Support IFuncs on Darwin platforms (PR #73686)

Jon Roelofs via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 29 14:08:06 PST 2023


https://github.com/jroelofs updated https://github.com/llvm/llvm-project/pull/73686

>From bc152095691b32d1ad8539dfd60f5089df5eed8d Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 28 Nov 2023 10:39:44 -0800
Subject: [PATCH 1/6] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?=
 =?UTF-8?q?itial=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 llvm/docs/LangRef.rst                         |   7 +-
 llvm/include/llvm/CodeGen/AsmPrinter.h        |   6 +-
 llvm/lib/CodeGen/GlobalISel/CallLowering.cpp  |   7 +-
 llvm/lib/IR/Verifier.cpp                      |  12 +-
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 308 ++++++++++++++++++
 llvm/lib/Target/X86/X86AsmPrinter.cpp         |  28 ++
 llvm/lib/Target/X86/X86AsmPrinter.h           |   1 +
 .../AArch64/GlobalISel/call-lowering-ifunc.ll |  37 +++
 llvm/test/CodeGen/AArch64/addrsig-macho.ll    |   4 +-
 llvm/test/CodeGen/AArch64/ifunc-asm.ll        |  82 +++++
 llvm/test/CodeGen/X86/ifunc-asm.ll            |  28 +-
 llvm/test/Verifier/ifunc-macho.ll             |  42 +++
 12 files changed, 539 insertions(+), 23 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/call-lowering-ifunc.ll
 create mode 100644 llvm/test/CodeGen/AArch64/ifunc-asm.ll
 create mode 100644 llvm/test/Verifier/ifunc-macho.ll

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

>From 8f6755e6b211c9b0206197f65304443e26e244eb Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 28 Nov 2023 11:04:43 -0800
Subject: [PATCH 2/6] git clang-format

Created using spr 1.3.4
---
 llvm/include/llvm/CodeGen/AsmPrinter.h        |  1 -
 llvm/lib/IR/Verifier.cpp                      |  4 +--
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 25 ++++++++++++-------
 llvm/lib/Target/X86/X86AsmPrinter.cpp         |  2 ++
 4 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 48fa6c478464c73..07b92871a0f0868 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -887,7 +887,6 @@ class AsmPrinter : public MachineFunctionPass {
   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/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 94e76a43bf38d6d..bd90047a411a654 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -959,7 +959,6 @@ 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) {
@@ -2240,7 +2239,8 @@ void Verifier::verifyFunctionAttrs(FunctionType *FT, AttributeList Attrs,
   }
 
   // Check EVEX512 feature.
-  if (MaxParameterWidth >= 512 && Attrs.hasFnAttr("target-features") && TT.isX86()) {
+  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);
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 2dab8e126c9abd0..f4128332008fb83 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -71,10 +71,15 @@ using namespace llvm;
 
 namespace {
 
-enum class IFuncLowering { SymbolResolverIfSupported, SymbolResolverAlways, SymbolResolverNever };
+enum class IFuncLowering {
+  SymbolResolverIfSupported,
+  SymbolResolverAlways,
+  SymbolResolverNever
+};
 
 static cl::opt<IFuncLowering> PreferredIFuncLowering(
-    "arm64-darwin-ifunc-symbol_resolver", cl::init(IFuncLowering::SymbolResolverNever),
+    "arm64-darwin-ifunc-symbol_resolver",
+    cl::init(IFuncLowering::SymbolResolverNever),
     cl::desc("Pick the lowering for ifuncs on darwin platforms"), cl::Hidden,
     cl::values(
         clEnumValN(
@@ -1853,8 +1858,8 @@ void AArch64AsmPrinter::emitLinkerSymbolResolver(Module &M,
   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.
+  // 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()))),
@@ -1887,8 +1892,9 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
       assert(GI.hasLocalLinkage() && "Invalid ifunc linkage");
   };
 
-  MCSymbol *LazyPointer = TM.getObjFileLowering()->getContext().getOrCreateSymbol(
-      "_" + GI.getName() + ".lazy_pointer");
+  MCSymbol *LazyPointer =
+      TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+          "_" + GI.getName() + ".lazy_pointer");
   MCSymbol *StubHelper =
       TM.getObjFileLowering()->getContext().getOrCreateSymbol(
           "_" + GI.getName() + ".stub_helper");
@@ -1943,9 +1949,10 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
   }
 
   OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui)
-    .addReg(AArch64::X16)
-    .addReg(AArch64::X16)
-    .addImm(0), *STI);
+                                   .addReg(AArch64::X16)
+                                   .addReg(AArch64::X16)
+                                   .addImm(0),
+                               *STI);
 
   OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
                                                  ? AArch64::BRAAZ
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 5241aa6e1c0eade..37158900d2404dd 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -556,6 +556,8 @@ void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
   JMP.setOpcode(X86::JMP_4);
   JMP.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver())));
   OutStreamer->emitInstruction(JMP, *Subtarget);
+
+  // FIXME: do the manual .symbol_resolver lowering that we did in AArch64AsmPrinter.
 }
 
 static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,

>From dc1fcb464e3d9e8dd37a5bda1aa8894e127654e9 Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Tue, 28 Nov 2023 14:24:45 -0800
Subject: [PATCH 3/6] avoid writeback stp's

Created using spr 1.3.4
---
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  48 ++++----
 llvm/lib/CodeGen/GlobalISel/CallLowering.cpp  |   2 +-
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 110 ++++++++++--------
 llvm/test/CodeGen/AArch64/addrsig-macho.ll    |  17 ++-
 llvm/test/CodeGen/AArch64/ifunc-asm.ll        |  99 ++++++++--------
 llvm/test/Verifier/ifunc-macho.ll             |  42 -------
 6 files changed, 153 insertions(+), 165 deletions(-)
 delete mode 100644 llvm/test/Verifier/ifunc-macho.ll

diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 15ff39883680369..b4ac0a70e7fde9c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2300,6 +2300,32 @@ bool AsmPrinter::doFinalization(Module &M) {
   // through user plugins.
   emitStackMaps();
 
+  // Print aliases in topological order, that is, for each alias a = b,
+  // b must be printed before a.
+  // This is because on some targets (e.g. PowerPC) linker expects aliases in
+  // such an order to generate correct TOC information.
+  SmallVector<const GlobalAlias *, 16> AliasStack;
+  SmallPtrSet<const GlobalAlias *, 16> AliasVisited;
+  for (const auto &Alias : M.aliases()) {
+    if (Alias.hasAvailableExternallyLinkage())
+      continue;
+    for (const GlobalAlias *Cur = &Alias; Cur;
+         Cur = dyn_cast<GlobalAlias>(Cur->getAliasee())) {
+      if (!AliasVisited.insert(Cur).second)
+        break;
+      AliasStack.push_back(Cur);
+    }
+    for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack))
+      emitGlobalAlias(M, *AncestorAlias);
+    AliasStack.clear();
+  }
+
+  // IFuncs must come before deubginfo in case the backend decides to emit them
+  // as actual functions, since on MachO targets, we cannot create regular
+  // sections after DWARF.
+  for (const auto &IFunc : M.ifuncs())
+    emitGlobalIFunc(M, IFunc);
+
   // Finalize debug and EH information.
   for (const HandlerInfo &HI : Handlers) {
     NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName,
@@ -2339,28 +2365,6 @@ bool AsmPrinter::doFinalization(Module &M) {
     }
   }
 
-  // Print aliases in topological order, that is, for each alias a = b,
-  // b must be printed before a.
-  // This is because on some targets (e.g. PowerPC) linker expects aliases in
-  // such an order to generate correct TOC information.
-  SmallVector<const GlobalAlias *, 16> AliasStack;
-  SmallPtrSet<const GlobalAlias *, 16> AliasVisited;
-  for (const auto &Alias : M.aliases()) {
-    if (Alias.hasAvailableExternallyLinkage())
-      continue;
-    for (const GlobalAlias *Cur = &Alias; Cur;
-         Cur = dyn_cast<GlobalAlias>(Cur->getAliasee())) {
-      if (!AliasVisited.insert(Cur).second)
-        break;
-      AliasStack.push_back(Cur);
-    }
-    for (const GlobalAlias *AncestorAlias : llvm::reverse(AliasStack))
-      emitGlobalAlias(M, *AncestorAlias);
-    AliasStack.clear();
-  }
-  for (const auto &IFunc : M.ifuncs())
-    emitGlobalIFunc(M, IFunc);
-
   GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
   assert(MI && "AsmPrinter didn't require GCModuleInfo?");
   for (GCModuleInfo::iterator I = MI->end(), E = MI->begin(); I != E; )
diff --git a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
index e0080b145d4f995..ce736178afc8b5a 100644
--- a/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CallLowering.cpp
@@ -147,7 +147,7 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB,
   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.
+    // must always be a direct call.
     Info.Callee = MachineOperand::CreateGA(IF, 0);
   } else if (const Function *F = dyn_cast<Function>(CalleeV))
     Info.Callee = MachineOperand::CreateGA(F, 0);
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index f4128332008fb83..26b3a14e22b2ad9 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -1965,65 +1965,71 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
   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]!
+  // stp	fp, lr, [sp, #-16]
+  // sub	fp, sp, 16
+  // stp	x1, x0, [sp, #-32]
+  // stp	x3, x2, [sp, #-48]
+  // stp	x5, x4, [sp, #-64]
+  // stp	x7, x6, [sp, #-80]
+  // stp	d1, d0, [sp, #-96]
+  // stp	d3, d2, [sp, #-112]
+  // stp	d5, d4, [sp, #-128]
+  // stp	d7, d6, [sp, #-144]
+  // sub	sp, sp, 144
   // 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
+  // add	sp, sp, 144
+  // ldp	d7, d6, [sp, #-144]
+  // ldp	d5, d4, [sp, #-128]
+  // ldp	d3, d2, [sp, #-112]
+  // ldp	d1, d0, [sp, #-96]
+  // ldp	x7, x6, [sp, #-80]
+  // ldp	x5, x4, [sp, #-64]
+  // ldp	x3, x2, [sp, #-48]
+  // ldp	x1, x0, [sp, #-32]
+  // ldp	fp, lr, [sp, #-16]
   // br	x16
 
-  OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre)
-                                   .addReg(AArch64::SP)
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
                                    .addReg(AArch64::FP)
                                    .addReg(AArch64::LR)
                                    .addReg(AArch64::SP)
                                    .addImm(-2),
                                *STI);
 
-  OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri)
                                    .addReg(AArch64::FP)
                                    .addReg(AArch64::SP)
-                                   .addImm(0)
+                                   .addImm(16)
                                    .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)
+  for (int I = 0; I != 8; I += 2)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
+                                     .addReg(AArch64::X1 + I)
+                                     .addReg(AArch64::X0 + I)
                                      .addReg(AArch64::SP)
-                                     .addImm(-2),
+                                     .addImm(-4 - I),
                                  *STI);
 
-  for (int I = 0; I != 4; ++I)
-    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre)
+  for (int I = 0; I != 8; I += 2)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDi)
+                                     .addReg(AArch64::D1 + I)
+                                     .addReg(AArch64::D0 + I)
                                      .addReg(AArch64::SP)
-                                     .addReg(AArch64::D1 + 2 * I)
-                                     .addReg(AArch64::D0 + 2 * I)
-                                     .addReg(AArch64::SP)
-                                     .addImm(-2),
+                                     .addImm(-12 - I),
                                  *STI);
 
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri)
+                                   .addReg(AArch64::SP)
+                                   .addReg(AArch64::SP)
+                                   .addImm(144)
+                                   .addImm(0),
+                               *STI);
+
   OutStreamer->emitInstruction(
       MCInstBuilder(AArch64::BL)
           .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
@@ -2070,30 +2076,34 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
                                    .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)
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri)
+                                   .addReg(AArch64::SP)
+                                   .addReg(AArch64::SP)
+                                   .addImm(144)
+                                   .addImm(0),
+                               *STI);
+
+  for (int I = 6; I != -2; I -= 2)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDi)
+                                     .addReg(AArch64::D1 + I)
+                                     .addReg(AArch64::D0 + I)
                                      .addReg(AArch64::SP)
-                                     .addImm(2),
+                                     .addImm(-12 - I),
                                  *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)
+  for (int I = 6; I != -2; I -= 2)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi)
+                                     .addReg(AArch64::X1 + I)
+                                     .addReg(AArch64::X0 + I)
                                      .addReg(AArch64::SP)
-                                     .addImm(2),
+                                     .addImm(-4 - I),
                                  *STI);
 
-  OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost)
-                                   .addReg(AArch64::SP)
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi)
                                    .addReg(AArch64::FP)
                                    .addReg(AArch64::LR)
                                    .addReg(AArch64::SP)
-                                   .addImm(2),
+                                   .addImm(-2),
                                *STI);
 
   OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e()
diff --git a/llvm/test/CodeGen/AArch64/addrsig-macho.ll b/llvm/test/CodeGen/AArch64/addrsig-macho.ll
index 980b0e7bc446695..62bc764e0251b33 100644
--- a/llvm/test/CodeGen/AArch64/addrsig-macho.ll
+++ b/llvm/test/CodeGen/AArch64/addrsig-macho.ll
@@ -3,6 +3,19 @@
 ; RUN: llvm-objdump --macho --section-headers %t | FileCheck %s --check-prefix=SECTIONS
 ; RUN: llvm-objdump --macho --reloc %t | FileCheck %s --check-prefix=RELOCS
 
+; CHECK:     .section __DATA,__data
+; CHECK: _i1.lazy_pointer:
+; CHECK:     .section __TEXT,__text,regular,pure_instructions
+; CHECK: _i1:
+; CHECK: _i1.stub_helper:
+; CHECK:     .section __DATA,__data
+; CHECK: _i2.lazy_pointer:
+; CHECK:     .section __TEXT,__text,regular,pure_instructions
+; CHECK: _i2:
+; CHECK: _i2.stub_helper:
+
+; CHECK:     .section __DWARF
+
 ; CHECK:			.addrsig{{$}}
 ; CHECK-NEXT:	.addrsig_sym _func03_takeaddr
 ; CHECK-NEXT:	.addrsig_sym _f1
@@ -118,8 +131,8 @@ declare void @f3() unnamed_addr
 @a1 = alias i32, i32* @g1
 @a2 = internal local_unnamed_addr alias i32, i32* @g2
 
- at i1 = external ifunc void(), void()* ()* @f1
- at i2 = external local_unnamed_addr ifunc void(), void()* ()* @f2
+ at i1 = ifunc void(), void()* ()* @f1
+ at i2 = internal 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
index fbc0f74cee46baa..ede669aa52703f7 100644
--- a/llvm/test/CodeGen/AArch64/ifunc-asm.ll
+++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
@@ -3,79 +3,82 @@
 ; 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
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -global-isel | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL
 
-define internal ptr @foo_resolver() {
+define internal ptr @the_resolver() {
 entry:
   ret ptr null
 }
-; ELF:                    .type foo_resolver, at function
-; ELF-NEXT:           foo_resolver:
+; ELF:                    .type the_resolver, at function
+; ELF-NEXT:           the_resolver:
 
 ; MACHO:                  .p2align 2
-; MACHO-NEXT:         _foo_resolver
+; MACHO-NEXT:         _the_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 global_ifunc = ifunc i32 (i32), ptr @the_resolver
+; ELF:                    .globl global_ifunc
+; ELF-NEXT:               .type global_ifunc, at gnu_indirect_function
+; ELF-NEXT:               .set global_ifunc, the_resolver
 
-; MACHO-LINKER:           .globl _foo_ifunc
+; MACHO-LINKER:           .globl _global_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-LINKER-NEXT:  _global_ifunc:
+; MACHO-LINKER-NEXT:      .symbol_resolver _global_ifunc
+; MACHO-LINKER-NEXT:      b _the_resolver
 
-; MACHO-DEFAULT:          .globl _foo_ifunc
+; MACHO-DEFAULT:          .globl _global_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-DEFAULT-NEXT: _global_ifunc:
+; MACHO-DEFAULT-NEXT:     .symbol_resolver _global_ifunc
+; MACHO-DEFAULT-NEXT:     b _the_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-NEXT:      .globl _global_ifunc.lazy_pointer
+; MACHO-MANUAL-NEXT:  _global_ifunc.lazy_pointer:
+; MACHO-MANUAL-NEXT:      .quad _global_ifunc.stub_helper
 
 ; MACHO-MANUAL:           .section __TEXT,__text,regular,pure_instructions
-; MACHO-MANUAL-NEXT:      .globl _foo_ifunc
+; MACHO-MANUAL-NEXT:      .globl _global_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:  _global_ifunc:
+; MACHO-MANUAL-NEXT:      adrp    x16, _global_ifunc.lazy_pointer at GOTPAGE
+; MACHO-MANUAL-NEXT:      ldr     x16, [x16, _global_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:      .globl  _global_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:  _global_ifunc.stub_helper:
+; MACHO-MANUAL-NEXT:      stp     x29, x30, [sp, #-16]
+; MACHO-MANUAL-NEXT:      sub     x29, sp, #16
+; MACHO-MANUAL-NEXT:      stp     x1, x0, [sp, #-32]
+; MACHO-MANUAL-NEXT:      stp     x3, x2, [sp, #-48]
+; MACHO-MANUAL-NEXT:      stp     x5, x4, [sp, #-64]
+; MACHO-MANUAL-NEXT:      stp     x7, x6, [sp, #-80]
+; MACHO-MANUAL-NEXT:      stp     d1, d0, [sp, #-96]
+; MACHO-MANUAL-NEXT:      stp     d3, d2, [sp, #-112]
+; MACHO-MANUAL-NEXT:      stp     d5, d4, [sp, #-128]
+; MACHO-MANUAL-NEXT:      stp     d7, d6, [sp, #-144]
+; MACHO-MANUAL-NEXT:      sub     sp, sp, #144
+; MACHO-MANUAL-NEXT:      bl      _the_resolver
+; MACHO-MANUAL-NEXT:      adrp    x16, _global_ifunc.lazy_pointer at GOTPAGE
+; MACHO-MANUAL-NEXT:      ldr     x16, [x16, _global_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:      add     sp, sp, #144
+; MACHO-MANUAL-NEXT:      ldp     d7, d6, [sp, #-144]
+; MACHO-MANUAL-NEXT:      ldp     d5, d4, [sp, #-128]
+; MACHO-MANUAL-NEXT:      ldp     d3, d2, [sp, #-112]
+; MACHO-MANUAL-NEXT:      ldp     d1, d0, [sp, #-96]
+; MACHO-MANUAL-NEXT:      ldp     x7, x6, [sp, #-80]
+; MACHO-MANUAL-NEXT:      ldp     x5, x4, [sp, #-64]
+; MACHO-MANUAL-NEXT:      ldp     x3, x2, [sp, #-48]
+; MACHO-MANUAL-NEXT:      ldp     x1, x0, [sp, #-32]
+; MACHO-MANUAL-NEXT:      ldp     x29, x30, [sp, #-16]
 ; MACHO-MANUAL-NEXT:      br      x16
 
 
- at weak_ifunc = weak ifunc i32 (i32), ptr @foo_resolver
+ at weak_ifunc = weak ifunc i32 (i32), ptr @the_resolver
 ; ELF:             .type weak_ifunc, at gnu_indirect_function
 ; MACHO-LINKER:    .symbol_resolver _weak_ifunc
 ; MACHO-MANUAL:    _weak_ifunc.stub_helper:
diff --git a/llvm/test/Verifier/ifunc-macho.ll b/llvm/test/Verifier/ifunc-macho.ll
deleted file mode 100644
index 2e2166645983ac3..000000000000000
--- a/llvm/test/Verifier/ifunc-macho.ll
+++ /dev/null
@@ -1,42 +0,0 @@
-; 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

>From bbeb3beaf37d91911a96a20bb1825fa16dcfc094 Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Wed, 29 Nov 2023 08:23:21 -0800
Subject: [PATCH 4/6] x86 support

Created using spr 1.3.4
---
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp |  72 +++++-----
 llvm/lib/Target/X86/X86AsmPrinter.cpp         | 124 +++++++++++++++---
 llvm/test/CodeGen/X86/ifunc-asm.ll            |  48 +++++--
 3 files changed, 178 insertions(+), 66 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 26b3a14e22b2ad9..1b5b7c556c79f6b 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -1901,6 +1901,9 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
 
   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getDataSection());
 
+  // _ifunc.lazy_pointer:
+  //   .quad _ifunc.stub_helper
+
   EmitLinkage(LazyPointer);
   OutStreamer->emitLabel(LazyPointer);
   emitVisibility(LazyPointer, GI.getVisibility());
@@ -1908,18 +1911,18 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
 
   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
 
-  MCSymbol *Stub = getSymbol(&GI);
+  // _ifunc:
+  //   adrp	x16, lazy_pointer at GOTPAGE
+  //   ldr	x16, [x16, lazy_pointer at GOTPAGEOFF]
+  //   ldr	x16, [x16]
+  //   br	x16
 
+  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);
@@ -1960,39 +1963,40 @@ void AArch64AsmPrinter::emitManualSymbolResolver(Module &M,
                                    .addReg(AArch64::X16),
                                *STI);
 
+  // _ifunc.stub_helper:
+  //   stp	fp, lr, [sp, #-16]
+  //   sub	fp, sp, 16
+  //   stp	x1, x0, [sp, #-32]
+  //   stp	x3, x2, [sp, #-48]
+  //   stp	x5, x4, [sp, #-64]
+  //   stp	x7, x6, [sp, #-80]
+  //   stp	d1, d0, [sp, #-96]
+  //   stp	d3, d2, [sp, #-112]
+  //   stp	d5, d4, [sp, #-128]
+  //   stp	d7, d6, [sp, #-144]
+  //   sub	sp, sp, 144
+  //   bl	_resolver
+  //   adrp	x16, lazy_pointer at GOTPAGE
+  //   ldr	x16, [x16, lazy_pointer at GOTPAGEOFF]
+  //   str	x0, [x16]
+  //   mov	x16, x0
+  //   add	sp, sp, 144
+  //   ldp	d7, d6, [sp, #-144]
+  //   ldp	d5, d4, [sp, #-128]
+  //   ldp	d3, d2, [sp, #-112]
+  //   ldp	d1, d0, [sp, #-96]
+  //   ldp	x7, x6, [sp, #-80]
+  //   ldp	x5, x4, [sp, #-64]
+  //   ldp	x3, x2, [sp, #-48]
+  //   ldp	x1, x0, [sp, #-32]
+  //   ldp	fp, lr, [sp, #-16]
+  //   br	x16
+
   EmitLinkage(StubHelper);
   OutStreamer->emitCodeAlignment(Align(4), STI);
   OutStreamer->emitLabel(StubHelper);
   emitVisibility(StubHelper, GI.getVisibility());
 
-  // stp	fp, lr, [sp, #-16]
-  // sub	fp, sp, 16
-  // stp	x1, x0, [sp, #-32]
-  // stp	x3, x2, [sp, #-48]
-  // stp	x5, x4, [sp, #-64]
-  // stp	x7, x6, [sp, #-80]
-  // stp	d1, d0, [sp, #-96]
-  // stp	d3, d2, [sp, #-112]
-  // stp	d5, d4, [sp, #-128]
-  // stp	d7, d6, [sp, #-144]
-  // sub	sp, sp, 144
-  // bl	_resolver
-  // adrp	x16, lazy_pointer at GOTPAGE
-  // ldr	x16, [x16, lazy_pointer at GOTPAGEOFF]
-  // str	x0, [x16]
-  // mov	x16, x0
-  // add	sp, sp, 144
-  // ldp	d7, d6, [sp, #-144]
-  // ldp	d5, d4, [sp, #-128]
-  // ldp	d3, d2, [sp, #-112]
-  // ldp	d1, d0, [sp, #-96]
-  // ldp	x7, x6, [sp, #-80]
-  // ldp	x5, x4, [sp, #-64]
-  // ldp	x3, x2, [sp, #-48]
-  // ldp	x1, x0, [sp, #-32]
-  // ldp	fp, lr, [sp, #-16]
-  // br	x16
-
   OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
                                    .addReg(AArch64::FP)
                                    .addReg(AArch64::LR)
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 37158900d2404dd..b0f4b9d98437284 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -14,6 +14,7 @@
 #include "X86AsmPrinter.h"
 #include "MCTargetDesc/X86ATTInstPrinter.h"
 #include "MCTargetDesc/X86BaseInfo.h"
+#include "MCTargetDesc/X86MCTargetDesc.h"
 #include "MCTargetDesc/X86TargetStreamer.h"
 #include "TargetInfo/X86TargetInfo.h"
 #include "X86InstrInfo.h"
@@ -34,6 +35,7 @@
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCInstBuilder.h"
 #include "llvm/MC/MCSectionCOFF.h"
 #include "llvm/MC/MCSectionELF.h"
@@ -534,30 +536,112 @@ void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
   if (!TM.getTargetTriple().isOSBinFormatMachO())
     return AsmPrinter::emitGlobalIFunc(M, GI);
 
-  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+  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 *Name = getSymbol(&GI);
+  MCSymbol *LazyPointer =
+      TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+          "_" + GI.getName() + ".lazy_pointer");
+  MCSymbol *StubHelper =
+      TM.getObjFileLowering()->getContext().getOrCreateSymbol(
+          "_" + GI.getName() + ".stub_helper");
 
-  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->switchSection(OutContext.getObjectFileInfo()->getDataSection());
+
+  // _ifunc.lazy_pointer:
+  //  .quad _ifunc.stub_helper
 
+  EmitLinkage(LazyPointer);
+  OutStreamer->emitLabel(LazyPointer);
+  emitVisibility(LazyPointer, GI.getVisibility());
+  OutStreamer->emitValue(MCSymbolRefExpr::create(StubHelper, OutContext), 8);
+
+  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
+
+  // _ifunc:
+  //   jmpq *lazy_pointer(%rip)
+
+  MCSymbol *Stub = getSymbol(&GI);
+  EmitLinkage(Stub);
+  OutStreamer->emitCodeAlignment(Align(16), Subtarget);
+  OutStreamer->emitLabel(Stub);
+  emitVisibility(Stub, GI.getVisibility());
+
+  OutStreamer->emitInstruction(
+      MCInstBuilder(X86::JMP32m)
+          .addReg(X86::RIP)
+          .addImm(1)
+          .addReg(0)
+          .addOperand(MCOperand::createExpr(
+              MCSymbolRefExpr::create(LazyPointer, OutContext)))
+          .addReg(0),
+      *Subtarget);
+
+  // _ifunc.stub_helper:
+  //   push %rax
+  //   push %rdi
+  //   push %rsi
+  //   push %rdx
+  //   push %rcx
+  //   push %r8
+  //   push %r9
+  //   callq foo
+  //   movq %rax,lazy_pointer(%rip)
+  //   pop %r9
+  //   pop %r8
+  //   pop %rcx
+  //   pop %rdx
+  //   pop %rsi
+  //   pop %rdi
+  //   pop %rax
+  //   jmpq *lazy_pointer(%rip)
+
+  EmitLinkage(StubHelper);
   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);
-
-  // FIXME: do the manual .symbol_resolver lowering that we did in AArch64AsmPrinter.
+  OutStreamer->emitLabel(StubHelper);
+  emitVisibility(StubHelper, GI.getVisibility());
+
+  for (int Reg :
+       {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9})
+    OutStreamer->emitInstruction(MCInstBuilder(X86::PUSH64r).addReg(Reg),
+                                 *Subtarget);
+
+  OutStreamer->emitInstruction(
+      MCInstBuilder(X86::CALL64pcrel32)
+          .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),
+      *Subtarget);
+
+  OutStreamer->emitInstruction(
+      MCInstBuilder(X86::MOV64mr)
+          .addReg(X86::RIP)
+          .addImm(1)
+          .addReg(0)
+          .addOperand(MCOperand::createExpr(
+              MCSymbolRefExpr::create(LazyPointer, OutContext)))
+          .addReg(0)
+          .addReg(X86::RAX),
+      *Subtarget);
+
+  for (int Reg :
+       {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX})
+    OutStreamer->emitInstruction(MCInstBuilder(X86::POP64r).addReg(Reg),
+                                 *Subtarget);
+
+  OutStreamer->emitInstruction(
+      MCInstBuilder(X86::JMP32m)
+          .addReg(X86::RIP)
+          .addImm(1)
+          .addReg(0)
+          .addOperand(MCOperand::createExpr(
+              MCSymbolRefExpr::create(LazyPointer, OutContext)))
+          .addReg(0),
+      *Subtarget);
 }
 
 static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,
diff --git a/llvm/test/CodeGen/X86/ifunc-asm.ll b/llvm/test/CodeGen/X86/ifunc-asm.ll
index 76efda71153207d..0f66febbe95b2da 100644
--- a/llvm/test/CodeGen/X86/ifunc-asm.ll
+++ b/llvm/test/CodeGen/X86/ifunc-asm.ll
@@ -5,20 +5,44 @@ define internal ptr @foo_resolver() {
 entry:
   ret ptr null
 }
-; ELF: .type foo_resolver, at function
-; ELF-NEXT: foo_resolver:
+; ELF:             .type foo_resolver, at function
+; ELF-NEXT:    foo_resolver:
 
-; MACHO: .p2align 4, 0x90
-; MACHO-NEXT: _foo_resolver
+; MACHO:           .p2align 4, 0x90
+; MACHO-NEXT:  _foo_resolver
 
 
 @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
+; ELF:             .globl foo_ifunc
+; ELF-NEXT:        .type foo_ifunc, at gnu_indirect_function
+; ELF-NEXT:        .set foo_ifunc, foo_resolver
 
-; MACHO:      .globl _foo_ifunc
-; MACHO-NEXT: .p2align 4, 0x90
-; MACHO-NEXT: _foo_ifunc:
-; MACHO-NEXT: .symbol_resolver _foo_ifunc
-; MACHO-NEXT: jmp _foo_resolver
+; MACHO:           .section __DATA,__data
+; MACHO-NEXT:      .globl _foo_ifunc.lazy_pointer
+; MACHO-NEXT:  _foo_ifunc.lazy_pointer:
+; MACHO-NEXT:      .quad _foo_ifunc.stub_helper
+; MACHO-NEXT:      .section __TEXT,__text,regular,pure_instructions
+; MACHO-NEXT:      .globl _foo_ifunc
+; MACHO-NEXT:      .p2align 4, 0x90
+; MACHO-NEXT:  _foo_ifunc:
+; MACHO-NEXT:      jmpl   *_foo_ifunc.lazy_pointer(%rip)
+; MACHO-NEXT:      .globl _foo_ifunc.stub_helper
+; MACHO-NEXT:      .p2align 4, 0x90
+; MACHO-NEXT:  _foo_ifunc.stub_helper:
+; MACHO-NEXT:      pushq   %rax
+; MACHO-NEXT:      pushq   %rdi
+; MACHO-NEXT:      pushq   %rsi
+; MACHO-NEXT:      pushq   %rdx
+; MACHO-NEXT:      pushq   %rcx
+; MACHO-NEXT:      pushq   %r8
+; MACHO-NEXT:      pushq   %r9
+; MACHO-NEXT:      callq   _foo_resolver
+; MACHO-NEXT:      movq    %rax, _foo_ifunc.lazy_pointer(%rip)
+; MACHO-NEXT:      popq    %r9
+; MACHO-NEXT:      popq    %r8
+; MACHO-NEXT:      popq    %rcx
+; MACHO-NEXT:      popq    %rdx
+; MACHO-NEXT:      popq    %rsi
+; MACHO-NEXT:      popq    %rdi
+; MACHO-NEXT:      popq    %rax
+; MACHO-NEXT:      jmpl    *_foo_ifunc.lazy_pointer(%rip)
\ No newline at end of file

>From b2d46d62984b685cd94597c957708e7b5b34d671 Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Wed, 29 Nov 2023 13:56:55 -0800
Subject: [PATCH 5/6] review feedback

Created using spr 1.3.4
---
 llvm/docs/LangRef.rst                      | 2 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index cb222e979db29d4..fece4ac7f127d6b 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -937,7 +937,7 @@ IFuncs, like as aliases, don't create any new data or func. They are just a new
 symbol that is resolved at runtime by calling a resolver function.
 
 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
+Mach-O 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
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index b4ac0a70e7fde9c..aaa7693c61f0e85 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -2321,7 +2321,7 @@ bool AsmPrinter::doFinalization(Module &M) {
   }
 
   // IFuncs must come before deubginfo in case the backend decides to emit them
-  // as actual functions, since on MachO targets, we cannot create regular
+  // as actual functions, since on Mach-O targets, we cannot create regular
   // sections after DWARF.
   for (const auto &IFunc : M.ifuncs())
     emitGlobalIFunc(M, IFunc);

>From e6af9eaa469fa0f2cf3b1df7ec80bed3c2354cbe Mon Sep 17 00:00:00 2001
From: Jon Roelofs <jonathan_roelofs at apple.com>
Date: Wed, 29 Nov 2023 14:07:49 -0800
Subject: [PATCH 6/6] fix docs build

Created using spr 1.3.4
---
 llvm/docs/LangRef.rst | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index fece4ac7f127d6b..51c60ecf5ac6586 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -937,8 +937,8 @@ IFuncs, like as aliases, don't create any new data or func. They are just a new
 symbol that is resolved at runtime by calling a resolver function.
 
 On ELF platforms, IFuncs are resolved by the dynamic linker at load time. On
-Mach-O platforms, they are lowered in terms of ``.symbol_resolver``s, which
-lazily resolve the callee the first time they are called.
+Mach-O platforms, they are lowered in terms of ``.symbol_resolver`` functions,
+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>`.



More information about the llvm-commits mailing list