Skip to content

Commit bd4cc70

Browse files
[IR] Add dead_on_return attribute
Introduce `dead_on_return` attribute, which is meant to be taken advantage by the frontend, and states that the memory pointed to by the argument is dead upon function return. As with `byval`, it is supposed to be used for passing aggregates by value. The difference lies in the ABI: `byval` implies that the pointer is explicitly passed as argument to the callee (during codegen the copy is emitted as per byval contract), whereas a `dead_on_return` -marked argument may imply that the copy already exists at the IR level, is located at a specific stack offset within the caller, and this memory will not be read further by the caller upon callee return – or otherwise poison, if read before being written.
1 parent 0e2103a commit bd4cc70

File tree

13 files changed

+63
-7
lines changed

13 files changed

+63
-7
lines changed

llvm/docs/LangRef.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,23 @@ Currently, only the following parameter attributes are defined:
17411741

17421742
This attribute cannot be applied to return values.
17431743

1744+
``dead_on_return``
1745+
This attribute indicates that the memory pointed to by the argument is dead
1746+
upon normal function return, meaning that the caller will not depend on its
1747+
contents. Stores that would only be observable on the normal return path may
1748+
be elided.
1749+
1750+
Specifically, the behavior is as-if any memory written through the pointer
1751+
during the execution of the function is overwritten with a poison value
1752+
upon normal function return. The caller may access the memory, but any load
1753+
not preceded by a store will return poison.
1754+
1755+
This attribute does not imply aliasing properties. For pointer arguments that
1756+
do not alias other memory locations, ``noalias`` attribute may be used in
1757+
conjunction.
1758+
1759+
This attribute cannot be applied to return values.
1760+
17441761
``range(<ty> <a>, <b>)``
17451762
This attribute expresses the possible range of the parameter or return value.
17461763
If the value is not in the specified range, it is converted to poison.

llvm/include/llvm/Bitcode/LLVMBitCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,7 @@ enum AttributeKindCodes {
798798
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
799799
ATTR_KIND_SANITIZE_TYPE = 101,
800800
ATTR_KIND_CAPTURES = 102,
801+
ATTR_KIND_DEAD_ON_RETURN = 103,
801802
};
802803

