41 changes: 41 additions & 0 deletions clang/test/CodeGen/ifunc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s

int foo(int) __attribute__ ((ifunc("foo_ifunc")));

static int f1(int i) {
return i + 1;
}

static int f2(int i) {
return i + 2;
}

typedef int (*foo_t)(int);

int global;

static foo_t foo_ifunc() {
return global ? f1 : f2;
}

int bar() {
return foo(1);
}

extern void goo(void);

void bar2(void) {
goo();
}

extern void goo(void) __attribute__ ((ifunc("goo_ifunc")));

void* goo_ifunc(void) {
return 0;
}
// CHECK: @foo = ifunc i32 (i32), bitcast (i32 (i32)* ()* @foo_ifunc to i32 (i32)*)
// CHECK: @goo = ifunc void (), bitcast (i8* ()* @goo_ifunc to void ()*)

// CHECK: call i32 @foo(i32
// CHECK: call void @goo()
2 changes: 1 addition & 1 deletion clang/test/Sema/attr-alias-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ typedef int b4;

void test2_bar() {}
void test2_foo() __attribute__((weak, alias("test2_bar")));
void test2_zed() __attribute__((alias("test2_foo"))); // expected-warning {{alias will always resolve to test2_bar even if weak definition of alias test2_foo is overridden}}
void test2_zed() __attribute__((alias("test2_foo"))); // expected-warning {{alias will always resolve to test2_bar even if weak definition of test2_foo is overridden}}

void test3_bar() { }
void test3_foo() __attribute__((section("test"))); // expected-warning {{alias will not be in section 'test' but in the same section as the aliasee}}
Expand Down
43 changes: 43 additions & 0 deletions clang/test/Sema/attr-ifunc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm -DCHECK_ALIASES %s
// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm %s

#if defined(_WIN32)
void foo() {}
void bar() __attribute__((ifunc("foo")));
//expected-warning@-1 {{'ifunc' attribute ignored}}

#else
#if defined(CHECK_ALIASES)
void* f1_ifunc();
void f1() __attribute__((ifunc("f1_ifunc")));
//expected-error@-1 {{ifunc must point to a defined function}}

void* f2_a() __attribute__((ifunc("f2_b")));
//expected-error@-1 {{ifunc definition is part of a cycle}}
void* f2_b() __attribute__((ifunc("f2_a")));
//expected-error@-1 {{ifunc definition is part of a cycle}}

void* f3_a() __attribute__((ifunc("f3_b")));
//expected-warning@-1 {{ifunc will always resolve to f3_c even if weak definition of f3_b is overridden}}
void* f3_b() __attribute__((weak, alias("f3_c")));
void* f3_c() { return 0; }

void f4_ifunc() {}
void f4() __attribute__((ifunc("f4_ifunc")));
//expected-error@-1 {{ifunc resolver function must return a pointer}}

void* f5_ifunc(int i) { return 0; }
void f5() __attribute__((ifunc("f5_ifunc")));
//expected-error@-1 {{ifunc resolver function must have no parameters}}

#else
void f1a() __asm("f1");
void f1a() {}
//expected-note@-1 {{previous definition is here}}
void f1() __attribute__((ifunc("f1_ifunc")));
//expected-error@-1 {{definition with same mangled name as another definition}}
void* f1_ifunc() { return 0; }

#endif
#endif