Skip to content

Commit 0488958

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, and the pointee is invisible once the call completes. They however differ in the ABI: with `byval` the pointer is explicitly passed as argument to the callee and already points at the copy, whereas `dead_on_return` implies the copy is located within the callee stack frame.
1 parent 0e2103a commit 0488958

File tree

13 files changed

+60
-6
lines changed

13 files changed

+60
-6
lines changed

llvm/docs/LangRef.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,6 +1741,20 @@ 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.
1747+
1748+
It is similar to ``byval`` in the regard that it is generally used to pass
1749+
structs and arrays by value, and the memory is caller-invisible when the
1750+
function returns. However, unlike ``byval``, it is intended for ABIs where the
1751+
*callee* allocates the hidden copy, rather than the caller. Stores that would
1752+
only be visible on the normal return path may be optimized out. Likewise,
1753+
optimizations may assume that the pointer does not alias any memory that
1754+
outlives the call.
1755+
1756+
This attribute cannot be applied to return values.
1757+
17441758
``range(<ty> <a>, <b>)``
17451759
This attribute expresses the possible range of the parameter or return value.
17461760
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+
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/Analysis/AliasAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ bool llvm::isNoAliasCall(const Value *V) {
818818

819819
static bool isNoAliasOrByValArgument(const Value *V) {
820820
if (const Argument *A = dyn_cast<Argument>(V))
821-
return A->hasNoAliasAttr() || A->hasByValAttr();
821+
return A->hasNoAliasAttr() || A->hasByValAttr() || A->hasDeadOnReturnAttr();
822822
return false;
823823
}
824824

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: 8 additions & 1 deletion
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;
@@ -176,7 +182,8 @@ bool Argument::hasPassPointeeByValueCopyAttr() const {
176182
AttributeList Attrs = getParent()->getAttributes();
177183
return Attrs.hasParamAttr(getArgNo(), Attribute::ByVal) ||
178184
Attrs.hasParamAttr(getArgNo(), Attribute::InAlloca) ||
179-
Attrs.hasParamAttr(getArgNo(), Attribute::Preallocated);
185+
Attrs.hasParamAttr(getArgNo(), Attribute::Preallocated) ||
186+
Attrs.hasParamAttr(getArgNo(), Attribute::DeadOnReturn);
180187
}
181188

182189
bool Argument::hasPointeeInMemoryValueAttr() const {

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)