[llvm-branch-commits] [clang] a12d2e4 - [𝘀𝗽𝗿] initial version

Jon Roelofs via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Nov 29 14:21:01 PST 2023


Author: Jon Roelofs
Date: 2023-11-29T14:20:52-08:00
New Revision: a12d2e4bf75a107e481b4aa446188a7561199d7b

URL: https://github.com/llvm/llvm-project/commit/a12d2e4bf75a107e481b4aa446188a7561199d7b
DIFF: https://github.com/llvm/llvm-project/commit/a12d2e4bf75a107e481b4aa446188a7561199d7b.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

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/TargetInfo.h
    clang/test/CodeGen/attr-cpuspecific.c
    clang/test/CodeGen/attr-ifunc.c
    clang/test/CodeGen/attr-ifunc.cpp
    clang/test/CodeGen/attr-target-clones.c
    clang/test/CodeGen/attr-target-mv-func-ptrs.c
    clang/test/CodeGen/attr-target-mv-va-args.c
    clang/test/CodeGen/attr-target-mv.c
    clang/test/CodeGen/ifunc.c
    clang/test/CodeGenCXX/attr-cpuspecific.cpp
    clang/test/CodeGenCXX/attr-target-clones.cpp
    clang/test/CodeGenCXX/attr-target-mv-diff-ns.cpp
    clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
    clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp
    clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp
    clang/test/CodeGenCXX/attr-target-mv-modules.cpp
    clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
    clang/test/CodeGenCXX/attr-target-mv-overloads.cpp
    clang/test/CodeGenCXX/externc-ifunc-resolver.cpp
    clang/test/SemaCXX/externc-ifunc-resolver.cpp
    compiler-rt/lib/builtins/cpu_model.c
    llvm/docs/LangRef.rst
    llvm/include/llvm/CodeGen/AsmPrinter.h
    llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    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/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 03ed6accf700c4e..cef9f5578fa2baa 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -455,6 +455,9 @@ def TargetMicrosoftCXXABI : TargetArch<["x86", "x86_64", "arm", "thumb", "aarch6
 def TargetELF : TargetSpec {
   let ObjectFormats = ["ELF"];
 }
+def TargetELFOrMachO : TargetSpec {
+  let ObjectFormats = ["ELF", "MachO"];
+}
 
 def TargetSupportsInitPriority : TargetSpec {
   let CustomCode = [{ !Target.getTriple().isOSzOS() }];
@@ -1665,7 +1668,7 @@ def IBOutletCollection : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
-def IFunc : Attr, TargetSpecificAttr<TargetELF> {
+def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
   let Spellings = [GCC<"ifunc">];
   let Args = [StringArgument<"Resolver">];
   let Subjects = SubjectList<[Function]>;

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index be74535e28d8a60..5e85ec52a4634e5 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5408,7 +5408,9 @@ considered inline.
 Not all targets support this attribute. ELF target support depends on both the
 linker and runtime linker, and is available in at least lld 4.0 and later,
 binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
-Non-ELF targets currently do not support this attribute.
+Mach-O targets support it, but with slightly 
diff erent semantics: the resolver
+is run at first call, instead of at load time by the runtime linker. Targets
+other than ELF and Mach-O currently do not support this attribute.
   }];
 }
 

