mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
9132d88d17
Adding NonNull as attributes to returned pointers has the unfortunate side effect of disabling tail calls. This patch ignores the NonNull attribute when we decide whether to tail merge, in the same way that we ignore the NoAlias attribute, as it has no affect on the call sequence. Differential Revision: https://reviews.llvm.org/D52238 llvm-svn: 343091
113 lines
3.6 KiB
LLVM
113 lines
3.6 KiB
LLVM
; RUN: llc -mtriple armv7 -target-abi apcs -O0 -o - < %s \
|
|
; RUN: | FileCheck %s -check-prefix CHECK-TAIL -check-prefix CHECK
|
|
; RUN: llc -mtriple armv7 -target-abi apcs -O0 -disable-tail-calls -o - < %s \
|
|
; RUN: | FileCheck %s -check-prefix CHECK-NO-TAIL -check-prefix CHECK
|
|
; RUN: llc -mtriple armv7 -target-abi aapcs -O0 -o - < %s \
|
|
; RUN: | FileCheck %s -check-prefix CHECK-TAIL-AAPCS -check-prefix CHECK
|
|
|
|
declare i32 @callee(i32 %i)
|
|
declare extern_weak fastcc void @callee_weak()
|
|
|
|
define i32 @caller(i32 %i) {
|
|
entry:
|
|
%r = tail call i32 @callee(i32 %i)
|
|
ret i32 %r
|
|
}
|
|
|
|
; CHECK-TAIL-LABEL: caller
|
|
; CHECK-TAIL: b callee
|
|
|
|
; CHECK-NO-TAIL-LABEL: caller
|
|
; CHECK-NO-TAIL: push {lr}
|
|
; CHECK-NO-TAIL: bl callee
|
|
; CHECK-NO-TAIL: pop {lr}
|
|
; CHECK-NO-TAIL: bx lr
|
|
|
|
|
|
; Weakly-referenced extern functions cannot be tail-called, as AAELF does
|
|
; not define the behaviour of branch instructions to undefined weak symbols.
|
|
define fastcc void @caller_weak() {
|
|
; CHECK-LABEL: caller_weak:
|
|
; CHECK: bl callee_weak
|
|
tail call void @callee_weak()
|
|
ret void
|
|
}
|
|
|
|
; A tail call can be optimized if all the arguments can be passed in registers
|
|
; R0-R3, or the remaining arguments are already in the caller's parameter area
|
|
; in the stack. Variadic functions are no different.
|
|
declare i32 @variadic(i32, ...)
|
|
|
|
; e.g. four integers
|
|
define void @v_caller_ints1(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: v_caller_ints1:
|
|
; CHECK-TAIL: b variadic
|
|
; CHECK-TAIL-AAPCS: b variadic
|
|
; CHECK-NO-TAIL: bl variadic
|
|
entry:
|
|
%call = tail call i32 (i32, ...) @variadic(i32 %a, i32 %b, i32 %b, i32 %a)
|
|
ret void
|
|
}
|
|
|
|
; e.g. two 32-bit integers, one 64-bit integer (needs to span two regs)
|
|
define void @v_caller_ints2(i32 %y, i64 %z) {
|
|
; CHECK-LABEL: v_caller_ints2:
|
|
; CHECK-TAIL: b variadic
|
|
; CHECK-TAIL-AAPCS: b variadic
|
|
; CHECK-NO-TAIL: bl variadic
|
|
entry:
|
|
%call = tail call i32 (i32, ...) @variadic(i32 %y, i32 %y, i64 %z)
|
|
ret void
|
|
}
|
|
|
|
; e.g. two 32-bit integers, one 64-bit integer (needs to span two regs). Notice
|
|
; that %z is passed in r1-r2 if APCS is used, contrary to AAPCS where r2-r3
|
|
; would be used (since double-word types must start at an even register). In the
|
|
; latter case, the third argument needs to be passed through the stack.
|
|
define void @v_caller_ints3(i32 %y, i64 %z) {
|
|
; CHECK-LABEL: v_caller_ints3:
|
|
; CHECK-TAIL: b variadic
|
|
; CHECK-TAIL-AAPCS: bl variadic
|
|
; CHECK-NO-TAIL: bl variadic
|
|
entry:
|
|
%call = tail call i32 (i32, ...) @variadic(i32 %y, i64 %z, i32 %y)
|
|
ret void
|
|
}
|
|
|
|
; e.g. two 32-bit integers, one 64-bit integer and another 64-bit integer that
|
|
; doesn't fit in r0-r3 but comes from the caller argument list and is in the
|
|
; same position.
|
|
define void @v_caller_ints4(i64 %a, i32 %b, i32 %c, i64 %d) {
|
|
; CHECK-LABEL: v_caller_ints4:
|
|
; CHECK-TAIL: b variadic
|
|
; CHECK-TAIL-AAPCS: b variadic
|
|
; CHECK-NO-TAIL: bl variadic
|
|
entry:
|
|
%call = tail call i32 (i32, ...) @variadic(i32 %b, i32 %c, i64 %a, i64 %d)
|
|
ret void
|
|
}
|
|
|
|
; If the arguments do not fit in r0-r3 and the existing parameters cannot be
|
|
; taken from the caller's parameter region, the optimization is not supported.
|
|
|
|
; e.g. one 32-bit integer, two 64-bit integers
|
|
define void @v_caller_ints_fail(i32 %y, i64 %z) {
|
|
; CHECK-LABEL: v_caller_ints_fail:
|
|
; CHECK: bl variadic
|
|
entry:
|
|
%call = tail call i32 (i32, ...) @variadic(i32 %y, i64 %z, i64 %z)
|
|
ret void
|
|
}
|
|
|
|
; Check that NonNull attributes don't inhibit tailcalls.
|
|
|
|
declare nonnull i8* @nonnull_callee(i8* %p, i32 %val)
|
|
define i8* @nonnull_caller(i8* %p, i32 %val) {
|
|
; CHECK-LABEL: nonnull_caller:
|
|
; CHECK-TAIL: b nonnull_callee
|
|
; CHECK-NO-TAIL: bl nonnull_callee
|
|
entry:
|
|
%call = tail call i8* @nonnull_callee(i8* %p, i32 %val)
|
|
ret i8* %call
|
|
}
|