xref: /llvm-project/clang/test/CodeGen/attr-function-return.c (revision 64473f1221fbc16af140407d5ea64d808f5853a7)
1 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
2 // RUN:   -Werror=ignored-attributes \
3 // RUN:   | FileCheck %s --check-prefixes=CHECK,CHECK-NOM
4 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
5 // RUN:   -Werror=ignored-attributes -mfunction-return=keep \
6 // RUN:   | FileCheck %s --check-prefixes=CHECK,CHECK-KEEP
7 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
8 // RUN:   -Werror=ignored-attributes -mfunction-return=thunk-extern \
9 // RUN:   | FileCheck %s --check-prefixes=CHECK,CHECK-EXTERN
10 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
11 // RUN:  -mfunction-return=thunk-extern -coverage-data-file=/dev/null \
12 // RUN:   | FileCheck %s --check-prefix=CHECK-GCOV
13 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
14 // RUN:  -mfunction-return=thunk-extern -fsanitize=address \
15 // RUN:   | FileCheck %s --check-prefix=CHECK-ASAN
16 // RUN: %clang_cc1 -std=gnu2x -triple x86_64-linux-gnu %s -emit-llvm -o - \
17 // RUN:  -mfunction-return=thunk-extern -fsanitize=thread \
18 // RUN:   | FileCheck %s --check-prefix=CHECK-TSAN
19 
20 #if !__has_attribute(function_return)
21 #error "missing attribute support for function_return"
22 #endif
23 
24 // CHECK: @keep() [[KEEP:#[0-9]+]]
keep(void)25 __attribute__((function_return("keep"))) void keep(void) {}
26 
27 // CHECK: @keep2() [[KEEP]]
keep2(void)28 [[gnu::function_return("keep")]] void keep2(void) {}
29 
30 // CHECK: @thunk_extern() [[EXTERN:#[0-9]+]]
thunk_extern(void)31 __attribute__((function_return("thunk-extern"))) void thunk_extern(void) {}
32 
33 // CHECK: @thunk_extern2() [[EXTERN]]
thunk_extern2(void)34 [[gnu::function_return("thunk-extern")]] void thunk_extern2(void) {}
35 
36 // CHECK: @double_thunk_keep() [[KEEP]]
37 // clang-format off
38 __attribute__((function_return("thunk-extern")))
39 __attribute__((function_return("keep")))
double_thunk_keep(void)40 void double_thunk_keep(void) {}
41 
42 // CHECK: @double_thunk_keep2() [[KEEP]]
43 [[gnu::function_return("thunk-extern")]][[gnu::function_return("keep")]]
double_thunk_keep2(void)44 void double_thunk_keep2(void) {}
45 
46 // CHECK: @double_keep_thunk() [[EXTERN]]
47 __attribute__((function_return("keep")))
48 __attribute__((function_return("thunk-extern")))
double_keep_thunk(void)49 void double_keep_thunk(void) {}
50 
51 // CHECK: @double_keep_thunk2() [[EXTERN]]
52 [[gnu::function_return("keep")]][[gnu::function_return("thunk-extern")]]
double_keep_thunk2(void)53 void double_keep_thunk2(void) {}
54 
55 // CHECK: @thunk_keep() [[KEEP]]
56 __attribute__((function_return("thunk-extern"), function_return("keep")))
thunk_keep(void)57 void thunk_keep(void) {}
58 
59 // CHECK: @thunk_keep2() [[KEEP]]
60 [[gnu::function_return("thunk-extern"), gnu::function_return("keep")]]
thunk_keep2(void)61 void thunk_keep2(void) {}
62 
63 // CHECK: @keep_thunk() [[EXTERN]]
64 __attribute__((function_return("keep"), function_return("thunk-extern")))
keep_thunk(void)65 void keep_thunk(void) {}
66 
67 // CHECK: @keep_thunk2() [[EXTERN]]
68 [[gnu::function_return("keep"), gnu::function_return("thunk-extern")]]
keep_thunk2(void)69 void keep_thunk2(void) {}
70 // clang-format on
71 
72 void undef(void);
73 // CHECK: @undef() [[KEEP]]
undef(void)74 __attribute__((function_return("keep"))) void undef(void) {}
75 
76 void undef2(void);
77 // CHECK: @undef2() [[EXTERN]]
undef2(void)78 __attribute__((function_return("thunk-extern"))) void undef2(void) {}
79 
80 __attribute__((function_return("thunk-extern"))) void change_def(void);
81 // CHECK: @change_def() [[KEEP]]
change_def(void)82 __attribute__((function_return("keep"))) void change_def(void) {}
83 
84 __attribute__((function_return("keep"))) void change_def2(void);
85 // CHECK: @change_def2() [[EXTERN]]
change_def2(void)86 __attribute__((function_return("thunk-extern"))) void change_def2(void) {}
87 
88 __attribute__((function_return("thunk-extern"))) void change_def3(void);
89 // CHECK: @change_def3() [[KEEP]]
change_def3(void)90 [[gnu::function_return("keep")]] void change_def3(void) {}
91 
92 [[gnu::function_return("keep")]] void change_def4(void);
93 // CHECK: @change_def4() [[EXTERN]]
change_def4(void)94 __attribute__((function_return("thunk-extern"))) void change_def4(void) {}
95 
96 // When there is no -mfunction-return= flag set (NOM) or it's set to keep,
97 // we don't emit anything into the IR for unattributed functions.
98 
99 // CHECK-NOM:    @no_attrs() [[NOATTR:#[0-9]+]]
100 // CHECK-KEEP:   @no_attrs() [[NOATTR:#[0-9]+]]
101 // CHECK-EXTERN: @no_attrs() [[EXTERN]]
no_attrs(void)102 void no_attrs(void) {}
103 
104 // Test synthetic functions.
105 // CHECK-GCOV: @__llvm_gcov_writeout() unnamed_addr [[EXTERNGCOV:#[0-9]+]]
106 // CHECK-GCOV: @__llvm_gcov_reset() unnamed_addr [[EXTERNGCOV]]
107 // CHECK-GCOV: @__llvm_gcov_init() unnamed_addr [[EXTERNGCOV]]
108 // CHECK-ASAN: @asan.module_ctor() [[EXTERNASAN:#[0-9]+]]
109 // CHECK-TSAN: @tsan.module_ctor() [[EXTERNTSAN:#[0-9]+]]
110 
111 // CHECK-NOM-NOT:  [[NOATTR]] = {{.*}}fn_ret_thunk_extern
112 // CHECK-KEEP-NOT: [[NOATTR]] = {{.*}}fn_ret_thunk_extern
113 // CHECK: [[EXTERN]] = {{.*}}fn_ret_thunk_extern
114 // CHECK-GCOV: [[EXTERNGCOV]] = {{.*}}fn_ret_thunk_extern
115 // CHECK-ASAN: [[EXTERNASAN]] = {{.*}}fn_ret_thunk_extern
116 // CHECK-TSAN: [[EXTERNTSAN]] = {{.*}}fn_ret_thunk_extern
117