Skip to content

Commit

Permalink
[LangRef] Disallow accessing byval arguments from tail-called functio…
Browse files Browse the repository at this point in the history
…ns (llvm#110093)

We already disallow accessing the callee's allocas from a tail-called
function, because their stack memory will have been de-allocated before
the tail call. I think this should apply to byval arguments too, as they
also occupy space in the caller's stack frame.

This was originally part of llvm#109943, spilt out for separate review.
  • Loading branch information
ostannard authored Sep 27, 2024
1 parent 3c09843 commit 8dd817b
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 23 deletions.
65 changes: 61 additions & 4 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12658,10 +12658,67 @@ This instruction requires several arguments:
the return value of the callee is returned to the caller's caller, even
if a void return type is in use.

Both markers imply that the callee does not access allocas from the caller.
The ``tail`` marker additionally implies that the callee does not access
varargs from the caller. Calls marked ``musttail`` must obey the following
additional rules:
Both markers imply that the callee does not access allocas, va_args, or
byval arguments from the caller. As an exception to that, an alloca or byval
argument may be passed to the callee as a byval argument, which can be
dereferenced inside the callee. For example:

.. code-block:: llvm

declare void @take_byval(ptr byval(i64))
declare void @take_ptr(ptr)

; Invalid (assuming @take_ptr dereferences the pointer), because %local
; may be de-allocated before the call to @take_ptr.
define void @invalid_alloca() {
entry:
%local = alloca i64
tail call void @take_ptr(ptr %local)
ret void
}

; Valid, the byval attribute causes the memory allocated by %local to be
; copied into @take_byval's stack frame.
define void @byval_alloca() {
entry:
%local = alloca i64
tail call void @take_byval(ptr byval(i64) %local)
ret void
}

; Invalid, because @use_global_va_list uses the variadic arguments from
; @invalid_va_list.
%struct.va_list = type { ptr }
@va_list = external global %struct.va_list
define void @use_global_va_list() {
entry:
%arg = va_arg ptr @va_list, i64
ret void
}
define void @invalid_va_list(i32 %a, ...) {
entry:
call void @llvm.va_start.p0(ptr @va_list)
tail call void @use_global_va_list()
ret void
}

; Valid, byval argument forwarded to tail call as another byval argument.
define void @forward_byval(ptr byval(i64) %x) {
entry:
tail call void @take_byval(ptr byval(i64) %x)
ret void
}

; Invalid (assuming @take_ptr dereferences the pointer), byval argument
; passed to tail callee as non-byval ptr.
define void @invalid_byval(ptr byval(i64) %x) {
entry:
tail call void @take_ptr(ptr %x)
ret void
}


Calls marked ``musttail`` must obey the following additional rules:

- The call must immediately precede a :ref:`ret <i_ret>` instruction,
or a pointer bitcast followed by a ret instruction.
Expand Down
19 changes: 0 additions & 19 deletions llvm/test/CodeGen/ARM/struct_byval.ll
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,6 @@ declare i32 @e1(ptr nocapture byval(%struct.SmallStruct) %in) nounwind
declare i32 @e2(ptr nocapture byval(%struct.LargeStruct) %in) nounwind
declare i32 @e3(ptr nocapture byval(%struct.LargeStruct) 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(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
; CHECK-LABEL: f3
; CHECK: bl _consumestruct
entry:
tail call void @consumestruct(ptr %s, i32 80) optsize
ret void
}

define void @f4(ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
; CHECK-LABEL: f4
; CHECK: bl _consumestruct
entry:
tail call void @consumestruct(ptr %s, 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, ptr nocapture byval(%struct.SmallStruct) %s) nounwind optsize {
; CHECK-LABEL: f5
Expand Down

0 comments on commit 8dd817b

Please sign in to comment.