803804
enum ComdatSelectionKindCodes {

llvm/include/llvm/IR/Argument.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ class Argument final : public Value {
7878
/// Return true if this argument has the byval attribute.
7979
LLVM_ABI bool hasByValAttr() const;
8080

81+
/// Return true if this argument has the dead_on_return attribute.
82+
LLVM_ABI bool hasDeadOnReturnAttr() const;
83+
8184
/// Return true if this argument has the byref attribute.
8285
LLVM_ABI bool hasByRefAttr() const;
8386

@@ -87,9 +90,9 @@ class Argument final : public Value {
8790
/// Return true if this argument has the swifterror attribute.
8891
LLVM_ABI bool hasSwiftErrorAttr() const;
8992

90-
/// Return true if this argument has the byval, inalloca, or preallocated
91-
/// attribute. These attributes represent arguments being passed by value,
92-
/// with an associated copy between the caller and callee
93+
/// Return true if this argument has the byval, inalloca, preallocated or
94+
/// dead_on_return attribute. These attributes represent arguments being
95+
/// passed by value, with an associated copy between the caller and callee.
9396
LLVM_ABI bool hasPassPointeeByValueCopyAttr() const;
9497

9598
/// If this argument satisfies has hasPassPointeeByValueAttr, return the

llvm/include/llvm/IR/Attributes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ def NoFree : EnumAttr<"nofree", IntersectAnd, [FnAttr, ParamAttr]>;
198198
/// Argument is dead if the call unwinds.
199199
def DeadOnUnwind : EnumAttr<"dead_on_unwind", IntersectAnd, [ParamAttr]>;
200200

201+
/// Argument is dead upon function return.
202+
def DeadOnReturn : EnumAttr<"dead_on_return", IntersectAnd, [ParamAttr]>;
203+
201204
/// Disable implicit floating point insts.
202205
def NoImplicitFloat : EnumAttr<"noimplicitfloat", IntersectPreserve, [FnAttr]>;
203206

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,6 +2246,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
22462246
return Attribute::NoExt;
22472247
case bitc::ATTR_KIND_CAPTURES:
22482248
return Attribute::Captures;
2249+
case bitc::ATTR_KIND_DEAD_ON_RETURN:
2250+
return Attribute::DeadOnReturn;
22492251
}
22502252
}
22512253

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
940940
return bitc::ATTR_KIND_NO_EXT;
941941
case Attribute::Captures:
942942
return bitc::ATTR_KIND_CAPTURES;
943+
case Attribute::DeadOnReturn:
944+
return bitc::ATTR_KIND_DEAD_ON_RETURN;
943945
case Attribute::EndAttrKinds:
944946
llvm_unreachable("Can not encode end-attribute kinds marker.");
945947
case Attribute::None:

llvm/lib/IR/Attributes.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2424,7 +2424,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
24242424
.addAttribute(Attribute::Writable)
24252425
.addAttribute(Attribute::DeadOnUnwind)
24262426
.addAttribute(Attribute::Initializes)
2427-
.addAttribute(Attribute::Captures);
2427+
.addAttribute(Attribute::Captures)
2428+
.addAttribute(Attribute::DeadOnReturn);
24282429
if (ASK & ASK_UNSAFE_TO_DROP)
24292430
Incompatible.addAttribute(Attribute::Nest)
24302431
.addAttribute(Attribute::SwiftError)

llvm/lib/IR/Function.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ bool Argument::hasByValAttr() const {
146146
return hasAttribute(Attribute::ByVal);
147147
}
148148

149+
bool Argument::hasDeadOnReturnAttr() const {
150+
if (!getType()->isPointerTy())
151+
return false;
152+
return hasAttribute(Attribute::DeadOnReturn);
153+
}
154+
149155
bool Argument::hasByRefAttr() const {
150156
if (!getType()->isPointerTy())
151157
return false;

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,10 +1017,10 @@ struct DSEState {
10171017
}
10181018
}
10191019

1020-
// Treat byval or inalloca arguments the same as Allocas, stores to them are
1021-
// dead at the end of the function.
1020+
// Treat byval, inalloca or dead on return arguments the same as Allocas,
1021+
// stores to them are dead at the end of the function.
10221022
for (Argument &AI : F.args())
1023-
if (AI.hasPassPointeeByValueCopyAttr())
1023+
if (AI.hasPassPointeeByValueCopyAttr() || AI.hasDeadOnReturnAttr())
10241024
InvisibleToCallerAfterRet.insert({&AI, true});
10251025

10261026
// Collect whether there is any irreducible control flow in the function.

llvm/lib/Transforms/Utils/CodeExtractor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
10251025
case Attribute::EndAttrKinds:
10261026
case Attribute::EmptyKey:
10271027
case Attribute::TombstoneKey:
1028+
case Attribute::DeadOnReturn:
10281029
llvm_unreachable("Not a function attribute");
10291030
}
10301031

llvm/test/Bitcode/attributes.ll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,11 @@ define void @captures(ptr captures(address) %p) {
567567
ret void
568568
}
569569

570+
; CHECK: define void @dead_on_return(ptr dead_on_return %p)
571+
define void @dead_on_return(ptr dead_on_return %p) {
572+
ret void
573+
}
574+
570575
; CHECK: attributes #0 = { noreturn }
571576
; CHECK: attributes #1 = { nounwind }
572577
; CHECK: attributes #2 = { memory(none) }

llvm/test/Transforms/DeadStoreElimination/simple.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,3 +855,11 @@ bb:
855855
store ptr null, ptr null, align 8
856856
ret void
857857
}
858+
859+
define void @test50(ptr dead_on_return %p) {
860+
; CHECK-LABEL: @test50(
861+
; CHECK-NEXT: ret void
862+
;
863+
store i8 0, ptr %p
864+
ret void
865+
}

llvm/test/Verifier/dead-on-return.ll

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
2+
3+
; CHECK: Attribute 'dead_on_return' applied to incompatible type!
4+
; CHECK-NEXT: ptr @arg_not_pointer
5+
define void @arg_not_pointer(i32 dead_on_return %arg) {
6+
ret void
7+
}

0 commit comments

Comments
 (0)