From: Manman Ren Date: Fri, 12 Oct 2012 23:39:43 +0000 (+0000) Subject: ARM: tail-call inside a function where part of a byval argument is on caller's X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=e6c3cc8dc5437069f71a38188173835ba4fb0dc1;p=oota-llvm.git 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 --- diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index bd0c659414e..21e7e98c85f 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -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(); + 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()) { diff --git a/test/CodeGen/ARM/2011-06-16-TailCallByVal.ll b/test/CodeGen/ARM/2011-06-16-TailCallByVal.ll index 3e78c462385..101a91396eb 100644 --- a/test/CodeGen/ARM/2011-06-16-TailCallByVal.ll +++ b/test/CodeGen/ARM/2011-06-16-TailCallByVal.ll @@ -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" diff --git a/test/CodeGen/ARM/struct_byval.ll b/test/CodeGen/ARM/struct_byval.ll index 99ba475ad7b..e9541c27880 100644 --- a/test/CodeGen/ARM/struct_byval.ll +++ b/test/CodeGen/ARM/struct_byval.ll @@ -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