diff  --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 41f3c2e403cbef6..1fe2a18cd5dc9cc 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1424,6 +1424,8 @@ class TargetInfo : public TransferrableTargetInfo,
 
   /// Identify whether this target supports IFuncs.
   bool supportsIFunc() const {
+    if (getTriple().isOSBinFormatMachO())
+      return true;
     return getTriple().isOSBinFormatELF() &&
            ((getTriple().isOSLinux() && !getTriple().isMusl()) ||
             getTriple().isOSFreeBSD());

diff  --git a/clang/test/CodeGen/attr-cpuspecific.c b/clang/test/CodeGen/attr-cpuspecific.c
index 9150597e8c5a847..5baa271b5240f0a 100644
--- a/clang/test/CodeGen/attr-cpuspecific.c
+++ b/clang/test/CodeGen/attr-cpuspecific.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX
 // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WINDOWS
 
 #ifdef _WIN64

diff  --git a/clang/test/CodeGen/attr-ifunc.c b/clang/test/CodeGen/attr-ifunc.c
index 4f8fe13530fdb7b..2ad41edf20dfa01 100644
--- a/clang/test/CodeGen/attr-ifunc.c
+++ b/clang/test/CodeGen/attr-ifunc.c
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify %s
 // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only -DCHECK_ALIASES %s
 // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
 
 #if defined(_WIN32)
 void foo(void) {}
@@ -36,6 +37,25 @@ void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver")));
 void f6(void) __attribute__((ifunc("f6_resolver")));
 // expected-error at -1 {{ifunc must point to a defined function}}
 
+#elif defined(__APPLE__)
+
+// NOTE: aliases are not supported on Darwin, so the above tests are not relevant.
+
+#define STR2(X) #X
+#define STR(X) STR2(X)
+#define PREFIX STR(__USER_LABEL_PREFIX__)
+
+void f1a(void) __asm("f1");
+void f1a(void) {}
+// expected-note at -1 {{previous definition is here}}
+void f1(void) __attribute__((ifunc(PREFIX "f1_ifunc"))) __asm("f1");
+// expected-error at -1 {{definition with same mangled name '<U+0001>f1' as another definition}}
+void *f1_ifunc(void) { return 0; }
+
+void *f6_ifunc(int i);
+void __attribute__((ifunc(PREFIX "f6_ifunc"))) f6(void) {}
+// expected-error at -1 {{definition 'f6' cannot also be an ifunc}}
+
 #else
 void f1a(void) __asm("f1");
 void f1a(void) {}

diff  --git a/clang/test/CodeGen/attr-ifunc.cpp b/clang/test/CodeGen/attr-ifunc.cpp
index 5b5b2c14b4074b7..b6e342df46eb583 100644
--- a/clang/test/CodeGen/attr-ifunc.cpp
+++ b/clang/test/CodeGen/attr-ifunc.cpp
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify -emit-llvm-only %s
 // RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
 
 void *f1_ifunc(void) { return nullptr; }
 void f1(void) __attribute__((ifunc("f1_ifunc")));

diff  --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c
index 98ffea40f56d887..32d4d6f32f68e56 100644
--- a/clang/test/CodeGen/attr-target-clones.c
+++ b/clang/test/CodeGen/attr-target-clones.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LINUX,CHECK
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=DARWIN,CHECK
 // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=WINDOWS,CHECK
 
 // LINUX: $foo.resolver = comdat any
@@ -7,6 +8,8 @@
 // LINUX: $foo_inline.resolver = comdat any
 // LINUX: $foo_inline2.resolver = comdat any
 
+// DARWIN-NOT: comdat any
+
 // WINDOWS: $foo = comdat any
 // WINDOWS: $foo_dupes = comdat any
 // WINDOWS: $unused = comdat any
@@ -16,6 +19,9 @@
 // LINUX: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
 // LINUX: @__cpu_features2 = external dso_local global [3 x i32]
 
+// DARWIN: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
+// DARWIN: @__cpu_features2 = external dso_local global [3 x i32]
+
 // LINUX: @internal.ifunc = internal ifunc i32 (), ptr @internal.resolver
 // LINUX: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver
 // LINUX: @foo_dupes.ifunc = weak_odr ifunc void (), ptr @foo_dupes.resolver
@@ -28,6 +34,7 @@ static int __attribute__((target_clones("sse4.2, default"))) internal(void) { re
 int use(void) { return internal(); }
 /// Internal linkage resolvers do not use comdat.
 // LINUX: define internal ptr @internal.resolver() {
+// DARWIN: define internal ptr @internal.resolver() {
 // WINDOWS: define internal i32 @internal() {
 
 int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
@@ -37,6 +44,12 @@ int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
 // LINUX: ret ptr @foo.sse4.2.0
 // LINUX: ret ptr @foo.default.1
 
+// DARWIN: define {{.*}}i32 @foo.sse4.2.0()
+// DARWIN: define {{.*}}i32 @foo.default.1()
+// DARWIN: define weak_odr ptr @foo.resolver() {
+// DARWIN: ret ptr @foo.sse4.2.0
+// DARWIN: ret ptr @foo.default.1
+
 // WINDOWS: define dso_local i32 @foo.sse4.2.0()
 // WINDOWS: define dso_local i32 @foo.default.1()
 // WINDOWS: define weak_odr dso_local i32 @foo() comdat
@@ -50,6 +63,12 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
 // LINUX: ret ptr @foo_dupes.sse4.2.0
 // LINUX: ret ptr @foo_dupes.default.1
 
+// DARWIN: define {{.*}}void @foo_dupes.default.1()
+// DARWIN: define {{.*}}void @foo_dupes.sse4.2.0()
+// DARWIN: define weak_odr ptr @foo_dupes.resolver() {
+// DARWIN: ret ptr @foo_dupes.sse4.2.0
+// DARWIN: ret ptr @foo_dupes.default.1
+
 // WINDOWS: define dso_local void @foo_dupes.default.1()
 // WINDOWS: define dso_local void @foo_dupes.sse4.2.0()
 // WINDOWS: define weak_odr dso_local void @foo_dupes() comdat
@@ -58,17 +77,21 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
 
 void bar2(void) {
   // LINUX: define {{.*}}void @bar2()
+  // DARWIN: define {{.*}}void @bar2()
   // WINDOWS: define dso_local void @bar2()
   foo_dupes();
   // LINUX: call void @foo_dupes.ifunc()
+  // DARWIN: call void @foo_dupes.ifunc()
   // WINDOWS: call void @foo_dupes()
 }
 
 int bar(void) {
   // LINUX: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
+  // DARWIN: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
   // WINDOWS: define dso_local i32 @bar() #[[DEF:[0-9]+]]
   return foo();
   // LINUX: call i32 @foo.ifunc()
+  // DARWIN: call i32 @foo.ifunc()
   // WINDOWS: call i32 @foo()
 }
 
@@ -79,6 +102,12 @@ void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
 // LINUX: ret ptr @unused.arch_ivybridge.0
 // LINUX: ret ptr @unused.default.1
 
+// DARWIN: define {{.*}}void @unused.default.1()
+// DARWIN: define {{.*}}void @unused.arch_ivybridge.0()
+// DARWIN: define weak_odr ptr @unused.resolver() {
+// DARWIN: ret ptr @unused.arch_ivybridge.0
+// DARWIN: ret ptr @unused.default.1
+
 // WINDOWS: define dso_local void @unused.default.1()
 // WINDOWS: define dso_local void @unused.arch_ivybridge.0()
 // WINDOWS: define weak_odr dso_local void @unused() comdat
@@ -93,10 +122,13 @@ foo_inline2(void);
 
 int bar3(void) {
   // LINUX: define {{.*}}i32 @bar3()
+  // DARWIN: define {{.*}}i32 @bar3()
   // WINDOWS: define dso_local i32 @bar3()
   return foo_inline() + foo_inline2();
   // LINUX: call i32 @foo_inline.ifunc()
   // LINUX: call i32 @foo_inline2.ifunc()
+  // DARWIN: call i32 @foo_inline.ifunc()
+  // DARWIN: call i32 @foo_inline2.ifunc()
   // WINDOWS: call i32 @foo_inline()
   // WINDOWS: call i32 @foo_inline2()
 }
@@ -106,6 +138,11 @@ int bar3(void) {
 // LINUX: ret ptr @foo_inline.sse4.2.1
 // LINUX: ret ptr @foo_inline.default.2
 
+// DARWIN: define weak_odr ptr @foo_inline.resolver() {
+// DARWIN: ret ptr @foo_inline.arch_sandybridge.0
+// DARWIN: ret ptr @foo_inline.sse4.2.1
+// DARWIN: ret ptr @foo_inline.default.2
+
 // WINDOWS: define weak_odr dso_local i32 @foo_inline() comdat
 // WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0
 // WINDOWS: musttail call i32 @foo_inline.sse4.2.1
@@ -118,6 +155,11 @@ foo_inline2(void){ return 0; }
 // LINUX: ret ptr @foo_inline2.sse4.2.1
 // LINUX: ret ptr @foo_inline2.default.2
 
+// DARWIN: define weak_odr ptr @foo_inline2.resolver() {
+// DARWIN: ret ptr @foo_inline2.arch_sandybridge.0
+// DARWIN: ret ptr @foo_inline2.sse4.2.1
+// DARWIN: ret ptr @foo_inline2.default.2
+
 // WINDOWS: define weak_odr dso_local i32 @foo_inline2() comdat
 // WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0
 // WINDOWS: musttail call i32 @foo_inline2.sse4.2.1
@@ -132,9 +174,11 @@ foo_used_no_defn(void);
 
 int test_foo_used_no_defn(void) {
   // LINUX: define {{.*}}i32 @test_foo_used_no_defn()
+  // DARWIN: define {{.*}}i32 @test_foo_used_no_defn()
   // WINDOWS: define dso_local i32 @test_foo_used_no_defn()
   return foo_used_no_defn();
   // LINUX: call i32 @foo_used_no_defn.ifunc()
+  // DARWIN: call i32 @foo_used_no_defn.ifunc()
   // WINDOWS: call i32 @foo_used_no_defn()
 }
 
@@ -143,6 +187,10 @@ int test_foo_used_no_defn(void) {
 // LINUX: ret ptr @foo_used_no_defn.sse4.2.0
 // LINUX: ret ptr @foo_used_no_defn.default.1
 
+// DARWIN: define weak_odr ptr @foo_used_no_defn.resolver() {
+// DARWIN: ret ptr @foo_used_no_defn.sse4.2.0
+// DARWIN: ret ptr @foo_used_no_defn.default.1
+
 // WINDOWS: define weak_odr dso_local i32 @foo_used_no_defn() comdat
 // WINDOWS: musttail call i32 @foo_used_no_defn.sse4.2.0
 // WINDOWS: musttail call i32 @foo_used_no_defn.default.1
@@ -170,12 +218,37 @@ int isa_level(int) { return 0; }
 // LINUX:        ret ptr @isa_level.arch_x86-64.0
 // LINUX:        ret ptr @isa_level.default.4
 
+// DARWIN:      define{{.*}} i32 @isa_level.default.4(
+// DARWIN:      define{{.*}} i32 @isa_level.arch_x86-64.0(
+// DARWIN:      define{{.*}} i32 @isa_level.arch_x86-64-v2.1(
+// DARWIN:      define{{.*}} i32 @isa_level.arch_x86-64-v3.2(
+// DARWIN:      define{{.*}} i32 @isa_level.arch_x86-64-v4.3(
+// DARWIN:      define weak_odr ptr @isa_level.resolver() {
+// DARWIN:        call void @__cpu_indicator_init()
+// DARWIN-NEXT:   load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
+// DARWIN-NEXT:   and i32 %[[#]], 4
+// DARWIN:        ret ptr @isa_level.arch_x86-64-v4.3
+// DARWIN:        load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
+// DARWIN-NEXT:   and i32 %[[#]], 2
+// DARWIN:        ret ptr @isa_level.arch_x86-64-v3.2
+// DARWIN:        load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
+// DARWIN-NEXT:   and i32 %[[#]], 1
+// DARWIN:        ret ptr @isa_level.arch_x86-64-v2.1
+// DARWIN:        load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1)
+// DARWIN-NEXT:   and i32 %[[#]], -2147483648
+// DARWIN:        ret ptr @isa_level.arch_x86-64.0
+// DARWIN:        ret ptr @isa_level.default.4
+
 // Deferred emission of inline definitions.
 
 // LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
 // LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
 // LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
 
+// DARWIN: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
+// DARWIN: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
+// DARWIN: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
+
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
@@ -185,6 +258,10 @@ int isa_level(int) { return 0; }
 // LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
 // LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
 
+// DARWIN: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
+// DARWIN: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
+// DARWIN: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
+
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]]
@@ -193,6 +270,9 @@ int isa_level(int) { return 0; }
 // LINUX: declare i32 @foo_used_no_defn.default.1()
 // LINUX: declare i32 @foo_used_no_defn.sse4.2.0()
 
+// DARWIN: declare i32 @foo_used_no_defn.default.1()
+// DARWIN: declare i32 @foo_used_no_defn.sse4.2.0()
+
 // WINDOWS: declare dso_local i32 @foo_used_no_defn.default.1()
 // WINDOWS: declare dso_local i32 @foo_used_no_defn.sse4.2.0()
 

diff  --git a/clang/test/CodeGen/attr-target-mv-func-ptrs.c b/clang/test/CodeGen/attr-target-mv-func-ptrs.c
index b5f3a1b02f36f4f..7792ca53a4f65ee 100644
--- a/clang/test/CodeGen/attr-target-mv-func-ptrs.c
+++ b/clang/test/CodeGen/attr-target-mv-func-ptrs.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
 // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 int __attribute__((target("sse4.2"))) foo(int i) { return 0; }
 int __attribute__((target("arch=sandybridge"))) foo(int);

diff  --git a/clang/test/CodeGen/attr-target-mv-va-args.c b/clang/test/CodeGen/attr-target-mv-va-args.c
index 96821c610235bdc..dbf5a74205c4c19 100644
--- a/clang/test/CodeGen/attr-target-mv-va-args.c
+++ b/clang/test/CodeGen/attr-target-mv-va-args.c
@@ -3,6 +3,7 @@
 // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,WINDOWS
 // RUN: %clang_cc1 -triple x86_64-linux-musl -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF
 // RUN: %clang_cc1 -triple x86_64-fuchsia -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF
+// RUN: %clang_cc1 -triple x86_64-apple-macho -emit-llvm %s -o - | FileCheck %s --check-prefix=IFUNC-MACHO
 int __attribute__((target("sse4.2"))) foo(int i, ...) { return 0; }
 int __attribute__((target("arch=sandybridge"))) foo(int i, ...);
 int __attribute__((target("arch=ivybridge"))) foo(int i, ...) {return 1;}
@@ -30,6 +31,24 @@ int bar(void) {
 // IFUNC-ELF: ret ptr @foo
 // IFUNC-ELF: declare i32 @foo.arch_sandybridge(i32 noundef, ...)
 
+// IFUNC-MACHO: @foo.ifunc = weak_odr ifunc i32 (i32, ...), ptr @foo.resolver
+// IFUNC-MACHO: define{{.*}} i32 @foo.sse4.2(i32 noundef %i, ...)
+// IFUNC-MACHO: ret i32 0
+// IFUNC-MACHO: define{{.*}} i32 @foo.arch_ivybridge(i32 noundef %i, ...)
+// IFUNC-MACHO: ret i32 1
+// IFUNC-MACHO: define{{.*}} i32 @foo(i32 noundef %i, ...)
+// IFUNC-MACHO: ret i32 2
+// IFUNC-MACHO: define{{.*}} i32 @bar()
+// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 1, i32 noundef 97, double
+// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 2, double noundef 2.2{{[0-9Ee+]+}}, ptr noundef
+
+// IFUNC-MACHO: define weak_odr ptr @foo.resolver()
+// IFUNC-MACHO: ret ptr @foo.arch_sandybridge
+// IFUNC-MACHO: ret ptr @foo.arch_ivybridge
+// IFUNC-MACHO: ret ptr @foo.sse4.2
+// IFUNC-MACHO: ret ptr @foo
+// IFUNC-MACHO: declare i32 @foo.arch_sandybridge(i32 noundef, ...)
+
 // NO-IFUNC: define dso_local i32 @foo.sse4.2(i32 noundef %i, ...)
 // NO-IFUNC: ret i32 0
 // NO-IFUNC: define dso_local i32 @foo.arch_ivybridge(i32 noundef %i, ...)

diff  --git a/clang/test/CodeGen/attr-target-mv.c b/clang/test/CodeGen/attr-target-mv.c
index bdf8c49de4ae869..67d57b7f277e094 100644
--- a/clang/test/CodeGen/attr-target-mv.c
+++ b/clang/test/CodeGen/attr-target-mv.c
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 
 int __attribute__((target("sse4.2"))) foo(void) { return 0; }
@@ -107,6 +108,8 @@ void calls_pr50025c(void) { pr50025c(); }
 // LINUX: $pr50025c.resolver = comdat any
 // LINUX: $pr50025b.resolver = comdat any
 
+// DARWIN-NOT: comdat
+
 // WINDOWS: $foo.resolver = comdat any
 // WINDOWS: $foo_inline.resolver = comdat any
 // WINDOWS: $foo_decls.resolver = comdat any
@@ -133,73 +136,74 @@ void calls_pr50025c(void) { pr50025c(); }
 
 
 // LINUX: @llvm.compiler.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
+// DARWIN: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
 // WINDOWS: @llvm.used = appending global [2 x ptr] [ptr @foo_used, ptr @foo_used2.avx_sse4.2], section "llvm.metadata"
 
 
-// LINUX: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver
-// LINUX: @foo_internal.ifunc = internal ifunc i32 (), ptr @foo_internal.resolver
-// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), ptr @foo_inline.resolver
-// LINUX: @foo_decls.ifunc = weak_odr ifunc void (), ptr @foo_decls.resolver
-// LINUX: @foo_multi.ifunc = weak_odr ifunc void (i32, double), ptr @foo_multi.resolver
-// LINUX: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_default.resolver
-// LINUX: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_avx.resolver
-
-// LINUX: define{{.*}} i32 @foo.sse4.2()
-// LINUX: ret i32 0
-// LINUX: define{{.*}} i32 @foo.arch_ivybridge()
-// LINUX: ret i32 1
-// LINUX: define{{.*}} i32 @foo.arch_goldmont()
-// LINUX: ret i32 3
-// LINUX: define{{.*}} i32 @foo.arch_goldmont-plus()
-// LINUX: ret i32 4
-// LINUX: define{{.*}} i32 @foo.arch_tremont()
-// LINUX: ret i32 5
-// LINUX: define{{.*}} i32 @foo.arch_icelake-client()
-// LINUX: ret i32 6
-// LINUX: define{{.*}} i32 @foo.arch_icelake-server()
-// LINUX: ret i32 7
-// LINUX: define{{.*}} i32 @foo.arch_cooperlake()
-// LINUX: ret i32 8
-// LINUX: define{{.*}} i32 @foo.arch_tigerlake()
-// LINUX: ret i32 9
-// LINUX: define{{.*}} i32 @foo.arch_sapphirerapids()
-// LINUX: ret i32 10
-// LINUX: define{{.*}} i32 @foo.arch_alderlake()
-// LINUX: ret i32 11
-// LINUX: define{{.*}} i32 @foo.arch_rocketlake()
-// LINUX: ret i32 12
-// LINUX: define{{.*}} i32 @foo.arch_core2()
-// LINUX: ret i32 13
-// LINUX: define{{.*}} i32 @foo.arch_raptorlake()
-// LINUX: ret i32 14
-// LINUX: define{{.*}} i32 @foo.arch_meteorlake()
-// LINUX: ret i32 15
-// LINUX: define{{.*}} i32 @foo.arch_sierraforest()
-// LINUX: ret i32 16
-// LINUX: define{{.*}} i32 @foo.arch_grandridge()
-// LINUX: ret i32 17
-// LINUX: define{{.*}} i32 @foo.arch_graniterapids()
-// LINUX: ret i32 18
-// LINUX: define{{.*}} i32 @foo.arch_emeraldrapids()
-// LINUX: ret i32 19
-// LINUX: define{{.*}} i32 @foo.arch_graniterapids-d()
-// LINUX: ret i32 20
-// LINUX: define{{.*}} i32 @foo.arch_arrowlake()
-// LINUX: ret i32 21
-// LINUX: define{{.*}} i32 @foo.arch_arrowlake-s()
-// LINUX: ret i32 22
-// LINUX: define{{.*}} i32 @foo.arch_lunarlake()
-// LINUX: ret i32 23
-// LINUX: define{{.*}} i32 @foo.arch_gracemont()
-// LINUX: ret i32 24
-// LINUX: define{{.*}} i32 @foo.arch_pantherlake()
-// LINUX: ret i32 25
-// LINUX: define{{.*}} i32 @foo.arch_clearwaterforest()
-// LINUX: ret i32 26
-// LINUX: define{{.*}} i32 @foo()
-// LINUX: ret i32 2
-// LINUX: define{{.*}} i32 @bar()
-// LINUX: call i32 @foo.ifunc()
+// ITANIUM: @foo.ifunc = weak_odr ifunc i32 (), ptr @foo.resolver
+// ITANIUM: @foo_internal.ifunc = internal ifunc i32 (), ptr @foo_internal.resolver
+// ITANIUM: @foo_inline.ifunc = weak_odr ifunc i32 (), ptr @foo_inline.resolver
+// ITANIUM: @foo_decls.ifunc = weak_odr ifunc void (), ptr @foo_decls.resolver
+// ITANIUM: @foo_multi.ifunc = weak_odr ifunc void (i32, double), ptr @foo_multi.resolver
+// ITANIUM: @fwd_decl_default.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_default.resolver
+// ITANIUM: @fwd_decl_avx.ifunc = weak_odr ifunc i32 (), ptr @fwd_decl_avx.resolver
+
+// ITANIUM: define{{.*}} i32 @foo.sse4.2()
+// ITANIUM: ret i32 0
+// ITANIUM: define{{.*}} i32 @foo.arch_ivybridge()
+// ITANIUM: ret i32 1
+// ITANIUM: define{{.*}} i32 @foo.arch_goldmont()
+// ITANIUM: ret i32 3
+// ITANIUM: define{{.*}} i32 @foo.arch_goldmont-plus()
+// ITANIUM: ret i32 4
+// ITANIUM: define{{.*}} i32 @foo.arch_tremont()
+// ITANIUM: ret i32 5
+// ITANIUM: define{{.*}} i32 @foo.arch_icelake-client()
+// ITANIUM: ret i32 6
+// ITANIUM: define{{.*}} i32 @foo.arch_icelake-server()
+// ITANIUM: ret i32 7
+// ITANIUM: define{{.*}} i32 @foo.arch_cooperlake()
+// ITANIUM: ret i32 8
+// ITANIUM: define{{.*}} i32 @foo.arch_tigerlake()
+// ITANIUM: ret i32 9
+// ITANIUM: define{{.*}} i32 @foo.arch_sapphirerapids()
+// ITANIUM: ret i32 10
+// ITANIUM: define{{.*}} i32 @foo.arch_alderlake()
+// ITANIUM: ret i32 11
+// ITANIUM: define{{.*}} i32 @foo.arch_rocketlake()
+// ITANIUM: ret i32 12
+// ITANIUM: define{{.*}} i32 @foo.arch_core2()
+// ITANIUM: ret i32 13
+// ITANIUM: define{{.*}} i32 @foo.arch_raptorlake()
+// ITANIUM: ret i32 14
+// ITANIUM: define{{.*}} i32 @foo.arch_meteorlake()
+// ITANIUM: ret i32 15
+// ITANIUM: define{{.*}} i32 @foo.arch_sierraforest()
+// ITANIUM: ret i32 16
+// ITANIUM: define{{.*}} i32 @foo.arch_grandridge()
+// ITANIUM: ret i32 17
+// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids()
+// ITANIUM: ret i32 18
+// ITANIUM: define{{.*}} i32 @foo.arch_emeraldrapids()
+// ITANIUM: ret i32 19
+// ITANIUM: define{{.*}} i32 @foo.arch_graniterapids-d()
+// ITANIUM: ret i32 20
+// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake()
+// ITANIUM: ret i32 21
+// ITANIUM: define{{.*}} i32 @foo.arch_arrowlake-s()
+// ITANIUM: ret i32 22
+// ITANIUM: define{{.*}} i32 @foo.arch_lunarlake()
+// ITANIUM: ret i32 23
+// ITANIUM: define{{.*}} i32 @foo.arch_gracemont()
+// ITANIUM: ret i32 24
+// ITANIUM: define{{.*}} i32 @foo.arch_pantherlake()
+// ITANIUM: ret i32 25
+// ITANIUM: define{{.*}} i32 @foo.arch_clearwaterforest()
+// ITANIUM: ret i32 26
+// ITANIUM: define{{.*}} i32 @foo()
+// ITANIUM: ret i32 2
+// ITANIUM: define{{.*}} i32 @bar()
+// ITANIUM: call i32 @foo.ifunc()
 
 // WINDOWS: define dso_local i32 @foo.sse4.2()
 // WINDOWS: ret i32 0
@@ -258,12 +262,13 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: define dso_local i32 @bar()
 // WINDOWS: call i32 @foo.resolver()
 
-// LINUX: define weak_odr ptr @foo.resolver() comdat
-// LINUX: call void @__cpu_indicator_init()
-// LINUX: ret ptr @foo.arch_sandybridge
-// LINUX: ret ptr @foo.arch_ivybridge
-// LINUX: ret ptr @foo.sse4.2
-// LINUX: ret ptr @foo
+// ITANIUM: define weak_odr ptr @foo.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: call void @__cpu_indicator_init()
+// ITANIUM: ret ptr @foo.arch_sandybridge
+// ITANIUM: ret ptr @foo.arch_ivybridge
+// ITANIUM: ret ptr @foo.sse4.2
+// ITANIUM: ret ptr @foo
 
 // WINDOWS: define weak_odr dso_local i32 @foo.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
@@ -273,22 +278,23 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: call i32 @foo
 
 /// Internal linkage resolvers do not use comdat.
-// LINUX: define internal ptr @foo_internal.resolver() {
+// ITANIUM: define internal ptr @foo_internal.resolver() {
 
 // WINDOWS: define internal i32 @foo_internal.resolver() {
 
-// LINUX: define{{.*}} i32 @bar2()
-// LINUX: call i32 @foo_inline.ifunc()
+// ITANIUM: define{{.*}} i32 @bar2()
+// ITANIUM: call i32 @foo_inline.ifunc()
 
 // WINDOWS: define dso_local i32 @bar2()
 // WINDOWS: call i32 @foo_inline.resolver()
 
-// LINUX: define weak_odr ptr @foo_inline.resolver() comdat
-// LINUX: call void @__cpu_indicator_init()
-// LINUX: ret ptr @foo_inline.arch_sandybridge
-// LINUX: ret ptr @foo_inline.arch_ivybridge
-// LINUX: ret ptr @foo_inline.sse4.2
-// LINUX: ret ptr @foo_inline
+// ITANIUM: define weak_odr ptr @foo_inline.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: call void @__cpu_indicator_init()
+// ITANIUM: ret ptr @foo_inline.arch_sandybridge
+// ITANIUM: ret ptr @foo_inline.arch_ivybridge
+// ITANIUM: ret ptr @foo_inline.sse4.2
+// ITANIUM: ret ptr @foo_inline
 
 // WINDOWS: define weak_odr dso_local i32 @foo_inline.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
@@ -297,38 +303,40 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: call i32 @foo_inline.sse4.2
 // WINDOWS: call i32 @foo_inline
 
-// LINUX: define{{.*}} void @bar3()
-// LINUX: call void @foo_decls.ifunc()
+// ITANIUM: define{{.*}} void @bar3()
+// ITANIUM: call void @foo_decls.ifunc()
 
 // WINDOWS: define dso_local void @bar3()
 // WINDOWS: call void @foo_decls.resolver()
 
-// LINUX: define weak_odr ptr @foo_decls.resolver() comdat
-// LINUX: ret ptr @foo_decls.sse4.2
-// LINUX: ret ptr @foo_decls
+// ITANIUM: define weak_odr ptr @foo_decls.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @foo_decls.sse4.2
+// ITANIUM: ret ptr @foo_decls
 
 // WINDOWS: define weak_odr dso_local void @foo_decls.resolver() comdat
 // WINDOWS: call void @foo_decls.sse4.2
 // WINDOWS: call void @foo_decls
 
-// LINUX: define{{.*}} void @bar4()
-// LINUX: call void @foo_multi.ifunc(i32 noundef 1, double noundef 5.{{[0+e]*}})
+// ITANIUM: define{{.*}} void @bar4()
+// ITANIUM: call void @foo_multi.ifunc(i32 noundef 1, double noundef 5.{{[0+e]*}})
 
 // WINDOWS: define dso_local void @bar4()
 // WINDOWS: call void @foo_multi.resolver(i32 noundef 1, double noundef 5.{{[0+e]*}})
 
-// LINUX: define weak_odr ptr @foo_multi.resolver() comdat
-// LINUX: and i32 %{{.*}}, 4352
-// LINUX: icmp eq i32 %{{.*}}, 4352
-// LINUX: ret ptr @foo_multi.fma4_sse4.2
-// LINUX: icmp eq i32 %{{.*}}, 12
-// LINUX: and i32 %{{.*}}, 4352
-// LINUX: icmp eq i32 %{{.*}}, 4352
-// LINUX: ret ptr @foo_multi.arch_ivybridge_fma4_sse4.2
-// LINUX: and i32 %{{.*}}, 768
-// LINUX: icmp eq i32 %{{.*}}, 768
-// LINUX: ret ptr @foo_multi.avx_sse4.2
-// LINUX: ret ptr @foo_multi
+// ITANIUM: define weak_odr ptr @foo_multi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: and i32 %{{.*}}, 4352
+// ITANIUM: icmp eq i32 %{{.*}}, 4352
+// ITANIUM: ret ptr @foo_multi.fma4_sse4.2
+// ITANIUM: icmp eq i32 %{{.*}}, 12
+// ITANIUM: and i32 %{{.*}}, 4352
+// ITANIUM: icmp eq i32 %{{.*}}, 4352
+// ITANIUM: ret ptr @foo_multi.arch_ivybridge_fma4_sse4.2
+// ITANIUM: and i32 %{{.*}}, 768
+// ITANIUM: icmp eq i32 %{{.*}}, 768
+// ITANIUM: ret ptr @foo_multi.avx_sse4.2
+// ITANIUM: ret ptr @foo_multi
 
 // WINDOWS: define weak_odr dso_local void @foo_multi.resolver(i32 %0, double %1) comdat
 // WINDOWS: and i32 %{{.*}}, 4352
@@ -347,12 +355,12 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: call void @foo_multi(i32 %0, double %1)
 // WINDOWS-NEXT: ret void
 
-// LINUX: define{{.*}} i32 @fwd_decl_default()
-// LINUX: ret i32 2
-// LINUX: define{{.*}} i32 @fwd_decl_avx.avx()
-// LINUX: ret i32 2
-// LINUX: define{{.*}} i32 @fwd_decl_avx()
-// LINUX: ret i32 2
+// ITANIUM: define{{.*}} i32 @fwd_decl_default()
+// ITANIUM: ret i32 2
+// ITANIUM: define{{.*}} i32 @fwd_decl_avx.avx()
+// ITANIUM: ret i32 2
+// ITANIUM: define{{.*}} i32 @fwd_decl_avx()
+// ITANIUM: ret i32 2
 
 // WINDOWS: define dso_local i32 @fwd_decl_default()
 // WINDOWS: ret i32 2
@@ -361,21 +369,23 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: define dso_local i32 @fwd_decl_avx()
 // WINDOWS: ret i32 2
 
-// LINUX: define{{.*}} void @bar5()
-// LINUX: call i32 @fwd_decl_default.ifunc()
-// LINUX: call i32 @fwd_decl_avx.ifunc()
+// ITANIUM: define{{.*}} void @bar5()
+// ITANIUM: call i32 @fwd_decl_default.ifunc()
+// ITANIUM: call i32 @fwd_decl_avx.ifunc()
 
 // WINDOWS: define dso_local void @bar5()
 // WINDOWS: call i32 @fwd_decl_default.resolver()
 // WINDOWS: call i32 @fwd_decl_avx.resolver()
 
-// LINUX: define weak_odr ptr @fwd_decl_default.resolver() comdat
-// LINUX: call void @__cpu_indicator_init()
-// LINUX: ret ptr @fwd_decl_default
-// LINUX: define weak_odr ptr @fwd_decl_avx.resolver() comdat
-// LINUX: call void @__cpu_indicator_init()
-// LINUX: ret ptr @fwd_decl_avx.avx
-// LINUX: ret ptr @fwd_decl_avx
+// ITANIUM: define weak_odr ptr @fwd_decl_default.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: call void @__cpu_indicator_init()
+// ITANIUM: ret ptr @fwd_decl_default
+// ITANIUM: define weak_odr ptr @fwd_decl_avx.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: call void @__cpu_indicator_init()
+// ITANIUM: ret ptr @fwd_decl_avx.avx
+// ITANIUM: ret ptr @fwd_decl_avx
 
 // WINDOWS: define weak_odr dso_local i32 @fwd_decl_default.resolver() comdat
 // WINDOWS: call void @__cpu_indicator_init()
@@ -385,55 +395,55 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: call i32 @fwd_decl_avx.avx
 // WINDOWS: call i32 @fwd_decl_avx
 
-// LINUX: define{{.*}} i32 @changed_to_mv.avx()
-// LINUX: define{{.*}} i32 @changed_to_mv.fma4()
+// ITANIUM: define{{.*}} i32 @changed_to_mv.avx()
+// ITANIUM: define{{.*}} i32 @changed_to_mv.fma4()
 
 // WINDOWS: define dso_local i32 @changed_to_mv.avx()
 // WINDOWS: define dso_local i32 @changed_to_mv.fma4()
 
-// LINUX: define linkonce void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}})
-// LINUX-NOT: @foo_used.avx_sse4.2(
-// LINUX-NOT: @foo_used2(
-// LINUX: define linkonce void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}})
+// ITANIUM: define linkonce void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}})
+// ITANIUM-NOT: @foo_used.avx_sse4.2(
+// ITANIUM-NOT: @foo_used2(
+// ITANIUM: define linkonce void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}})
 
 // WINDOWS: define linkonce_odr dso_local void @foo_used(i32 noundef %{{.*}}, double noundef %{{.*}})
 // WINDOWS-NOT: @foo_used.avx_sse4.2(
 // WINDOWS-NOT: @foo_used2(
 // WINDOWS: define linkonce_odr dso_local void @foo_used2.avx_sse4.2(i32 noundef %{{.*}}, double noundef %{{.*}})
 
-// LINUX: declare i32 @foo.arch_sandybridge()
+// ITANIUM: declare i32 @foo.arch_sandybridge()
 // WINDOWS: declare dso_local i32 @foo.arch_sandybridge()
 
-// LINUX: define linkonce i32 @foo_inline.sse4.2()
-// LINUX: ret i32 0
+// ITANIUM: define linkonce i32 @foo_inline.sse4.2()
+// ITANIUM: ret i32 0
 
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2()
 // WINDOWS: ret i32 0
 
-// LINUX: declare i32 @foo_inline.arch_sandybridge()
+// ITANIUM: declare i32 @foo_inline.arch_sandybridge()
 
 // WINDOWS: declare dso_local i32 @foo_inline.arch_sandybridge()
 
-// LINUX: define linkonce i32 @foo_inline.arch_ivybridge()
-// LINUX: ret i32 1
-// LINUX: define linkonce i32 @foo_inline()
-// LINUX: ret i32 2
+// ITANIUM: define linkonce i32 @foo_inline.arch_ivybridge()
+// ITANIUM: ret i32 1
+// ITANIUM: define linkonce i32 @foo_inline()
+// ITANIUM: ret i32 2
 
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_ivybridge()
 // WINDOWS: ret i32 1
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline()
 // WINDOWS: ret i32 2
 
-// LINUX: define linkonce void @foo_decls()
-// LINUX: define linkonce void @foo_decls.sse4.2()
+// ITANIUM: define linkonce void @foo_decls()
+// ITANIUM: define linkonce void @foo_decls.sse4.2()
 
 // WINDOWS: define linkonce_odr dso_local void @foo_decls()
 // WINDOWS: define linkonce_odr dso_local void @foo_decls.sse4.2()
 
-// LINUX: define linkonce void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
-// LINUX: define linkonce void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
-// LINUX: define linkonce void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
-// LINUX: define linkonce void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
+// ITANIUM: define linkonce void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
+// ITANIUM: define linkonce void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
+// ITANIUM: define linkonce void @foo_multi.fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
+// ITANIUM: define linkonce void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
 
 // WINDOWS: define linkonce_odr dso_local void @foo_multi(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
 // WINDOWS: define linkonce_odr dso_local void @foo_multi.avx_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
@@ -441,22 +451,23 @@ void calls_pr50025c(void) { pr50025c(); }
 // WINDOWS: define linkonce_odr dso_local void @foo_multi.arch_ivybridge_fma4_sse4.2(i32 noundef %{{[^,]+}}, double noundef %{{[^\)]+}})
 
 // Ensure that we emit the 'static' function here.
-// LINUX: define linkonce void @pr50025()
-// LINUX: call void @must_be_emitted
-// LINUX: define internal void @must_be_emitted()
+// ITANIUM: define linkonce void @pr50025()
+// ITANIUM: call void @must_be_emitted
+// ITANIUM: define internal void @must_be_emitted()
 // WINDOWS: define linkonce_odr dso_local void @pr50025() #{{[0-9]*}} comdat
 // WINDOWS: call void @must_be_emitted
 // WINDOWS: define internal void @must_be_emitted()
 
-// LINUX: define linkonce void @pr50025c()
-// LINUX: call void @pr50025b.ifunc()
+// ITANIUM: define linkonce void @pr50025c()
+// ITANIUM: call void @pr50025b.ifunc()
 // WINDOWS: define linkonce_odr dso_local void @pr50025c() #{{[0-9]*}} comdat
 // WINDOWS: call void @pr50025b.resolver()
 
-// LINUX: define weak_odr ptr @pr50025b.resolver() comdat
-// LINUX: ret ptr @pr50025b
-// LINUX: define linkonce void @pr50025b()
-// LINUX: call void @must_be_emitted()
+// ITANIUM: define weak_odr ptr @pr50025b.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @pr50025b
+// ITANIUM: define linkonce void @pr50025b()
+// ITANIUM: call void @must_be_emitted()
 // WINDOWS: define weak_odr dso_local void @pr50025b.resolver() comdat
 // WINDOWS: musttail call void @pr50025b()
 // WINDOWS: define linkonce_odr dso_local void @pr50025b() #{{[0-9]*}} comdat

diff  --git a/clang/test/CodeGen/ifunc.c b/clang/test/CodeGen/ifunc.c
index 0b0a0549620f8b8..a29b500e80bd50b 100644
--- a/clang/test/CodeGen/ifunc.c
+++ b/clang/test/CodeGen/ifunc.c
@@ -3,6 +3,14 @@
 // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
 // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
 // RUN: %clang_cc1 -triple i386-unknown-linux-gnu -fsanitize=memory -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
+// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -O2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
+// RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=MACSAN
 
 int foo(int) __attribute__ ((ifunc("foo_ifunc")));
 
@@ -44,9 +52,13 @@ void* goo_ifunc(void) {
 // CHECK: call void @goo()
 
 // SAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
+// MACSAN: define internal nonnull ptr @foo_ifunc() #[[#FOO_IFUNC:]] {
 
 // SAN: define dso_local noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {
+// MACSAN: define noalias ptr @goo_ifunc() #[[#GOO_IFUNC:]] {
 
 // SAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
+// MACSAN-DAG: attributes #[[#FOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
 
 // SAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}
+// MACSAN-DAG: attributes #[[#GOO_IFUNC]] = {{{.*}} disable_sanitizer_instrumentation {{.*}}

diff  --git a/clang/test/CodeGenCXX/attr-cpuspecific.cpp b/clang/test/CodeGenCXX/attr-cpuspecific.cpp
index 60cba6da01754dc..2294ee4b4c153f8 100644
--- a/clang/test/CodeGenCXX/attr-cpuspecific.cpp
+++ b/clang/test/CodeGenCXX/attr-cpuspecific.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX
 // RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefix=WINDOWS
 
 struct S {

diff  --git a/clang/test/CodeGenCXX/attr-target-clones.cpp b/clang/test/CodeGenCXX/attr-target-clones.cpp
index 86293b98dbbd35f..d540c8f8ac289f5 100644
--- a/clang/test/CodeGenCXX/attr-target-clones.cpp
+++ b/clang/test/CodeGenCXX/attr-target-clones.cpp
@@ -1,20 +1,24 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 
+// DARWIN-NOT: comdat
+
 // Overloaded ifuncs
-// LINUX: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z10overloadedi.resolver
-// LINUX: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (ptr), ptr @_Z10overloadedPKc.resolver
+// ITANIUM: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z10overloadedi.resolver
+// ITANIUM: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (ptr), ptr @_Z10overloadedPKc.resolver
 // struct 'C' ifuncs, note the 'float, U' one doesn't get one.
-// LINUX: @_ZN1CIssE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIssE3fooEv.resolver
-// LINUX: @_ZN1CIisE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIisE3fooEv.resolver
-// LINUX: @_ZN1CIdfE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIdfE3fooEv.resolver
+// ITANIUM: @_ZN1CIssE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIssE3fooEv.resolver
+// ITANIUM: @_ZN1CIisE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIisE3fooEv.resolver
+// ITANIUM: @_ZN1CIdfE3fooEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN1CIdfE3fooEv.resolver
 
 int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return 1; }
-// LINUX: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}})
-// LINUX: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}})
-// LINUX: define weak_odr ptr @_Z10overloadedi.resolver() comdat
-// LINUX: ret ptr @_Z10overloadedi.sse4.2.0
-// LINUX: ret ptr @_Z10overloadedi.default.1
+// ITANIUM: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}})
+// ITANIUM: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}})
+// ITANIUM: define weak_odr ptr @_Z10overloadedi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_Z10overloadedi.sse4.2.0
+// ITANIUM: ret ptr @_Z10overloadedi.default.1
 
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH at Z.sse4.2.0"(i32{{.+}})
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH at Z.default.1"(i32{{.+}})
@@ -23,11 +27,12 @@ int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return
 // WINDOWS: call i32 @"?overloaded@@YAHH at Z.default.1"
 
 int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const char *) { return 2; }
-// LINUX: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(ptr{{.+}})
-// LINUX: define {{.*}}i32 @_Z10overloadedPKc.default.1(ptr{{.+}})
-// LINUX: define weak_odr ptr @_Z10overloadedPKc.resolver() comdat
-// LINUX: ret ptr @_Z10overloadedPKc.arch_ivybridge.0
-// LINUX: ret ptr @_Z10overloadedPKc.default.1
+// ITANIUM: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(ptr{{.+}})
+// ITANIUM: define {{.*}}i32 @_Z10overloadedPKc.default.1(ptr{{.+}})
+// ITANIUM: define weak_odr ptr @_Z10overloadedPKc.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_Z10overloadedPKc.arch_ivybridge.0
+// ITANIUM: ret ptr @_Z10overloadedPKc.default.1
 
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD at Z.arch_ivybridge.0"(ptr{{.+}})
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD at Z.default.1"(ptr{{.+}})
@@ -37,10 +42,10 @@ int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const
 
 void use_overloaded() {
   overloaded(1);
-  // LINUX: call noundef i32 @_Z10overloadedi.ifunc
+  // ITANIUM: call noundef i32 @_Z10overloadedi.ifunc
   // WINDOWS: call noundef i32 @"?overloaded@@YAHH at Z"
   overloaded(nullptr);
-  // LINUX: call noundef i32 @_Z10overloadedPKc.ifunc 
+  // ITANIUM: call noundef i32 @_Z10overloadedPKc.ifunc 
   // WINDOWS: call noundef i32 @"?overloaded@@YAHPEBD at Z"
 }
 
@@ -64,53 +69,56 @@ int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 3;}
 void uses_specialized() {
   C<short, short> c;
   c.foo();
-  // LINUX: call noundef i32 @_ZN1CIssE3fooEv.ifunc(ptr
+  // ITANIUM: call noundef i32 @_ZN1CIssE3fooEv.ifunc(ptr
   // WINDOWS: call noundef i32 @"?foo@?$C at FF@@QEAAHXZ"(ptr
   C<int, short> c2;
   c2.foo();
-  // LINUX: call noundef i32 @_ZN1CIisE3fooEv.ifunc(ptr
+  // ITANIUM: call noundef i32 @_ZN1CIisE3fooEv.ifunc(ptr
   // WINDOWS: call noundef i32 @"?foo@?$C at HF@@QEAAHXZ"(ptr
   C<float, short> c3;
   c3.foo();
   // Note this is not an ifunc/mv
-  // LINUX: call noundef i32 @_ZN1CIfsE3fooEv(ptr
+  // ITANIUM: call noundef i32 @_ZN1CIfsE3fooEv(ptr
   // WINDOWS: call noundef i32 @"?foo@?$C at MF@@QEAAHXZ"(ptr
   C<double, float> c4;
   c4.foo();
-  // LINUX: call noundef i32 @_ZN1CIdfE3fooEv.ifunc(ptr
+  // ITANIUM: call noundef i32 @_ZN1CIdfE3fooEv.ifunc(ptr
   // WINDOWS: call noundef i32 @"?foo@?$C at NM@@QEAAHXZ"(ptr
 }
 
-// LINUX: define weak_odr ptr @_ZN1CIssE3fooEv.resolver() comdat
-// LINUX: ret ptr @_ZN1CIssE3fooEv.sse4.2.0
-// LINUX: ret ptr @_ZN1CIssE3fooEv.default.1
+// ITANIUM: define weak_odr ptr @_ZN1CIssE3fooEv.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1CIssE3fooEv.sse4.2.0
+// ITANIUM: ret ptr @_ZN1CIssE3fooEv.default.1
 
 // WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ"(ptr
 // WINDOWS: call i32 @"?foo@?$C at FF@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C at FF@@QEAAHXZ.default.1"
 
-// LINUX: define weak_odr ptr @_ZN1CIisE3fooEv.resolver() comdat
-// LINUX: ret ptr @_ZN1CIisE3fooEv.sse4.2.0
-// LINUX: ret ptr @_ZN1CIisE3fooEv.default.1
+// ITANIUM: define weak_odr ptr @_ZN1CIisE3fooEv.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1CIisE3fooEv.sse4.2.0
+// ITANIUM: ret ptr @_ZN1CIisE3fooEv.default.1
 
 // WINDOWS: define {{.*}}i32 @"?foo@?$C at HF@@QEAAHXZ"(ptr
 // WINDOWS: call i32 @"?foo@?$C at HF@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C at HF@@QEAAHXZ.default.1"
 
-// LINUX: define weak_odr ptr @_ZN1CIdfE3fooEv.resolver() comdat
-// LINUX: ret ptr @_ZN1CIdfE3fooEv.sse4.2.0
-// LINUX: ret ptr @_ZN1CIdfE3fooEv.default.1
+// ITANIUM: define weak_odr ptr @_ZN1CIdfE3fooEv.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1CIdfE3fooEv.sse4.2.0
+// ITANIUM: ret ptr @_ZN1CIdfE3fooEv.default.1
 
 // WINDOWS: define {{.*}}i32 @"?foo@?$C at NM@@QEAAHXZ"(ptr
 // WINDOWS: call i32 @"?foo@?$C at NM@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C at NM@@QEAAHXZ.default.1"
 
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(ptr
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(ptr
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(ptr
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(ptr
-// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(ptr
-// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(ptr
+// ITANIUM: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(ptr
 
 // WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ.sse4.2.0"(ptr
 // WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ.default.1"(ptr

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-
diff -ns.cpp b/clang/test/CodeGenCXX/attr-target-mv-
diff -ns.cpp
index 1157450835bda97..a6ec608240c767a 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-
diff -ns.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-
diff -ns.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 // Test ensures that this properly 
diff erentiates between types in 
diff erent
 // namespaces.
@@ -18,15 +19,17 @@ int bar() {
   return foo(1) + ns::foo(2);
 }
 
-// LINUX: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver
-// LINUX: @_ZN2ns3fooEi.ifunc = weak_odr ifunc i32 (i32), ptr @_ZN2ns3fooEi.resolver
+// DARWIN-NOT: comdat
 
-// LINUX: define{{.*}} i32 @_Z3fooi.sse4.2(i32 noundef %0)
-// LINUX: ret i32 0
-// LINUX: define{{.*}} i32 @_Z3fooi.arch_ivybridge(i32 noundef %0)
-// LINUX: ret i32 1
-// LINUX: define{{.*}} i32 @_Z3fooi(i32 noundef %0)
-// LINUX: ret i32 2
+// ITANIUM: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver
+// ITANIUM: @_ZN2ns3fooEi.ifunc = weak_odr ifunc i32 (i32), ptr @_ZN2ns3fooEi.resolver
+
+// ITANIUM: define{{.*}} i32 @_Z3fooi.sse4.2(i32 noundef %0)
+// ITANIUM: ret i32 0
+// ITANIUM: define{{.*}} i32 @_Z3fooi.arch_ivybridge(i32 noundef %0)
+// ITANIUM: ret i32 1
+// ITANIUM: define{{.*}} i32 @_Z3fooi(i32 noundef %0)
+// ITANIUM: ret i32 2
 
 // WINDOWS: define dso_local noundef i32 @"?foo@@YAHH at Z.sse4.2"(i32 noundef %0)
 // WINDOWS: ret i32 0
@@ -35,12 +38,12 @@ int bar() {
 // WINDOWS: define dso_local noundef i32 @"?foo@@YAHH at Z"(i32 noundef %0)
 // WINDOWS: ret i32 2
 
-// LINUX: define{{.*}} i32 @_ZN2ns3fooEi.sse4.2(i32 noundef %0)
-// LINUX: ret i32 0
-// LINUX: define{{.*}} i32 @_ZN2ns3fooEi.arch_ivybridge(i32 noundef %0)
-// LINUX: ret i32 1
-// LINUX: define{{.*}} i32 @_ZN2ns3fooEi(i32 noundef %0)
-// LINUX: ret i32 2
+// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi.sse4.2(i32 noundef %0)
+// ITANIUM: ret i32 0
+// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi.arch_ivybridge(i32 noundef %0)
+// ITANIUM: ret i32 1
+// ITANIUM: define{{.*}} i32 @_ZN2ns3fooEi(i32 noundef %0)
+// ITANIUM: ret i32 2
 
 // WINDOWS: define dso_local noundef i32 @"?foo at ns@@YAHH at Z.sse4.2"(i32 noundef %0)
 // WINDOWS: ret i32 0
@@ -49,19 +52,20 @@ int bar() {
 // WINDOWS: define dso_local noundef i32 @"?foo at ns@@YAHH at Z"(i32 noundef %0)
 // WINDOWS: ret i32 2
 
-// LINUX: define{{.*}} i32 @_Z3barv()
-// LINUX: call noundef i32 @_Z3fooi.ifunc(i32 noundef 1)
-// LINUX: call noundef i32 @_ZN2ns3fooEi.ifunc(i32 noundef 2)
+// ITANIUM: define{{.*}} i32 @_Z3barv()
+// ITANIUM: call noundef i32 @_Z3fooi.ifunc(i32 noundef 1)
+// ITANIUM: call noundef i32 @_ZN2ns3fooEi.ifunc(i32 noundef 2)
 
 // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"()
 // WINDOWS: call noundef i32 @"?foo@@YAHH at Z.resolver"(i32 noundef 1)
 // WINDOWS: call noundef i32 @"?foo at ns@@YAHH at Z.resolver"(i32 noundef 2)
 
-// LINUX: define weak_odr ptr @_Z3fooi.resolver() comdat
-// LINUX: ret ptr @_Z3fooi.arch_sandybridge
-// LINUX: ret ptr @_Z3fooi.arch_ivybridge
-// LINUX: ret ptr @_Z3fooi.sse4.2
-// LINUX: ret ptr @_Z3fooi
+// ITANIUM: define weak_odr ptr @_Z3fooi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_Z3fooi.arch_sandybridge
+// ITANIUM: ret ptr @_Z3fooi.arch_ivybridge
+// ITANIUM: ret ptr @_Z3fooi.sse4.2
+// ITANIUM: ret ptr @_Z3fooi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo@@YAHH at Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo@@YAHH at Z.arch_sandybridge"(i32 %0)
@@ -69,11 +73,12 @@ int bar() {
 // WINDOWS: call i32 @"?foo@@YAHH at Z.sse4.2"(i32 %0)
 // WINDOWS: call i32 @"?foo@@YAHH at Z"(i32 %0)
 
-// LINUX: define weak_odr ptr @_ZN2ns3fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN2ns3fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN2ns3fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN2ns3fooEi.sse4.2
-// LINUX: ret ptr @_ZN2ns3fooEi
+// ITANIUM: define weak_odr ptr @_ZN2ns3fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN2ns3fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN2ns3fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN2ns3fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN2ns3fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo at ns@@YAHH at Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo at ns@@YAHH at Z.arch_sandybridge"(i32 %0)
@@ -81,8 +86,8 @@ int bar() {
 // WINDOWS: call i32 @"?foo at ns@@YAHH at Z.sse4.2"(i32 %0)
 // WINDOWS: call i32 @"?foo at ns@@YAHH at Z"(i32 %0)
 
-// LINUX: declare noundef i32 @_Z3fooi.arch_sandybridge(i32 noundef)
-// LINUX: declare noundef i32 @_ZN2ns3fooEi.arch_sandybridge(i32 noundef)
+// ITANIUM: declare noundef i32 @_Z3fooi.arch_sandybridge(i32 noundef)
+// ITANIUM: declare noundef i32 @_ZN2ns3fooEi.arch_sandybridge(i32 noundef)
 
 // WINDOWS: declare dso_local noundef i32 @"?foo@@YAHH at Z.arch_sandybridge"(i32 noundef)
 // WINDOWS: declare dso_local noundef i32 @"?foo at ns@@YAHH at Z.arch_sandybridge"(i32 noundef)

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp b/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
index 690f44ceb58be84..111f6828c43597f 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-func-ptrs.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 void temp();
 void temp(int);

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp b/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp
index 614e44ee6df57c1..f11ac76ca771d34 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-inalloca.cpp
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -std=c++11 -triple i686-windows-msvc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS64
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-pc-linux -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefix=DARWIN
 
 struct Foo {
   Foo();
@@ -16,6 +18,9 @@ void usage() {
   bar(f);
 }
 
+// DARWIN-NOT: inalloca(
+// LINUX-NOT: inalloca(
+
 // WINDOWS: define dso_local noundef i32 @"?bar@@YAHUFoo@@@Z"(ptr inalloca(<{ %struct.Foo }>) %0)
 // WINDOWS: %[[O:[0-9a-zA-Z]+]] = getelementptr inbounds <{ %struct.Foo }>, ptr %0, i32 0, i32 0
 // WINDOWS: %[[X:[0-9a-zA-Z]+]] = getelementptr inbounds %struct.Foo, ptr %[[O]], i32 0, i32 0

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp
index cf3ba290714e0bd..35a62ee7e773c70 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 
 struct S {
@@ -65,22 +66,24 @@ int templ_use() {
   return a.foo(1) + b.foo(2);
 }
 
-// LINUX: @_ZN1SaSERKS_.ifunc = weak_odr ifunc ptr (ptr, ptr), ptr @_ZN1SaSERKS_.resolver
-// LINUX: @_ZNK9ConvertTocv1SEv.ifunc = weak_odr ifunc void (ptr), ptr @_ZNK9ConvertTocv1SEv.resolver
-// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver
-// LINUX: @_ZN2S23fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN2S23fooEi.resolver
+// DARWIN-NOT: comdat
+
+// ITANIUM: @_ZN1SaSERKS_.ifunc = weak_odr ifunc ptr (ptr, ptr), ptr @_ZN1SaSERKS_.resolver
+// ITANIUM: @_ZNK9ConvertTocv1SEv.ifunc = weak_odr ifunc void (ptr), ptr @_ZNK9ConvertTocv1SEv.resolver
+// ITANIUM: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver
+// ITANIUM: @_ZN2S23fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN2S23fooEi.resolver
 // Templates:
-// LINUX: @_ZN5templIiE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIiE3fooEi.resolver
-// LINUX: @_ZN5templIdE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIdE3fooEi.resolver
-
-// LINUX: define{{.*}} i32 @_Z3barv()
-// LINUX: %s = alloca %struct.S, align 1
-// LINUX: %s2 = alloca %struct.S, align 1
-// LINUX: %C = alloca %struct.ConvertTo, align 1
-// LINUX: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2
-// LINUX: call void @_ZNK9ConvertTocv1SEv.ifunc(ptr {{[^,]*}} %C)
-// LINUX: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2
-// LINUX: call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0)
+// ITANIUM: @_ZN5templIiE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIiE3fooEi.resolver
+// ITANIUM: @_ZN5templIdE3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN5templIdE3fooEi.resolver
+
+// ITANIUM: define{{.*}} i32 @_Z3barv()
+// ITANIUM: %s = alloca %struct.S, align 1
+// ITANIUM: %s2 = alloca %struct.S, align 1
+// ITANIUM: %C = alloca %struct.ConvertTo, align 1
+// ITANIUM: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2
+// ITANIUM: call void @_ZNK9ConvertTocv1SEv.ifunc(ptr {{[^,]*}} %C)
+// ITANIUM: call noundef nonnull align 1 dereferenceable(1) ptr @_ZN1SaSERKS_.ifunc(ptr {{[^,]*}} %s2
+// ITANIUM: call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0)
 
 // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"()
 // WINDOWS: %s = alloca %struct.S, align 1
@@ -91,27 +94,30 @@ int templ_use() {
 // WINDOWS: call noundef nonnull align 1 dereferenceable(1) ptr @"??4S@@QEAAAEAU0 at AEBU0@@Z.resolver"(ptr {{[^,]*}} %s2
 // WINDOWS: call noundef i32 @"?foo at S@@QEAAHH at Z.resolver"(ptr {{[^,]*}} %s, i32 noundef 0)
 
-// LINUX: define weak_odr ptr @_ZN1SaSERKS_.resolver() comdat
-// LINUX: ret ptr @_ZN1SaSERKS_.arch_ivybridge
-// LINUX: ret ptr @_ZN1SaSERKS_
+// ITANIUM: define weak_odr ptr @_ZN1SaSERKS_.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1SaSERKS_.arch_ivybridge
+// ITANIUM: ret ptr @_ZN1SaSERKS_
 
 // WINDOWS: define weak_odr dso_local ptr @"??4S@@QEAAAEAU0 at AEBU0@@Z.resolver"(ptr %0, ptr %1)
 // WINDOWS: call ptr @"??4S@@QEAAAEAU0 at AEBU0@@Z.arch_ivybridge"
 // WINDOWS: call ptr @"??4S@@QEAAAEAU0 at AEBU0@@Z"
 
-// LINUX: define weak_odr ptr @_ZNK9ConvertTocv1SEv.resolver() comdat
-// LINUX: ret ptr @_ZNK9ConvertTocv1SEv.arch_ivybridge
-// LINUX: ret ptr @_ZNK9ConvertTocv1SEv
+// ITANIUM: define weak_odr ptr @_ZNK9ConvertTocv1SEv.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZNK9ConvertTocv1SEv.arch_ivybridge
+// ITANIUM: ret ptr @_ZNK9ConvertTocv1SEv
 
 // WINDOWS: define weak_odr dso_local void @"??BConvertTo@@QEBA?AUS@@XZ.resolver"(ptr %0, ptr %1)
 // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ.arch_ivybridge"
 // WINDOWS: call void @"??BConvertTo@@QEBA?AUS@@XZ"
 
-// LINUX: define weak_odr ptr @_ZN1S3fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN1S3fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN1S3fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN1S3fooEi.sse4.2
-// LINUX: ret ptr @_ZN1S3fooEi
+// ITANIUM: define weak_odr ptr @_ZN1S3fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1S3fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN1S3fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN1S3fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN1S3fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo at S@@QEAAHH at Z.resolver"(ptr %0, i32 %1)
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z.arch_sandybridge"
@@ -119,17 +125,18 @@ int templ_use() {
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z.sse4.2"
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z"
 
-// LINUX: define{{.*}} i32 @_Z4bar2v()
-// LINUX: call noundef i32 @_ZN2S23fooEi.ifunc
+// ITANIUM: define{{.*}} i32 @_Z4bar2v()
+// ITANIUM: call noundef i32 @_ZN2S23fooEi.ifunc
 
 // WINDOWS: define dso_local noundef i32 @"?bar2@@YAHXZ"()
 // WINDOWS: call noundef i32 @"?foo at S2@@QEAAHH at Z.resolver"
 
-// LINUX: define weak_odr ptr @_ZN2S23fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN2S23fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN2S23fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN2S23fooEi.sse4.2
-// LINUX: ret ptr @_ZN2S23fooEi
+// ITANIUM: define weak_odr ptr @_ZN2S23fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN2S23fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN2S23fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN2S23fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN2S23fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo at S2@@QEAAHH at Z.resolver"(ptr %0, i32 %1)
 // WINDOWS: call i32 @"?foo at S2@@QEAAHH at Z.arch_sandybridge"
@@ -137,27 +144,28 @@ int templ_use() {
 // WINDOWS: call i32 @"?foo at S2@@QEAAHH at Z.sse4.2"
 // WINDOWS: call i32 @"?foo at S2@@QEAAHH at Z"
 
-// LINUX: define{{.*}} i32 @_ZN2S23fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: define{{.*}} i32 @_ZN2S23fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: define{{.*}} i32 @_ZN2S23fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: define{{.*}} i32 @_ZN2S23fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
 
 // WINDOWS: define dso_local noundef i32 @"?foo at S2@@QEAAHH at Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: define dso_local noundef i32 @"?foo at S2@@QEAAHH at Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: define dso_local noundef i32 @"?foo at S2@@QEAAHH at Z"(ptr {{[^,]*}} %this, i32 noundef %0)
 
-// LINUX: define{{.*}} i32 @_Z9templ_usev()
-// LINUX: call noundef i32 @_ZN5templIiE3fooEi.ifunc
-// LINUX: call noundef i32 @_ZN5templIdE3fooEi.ifunc
+// ITANIUM: define{{.*}} i32 @_Z9templ_usev()
+// ITANIUM: call noundef i32 @_ZN5templIiE3fooEi.ifunc
+// ITANIUM: call noundef i32 @_ZN5templIdE3fooEi.ifunc
 
 // WINDOWS: define dso_local noundef i32 @"?templ_use@@YAHXZ"()
 // WINDOWS: call noundef i32 @"?foo@?$templ at H@@QEAAHH at Z.resolver"
 // WINDOWS: call noundef i32 @"?foo@?$templ at N@@QEAAHH at Z.resolver"
 
-// LINUX: define weak_odr ptr @_ZN5templIiE3fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN5templIiE3fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN5templIiE3fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN5templIiE3fooEi.sse4.2
-// LINUX: ret ptr @_ZN5templIiE3fooEi
+// ITANIUM: define weak_odr ptr @_ZN5templIiE3fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN5templIiE3fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN5templIiE3fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN5templIiE3fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN5templIiE3fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ at H@@QEAAHH at Z.resolver"(ptr %0, i32 %1)
 // WINDOWS: call i32 @"?foo@?$templ at H@@QEAAHH at Z.arch_sandybridge"
@@ -165,11 +173,12 @@ int templ_use() {
 // WINDOWS: call i32 @"?foo@?$templ at H@@QEAAHH at Z.sse4.2"
 // WINDOWS: call i32 @"?foo@?$templ at H@@QEAAHH at Z"
 
-// LINUX: define weak_odr ptr @_ZN5templIdE3fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN5templIdE3fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN5templIdE3fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN5templIdE3fooEi.sse4.2
-// LINUX: ret ptr @_ZN5templIdE3fooEi
+// ITANIUM: define weak_odr ptr @_ZN5templIdE3fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN5templIdE3fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN5templIdE3fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN5templIdE3fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN5templIdE3fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo@?$templ at N@@QEAAHH at Z.resolver"(ptr %0, i32 %1) comdat
 // WINDOWS: call i32 @"?foo@?$templ at N@@QEAAHH at Z.arch_sandybridge"
@@ -177,42 +186,42 @@ int templ_use() {
 // WINDOWS: call i32 @"?foo@?$templ at N@@QEAAHH at Z.sse4.2"
 // WINDOWS: call i32 @"?foo@?$templ at N@@QEAAHH at Z"
 
-// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 0
+// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 0
 
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo at S@@QEAAHH at Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 0
 
-// LINUX: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef)
+// ITANIUM: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef)
 
 // WINDOWS: declare dso_local noundef i32 @"?foo at S@@QEAAHH at Z.arch_sandybridge"(ptr {{[^,]*}}, i32 noundef)
 
-// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 1
+// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 1
 
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo at S@@QEAAHH at Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 1
 
-// LINUX: define linkonce_odr noundef i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 2
+// ITANIUM: define linkonce_odr noundef i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 2
 
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo at S@@QEAAHH at Z"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 2
 
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.sse4.2
-// LINUX: declare noundef i32 @_ZN5templIiE3fooEi.arch_sandybridge
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.arch_ivybridge
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.sse4.2
+// ITANIUM: declare noundef i32 @_ZN5templIiE3fooEi.arch_sandybridge
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi.arch_ivybridge
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIiE3fooEi
 
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ at H@@QEAAHH at Z.sse4.2"
 // WINDOWS: declare dso_local noundef i32 @"?foo@?$templ at H@@QEAAHH at Z.arch_sandybridge"
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ at H@@QEAAHH at Z.arch_ivybridge"
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ at H@@QEAAHH at Z"
 
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.sse4.2
-// LINUX: declare noundef i32 @_ZN5templIdE3fooEi.arch_sandybridge
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.arch_ivybridge
-// LINUX: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.sse4.2
+// ITANIUM: declare noundef i32 @_ZN5templIdE3fooEi.arch_sandybridge
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi.arch_ivybridge
+// ITANIUM: define linkonce_odr noundef i32 @_ZN5templIdE3fooEi
 
 // WINDOWS: define linkonce_odr dso_local noundef i32 @"?foo@?$templ at N@@QEAAHH at Z.sse4.2"
 // WINDOWS: declare dso_local noundef i32 @"?foo@?$templ at N@@QEAAHH at Z.arch_sandybridge"

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-modules.cpp b/clang/test/CodeGenCXX/attr-target-mv-modules.cpp
index c91cf71fc5f8d4f..3a70e270e9a38fb 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-modules.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-modules.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fmodules -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -fmodules -emit-llvm %s -o - | FileCheck %s
 #pragma clang module build A
 module A {}
 #pragma clang module contents

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp b/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
index dda7de08aed43ed..b81897afb90b82d 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-out-of-line-defs.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 struct S {
   int __attribute__((target("sse4.2"))) foo(int);
@@ -16,39 +17,42 @@ int bar() {
   return s.foo(0);
 }
 
-// LINUX: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver
+// DARWIN-NOT: comdat
 
-// LINUX: define{{.*}} i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 2
+// ITANIUM: @_ZN1S3fooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN1S3fooEi.resolver
+
+// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 2
 
 // WINDOWS: define dso_local noundef i32 @"?foo at S@@QEAAHH at Z"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 2
 
-// LINUX: define{{.*}} i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 0
+// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi.sse4.2(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 0
 
 // WINDOWS: define dso_local noundef i32 @"?foo at S@@QEAAHH at Z.sse4.2"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 0
 
-// LINUX: define{{.*}} i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
-// LINUX: ret i32 1
+// ITANIUM: define{{.*}} i32 @_ZN1S3fooEi.arch_ivybridge(ptr {{[^,]*}} %this, i32 noundef %0)
+// ITANIUM: ret i32 1
 
 // WINDOWS: define dso_local noundef i32 @"?foo at S@@QEAAHH at Z.arch_ivybridge"(ptr {{[^,]*}} %this, i32 noundef %0)
 // WINDOWS: ret i32 1
 
-// LINUX: define{{.*}} i32 @_Z3barv()
-// LINUX: %s = alloca %struct.S, align 1
-// LINUX: %call = call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0)
+// ITANIUM: define{{.*}} i32 @_Z3barv()
+// ITANIUM: %s = alloca %struct.S, align 1
+// ITANIUM: %call = call noundef i32 @_ZN1S3fooEi.ifunc(ptr {{[^,]*}} %s, i32 noundef 0)
 
 // WINDOWS: define dso_local noundef i32 @"?bar@@YAHXZ"()
 // WINDOWS: %s = alloca %struct.S, align 1
 // WINDOWS: %call = call noundef i32 @"?foo at S@@QEAAHH at Z.resolver"(ptr {{[^,]*}} %s, i32 noundef 0)
 
-// LINUX: define weak_odr ptr @_ZN1S3fooEi.resolver() comdat
-// LINUX: ret ptr @_ZN1S3fooEi.arch_sandybridge
-// LINUX: ret ptr @_ZN1S3fooEi.arch_ivybridge
-// LINUX: ret ptr @_ZN1S3fooEi.sse4.2
-// LINUX: ret ptr @_ZN1S3fooEi
+// ITANIUM: define weak_odr ptr @_ZN1S3fooEi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_ZN1S3fooEi.arch_sandybridge
+// ITANIUM: ret ptr @_ZN1S3fooEi.arch_ivybridge
+// ITANIUM: ret ptr @_ZN1S3fooEi.sse4.2
+// ITANIUM: ret ptr @_ZN1S3fooEi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo at S@@QEAAHH at Z.resolver"(ptr %0, i32 %1) comdat
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z.arch_sandybridge"(ptr %0, i32 %1)
@@ -56,6 +60,6 @@ int bar() {
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z.sse4.2"(ptr %0, i32 %1)
 // WINDOWS: call i32 @"?foo at S@@QEAAHH at Z"(ptr %0, i32 %1)
 
-// LINUX: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef)
+// ITANIUM: declare noundef i32 @_ZN1S3fooEi.arch_sandybridge(ptr {{[^,]*}}, i32 noundef)
 
 // WINDOWS: declare dso_local noundef i32 @"?foo at S@@QEAAHH at Z.arch_sandybridge"(ptr {{[^,]*}}, i32 noundef)

diff  --git a/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp b/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp
index 49a05e7485a5de1..dddd8981954e3cb 100644
--- a/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp
+++ b/clang/test/CodeGenCXX/attr-target-mv-overloads.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,LINUX
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx -emit-llvm %s -o - | FileCheck %s --check-prefixes=ITANIUM,DARWIN
 // RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
 
 int __attribute__((target("sse4.2"))) foo_overload(int) { return 0; }
@@ -14,21 +15,23 @@ int bar2() {
   return foo_overload() + foo_overload(1);
 }
 
-// LINUX: @_Z12foo_overloadv.ifunc = weak_odr ifunc i32 (), ptr @_Z12foo_overloadv.resolver
-// LINUX: @_Z12foo_overloadi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z12foo_overloadi.resolver
+// DARWIN-NOT: comdat
 
-// LINUX: define{{.*}} i32 @_Z12foo_overloadi.sse4.2(i32 noundef %0)
-// LINUX: ret i32 0
-// LINUX: define{{.*}} i32 @_Z12foo_overloadi.arch_ivybridge(i32 noundef %0)
-// LINUX: ret i32 1
-// LINUX: define{{.*}} i32 @_Z12foo_overloadi(i32 noundef %0)
-// LINUX: ret i32 2
-// LINUX: define{{.*}} i32 @_Z12foo_overloadv.sse4.2()
-// LINUX: ret i32 0
-// LINUX: define{{.*}} i32 @_Z12foo_overloadv.arch_ivybridge()
-// LINUX: ret i32 1
-// LINUX: define{{.*}} i32 @_Z12foo_overloadv()
-// LINUX: ret i32 2
+// ITANIUM: @_Z12foo_overloadv.ifunc = weak_odr ifunc i32 (), ptr @_Z12foo_overloadv.resolver
+// ITANIUM: @_Z12foo_overloadi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z12foo_overloadi.resolver
+
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi.sse4.2(i32 noundef %0)
+// ITANIUM: ret i32 0
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi.arch_ivybridge(i32 noundef %0)
+// ITANIUM: ret i32 1
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadi(i32 noundef %0)
+// ITANIUM: ret i32 2
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv.sse4.2()
+// ITANIUM: ret i32 0
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv.arch_ivybridge()
+// ITANIUM: ret i32 1
+// ITANIUM: define{{.*}} i32 @_Z12foo_overloadv()
+// ITANIUM: ret i32 2
 
 // WINDOWS: define dso_local noundef i32 @"?foo_overload@@YAHH at Z.sse4.2"(i32 noundef %0)
 // WINDOWS: ret i32 0
@@ -43,19 +46,20 @@ int bar2() {
 // WINDOWS: define dso_local noundef i32 @"?foo_overload@@YAHXZ"()
 // WINDOWS: ret i32 2
 
-// LINUX: define{{.*}} i32 @_Z4bar2v()
-// LINUX: call noundef i32 @_Z12foo_overloadv.ifunc()
-// LINUX: call noundef i32 @_Z12foo_overloadi.ifunc(i32 noundef 1)
+// ITANIUM: define{{.*}} i32 @_Z4bar2v()
+// ITANIUM: call noundef i32 @_Z12foo_overloadv.ifunc()
+// ITANIUM: call noundef i32 @_Z12foo_overloadi.ifunc(i32 noundef 1)
 
 // WINDOWS: define dso_local noundef i32 @"?bar2@@YAHXZ"()
 // WINDOWS: call noundef i32 @"?foo_overload@@YAHXZ.resolver"()
 // WINDOWS: call noundef i32 @"?foo_overload@@YAHH at Z.resolver"(i32 noundef 1)
 
-// LINUX: define weak_odr ptr @_Z12foo_overloadv.resolver() comdat
-// LINUX: ret ptr @_Z12foo_overloadv.arch_sandybridge
-// LINUX: ret ptr @_Z12foo_overloadv.arch_ivybridge
-// LINUX: ret ptr @_Z12foo_overloadv.sse4.2
-// LINUX: ret ptr @_Z12foo_overloadv
+// ITANIUM: define weak_odr ptr @_Z12foo_overloadv.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_Z12foo_overloadv.arch_sandybridge
+// ITANIUM: ret ptr @_Z12foo_overloadv.arch_ivybridge
+// ITANIUM: ret ptr @_Z12foo_overloadv.sse4.2
+// ITANIUM: ret ptr @_Z12foo_overloadv
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHXZ.resolver"() comdat
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.arch_sandybridge"
@@ -63,11 +67,12 @@ int bar2() {
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ.sse4.2"
 // WINDOWS: call i32 @"?foo_overload@@YAHXZ"
 
-// LINUX: define weak_odr ptr @_Z12foo_overloadi.resolver() comdat
-// LINUX: ret ptr @_Z12foo_overloadi.arch_sandybridge
-// LINUX: ret ptr @_Z12foo_overloadi.arch_ivybridge
-// LINUX: ret ptr @_Z12foo_overloadi.sse4.2
-// LINUX: ret ptr @_Z12foo_overloadi
+// ITANIUM: define weak_odr ptr @_Z12foo_overloadi.resolver()
+// LINUX-SAME: comdat
+// ITANIUM: ret ptr @_Z12foo_overloadi.arch_sandybridge
+// ITANIUM: ret ptr @_Z12foo_overloadi.arch_ivybridge
+// ITANIUM: ret ptr @_Z12foo_overloadi.sse4.2
+// ITANIUM: ret ptr @_Z12foo_overloadi
 
 // WINDOWS: define weak_odr dso_local i32 @"?foo_overload@@YAHH at Z.resolver"(i32 %0) comdat
 // WINDOWS: call i32 @"?foo_overload@@YAHH at Z.arch_sandybridge"
@@ -75,8 +80,8 @@ int bar2() {
 // WINDOWS: call i32 @"?foo_overload@@YAHH at Z.sse4.2"
 // WINDOWS: call i32 @"?foo_overload@@YAHH at Z"
 
-// LINUX: declare noundef i32 @_Z12foo_overloadv.arch_sandybridge()
-// LINUX: declare noundef i32 @_Z12foo_overloadi.arch_sandybridge(i32 noundef)
+// ITANIUM: declare noundef i32 @_Z12foo_overloadv.arch_sandybridge()
+// ITANIUM: declare noundef i32 @_Z12foo_overloadi.arch_sandybridge(i32 noundef)
 
 // WINDOWS: declare dso_local noundef i32 @"?foo_overload@@YAHXZ.arch_sandybridge"()
 // WINDOWS: declare dso_local noundef i32 @"?foo_overload@@YAHH at Z.arch_sandybridge"(i32 noundef)

diff  --git a/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp b/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp
index 0518a8dcc831dd4..be4453ae7eb08ce 100644
--- a/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp
+++ b/clang/test/CodeGenCXX/externc-ifunc-resolver.cpp
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm64-apple-macosx -emit-llvm -o - %s | FileCheck %s
 
 extern "C" {
 __attribute__((used)) static void *resolve_foo() { return 0; }

diff  --git a/clang/test/SemaCXX/externc-ifunc-resolver.cpp b/clang/test/SemaCXX/externc-ifunc-resolver.cpp
index aa44525bde2cae1..6c6c262c5f09d8e 100644
--- a/clang/test/SemaCXX/externc-ifunc-resolver.cpp
+++ b/clang/test/SemaCXX/externc-ifunc-resolver.cpp
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -emit-llvm-only -triple x86_64-linux-gnu -verify %s
+// RUN: %clang_cc1 -emit-llvm-only -triple x86_64-apple-macosx -verify %s
+// RUN: %clang_cc1 -emit-llvm-only -triple arm64-apple-macosx -verify %s
 // RUN: not %clang_cc1 -triple x86_64-linux -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple x86_64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
+// RUN: not %clang_cc1 -triple arm64-apple-macosx -emit-llvm-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
 
 extern "C" {
 __attribute__((used)) static void *resolve_foo() { return 0; }

diff  --git a/compiler-rt/lib/builtins/cpu_model.c b/compiler-rt/lib/builtins/cpu_model.c
index b0ec5e51e96d491..001467a9f7ff511 100644
--- a/compiler-rt/lib/builtins/cpu_model.c
+++ b/compiler-rt/lib/builtins/cpu_model.c
@@ -948,6 +948,8 @@ _Bool __aarch64_have_lse_atomics
 #if defined(__has_include)
 #if __has_include(<sys/auxv.h>)
 #include <sys/auxv.h>
+#define HAVE_SYS_AUXV
+#endif
 
 #if __has_include(<sys/ifunc.h>)
 #include <sys/ifunc.h>
@@ -961,6 +963,8 @@ typedef struct __ifunc_arg_t {
 
 #if __has_include(<asm/hwcap.h>)
 #include <asm/hwcap.h>
+#include HAVE_SYS_HWCAP
+#endif
 
 #if defined(__ANDROID__)
 #include <string.h>
@@ -997,6 +1001,9 @@ typedef struct __ifunc_arg_t {
 #ifndef HWCAP_SHA2
 #define HWCAP_SHA2 (1 << 6)
 #endif
+#ifndef HWCAP_CRC32
+#define HWCAP_CRC32 (1 << 7)
+#endif
 #ifndef HWCAP_ATOMICS
 #define HWCAP_ATOMICS (1 << 8)
 #endif
@@ -1149,6 +1156,7 @@ typedef struct __ifunc_arg_t {
   if (__system_property_get("ro.arch", arch) > 0 &&                            \
       strncmp(arch, "exynos9810", sizeof("exynos9810") - 1) == 0)
 
+#if !defined(__APPLE__)
 static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) {
 #if defined(__FreeBSD__)
   unsigned long hwcap;
@@ -1162,7 +1170,7 @@ static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) {
   zx_status_t status = _zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
   __aarch64_have_lse_atomics =
       status == ZX_OK && (features & ZX_ARM64_FEATURE_ISA_ATOMICS) != 0;
-#else
+#elif defined(HAVE_SYS_AUXV)
   unsigned long hwcap = getauxval(AT_HWCAP);
   _Bool result = (hwcap & HWCAP_ATOMICS) != 0;
 #if defined(__ANDROID__)
@@ -1180,8 +1188,11 @@ static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) {
   }
 #endif // defined(__ANDROID__)
   __aarch64_have_lse_atomics = result;
+#else
+#error No support for checking for lse atomics on this platfrom yet.
 #endif // defined(__FreeBSD__)
 }
+#endif // !defined(__APPLE__)
 
 #if !defined(DISABLE_AARCH64_FMV)
 // CPUFeatures must correspond to the same AArch64 features in
@@ -1259,6 +1270,72 @@ struct {
   // As features grows new fields could be added
 } __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon));
 
+#if defined(__APPLE__)
+#include <TargetConditionals.h>
+#if TARGET_OS_OSX || TARGET_OS_IPHONE
+#include <dispatch/dispatch.h>
+#include <sys/sysctl.h>
+
+static bool isKnownAndSupported(const char *name) {
+  int32_t val = 0;
+  size_t size = sizeof(val);
+  if (sysctlbyname(name, &val, &size, NULL, 0))
+    return false;
+  return val;
+}
+
+void __init_cpu_features_resolver(void) {
+  // On Darwin platforms, this may be called concurrently by multiple threads
+  // because the resolvers that use it are called lazily at runtime (unlike on
+  // ELF platforms, where IFuncs are resolved serially at load time).  This
+  // function's effect on __aarch64_cpu_features should be idempotent, but even
+  // so we need dispatch_once to resolve the race condition.  Dispatch is
+  // available through libSystem, which we need anyway for the sysctl, so this
+  // does not add a new dependency.
+
+  static dispatch_once_t onceToken = 0;
+  dispatch_once(&onceToken, ^{
+    // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
+    static struct {
+      const char *sysctl_name;
+      enum CPUFeatures feature;
+    } features[] = {
+        {"hw.optional.arm.FEAT_FlagM", FEAT_FLAGM},
+        {"hw.optional.arm.FEAT_FlagM2", FEAT_FLAGM2},
+        {"hw.optional.arm.FEAT_FHM", FEAT_FP16FML},
+        {"hw.optional.arm.FEAT_DotProd", FEAT_DOTPROD},
+        {"hw.optional.arm.FEAT_RDM", FEAT_RDM},
+        {"hw.optional.arm.FEAT_LSE", FEAT_LSE},
+        {"hw.optional.floatingpoint", FEAT_FP},
+        {"hw.optional.AdvSIMD", FEAT_SIMD},
+        {"hw.optional.armv8_crc32", FEAT_CRC},
+        {"hw.optional.arm.FEAT_SHA1", FEAT_SHA1},
+        {"hw.optional.arm.FEAT_SHA256", FEAT_SHA2},
+        {"hw.optional.armv8_2_sha3", FEAT_SHA3},
+        {"hw.optional.arm.FEAT_AES", FEAT_AES},
+        {"hw.optional.arm.FEAT_PMULL", FEAT_PMULL},
+        {"hw.optional.arm.FEAT_FP16", FEAT_FP16},
+        {"hw.optional.arm.FEAT_JSCVT", FEAT_JSCVT},
+        {"hw.optional.arm.FEAT_FCMA", FEAT_FCMA},
+        {"hw.optional.arm.FEAT_LRCPC", FEAT_RCPC},
+        {"hw.optional.arm.FEAT_LRCPC2", FEAT_RCPC2},
+        {"hw.optional.arm.FEAT_FRINTTS", FEAT_FRINTTS},
+        {"hw.optional.arm.FEAT_I8MM", FEAT_I8MM},
+        {"hw.optional.arm.FEAT_BF16", FEAT_BF16},
+        {"hw.optional.arm.FEAT_SB", FEAT_SB},
+        {"hw.optional.arm.FEAT_SSBS", FEAT_SSBS2},
+        {"hw.optional.arm.FEAT_BTI", FEAT_BTI},
+    };
+
+    for (size_t I = 0, E = sizeof(features) / sizeof(features[0]); I != E; ++I)
+      if (isKnownAndSupported(features[I].sysctl_name))
+        __aarch64_cpu_features.features |= (1ULL << features[I].feature);
+
+    __aarch64_cpu_features.features |= (1ULL << FEAT_INIT);
+  });
+}
+#endif // TARGET_OS_OSX || TARGET_OS_IPHONE
+#else  // defined(__APPLE__)
 static void __init_cpu_features_constructor(unsigned long hwcap,
                                             const __ifunc_arg_t *arg) {
 #define setCPUFeature(F) __aarch64_cpu_features.features |= 1ULL << F
@@ -1467,8 +1544,8 @@ void __init_cpu_features_resolver(unsigned long hwcap,
 }
 
 void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) {
-  unsigned long hwcap;
-  unsigned long hwcap2;
+  unsigned long hwcap = 0;
+  unsigned long hwcap2 = 0;
   // CPU features already initialized.
   if (__aarch64_cpu_features.features)
     return;
@@ -1478,7 +1555,7 @@ void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) {
   res |= elf_aux_info(AT_HWCAP2, &hwcap2, sizeof hwcap2);
   if (res)
     return;
-#else
+#elif defined(HAVE_SYS_AUXV)
 #if defined(__ANDROID__)
   // Don't set any CPU features,
   // detection could be wrong on Exynos 9810.
@@ -1486,6 +1563,8 @@ void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) {
 #endif // defined(__ANDROID__)
   hwcap = getauxval(AT_HWCAP);
   hwcap2 = getauxval(AT_HWCAP2);
+#else
+#error No support for checking hwcap on this platform yet.
 #endif // defined(__FreeBSD__)
   __ifunc_arg_t arg;
   arg._size = sizeof(__ifunc_arg_t);
@@ -1497,8 +1576,7 @@ void CONSTRUCTOR_ATTRIBUTE __init_cpu_features(void) {
 #undef setCPUFeature
 #undef IF_EXYNOS9810
 }
+#endif // defined(__APPLE__)
 #endif // !defined(DISABLE_AARCH64_FMV)
 #endif // defined(__has_include)
-#endif // __has_include(<sys/auxv.h>)
-#endif // __has_include(<asm/hwcap.h>)
 #endif // defined(__aarch64__)

diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index e448c5ed5c5d947..51c60ecf5ac6586 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
+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>`.

diff  --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 2731ef452c79cbb..07b92871a0f0868 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -882,8 +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/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 15ff39883680369..aaa7693c61f0e85 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 Mach-O 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 2527b1431289677..ce736178afc8b5a 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 direct 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..bd90047a411a654 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2239,13 +2239,11 @@ 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..1b5b7c556c79f6b 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,27 @@ 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 +222,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 +1838,306 @@ 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());
+
+  // _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:
+  //   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());
+
+  {
+    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);
+
+  // _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());
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi)
+                                   .addReg(AArch64::FP)
+                                   .addReg(AArch64::LR)
+                                   .addReg(AArch64::SP)
+                                   .addImm(-2),
+                               *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBXri)
+                                   .addReg(AArch64::FP)
+                                   .addReg(AArch64::SP)
+                                   .addImm(16)
+                                   .addImm(0),
+                               *STI);
+
+  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(-4 - I),
+                                 *STI);
+
+  for (int I = 0; I != 8; I += 2)
+    OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDi)
+                                     .addReg(AArch64::D1 + I)
+                                     .addReg(AArch64::D0 + I)
+                                     .addReg(AArch64::SP)
+                                     .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()))),
+      *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);
+
+  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(-12 - I),
+                                 *STI);
+
+  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(-4 - I),
+                                 *STI);
+
+  OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXi)
+                                   .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..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"
@@ -530,6 +532,118 @@ void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
   O << ']';
 }
 
+void X86AsmPrinter::emitGlobalIFunc(Module &M, const GlobalIFunc &GI) {
+  if (!TM.getTargetTriple().isOSBinFormatMachO())
+    return AsmPrinter::emitGlobalIFunc(M, 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());
+
+  // _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(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,
                               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..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

diff  --git a/llvm/test/CodeGen/AArch64/ifunc-asm.ll b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
new file mode 100644
index 000000000000000..ede669aa52703f7
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ifunc-asm.ll
@@ -0,0 +1,85 @@
+; 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
+; RUN: llc -mtriple=arm64-apple-darwin %s -filetype=asm -o - -global-isel | FileCheck %s --check-prefixes=MACHO,MACHO-MANUAL
+
+define internal ptr @the_resolver() {
+entry:
+  ret ptr null
+}
+; ELF:                    .type the_resolver, at function
+; ELF-NEXT:           the_resolver:
+
+; MACHO:                  .p2align 2
+; MACHO-NEXT:         _the_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 _global_ifunc
+; MACHO-LINKER-NEXT:      .p2align 2
+; MACHO-LINKER-NEXT:  _global_ifunc:
+; MACHO-LINKER-NEXT:      .symbol_resolver _global_ifunc
+; MACHO-LINKER-NEXT:      b _the_resolver
+
+; MACHO-DEFAULT:          .globl _global_ifunc
+; MACHO-DEFAULT-NEXT:     .p2align 2
+; 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 _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 _global_ifunc
+; MACHO-MANUAL-NEXT:      .p2align 2
+; 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  _global_ifunc.stub_helper
+; MACHO-MANUAL-NEXT:      .p2align        2
+; 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:      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 @the_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..0f66febbe95b2da 100644
--- a/llvm/test/CodeGen/X86/ifunc-asm.ll
+++ b/llvm/test/CodeGen/X86/ifunc-asm.ll
@@ -1,14 +1,48 @@
-; 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:           .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


        


More information about the llvm-branch-commits mailing list