From 168b84c52f0b1739bab9c40f3e85f561c82ad6ca Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Wed, 29 Apr 2020 17:44:11 -0700 Subject: [PATCH] [ARM] Fix tail call validity checking for varargs calls. If a varargs function is calling a non-varargs function, or vice versa, make sure we use the correct "varargs" bit for each. Fixes https://bugs.llvm.org/show_bug.cgi?id=45234 Differential Revision: https://reviews.llvm.org/D79199 --- lib/Target/ARM/ARMISelLowering.cpp | 8 +- test/CodeGen/ARM/tail-call-results.ll | 187 ++++++++++++++++++++++++++ 2 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/ARM/tail-call-results.ll diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index e6428f55d01..3d6841ed7ce 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -2663,9 +2663,11 @@ bool ARMTargetLowering::IsEligibleForTailCallOptimization( // Check that the call results are passed in the same way. LLVMContext &C = *DAG.getContext(); - if (!CCState::resultsCompatible(CalleeCC, CallerCC, MF, C, Ins, - CCAssignFnForReturn(CalleeCC, isVarArg), - CCAssignFnForReturn(CallerCC, isVarArg))) + if (!CCState::resultsCompatible( + getEffectiveCallingConv(CalleeCC, isVarArg), + getEffectiveCallingConv(CallerCC, CallerF.isVarArg()), MF, C, Ins, + CCAssignFnForReturn(CalleeCC, isVarArg), + CCAssignFnForReturn(CallerCC, CallerF.isVarArg()))) return false; // The callee has to preserve all registers the caller needs to preserve. const ARMBaseRegisterInfo *TRI = Subtarget->getRegisterInfo(); diff --git a/test/CodeGen/ARM/tail-call-results.ll b/test/CodeGen/ARM/tail-call-results.ll new file mode 100644 index 00000000000..8b90e18f801 --- /dev/null +++ b/test/CodeGen/ARM/tail-call-results.ll @@ -0,0 +1,187 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=thumbv7-linux-gnueabihf %s -o - | FileCheck %s +; RUN: llc -mtriple=thumbv7-linux-gnueabi %s -o - | FileCheck -check-prefix=SOFTFLOAT %s +; RUN: llc -mtriple=thumbv7-linux-gnueabihf -disable-tail-calls %s -o - | FileCheck -check-prefix=HF-NOTAIL %s + +; On hard-float targets, the register used to store a float return value +; changes if the call signature is varargs. The HF-NOTAIL lines are there to +; easily see when this happens. + +declare float @callee_float() +declare i32 @callee_int() +declare float @callee_float_vararg(i32, ...) +declare i32 @callee_int_vararg(i32, ...) + +define float @caller_float__callee_float() { +; CHECK-LABEL: caller_float__callee_float: +; CHECK: @ %bb.0: +; CHECK-NEXT: b callee_float +; +; SOFTFLOAT-LABEL: caller_float__callee_float: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: b callee_float +; +; HF-NOTAIL-LABEL: caller_float__callee_float: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: bl callee_float +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call float @callee_float() + ret float %r +} + +define float @caller_float__callee_float_vararg() { +; CHECK-LABEL: caller_float__callee_float_vararg: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: movs r0, #0 +; CHECK-NEXT: bl callee_float_vararg +; CHECK-NEXT: vmov s0, r0 +; CHECK-NEXT: pop {r7, pc} +; +; SOFTFLOAT-LABEL: caller_float__callee_float_vararg: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: movs r0, #0 +; SOFTFLOAT-NEXT: b callee_float_vararg +; +; HF-NOTAIL-LABEL: caller_float__callee_float_vararg: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: movs r0, #0 +; HF-NOTAIL-NEXT: bl callee_float_vararg +; HF-NOTAIL-NEXT: vmov s0, r0 +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call float (i32, ...) @callee_float_vararg(i32 0) + ret float %r +} + +define float @caller_float_vararg__callee_float(i32, ...) { +; CHECK-LABEL: caller_float_vararg__callee_float: +; CHECK: @ %bb.0: +; CHECK-NEXT: .save {r7, lr} +; CHECK-NEXT: push {r7, lr} +; CHECK-NEXT: bl callee_float +; CHECK-NEXT: vmov r0, s0 +; CHECK-NEXT: pop {r7, pc} +; +; SOFTFLOAT-LABEL: caller_float_vararg__callee_float: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: b callee_float +; +; HF-NOTAIL-LABEL: caller_float_vararg__callee_float: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: bl callee_float +; HF-NOTAIL-NEXT: vmov r0, s0 +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call float @callee_float() + ret float %r +} + +define float @caller_float_vararg__callee_float_vararg(i32, ...) { +; CHECK-LABEL: caller_float_vararg__callee_float_vararg: +; CHECK: @ %bb.0: +; CHECK-NEXT: movs r0, #0 +; CHECK-NEXT: b callee_float_vararg +; +; SOFTFLOAT-LABEL: caller_float_vararg__callee_float_vararg: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: movs r0, #0 +; SOFTFLOAT-NEXT: b callee_float_vararg +; +; HF-NOTAIL-LABEL: caller_float_vararg__callee_float_vararg: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: movs r0, #0 +; HF-NOTAIL-NEXT: bl callee_float_vararg +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call float (i32, ...) @callee_float_vararg(i32 0) + ret float %r +} + +define i32 @caller_int__callee_int() { +; CHECK-LABEL: caller_int__callee_int: +; CHECK: @ %bb.0: +; CHECK-NEXT: b callee_int +; +; SOFTFLOAT-LABEL: caller_int__callee_int: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: b callee_int +; +; HF-NOTAIL-LABEL: caller_int__callee_int: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: bl callee_int +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call i32 @callee_int() + ret i32 %r +} + +define i32 @caller_int__callee_int_vararg() { +; CHECK-LABEL: caller_int__callee_int_vararg: +; CHECK: @ %bb.0: +; CHECK-NEXT: movs r0, #0 +; CHECK-NEXT: b callee_int_vararg +; +; SOFTFLOAT-LABEL: caller_int__callee_int_vararg: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: movs r0, #0 +; SOFTFLOAT-NEXT: b callee_int_vararg +; +; HF-NOTAIL-LABEL: caller_int__callee_int_vararg: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: movs r0, #0 +; HF-NOTAIL-NEXT: bl callee_int_vararg +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call i32 (i32, ...) @callee_int_vararg(i32 0) + ret i32 %r +} + +define i32 @caller_int_vararg__callee_int(i32, ...) { +; CHECK-LABEL: caller_int_vararg__callee_int: +; CHECK: @ %bb.0: +; CHECK-NEXT: b callee_int +; +; SOFTFLOAT-LABEL: caller_int_vararg__callee_int: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: b callee_int +; +; HF-NOTAIL-LABEL: caller_int_vararg__callee_int: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: bl callee_int +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call i32 @callee_int() + ret i32 %r +} + +define i32 @caller_int_vararg__callee_int_vararg(i32, ...) { +; CHECK-LABEL: caller_int_vararg__callee_int_vararg: +; CHECK: @ %bb.0: +; CHECK-NEXT: movs r0, #0 +; CHECK-NEXT: b callee_int_vararg +; +; SOFTFLOAT-LABEL: caller_int_vararg__callee_int_vararg: +; SOFTFLOAT: @ %bb.0: +; SOFTFLOAT-NEXT: movs r0, #0 +; SOFTFLOAT-NEXT: b callee_int_vararg +; +; HF-NOTAIL-LABEL: caller_int_vararg__callee_int_vararg: +; HF-NOTAIL: @ %bb.0: +; HF-NOTAIL-NEXT: .save {r7, lr} +; HF-NOTAIL-NEXT: push {r7, lr} +; HF-NOTAIL-NEXT: movs r0, #0 +; HF-NOTAIL-NEXT: bl callee_int_vararg +; HF-NOTAIL-NEXT: pop {r7, pc} + %r = tail call i32 (i32, ...) @callee_int_vararg(i32 0) + ret i32 %r +}