Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1741,6 +1741,23 @@ Currently, only the following parameter attributes are defined:

This attribute cannot be applied to return values.

``dead_on_return``
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.

``range(<ty> <a>, <b>)``
This attribute expresses the possible range of the parameter or return value.
If the value is not in the specified range, it is converted to poison.
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/Bitcode/LLVMBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ enum AttributeKindCodes {
ATTR_KIND_NO_DIVERGENCE_SOURCE = 100,
ATTR_KIND_SANITIZE_TYPE = 101,
ATTR_KIND_CAPTURES = 102,
ATTR_KIND_DEAD_ON_RETURN = 103,
};

enum ComdatSelectionKindCodes {
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Argument.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class Argument final : public Value {
/// Return true if this argument has the byval attribute.
LLVM_ABI bool hasByValAttr() const;

/// Return true if this argument has the dead_on_return attribute.
LLVM_ABI bool hasDeadOnReturnAttr() const;

/// Return true if this argument has the byref attribute.
LLVM_ABI bool hasByRefAttr() const;

Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Attributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ def NoFree : EnumAttr<"nofree", IntersectAnd, [FnAttr, ParamAttr]>;
/// Argument is dead if the call unwinds.
def DeadOnUnwind : EnumAttr<"dead_on_unwind", IntersectAnd, [ParamAttr]>;

/// Argument is dead upon function return.
def DeadOnReturn : EnumAttr<"dead_on_return", IntersectAnd, [ParamAttr]>;

/// Disable implicit floating point insts.
def NoImplicitFloat : EnumAttr<"noimplicitfloat", IntersectPreserve, [FnAttr]>;

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2244,6 +2244,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
return Attribute::NoExt;
case bitc::ATTR_KIND_CAPTURES:
return Attribute::Captures;
case bitc::ATTR_KIND_DEAD_ON_RETURN:
return Attribute::DeadOnReturn;
}
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
return bitc::ATTR_KIND_NO_EXT;
case Attribute::Captures:
return bitc::ATTR_KIND_CAPTURES;
case Attribute::DeadOnReturn:
return bitc::ATTR_KIND_DEAD_ON_RETURN;
case Attribute::EndAttrKinds:
llvm_unreachable("Can not encode end-attribute kinds marker.");
case Attribute::None:
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/IR/Attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2424,7 +2424,8 @@ AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, AttributeSet AS,
.addAttribute(Attribute::Writable)
.addAttribute(Attribute::DeadOnUnwind)
.addAttribute(Attribute::Initializes)
.addAttribute(Attribute::Captures);
.addAttribute(Attribute::Captures)
.addAttribute(Attribute::DeadOnReturn);
if (ASK & ASK_UNSAFE_TO_DROP)
Incompatible.addAttribute(Attribute::Nest)
.addAttribute(Attribute::SwiftError)
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ bool Argument::hasByValAttr() const {
return hasAttribute(Attribute::ByVal);
}

bool Argument::hasDeadOnReturnAttr() const {
if (!getType()->isPointerTy())
return false;
return hasAttribute(Attribute::DeadOnReturn);
}

bool Argument::hasByRefAttr() const {
if (!getType()->isPointerTy())
return false;
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,10 @@ struct DSEState {
}
}

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

// Collect whether there is any irreducible control flow in the function.
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Utils/CodeExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
case Attribute::EndAttrKinds:
case Attribute::EmptyKey:
case Attribute::TombstoneKey:
case Attribute::DeadOnReturn:
llvm_unreachable("Not a function attribute");
}

Expand Down
5 changes: 5 additions & 0 deletions llvm/test/Bitcode/attributes.ll
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ define void @captures(ptr captures(address) %p) {
ret void
}

; CHECK: define void @dead_on_return(ptr dead_on_return %p)
define void @dead_on_return(ptr dead_on_return %p) {
ret void
}

; CHECK: attributes #0 = { noreturn }
; CHECK: attributes #1 = { nounwind }
; CHECK: attributes #2 = { memory(none) }
Expand Down
35 changes: 34 additions & 1 deletion llvm/test/Transforms/DeadStoreElimination/simple.ll
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please also add a test variant that returns %p? To show that we can still elide the store in that case as well.

Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ define ptr @test25(ptr %p) nounwind {
; CHECK-NEXT: [[P_4:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 4
; CHECK-NEXT: [[TMP:%.*]] = load i8, ptr [[P_4]], align 1
; CHECK-NEXT: store i8 0, ptr [[P_4]], align 1
; CHECK-NEXT: [[Q:%.*]] = call ptr @strdup(ptr [[P]]) #[[ATTR13:[0-9]+]]
; CHECK-NEXT: [[Q:%.*]] = call ptr @strdup(ptr [[P]]) #[[ATTR14:[0-9]+]]
; CHECK-NEXT: store i8 [[TMP]], ptr [[P_4]], align 1
; CHECK-NEXT: ret ptr [[Q]]
;
Expand Down Expand Up @@ -855,3 +855,36 @@ bb:
store ptr null, ptr null, align 8
ret void
}

define void @test_dead_on_return(ptr dead_on_return %p) {
; CHECK-LABEL: @test_dead_on_return(
; CHECK-NEXT: ret void
;
store i8 0, ptr %p
ret void
}

define void @test_dead_on_return_maythrow(ptr dead_on_return %p) {
; CHECK-LABEL: @test_dead_on_return_maythrow(
; CHECK-NEXT: call void @maythrow()
; CHECK-NEXT: ret void
;
store i8 0, ptr %p
call void @maythrow()
ret void
}

define ptr @test_dead_on_return_ptr_returned(ptr dead_on_return %p) {
; CHECK-LABEL: @test_dead_on_return_ptr_returned(
; CHECK-NEXT: [[LOCAL_VAR:%.*]] = alloca ptr, align 8
; CHECK-NEXT: call void @opaque(ptr [[LOCAL_VAR]])
; CHECK-NEXT: ret ptr [[P:%.*]]
;
%local.var = alloca ptr
call void @opaque(ptr %local.var)
store ptr %local.var, ptr %p
ret ptr %p
}

declare void @opaque(ptr)
declare void @maythrow() memory(none)
7 changes: 7 additions & 0 deletions llvm/test/Verifier/dead-on-return.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s

; CHECK: Attribute 'dead_on_return' applied to incompatible type!
; CHECK-NEXT: ptr @arg_not_pointer
define void @arg_not_pointer(i32 dead_on_return %arg) {
ret void
}
Loading