const Value *Object = GetUnderlyingObject(Loc.Ptr, DL);
- // If this is a tail call and Loc.Ptr points to a stack location, we know that
- // the tail call cannot access or modify the local stack.
- // We cannot exclude byval arguments here; these belong to the caller of
- // the current function not to the current function, and a tail callee
- // may reference them.
+ // Calls marked 'tail' cannot read or write allocas from the current frame
+ // because the current frame might be destroyed by the time they run. However,
+ // a tail call may use an alloca with byval. Calling with byval copies the
+ // contents of the alloca into argument registers or stack slots, so there is
+ // no lifetime issue.
if (isa<AllocaInst>(Object))
if (const CallInst *CI = dyn_cast<CallInst>(CS.getInstruction()))
- if (CI->isTailCall())
+ if (CI->isTailCall() &&
+ !CI->getAttributes().hasAttrSomewhere(Attribute::ByVal))
return ModRefInfo::NoModRef;
// If the pointer is to a locally allocated object that does not escape,
--- /dev/null
+; RUN: opt -basicaa -aa-eval -print-all-alias-modref-info -disable-output < %s 2>&1 | FileCheck %s
+
+declare void @takebyval(i32* byval %p)
+
+define i32 @tailbyval() {
+entry:
+ %p = alloca i32
+ store i32 42, i32* %p
+ tail call void @takebyval(i32* byval %p)
+ %rv = load i32, i32* %p
+ ret i32 %rv
+}
+; FIXME: This should be Just Ref.
+; CHECK-LABEL: Function: tailbyval: 1 pointers, 1 call sites
+; CHECK-NEXT: Both ModRef: Ptr: i32* %p <-> tail call void @takebyval(i32* byval %p)
--- /dev/null
+; RUN: opt -dse -S < %s | FileCheck %s
+
+; Don't eliminate stores to allocas before tail calls to functions that use
+; byval. It's correct to mark calls like these as 'tail'. To implement this tail
+; call, the backend should copy the bytes from the alloca into the argument area
+; before clearing the stack.
+
+target datalayout = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"
+target triple = "i386-unknown-linux-gnu"
+
+declare void @g(i32* byval %p)
+
+define void @f(i32* byval %x) {
+entry:
+ %p = alloca i32
+ %v = load i32, i32* %x
+ store i32 %v, i32* %p
+ tail call void @g(i32* byval %p)
+ ret void
+}
+; CHECK-LABEL: define void @f(i32* byval %x)
+; CHECK: store i32 %v, i32* %p
+; CHECK: tail call void @g(i32* byval %p)