Skip to content

Commit f1cc0b6

Browse files
[IR] Introduce dead_on_return attribute
Add `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 implies that the copy already exists in the IR, 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. RFC: https://discourse.llvm.org/t/rfc-add-dead-on-return-attribute/86871.
1 parent d5608d6 commit f1cc0b6

File tree

13 files changed

+86
-5
lines changed

13 files changed

+86
-5
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 function return, both upon normal return and if the calls unwinds, meaning
1747+
that the caller will not depend on its contents. Stores that would be observable
1748+
either on the return path or on the unwind path may 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 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. Conversely, this attribute always implies ``dead_on_unwind``.
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: 3 additions & 0 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

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
@@ -2244,6 +2244,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
22442244
return Attribute::NoExt;
22452245
case bitc::ATTR_KIND_CAPTURES:
22462246
return Attribute::Captures;
2247+
case bitc::ATTR_KIND_DEAD_ON_RETURN:
2248+
return Attribute::DeadOnReturn;
22472249
}
22482250
}
22492251

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
938938
return bitc::ATTR_KIND_NO_EXT;
939939
case Attribute::Captures:
940940
return bitc::ATTR_KIND_CAPTURES;
941+
case Attribute::DeadOnReturn:
942+
return bitc::ATTR_KIND_DEAD_ON_RETURN;
941943
case Attribute::EndAttrKinds:
942944
llvm_unreachable("Can not encode end-attribute kinds marker.");
943945
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
@@ -130,6 +130,12 @@ bool Argument::hasByValAttr() const {
130130
return hasAttribute(Attribute::ByVal);
131131
}
132132

133+
bool Argument::hasDeadOnReturnAttr() const {
134+
if (!getType()->isPointerTy())
135+
return false;
136+
return hasAttribute(Attribute::DeadOnReturn);
137+
}
138+
133139
bool Argument::hasByRefAttr() const {
134140
if (!getType()->isPointerTy())
135141
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
@@ -1020,6 +1020,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
10201020
case Attribute::EndAttrKinds:
10211021
case Attribute::EmptyKey:
10221022
case Attribute::TombstoneKey:
1023+
case Attribute::DeadOnReturn:
10231024
llvm_unreachable("Not a function attribute");
10241025
}
10251026

0 commit comments

Comments
 (0)