Skip to content

Commit 8fc387c

Browse files
ahmedbougachadtapuska
authored andcommitted
[AArch64] Support musttail, including variadic.
FIXME: one case currently miscompiled.
1 parent 2b9d44d commit 8fc387c

File tree

2 files changed

+82
-12
lines changed

2 files changed

+82
-12
lines changed

llvm/lib/Target/AArch64/AArch64ISelLowering.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8707,20 +8707,22 @@ bool AArch64TargetLowering::isEligibleForTailCallOptimization(
87078707
// Byval parameters hand the function a pointer directly into the stack area
87088708
// we want to reuse during a tail call. Working around this *is* possible (see
87098709
// X86) but less efficient and uglier in LowerCall.
8710-
for (Function::const_arg_iterator i = CallerF.arg_begin(),
8711-
e = CallerF.arg_end();
8712-
i != e; ++i) {
8713-
if (i->hasByValAttr())
8714-
return false;
8710+
if (!(CLI.CB && CLI.CB->isMustTailCall() && Subtarget->isTargetDarwin())) {
8711+
for (Function::const_arg_iterator i = CallerF.arg_begin(),
8712+
e = CallerF.arg_end();
8713+
i != e; ++i) {
8714+
if (i->hasByValAttr())
8715+
return false;
87158716

8716-
// On Windows, "inreg" attributes signify non-aggregate indirect returns.
8717-
// In this case, it is necessary to save/restore X0 in the callee. Tail
8718-
// call opt interferes with this. So we disable tail call opt when the
8719-
// caller has an argument with "inreg" attribute.
8717+
// On Windows, "inreg" attributes signify non-aggregate indirect returns.
8718+
// In this case, it is necessary to save/restore X0 in the callee. Tail
8719+
// call opt interferes with this. So we disable tail call opt when the
8720+
// caller has an argument with "inreg" attribute.
87208721

8721-
// FIXME: Check whether the callee also has an "inreg" argument.
8722-
if (i->hasInRegAttr())
8723-
return false;
8722+
// FIXME: Check whether the callee also has an "inreg" argument.
8723+
if (i->hasInRegAttr())
8724+
return false;
8725+
}
87248726
}
87258727

87268728
if (canGuaranteeTCO(CalleeCC, getTargetMachine().Options.GuaranteedTailCallOpt))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
; RUN: llc -mtriple arm64-apple-darwin -asm-verbose=false -o - %s | FileCheck --check-prefix=CHECK-DAG-ISEL --check-prefix=CHECK %s
2+
; RUN: llc -mtriple arm64-apple-darwin -fast-isel -asm-verbose=false -o - %s | FileCheck --check-prefix=CHECK-FAST-ISEL --check-prefix=CHECK %s
3+
4+
; CHECK-LABEL: _test_musttail:
5+
; CHECK: b _musttail_callee
6+
7+
declare i32 @musttail_callee(i32)
8+
9+
define i32 @test_musttail(i32 %arg0) {
10+
%r = musttail call i32 @musttail_callee(i32 %arg0)
11+
ret i32 %r
12+
}
13+
14+
; CHECK-LABEL: _test_musttail_variadic:
15+
; CHECK: b _musttail_variadic_callee
16+
17+
declare i32 @musttail_variadic_callee(i32, ...)
18+
19+
define i32 @test_musttail_variadic(i32 %arg0, ...) {
20+
%r = musttail call i32 (i32, ...) @musttail_variadic_callee(i32 %arg0, ...)
21+
ret i32 %r
22+
}
23+
24+
; CHECK-LABEL: _test_musttail_variadic_aggret:
25+
; CHECK: b _musttail_variadic_aggret_callee
26+
27+
declare [2 x i64] @musttail_variadic_aggret_callee(i32 %arg0, ...)
28+
29+
define [2 x i64] @test_musttail_variadic_aggret(i32 %arg0, ...) {
30+
%r = musttail call [2 x i64] (i32, ...) @musttail_variadic_aggret_callee(i32 %arg0, ...)
31+
ret [2 x i64] %r
32+
}
33+
34+
; CHECK-LABEL: _test_musttail_variadic_stack:
35+
; CHECK-FAST-ISEL: ldp x9, x12, [sp]
36+
; CHECK-FAST-ISEL: ldp x10, x11, [sp, #16]
37+
; CHECK-FAST-ISEL: stp x9, x12, [sp, #16]
38+
; CHECK-FAST-ISEL: stp x10, x11, [sp]
39+
; CHECK-DAG-ISEL: ldp x9, x10, [sp]
40+
; CHECK-DAG-ISEL: ldr q16, [sp, #16]
41+
; CHECK-DAG-ISEL: str q16, [sp]
42+
; CHECK-DAG-ISEL: stp x9, x10, [sp, #16]
43+
; CHECK: b _musttail_variadic_stack_callee
44+
45+
declare i32 @musttail_variadic_stack_callee([2 x i64] %a0, [2 x i64] %a1, [2 x i64] %a2, [2 x i64] %a3, [2 x i64] %a4, [2 x i64] %a5, ...)
46+
47+
define i32 @test_musttail_variadic_stack([2 x i64] %a0, [2 x i64] %a1, [2 x i64] %a2, [2 x i64] %a3, [2 x i64] %a4, [2 x i64] %a5, ...) {
48+
%r = musttail call i32 ([2 x i64], [2 x i64], [2 x i64], [2 x i64], [2 x i64], [2 x i64], ...) @musttail_variadic_stack_callee([2 x i64] %a0, [2 x i64] %a1, [2 x i64] %a2, [2 x i64] %a3, [2 x i64] %a5, [2 x i64] %a4, ...)
49+
ret i32 %r
50+
}
51+
52+
; We still mis-compile this test case because %arg2 is written to its argument
53+
; slot before %arg1 is read from its slot.
54+
;
55+
; ldr q16, [sp, #16] # read %arg2
56+
; str q16, [sp] # write %arg2. this overwrites %arg1.
57+
; ldr q16, [sp] # read %arg1
58+
; str q16, [sp, #16] # write %arg1
59+
; b _musttail_variadic_byval_callee
60+
61+
%Struct = type { i64, i64 }
62+
63+
declare i32 @musttail_variadic_byval_callee(i32, %Struct* byval(%Struct), %Struct* byval(%Struct), ...)
64+
65+
define i32 @test_musttail_variadic_byval(i32 %arg0, %Struct* byval(%Struct) %arg1, %Struct* byval(%Struct) %arg2, ...) {
66+
%r = musttail call i32 (i32, %Struct*, %Struct*, ...) @musttail_variadic_byval_callee(i32 %arg0, %Struct* byval(%Struct) %arg2, %Struct* byval(%Struct) %arg1, ...)
67+
ret i32 %r
68+
}

0 commit comments

Comments
 (0)