diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 91c3e60bb0acb..dcf6ca4cb58a7 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -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 ` instruction, or a pointer bitcast followed by a ret instruction. diff --git a/llvm/test/CodeGen/ARM/struct_byval.ll b/llvm/test/CodeGen/ARM/struct_byval.ll index 73a1b5ee33bca..2bc4f9c816d53 100644 --- a/llvm/test/CodeGen/ARM/struct_byval.ll +++ b/llvm/test/CodeGen/ARM/struct_byval.ll @@ -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