Skip to content

Commit

Permalink
[饾榾饾椊饾椏] initial version
Browse files Browse the repository at this point in the history
Created using spr 1.3.4
  • Loading branch information
jroelofs committed Nov 29, 2023
2 parents 50b9930 + a408a0c commit a12d2e4
Show file tree
Hide file tree
Showing 35 changed files with 1,276 additions and 374 deletions.
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -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() }];
Expand Down Expand Up @@ -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]>;
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 different 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.
}];
}

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions clang/test/CodeGen/attr-cpuspecific.c
Original file line number Diff line number Diff line change
@@ -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
Expand Down
20 changes: 20 additions & 0 deletions clang/test/CodeGen/attr-ifunc.c
Original file line number Diff line number Diff line change
@@ -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) {}
Expand Down Expand Up @@ -36,6 +37,25 @@ void *f6_resolver(void) __attribute__((ifunc("f6_resolver_resolver")));
void f6(void) __attribute__((ifunc("f6_resolver")));
// expected-error@-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@-1 {{previous definition is here}}
void f1(void) __attribute__((ifunc(PREFIX "f1_ifunc"))) __asm("f1");
// expected-error@-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@-1 {{definition 'f6' cannot also be an ifunc}}

#else
void f1a(void) __asm("f1");
void f1a(void) {}
Expand Down
4 changes: 4 additions & 0 deletions clang/test/CodeGen/attr-ifunc.cpp
Original file line number Diff line number Diff line change
@@ -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")));
Expand Down
80 changes: 80 additions & 0 deletions clang/test/CodeGen/attr-target-clones.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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; }
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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()
}

Expand All @@ -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
Expand All @@ -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()
}
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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()
}

Expand All @@ -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
Expand Down Expand Up @@ -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]+]]
Expand All @@ -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]]
Expand All @@ -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()

Expand Down
1 change: 1 addition & 0 deletions clang/test/CodeGen/attr-target-mv-func-ptrs.c
Original file line number Diff line number Diff line change
@@ -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);
Expand Down
19 changes: 19 additions & 0 deletions clang/test/CodeGen/attr-target-mv-va-args.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;}
Expand Down Expand Up @@ -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, ...)
Expand Down

0 comments on commit a12d2e4

Please sign in to comment.