mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
ARM: tail-call inside a function where part of a byval argument is on caller's
local frame causes problem. For example: void f(StructToPass s) { g(&s, sizeof(s)); } will cause problem with tail-call since part of s is passed via registers and saved in f's local frame. When g tries to access s, part of s may be corrupted since f's local frame is popped out before the tail-call. The current fix is to disable tail-call if getVarArgsRegSaveSize is not 0 for the caller. This is a conservative approach, if we can prove the address of s or part of s is not taken and passed to g, it should be okay to perform tail-call. rdar://12442472 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165853 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7a2b624bb3
commit
e6c3cc8dc5
@ -1804,6 +1804,14 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee,
|
||||
}
|
||||
}
|
||||
|
||||
// If Caller's vararg or byval argument has been split between registers and
|
||||
// stack, do not perform tail call, since part of the argument is in caller's
|
||||
// local frame.
|
||||
const ARMFunctionInfo *AFI_Caller = DAG.getMachineFunction().
|
||||
getInfo<ARMFunctionInfo>();
|
||||
if (AFI_Caller->getVarArgsRegSaveSize())
|
||||
return false;
|
||||
|
||||
// If the callee takes no arguments then go on to check the results of the
|
||||
// call.
|
||||
if (!Outs.empty()) {
|
||||
|
@ -1,4 +1,9 @@
|
||||
; RUN: llc < %s -arm-tail-calls=1 | FileCheck %s
|
||||
|
||||
; tail call inside a function where byval argument is splitted between
|
||||
; registers and stack is currently unsupported.
|
||||
; XFAIL: *
|
||||
|
||||
target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
|
||||
target triple = "thumbv7-apple-ios"
|
||||
|
||||
|
@ -44,3 +44,47 @@ entry:
|
||||
declare i32 @e1(%struct.SmallStruct* nocapture byval %in) nounwind
|
||||
declare i32 @e2(%struct.LargeStruct* nocapture byval %in) nounwind
|
||||
declare i32 @e3(%struct.LargeStruct* nocapture byval align 16 %in) nounwind
|
||||
|
||||
; rdar://12442472
|
||||
; We can't do tail call since address of s is passed to the callee and part of
|
||||
; s is in caller's local frame.
|
||||
define void @f3(%struct.SmallStruct* nocapture byval %s) nounwind optsize {
|
||||
; CHECK: f3
|
||||
; CHECK: bl _consumestruct
|
||||
entry:
|
||||
%0 = bitcast %struct.SmallStruct* %s to i8*
|
||||
tail call void @consumestruct(i8* %0, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f4(%struct.SmallStruct* nocapture byval %s) nounwind optsize {
|
||||
; CHECK: f4
|
||||
; CHECK: bl _consumestruct
|
||||
entry:
|
||||
%addr = getelementptr inbounds %struct.SmallStruct* %s, i32 0, i32 0
|
||||
%0 = bitcast i32* %addr to i8*
|
||||
tail call void @consumestruct(i8* %0, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
; We can do tail call here since s is in the incoming argument area.
|
||||
define void @f5(i32 %a, i32 %b, i32 %c, i32 %d, %struct.SmallStruct* nocapture byval %s) nounwind optsize {
|
||||
; CHECK: f5
|
||||
; CHECK: b _consumestruct
|
||||
entry:
|
||||
%0 = bitcast %struct.SmallStruct* %s to i8*
|
||||
tail call void @consumestruct(i8* %0, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f6(i32 %a, i32 %b, i32 %c, i32 %d, %struct.SmallStruct* nocapture byval %s) nounwind optsize {
|
||||
; CHECK: f6
|
||||
; CHECK: b _consumestruct
|
||||
entry:
|
||||
%addr = getelementptr inbounds %struct.SmallStruct* %s, i32 0, i32 0
|
||||
%0 = bitcast i32* %addr to i8*
|
||||
tail call void @consumestruct(i8* %0, i32 80) optsize
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @consumestruct(i8* nocapture %structp, i32 %structsize) nounwind
|
||||
|
Loading…
Reference in New Issue
Block a user