[RFC] Add `dead_on_return` attribute

Background

Consider the following callee-optimized IR, where the caller passes by value an aggregate to the callee, and the callee zeroes out the temporary allocation:

%struct.f = type { [1024 x i32] }

define void @callee(ptr %arg) {
entry:
  call void @llvm.memset.p0.i64(ptr align 4 %arg, i8 0, i64 4096, i1 false)
  ret void
}

define void @caller() {
entry:
  %a = alloca %struct.f, align 4
  %byval-temp = alloca %struct.f, align 4
  store i32 1, ptr %a, align 4
  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %byval-temp, ptr align 4 %a, i64 4096, i1 false)
  call void @callee(ptr %byval-temp)
  ret void
}

Depending on the ABI, passing a large struct by value is achieved either by marking it byval (and let the backend emit the copy), or having the caller explicitly emitting the copy. The IR above represents the latter scenario. Thus, as being passed by value, the memset in the callee happens to be dead upon return, but it cannot be currently proved as such.

Proposal

We would like to address this by introducing a new dead_on_return optimization attribute in LLVM. The semantics resembles quite closely the one of dead_on_unwind, and reads as follows:

This attribute indicates that the memory pointed to by the argument is dead
upon function return, both upon normal return and if the calls unwinds, meaning
that the caller will not depend on its contents. Stores that would be observable
either on the return path or on the unwind path may be elided.

Specifically, the behavior is as-if any memory written through the pointer
during the execution of the function is overwritten with a poison value
upon function return. The caller may access the memory, but any load
not preceded by a store will return poison.

This attribute does not imply aliasing properties. For pointer arguments that
do not alias other memory locations, noalias attribute may be used in
conjunction. Conversely, this attribute always implies dead_on_unwind.

This attribute cannot be applied to return values.

While the attribute may be plausibly conceived as orthogonal to dead_on_unwind (argument is dead only upon normal function return), we started leaning towards making dead_on_return imply dead_on_unwind (dead on the exception path too). Arguments passed by value, which are dead upon return, are expected to be frontend-annotated with dead_on_return.

As already hinted, one advantage here is being able to perform DSE for parameters marked as such.

An implementation for this RFC (and further comments) can be find at [IR] Add `dead_on_return` attribute by antoniofrighetto · Pull Request #143271 · llvm/llvm-project · GitHub. Any feedback or suggestions are welcome.

2 Likes