Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / LowerIFunc / lower-ifunc.ll
blob95fbe5b5beb1f5929c4bcec5bd4c389b63ab5bf8
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals --include-generated-funcs
2 ; RUN: opt -S -passes=lower-ifunc < %s | FileCheck %s
4 @initialized_with_ifunc = global ptr @ifunc_constant_initializer_user
6 @ifunc_1 = ifunc void (), ptr @resolver1
7 @ifunc_2 = ifunc void (), ptr @resolver1
10 ; Keep one with no users
11 @ifunc_no_users = ifunc float (i64), ptr @resolver2
14 @ifunc7 = ifunc float (i64), ptr @resolver3
15 @ifunc_ptr_arg = ifunc void (ptr), ptr @resolver4
17 @ifunc_nonvoid_0 = ifunc i32 (double), ptr @resolver5
18 @ifunc_nonvoid_1 = ifunc i32 (double), ptr @resolver5
19 @ifunc_constant_initializer_user = ifunc i32 (double), ptr @resolver5
21 define ptr @resolver1() {
22   ret ptr inttoptr (i64 123 to ptr)
25 define ptr @resolver2() {
26   ret ptr inttoptr (i64 456 to ptr)
29 define ptr @resolver3() {
30   ret ptr inttoptr (i64 789 to ptr)
33 define ptr @resolver4() {
34   ret ptr inttoptr (i64 999 to ptr)
37 define ptr @resolver5() {
38   ret ptr inttoptr (i64 420 to ptr)
42 ; Test call to  ifunc
43 define void @call_ifunc(ptr %ptr) {
44   call void @ifunc_1()
45   call void @ifunc_2()
46   ret void
49 ; Test value use of  ifunc
50 define void @store_ifunc_2(ptr %ptr) {
51   store ptr @ifunc_2, ptr %ptr
52   store ptr %ptr, ptr @ifunc_2
53   ret void
56 declare void @other_func(ptr)
58 ; Check a call user, but not as the call operand
59 define void @call_ifunc_is_argument(ptr %ptr) {
60   call void @other_func(ptr @ifunc_2)
61   ret void
64 ; Check a call user calling the ifunc, and using the ifunc as an argument
65 define void @call_ifunc_both_call_argument(ptr %ptr) {
66   call void @ifunc_ptr_arg(ptr @ifunc_ptr_arg)
67   ret void
70 define i32 @call_ifunc_nonvoid(double %arg) {
71   %ret = call i32 @ifunc_nonvoid_0(double %arg)
72   ret i32 %ret
75 ; Use site is different than ifunc function type
76 define float @call_different_type_ifunc_nonvoid(double %arg) {
77   %cast.arg = bitcast double %arg to i64
78   %ret = call float(i64) @ifunc_nonvoid_0(i64 %cast.arg)
79   ret float %ret
82 ; FIXME: Should be able to expand this, but we miss the call
83 ; instruction in the constexpr cast.
84 define i32 @call_addrspacecast_callee_type_ifunc_nonvoid(double %arg) {
85   %ret = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_1 to ptr addrspace(1)) (double %arg)
86   ret i32 %ret
89 define i32 @call_used_in_initializer(double %arg) {
90   %ret = call i32 @ifunc_constant_initializer_user(double %arg)
91   ret i32 %ret
94 ; CHECK: @[[INITIALIZED_WITH_IFUNC:[a-zA-Z0-9_$"\\.-]+]] = global ptr @ifunc_constant_initializer_user
95 ; CHECK: @[[GLOB0:[0-9]+]] = internal global [8 x ptr] poison, align 8
96 ; CHECK: @[[LLVM_GLOBAL_CTORS:[a-zA-Z0-9_$"\\.-]+]] = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @[[GLOB1:[0-9]+]], ptr null }]
97 ; CHECK: @[[IFUNC_NONVOID_1:[a-zA-Z0-9_$"\\.-]+]] = ifunc i32 (double), ptr @resolver5
98 ; CHECK: @[[IFUNC_CONSTANT_INITIALIZER_USER:[a-zA-Z0-9_$"\\.-]+]] = ifunc i32 (double), ptr @resolver5
100 ; CHECK-LABEL: define {{[^@]+}}@resolver1(
101 ; CHECK-NEXT:    ret ptr inttoptr (i64 123 to ptr)
104 ; CHECK-LABEL: define {{[^@]+}}@resolver2(
105 ; CHECK-NEXT:    ret ptr inttoptr (i64 456 to ptr)
108 ; CHECK-LABEL: define {{[^@]+}}@resolver3(
109 ; CHECK-NEXT:    ret ptr inttoptr (i64 789 to ptr)
112 ; CHECK-LABEL: define {{[^@]+}}@resolver4(
113 ; CHECK-NEXT:    ret ptr inttoptr (i64 999 to ptr)
116 ; CHECK-LABEL: define {{[^@]+}}@resolver5(
117 ; CHECK-NEXT:    ret ptr inttoptr (i64 420 to ptr)
120 ; CHECK-LABEL: define {{[^@]+}}@call_ifunc(
121 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr @[[GLOB0]], align 8
122 ; CHECK-NEXT:    call void [[TMP1]]()
123 ; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8
124 ; CHECK-NEXT:    call void [[TMP2]]()
125 ; CHECK-NEXT:    ret void
128 ; CHECK-LABEL: define {{[^@]+}}@store_ifunc_2(
129 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8
130 ; CHECK-NEXT:    store ptr [[TMP1]], ptr [[PTR:%.*]], align 8
131 ; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8
132 ; CHECK-NEXT:    store ptr [[PTR]], ptr [[TMP2]], align 8
133 ; CHECK-NEXT:    ret void
136 ; CHECK-LABEL: define {{[^@]+}}@call_ifunc_is_argument(
137 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8
138 ; CHECK-NEXT:    call void @other_func(ptr [[TMP1]])
139 ; CHECK-NEXT:    ret void
142 ; CHECK-LABEL: define {{[^@]+}}@call_ifunc_both_call_argument(
143 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 4), align 8
144 ; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 4), align 8
145 ; CHECK-NEXT:    call void [[TMP1]](ptr [[TMP1]])
146 ; CHECK-NEXT:    ret void
149 ; CHECK-LABEL: define {{[^@]+}}@call_ifunc_nonvoid(
150 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 5), align 8
151 ; CHECK-NEXT:    [[RET:%.*]] = call i32 [[TMP1]](double [[ARG:%.*]])
152 ; CHECK-NEXT:    ret i32 [[RET]]
155 ; CHECK-LABEL: define {{[^@]+}}@call_different_type_ifunc_nonvoid(
156 ; CHECK-NEXT:    [[CAST_ARG:%.*]] = bitcast double [[ARG:%.*]] to i64
157 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 5), align 8
158 ; CHECK-NEXT:    [[RET:%.*]] = call float [[TMP1]](i64 [[CAST_ARG]])
159 ; CHECK-NEXT:    ret float [[RET]]
162 ; CHECK-LABEL: define {{[^@]+}}@call_addrspacecast_callee_type_ifunc_nonvoid(
163 ; CHECK-NEXT:    [[RET:%.*]] = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_1 to ptr addrspace(1))(double [[ARG:%.*]])
164 ; CHECK-NEXT:    ret i32 [[RET]]
167 ; CHECK-LABEL: define {{[^@]+}}@call_used_in_initializer(
168 ; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 7), align 8
169 ; CHECK-NEXT:    [[RET:%.*]] = call i32 [[TMP1]](double [[ARG:%.*]])
170 ; CHECK-NEXT:    ret i32 [[RET]]
173 ; CHECK-LABEL: define {{[^@]+}}@1(
174 ; CHECK-NEXT:    [[TMP1:%.*]] = call ptr @resolver1()
175 ; CHECK-NEXT:    store ptr [[TMP1]], ptr @[[GLOB0]], align 8
176 ; CHECK-NEXT:    [[TMP2:%.*]] = call ptr @resolver1()
177 ; CHECK-NEXT:    store ptr [[TMP2]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 1), align 8
178 ; CHECK-NEXT:    [[TMP3:%.*]] = call ptr @resolver2()
179 ; CHECK-NEXT:    store ptr [[TMP3]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 2), align 8
180 ; CHECK-NEXT:    [[TMP4:%.*]] = call ptr @resolver3()
181 ; CHECK-NEXT:    store ptr [[TMP4]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 3), align 8
182 ; CHECK-NEXT:    [[TMP5:%.*]] = call ptr @resolver4()
183 ; CHECK-NEXT:    store ptr [[TMP5]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 4), align 8
184 ; CHECK-NEXT:    [[TMP6:%.*]] = call ptr @resolver5()
185 ; CHECK-NEXT:    store ptr [[TMP6]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 5), align 8
186 ; CHECK-NEXT:    [[TMP7:%.*]] = call ptr @resolver5()
187 ; CHECK-NEXT:    store ptr [[TMP7]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 6), align 8
188 ; CHECK-NEXT:    [[TMP8:%.*]] = call ptr @resolver5()
189 ; CHECK-NEXT:    store ptr [[TMP8]], ptr getelementptr inbounds ([8 x ptr], ptr @[[GLOB0]], i32 0, i32 7), align 8
190 ; CHECK-NEXT:    ret void