Skip to content

Commit 6c12fd9

Browse files
authored
[clang] Function Multi Versioning supports IFunc lowerings on Darwin platforms (#73688)
1 parent acf9aa3 commit 6c12fd9

15 files changed

+482
-328
lines changed

clang/include/clang/Basic/TargetInfo.h

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

14241424
/// Identify whether this target supports IFuncs.
14251425
bool supportsIFunc() const {
1426+
if (getTriple().isOSBinFormatMachO())
1427+
return true;
14261428
return getTriple().isOSBinFormatELF() &&
14271429
((getTriple().isOSLinux() && !getTriple().isMusl()) ||
14281430
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: 81 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
@@ -16,6 +19,9 @@
1619
// LINUX: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
1720
// LINUX: @__cpu_features2 = external dso_local global [3 x i32]
1821

22+
// DARWIN: @__cpu_model = external dso_local global { i32, i32, i32, [1 x i32] }
23+
// DARWIN: @__cpu_features2 = external dso_local global [3 x i32]
24+
1925
// LINUX: @internal.ifunc = internal alias i32 (), ptr @internal
2026
// LINUX: @foo.ifunc = weak_odr alias i32 (), ptr @foo
2127
// LINUX: @foo_dupes.ifunc = weak_odr alias void (), ptr @foo_dupes
@@ -34,10 +40,12 @@
3440
// LINUX: @foo_used_no_defn = weak_odr ifunc i32 (), ptr @foo_used_no_defn.resolver
3541
// LINUX: @isa_level = weak_odr ifunc i32 (i32), ptr @isa_level.resolver
3642

43+
3744
static int __attribute__((target_clones("sse4.2, default"))) internal(void) { return 0; }
3845
int use(void) { return internal(); }
3946
/// Internal linkage resolvers do not use comdat.
4047
// LINUX: define internal ptr @internal.resolver() {
48+
// DARWIN: define internal ptr @internal.resolver() {
4149
// WINDOWS: define internal i32 @internal() {
4250

4351
int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
@@ -47,6 +55,12 @@ int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
4755
// LINUX: ret ptr @foo.sse4.2.0
4856
// LINUX: ret ptr @foo.default.1
4957

58+
// DARWIN: define {{.*}}i32 @foo.sse4.2.0()
59+
// DARWIN: define {{.*}}i32 @foo.default.1()
60+
// DARWIN: define weak_odr ptr @foo.resolver() {
61+
// DARWIN: ret ptr @foo.sse4.2.0
62+
// DARWIN: ret ptr @foo.default.1
63+
5064
// WINDOWS: define dso_local i32 @foo.sse4.2.0()
5165
// WINDOWS: define dso_local i32 @foo.default.1()
5266
// WINDOWS: define weak_odr dso_local i32 @foo() comdat
@@ -60,6 +74,12 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
6074
// LINUX: ret ptr @foo_dupes.sse4.2.0
6175
// LINUX: ret ptr @foo_dupes.default.1
6276

77+
// DARWIN: define {{.*}}void @foo_dupes.default.1()
78+
// DARWIN: define {{.*}}void @foo_dupes.sse4.2.0()
79+
// DARWIN: define weak_odr ptr @foo_dupes.resolver() {
80+
// DARWIN: ret ptr @foo_dupes.sse4.2.0
81+
// DARWIN: ret ptr @foo_dupes.default.1
82+
6383
// WINDOWS: define dso_local void @foo_dupes.default.1()
6484
// WINDOWS: define dso_local void @foo_dupes.sse4.2.0()
6585
// WINDOWS: define weak_odr dso_local void @foo_dupes() comdat
@@ -68,17 +88,21 @@ __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {
6888

6989
void bar2(void) {
7090
// LINUX: define {{.*}}void @bar2()
91+
// DARWIN: define {{.*}}void @bar2()
7192
// WINDOWS: define dso_local void @bar2()
7293
foo_dupes();
7394
// LINUX: call void @foo_dupes()
95+
// DARWIN: call void @foo_dupes()
7496
// WINDOWS: call void @foo_dupes()
7597
}
7698

7799
int bar(void) {
78100
// LINUX: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
101+
// DARWIN: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
79102
// WINDOWS: define dso_local i32 @bar() #[[DEF:[0-9]+]]
80103
return foo();
81104
// LINUX: call i32 @foo()
105+
// DARWIN: call i32 @foo()
82106
// WINDOWS: call i32 @foo()
83107
}
84108

@@ -89,6 +113,12 @@ void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
89113
// LINUX: ret ptr @unused.arch_ivybridge.0
90114
// LINUX: ret ptr @unused.default.1
91115

116+
// DARWIN: define {{.*}}void @unused.default.1()
117+
// DARWIN: define {{.*}}void @unused.arch_ivybridge.0()
118+
// DARWIN: define weak_odr ptr @unused.resolver() {
119+
// DARWIN: ret ptr @unused.arch_ivybridge.0
120+
// DARWIN: ret ptr @unused.default.1
121+
92122
// WINDOWS: define dso_local void @unused.default.1()
93123
// WINDOWS: define dso_local void @unused.arch_ivybridge.0()
94124
// WINDOWS: define weak_odr dso_local void @unused() comdat
@@ -103,10 +133,13 @@ foo_inline2(void);
103133

104134
int bar3(void) {
105135
// LINUX: define {{.*}}i32 @bar3()
136+
// DARWIN: define {{.*}}i32 @bar3()
106137
// WINDOWS: define dso_local i32 @bar3()
107138
return foo_inline() + foo_inline2();
108139
// LINUX: call i32 @foo_inline()
109140
// LINUX: call i32 @foo_inline2()
141+
// DARWIN: call i32 @foo_inline()
142+
// DARWIN: call i32 @foo_inline2()
110143
// WINDOWS: call i32 @foo_inline()
111144
// WINDOWS: call i32 @foo_inline2()
112145
}
@@ -116,6 +149,11 @@ int bar3(void) {
116149
// LINUX: ret ptr @foo_inline.sse4.2.1
117150
// LINUX: ret ptr @foo_inline.default.2
118151

152+
// DARWIN: define weak_odr ptr @foo_inline.resolver() {
153+
// DARWIN: ret ptr @foo_inline.arch_sandybridge.0
154+
// DARWIN: ret ptr @foo_inline.sse4.2.1
155+
// DARWIN: ret ptr @foo_inline.default.2
156+
119157
// WINDOWS: define weak_odr dso_local i32 @foo_inline() comdat
120158
// WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0
121159
// WINDOWS: musttail call i32 @foo_inline.sse4.2.1
@@ -128,6 +166,11 @@ foo_inline2(void){ return 0; }
128166
// LINUX: ret ptr @foo_inline2.sse4.2.1
129167
// LINUX: ret ptr @foo_inline2.default.2
130168

169+
// DARWIN: define weak_odr ptr @foo_inline2.resolver() {
170+
// DARWIN: ret ptr @foo_inline2.arch_sandybridge.0
171+
// DARWIN: ret ptr @foo_inline2.sse4.2.1
172+
// DARWIN: ret ptr @foo_inline2.default.2
173+
131174
// WINDOWS: define weak_odr dso_local i32 @foo_inline2() comdat
132175
// WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0
133176
// WINDOWS: musttail call i32 @foo_inline2.sse4.2.1
@@ -142,9 +185,11 @@ foo_used_no_defn(void);
142185

143186
int test_foo_used_no_defn(void) {
144187
// LINUX: define {{.*}}i32 @test_foo_used_no_defn()
188+
// DARWIN: define {{.*}}i32 @test_foo_used_no_defn()
145189
// WINDOWS: define dso_local i32 @test_foo_used_no_defn()
146190
return foo_used_no_defn();
147191
// LINUX: call i32 @foo_used_no_defn()
192+
// DARWIN: call i32 @foo_used_no_defn()
148193
// WINDOWS: call i32 @foo_used_no_defn()
149194
}
150195

@@ -153,6 +198,10 @@ int test_foo_used_no_defn(void) {
153198
// LINUX: ret ptr @foo_used_no_defn.sse4.2.0
154199
// LINUX: ret ptr @foo_used_no_defn.default.1
155200

201+
// DARWIN: define weak_odr ptr @foo_used_no_defn.resolver() {
202+
// DARWIN: ret ptr @foo_used_no_defn.sse4.2.0
203+
// DARWIN: ret ptr @foo_used_no_defn.default.1
204+
156205
// WINDOWS: define weak_odr dso_local i32 @foo_used_no_defn() comdat
157206
// WINDOWS: musttail call i32 @foo_used_no_defn.sse4.2.0
158207
// WINDOWS: musttail call i32 @foo_used_no_defn.default.1
@@ -180,12 +229,37 @@ int isa_level(int) { return 0; }
180229
// LINUX: ret ptr @isa_level.arch_x86-64.0
181230
// LINUX: ret ptr @isa_level.default.4
182231

232+
// DARWIN: define{{.*}} i32 @isa_level.default.4(
233+
// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64.0(
234+
// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v2.1(
235+
// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v3.2(
236+
// DARWIN: define{{.*}} i32 @isa_level.arch_x86-64-v4.3(
237+
// DARWIN: define weak_odr ptr @isa_level.resolver() {
238+
// DARWIN: call void @__cpu_indicator_init()
239+
// DARWIN-NEXT: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
240+
// DARWIN-NEXT: and i32 %[[#]], 4
241+
// DARWIN: ret ptr @isa_level.arch_x86-64-v4.3
242+
// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
243+
// DARWIN-NEXT: and i32 %[[#]], 2
244+
// DARWIN: ret ptr @isa_level.arch_x86-64-v3.2
245+
// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2)
246+
// DARWIN-NEXT: and i32 %[[#]], 1
247+
// DARWIN: ret ptr @isa_level.arch_x86-64-v2.1
248+
// DARWIN: load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1)
249+
// DARWIN-NEXT: and i32 %[[#]], -2147483648
250+
// DARWIN: ret ptr @isa_level.arch_x86-64.0
251+
// DARWIN: ret ptr @isa_level.default.4
252+
183253
// Deferred emission of inline definitions.
184254

185255
// LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
186256
// LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
187257
// LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
188258

259+
// DARWIN: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
260+
// DARWIN: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
261+
// DARWIN: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
262+
189263
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
190264
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]]
191265
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
@@ -195,6 +269,10 @@ int isa_level(int) { return 0; }
195269
// LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
196270
// LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
197271

272+
// DARWIN: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
273+
// DARWIN: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
274+
// DARWIN: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
275+
198276
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
199277
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]]
200278
// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]]
@@ -203,6 +281,9 @@ int isa_level(int) { return 0; }
203281
// LINUX: declare i32 @foo_used_no_defn.default.1()
204282
// LINUX: declare i32 @foo_used_no_defn.sse4.2.0()
205283

284+
// DARWIN: declare i32 @foo_used_no_defn.default.1()
285+
// DARWIN: declare i32 @foo_used_no_defn.sse4.2.0()
286+
206287
// WINDOWS: declare dso_local i32 @foo_used_no_defn.default.1()
207288
// WINDOWS: declare dso_local i32 @foo_used_no_defn.sse4.2.0()
208289

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)