Skip to content

Commit f6057ae

Browse files
committed
Function Multi Versioning supports IFunc lowerings on Darwin platforms (llvm#73688)
1 parent 372756b commit f6057ae

15 files changed

+437
-309
lines changed

clang/include/clang/Basic/TargetInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,8 @@ class TargetInfo : public TransferrableTargetInfo,
14161416

14171417
/// Identify whether this target supports IFuncs.
14181418
bool supportsIFunc() const {
1419+
if (getTriple().isOSBinFormatMachO())
1420+
return true;
14191421
return getTriple().isOSBinFormatELF() &&
14201422
((getTriple().isOSLinux() && !getTriple().isMusl()) ||
14211423
getTriple().isOSFreeBSD());

clang/test/CodeGen/attr-cpuspecific.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX
2+
// RUN: %clang_cc1 -triple x86_64-apple-macos -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,LINUX
23
// RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK,WINDOWS
34

45
#ifdef _WIN64

clang/test/CodeGen/attr-target-clones.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LINUX,CHECK
2+
// RUN: %clang_cc1 -triple x86_64-apple-macos -emit-llvm %s -o - | FileCheck %s --check-prefixes=DARWIN,CHECK
23
// RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=WINDOWS,CHECK
34

45
// LINUX: $foo.resolver = comdat any
@@ -7,6 +8,8 @@
78
// LINUX: $foo_inline.resolver = comdat any
89
// LINUX: $foo_inline2.resolver = comdat any
910

11+
// DARWIN-NOT: comdat any
12+
1013
// WINDOWS: $foo = comdat any
1114
// WINDOWS: $foo_dupes = comdat any
1215
// WINDOWS: $unused = comdat any
@@ -27,6 +30,12 @@ int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
2730
// LINUX: ret ptr @foo.sse4.2.0
2831
// LINUX: ret ptr @foo.default.1
2932

33+
// DARWIN: define {{.*}}i32 @foo.sse4.2.0()
34+
// DARWIN: define {{.*}}i32 @foo.default.1()
35+
// DARWIN: define weak_odr ptr @foo.resolver() {
36+
// DARWIN: ret ptr @foo.sse4.2.0
37+
// DARWIN: ret ptr @foo.default.1
38+
3039
// WINDOWS: define dso_local i32 @foo.sse4.2.0()
3140
// WINDOWS: define dso_local i32 @foo.default.1()
3241
// WINDOWS: define weak_odr dso_local i32 @foo() comdat
@@ -40,6 +49,12 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
4049
// LINUX: ret ptr @foo_dupes.sse4.2.0
4150
// LINUX: ret ptr @foo_dupes.default.1
4251

52+
// DARWIN: define {{.*}}void @foo_dupes.default.1()
53+
// DARWIN: define {{.*}}void @foo_dupes.sse4.2.0()
54+
// DARWIN: define weak_odr ptr @foo_dupes.resolver() {
55+
// DARWIN: ret ptr @foo_dupes.sse4.2.0
56+
// DARWIN: ret ptr @foo_dupes.default.1
57+
4358
// WINDOWS: define dso_local void @foo_dupes.default.1()
4459
// WINDOWS: define dso_local void @foo_dupes.sse4.2.0()
4560
// WINDOWS: define weak_odr dso_local void @foo_dupes() comdat
@@ -48,17 +63,21 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
4863

4964
void bar2(void) {
5065
// LINUX: define {{.*}}void @bar2()
66+
// DARWIN: define {{.*}}void @bar2()
5167
// WINDOWS: define dso_local void @bar2()
5268
foo_dupes();
5369
// LINUX: call void @foo_dupes.ifunc()
70+
// DARWIN: call void @foo_dupes.ifunc()
5471
// WINDOWS: call void @foo_dupes()
5572
}
5673

5774
int bar(void) {
5875
// LINUX: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
76+
// DARWIN: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
5977
// WINDOWS: define dso_local i32 @bar() #[[DEF:[0-9]+]]
6078
return foo();
6179
// LINUX: call i32 @foo.ifunc()
80+
// DARWIN: call i32 @foo.ifunc()
6281
// WINDOWS: call i32 @foo()
6382
}
6483

@@ -69,6 +88,12 @@ void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
6988
// LINUX: ret ptr @unused.arch_ivybridge.0
7089
// LINUX: ret ptr @unused.default.1
7190

91+
// DARWIN: define {{.*}}void @unused.default.1()
92+
// DARWIN: define {{.*}}void @unused.arch_ivybridge.0()
93+
// DARWIN: define weak_odr ptr @unused.resolver() {
94+
// DARWIN: ret ptr @unused.arch_ivybridge.0
95+
// DARWIN: ret ptr @unused.default.1
96+
7297
// WINDOWS: define dso_local void @unused.default.1()
7398
// WINDOWS: define dso_local void @unused.arch_ivybridge.0()
7499
// WINDOWS: define weak_odr dso_local void @unused() comdat
@@ -83,10 +108,13 @@ foo_inline2(void);
83108

84109
int bar3(void) {
85110
// LINUX: define {{.*}}i32 @bar3()
111+
// DARWIN: define {{.*}}i32 @bar3()
86112
// WINDOWS: define dso_local i32 @bar3()
87113
return foo_inline() + foo_inline2();
88114
// LINUX: call i32 @foo_inline.ifunc()
89115
// LINUX: call i32 @foo_inline2.ifunc()
116+
// DARWIN: call i32 @foo_inline.ifunc()
117+
// DARWIN: call i32 @foo_inline2.ifunc()
90118
// WINDOWS: call i32 @foo_inline()
91119
// WINDOWS: call i32 @foo_inline2()
92120
}
@@ -96,6 +124,11 @@ int bar3(void) {
96124
// LINUX: ret ptr @foo_inline.sse4.2.1
97125
// LINUX: ret ptr @foo_inline.default.2
98126

127+
// DARWIN: define weak_odr ptr @foo_inline.resolver() {
128+
// DARWIN: ret ptr @foo_inline.arch_sandybridge.0
129+
// DARWIN: ret ptr @foo_inline.sse4.2.1
130+
// DARWIN: ret ptr @foo_inline.default.2
131+
99132
// WINDOWS: define weak_odr dso_local i32 @foo_inline() comdat
100133
// WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0
101134
// WINDOWS: musttail call i32 @foo_inline.sse4.2.1
@@ -108,6 +141,11 @@ foo_inline2(void){ return 0; }
108141
// LINUX: ret ptr @foo_inline2.sse4.2.1
109142
// LINUX: ret ptr @foo_inline2.default.2
110143

144+
// DARWIN: define weak_odr ptr @foo_inline2.resolver() {
145+
// DARWIN: ret ptr @foo_inline2.arch_sandybridge.0
146+
// DARWIN: ret ptr @foo_inline2.sse4.2.1
147+
// DARWIN: ret ptr @foo_inline2.default.2
148+
111149
// WINDOWS: define weak_odr dso_local i32 @foo_inline2() comdat
112150
// WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0
113151
// WINDOWS: musttail call i32 @foo_inline2.sse4.2.1
@@ -122,9 +160,11 @@ foo_used_no_defn(void);
122160

123161
int test_foo_used_no_defn(void) {
124162
// LINUX: define {{.*}}i32 @test_foo_used_no_defn()
163+
// DARWIN: define {{.*}}i32 @test_foo_used_no_defn()
125164
// WINDOWS: define dso_local i32 @test_foo_used_no_defn()
126165
return foo_used_no_defn();
127166
// LINUX: call i32 @foo_used_no_defn.ifunc()
167+
// DARWIN: call i32 @foo_used_no_defn.ifunc()
128168
// WINDOWS: call i32 @foo_used_no_defn()
129169
}
130170

@@ -133,6 +173,10 @@ int test_foo_used_no_defn(void) {
133173
// LINUX: ret ptr @foo_used_no_defn.sse4.2.0
134174
// LINUX: ret ptr @foo_used_no_defn.default.1
135175

176+
// DARWIN: define weak_odr ptr @foo_used_no_defn.resolver() {
177+
// DARWIN: ret ptr @foo_used_no_defn.sse4.2.0
178+
// DARWIN: ret ptr @foo_used_no_defn.default.1
179+
136180
// WINDOWS: define weak_odr dso_local i32 @foo_used_no_defn() comdat
137181
// WINDOWS: musttail call i32 @foo_used_no_defn.sse4.2.0
138182
// WINDOWS: musttail call i32 @foo_used_no_defn.default.1
@@ -144,6 +188,10 @@ int test_foo_used_no_defn(void) {
144188
// LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
145189
// LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
146190

191+
// DARWIN: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
192+
// DARWIN: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
193+
// DARWIN: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
194+
147195
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
148196
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]]
149197
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
@@ -153,6 +201,10 @@ int test_foo_used_no_defn(void) {
153201
// LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
154202
// LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
155203

204+
// DARWIN: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
205+
// DARWIN: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
206+
// DARWIN: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
207+
156208
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
157209
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]]
158210
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]]
@@ -161,6 +213,9 @@ int test_foo_used_no_defn(void) {
161213
// LINUX: declare i32 @foo_used_no_defn.default.1()
162214
// LINUX: declare i32 @foo_used_no_defn.sse4.2.0()
163215

216+
// DARWIN: declare i32 @foo_used_no_defn.default.1()
217+
// DARWIN: declare i32 @foo_used_no_defn.sse4.2.0()
218+
164219
// WINDOWS: declare dso_local i32 @foo_used_no_defn.default.1()
165220
// WINDOWS: declare dso_local i32 @foo_used_no_defn.sse4.2.0()
166221

clang/test/CodeGen/attr-target-mv-func-ptrs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
2+
// RUN: %clang_cc1 -triple x86_64-apple-macos -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
23
// RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
34
int __attribute__((target("sse4.2"))) foo(int i) { return 0; }
45
int __attribute__((target("arch=sandybridge"))) foo(int);

clang/test/CodeGen/attr-target-mv-va-args.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,WINDOWS
44
// RUN: %clang_cc1 -triple x86_64-linux-musl -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF
55
// RUN: %clang_cc1 -triple x86_64-fuchsia -emit-llvm %s -o - | FileCheck %s --check-prefixes=NO-IFUNC,NO-IFUNC-ELF
6+
// RUN: %clang_cc1 -triple x86_64-apple-macho -emit-llvm %s -o - | FileCheck %s --check-prefix=IFUNC-MACHO
67
int __attribute__((target("sse4.2"))) foo(int i, ...) { return 0; }
78
int __attribute__((target("arch=sandybridge"))) foo(int i, ...);
89
int __attribute__((target("arch=ivybridge"))) foo(int i, ...) {return 1;}
@@ -30,6 +31,24 @@ int bar(void) {
3031
// IFUNC-ELF: ret ptr @foo
3132
// IFUNC-ELF: declare i32 @foo.arch_sandybridge(i32 noundef, ...)
3233

34+
// IFUNC-MACHO: @foo.ifunc = weak_odr ifunc i32 (i32, ...), ptr @foo.resolver
35+
// IFUNC-MACHO: define{{.*}} i32 @foo.sse4.2(i32 noundef %i, ...)
36+
// IFUNC-MACHO: ret i32 0
37+
// IFUNC-MACHO: define{{.*}} i32 @foo.arch_ivybridge(i32 noundef %i, ...)
38+
// IFUNC-MACHO: ret i32 1
39+
// IFUNC-MACHO: define{{.*}} i32 @foo(i32 noundef %i, ...)
40+
// IFUNC-MACHO: ret i32 2
41+
// IFUNC-MACHO: define{{.*}} i32 @bar()
42+
// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 1, i32 noundef 97, double
43+
// IFUNC-MACHO: call i32 (i32, ...) @foo.ifunc(i32 noundef 2, double noundef 2.2{{[0-9Ee+]+}}, ptr noundef
44+
45+
// IFUNC-MACHO: define weak_odr ptr @foo.resolver()
46+
// IFUNC-MACHO: ret ptr @foo.arch_sandybridge
47+
// IFUNC-MACHO: ret ptr @foo.arch_ivybridge
48+
// IFUNC-MACHO: ret ptr @foo.sse4.2
49+
// IFUNC-MACHO: ret ptr @foo
50+
// IFUNC-MACHO: declare i32 @foo.arch_sandybridge(i32 noundef, ...)
51+
3352
// NO-IFUNC: define dso_local i32 @foo.sse4.2(i32 noundef %i, ...)
3453
// NO-IFUNC: ret i32 0
3554
// NO-IFUNC: define dso_local i32 @foo.arch_ivybridge(i32 noundef %i, ...)

0 commit comments

Comments
 (0)