199 lines · plain
1; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=ifuncs --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t2; RUN: FileCheck --check-prefixes=CHECK-FINAL --input-file=%t %s3 4 5; CHECK-FINAL: @initialized_with_ifunc = global ptr @ifunc_constant_initializer_user6@initialized_with_ifunc = global ptr @ifunc_constant_initializer_user7 8 9; CHECK-FINAL: [[TABLE:@[0-9]+]] = internal global [[[TABLE_SIZE:[0-9]+]] x ptr] poison10; CHECK-FINAL: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @1, ptr null }]11 12 13; CHECK-INTERESTINGNESS: @ifunc_kept1 = ifunc14 15; CHECK-FINAL: @ifunc_kept1 = ifunc void (), ptr @resolver116@ifunc_kept1 = ifunc void (), ptr @resolver117@ifunc_removed2 = ifunc void (), ptr @resolver118 19; CHECK-INTERESTINGNESS: @ifunc_kept3 =20; CHECK-FINAL: @ifunc_kept3 = ifunc i32 (double), ptr @resolver221@ifunc_kept3 = ifunc i32 (double), ptr @resolver222 23 24; Remove one with no users25@ifunc4_removed = ifunc float (i64), ptr @resolver226 27; Keep one with no users28; CHECK-INTERESTINGNESS: @ifunc5_kept = ifunc29@ifunc5_kept = ifunc float (i64), ptr @resolver230 31 32; Make sure the hidden is preserved33; CHECK-INTERESTINGNESS: @ifunc_kept_hidden =34; CHECK-FINAL: @ifunc_kept_hidden = hidden ifunc i32 (double), ptr @resolver335@ifunc_kept_hidden = hidden ifunc i32 (double), ptr @resolver336@ifunc7 = ifunc float (i64), ptr @resolver337 38@ifunc_ptr_arg = ifunc void (ptr), ptr @resolver439 40 41; CHECK-INTERESTINGNESS: @ifunc_nonvoid_kept0 = ifunc42@ifunc_nonvoid_kept0 = ifunc i32 (double), ptr @resolver543@ifunc_nonvoid_removed0 = ifunc i32 (double), ptr @resolver544 45; CHECK-INTERESTINGNESS: @ifunc_nonvoid_kept1 = ifunc46@ifunc_nonvoid_kept1 = ifunc i32 (double), ptr @resolver547@ifunc_nonvoid_removed1 = ifunc i32 (double), ptr @resolver548 49; CHECK-FINAL: @ifunc_constant_initializer_user = ifunc i32 (double), ptr @resolver550@ifunc_constant_initializer_user = ifunc i32 (double), ptr @resolver551 52 53 54define ptr @resolver1() {55 ret ptr inttoptr (i64 123 to ptr)56}57 58define ptr @resolver2() {59 ret ptr inttoptr (i64 456 to ptr)60}61 62define ptr @resolver3() {63 ret ptr inttoptr (i64 789 to ptr)64}65 66define ptr @resolver4() {67 ret ptr inttoptr (i64 999 to ptr)68}69 70define ptr @resolver5() {71 ret ptr inttoptr (i64 420 to ptr)72}73 74define void @call_ifunc_kept1() {75 ; CHECK-FINAL-LABEL: define void @call_ifunc_kept1() {76 ; CHECK-FINAL-NEXT: call void @ifunc_kept1()77 ; CHECK-FINAL-NEXT: ret void78 call void @ifunc_kept1()79 ret void80}81 82; Test call to removed ifunc83define void @call_ifunc_removed(ptr %ptr) {84 ; CHECK-FINAL-LABEL: define void @call_ifunc_removed(ptr %ptr)85 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr @0, align 886 ; CHECK-FINAL-NEXT: call void %1()87 ; CHECK-FINAL-NEXT: ret void88 call void @ifunc_removed2()89 ret void90}91 92; Test value use of removed ifunc93define void @store_ifunc_removed2(ptr %ptr) {94 ; CHECK-FINAL-LABEL: define void @store_ifunc_removed2(ptr %ptr) {95 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr [[TABLE]], align 896 ; CHECK-FINAL-NEXT: store ptr %1, ptr %ptr, align 897 ; CHECK-FINAL-NEXT: %2 = load ptr, ptr @0, align 898 ; CHECK-FINAL-NEXT: store ptr %ptr, ptr %2, align 899 ; CHECK-FINAL-NEXT: ret void100 store ptr @ifunc_removed2, ptr %ptr101 store ptr %ptr, ptr @ifunc_removed2102 ret void103}104 105declare void @other_func(ptr)106 107; Check a call user, but not as the call operand108define void @call_ifunc_removed_is_argument(ptr %ptr) {109 ; CHECK-FINAL-LABEL: define void @call_ifunc_removed_is_argument(ptr %ptr) {110 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr [[TABLE]], align 8111 ; CHECK-FINAL-NEXT: call void @other_func(ptr %1)112 ; CHECK-FINAL-NEXT: ret void113 call void @other_func(ptr @ifunc_removed2)114 ret void115}116 117; Check a call user calling the ifunc, and using the ifunc as an argument118define void @call_ifunc_removed_both_call_argument(ptr %ptr) {119 ; CHECK-FINAL-LABEL: define void @call_ifunc_removed_both_call_argument(120 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr getelementptr inbounds ([[[TABLE_SIZE]] x ptr], ptr [[TABLE]], i32 0, i32 3), align 8121 ; CHECK-FINAL-NEXT: %2 = load ptr, ptr getelementptr inbounds ([[[TABLE_SIZE]] x ptr], ptr [[TABLE]], i32 0, i32 3), align 8122 ; CHECK-FINAL-NEXT: call void %1(ptr %1)123 ; CHECK-FINAL-NEXT: ret void124 call void @ifunc_ptr_arg(ptr @ifunc_ptr_arg)125 ret void126}127 128define i32 @call_ifunc_nonvoid(double %arg) {129 ; CHECK-FINAL-LABEL: define i32 @call_ifunc_nonvoid(double %arg) {130 ; CHECK-FINAL-NEXT: %ret0 = call i32 @ifunc_nonvoid_kept0(double %arg)131 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr getelementptr inbounds ([[[TABLE_SIZE]] x ptr], ptr [[TABLE]], i32 0, i32 4), align 8132 ; CHECK-FINAL-NEXT: %ret1 = call i32 %1(double %arg)133 ; CHECK-FINAL-NEXT: %add = add i32 %ret0, %ret1134 ; CHECK-FINAL-NEXT: ret i32 %add135 %ret0 = call i32 @ifunc_nonvoid_kept0(double %arg)136 %ret1 = call i32 @ifunc_nonvoid_removed0(double %arg)137 %add = add i32 %ret0, %ret1138 ret i32 %add139}140 141; Use site is different than ifunc function type142define float @call_different_type_ifunc_nonvoid(double %arg) {143 ; CHECK-FINAL-LABEL: define float @call_different_type_ifunc_nonvoid(double %arg) {144 ; CHECK-FINAL-NEXT: %cast.arg = bitcast double %arg to i64145 ; CHECK-FINAL-NEXT: %ret0 = call float @ifunc_nonvoid_kept0(i64 %cast.arg)146 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr getelementptr inbounds ([[[TABLE_SIZE]] x ptr], ptr [[TABLE]], i32 0, i32 4), align 8147 ; CHECK-FINAL-NEXT: %ret1 = call float %1(i64 %cast.arg)148 ; CHECK-FINAL-NEXT: %fadd = fadd float %ret0, %ret1149 ; CHECK-FINAL-NEXT: ret float %fadd150 %cast.arg = bitcast double %arg to i64151 %ret0 = call float(i64) @ifunc_nonvoid_kept0(i64 %cast.arg)152 %ret1 = call float(i64) @ifunc_nonvoid_removed0(i64 %cast.arg)153 %fadd = fadd float %ret0, %ret1154 ret float %fadd155}156 157; FIXME: Should be able to expand this, but we miss the call158; instruction in the constexpr cast.159define i32 @call_addrspacecast_callee_type_ifunc_nonvoid(double %arg) {160 ; CHECK-FINAL-LABEL: define i32 @call_addrspacecast_callee_type_ifunc_nonvoid(double %arg) {161 ; CHECK-FINAL-NEXT: %ret0 = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_kept1 to ptr addrspace(1))(double %arg)162 ; CHECK-FINAL-NEXT: %ret1 = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_removed1 to ptr addrspace(1))(double %arg)163 ; CHECK-FINAL-NEXT: %add = add i32 %ret0, %ret1164 ; CHECK-FINAL-NEXT: ret i32 %add165 %ret0 = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_kept1 to ptr addrspace(1)) (double %arg)166 %ret1 = call addrspace(1) i32 addrspacecast (ptr @ifunc_nonvoid_removed1 to ptr addrspace(1)) (double %arg)167 %add = add i32 %ret0, %ret1168 ret i32 %add169}170 171define i32 @call_used_in_initializer(double %arg) {172 ; CHECK-FINAL-LABEL: define i32 @call_used_in_initializer(double %arg) {173 ; CHECK-FINAL-NEXT: %1 = load ptr, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 7), align 8174 ; CHECK-FINAL-NEXT: %ret = call i32 %1(double %arg)175 ; CHECK-FINAL-NEXT: ret i32 %ret176 %ret = call i32 @ifunc_constant_initializer_user(double %arg)177 ret i32 %ret178}179 180; CHECK-FINAL-LABEL: define internal void @1() {181; CHECK-FINAL-NEXT: %1 = call ptr @resolver1()182; CHECK-FINAL-NEXT: store ptr %1, ptr @0, align 8183; CHECK-FINAL-NEXT: %2 = call ptr @resolver2()184; CHECK-FINAL-NEXT: store ptr %2, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 1), align 8185; CHECK-FINAL-NEXT: %3 = call ptr @resolver3()186; CHECK-FINAL-NEXT: store ptr %3, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 2), align 8187; CHECK-FINAL-NEXT: %4 = call ptr @resolver4()188; CHECK-FINAL-NEXT: store ptr %4, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 3), align 8189; CHECK-FINAL-NEXT: %5 = call ptr @resolver5()190; CHECK-FINAL-NEXT: store ptr %5, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 4), align 8191; CHECK-FINAL-NEXT: %6 = call ptr @resolver5()192; CHECK-FINAL-NEXT: store ptr %6, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 5), align 8193; CHECK-FINAL-NEXT: %7 = call ptr @resolver5()194; CHECK-FINAL-NEXT: store ptr %7, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 6), align 8195; CHECK-FINAL-NEXT: %8 = call ptr @resolver5()196; CHECK-FINAL-NEXT: store ptr %8, ptr getelementptr inbounds ([8 x ptr], ptr @0, i32 0, i32 7), align 8197; CHECK-FINAL-NEXT: ret void198; CHECK-FINAL-NEXT: }199