forked from OSchip/llvm-project
[DAE] Adjust param/arg attributes when changing parameter to undef
In DeadArgumentElimination pass, if a function's argument is never used, corresponding caller's parameter can be changed to undef. If the param/arg has attribute noundef or other related attributes, LLVM LangRef(https://llvm.org/docs/LangRef.html#parameter-attributes) says its behavior is undefined. SimplifyCFG(D97244) takes advantage of this behavior and does bad transformation on valid code. To avoid this undefined behavior when change caller's parameter to undef, this patch removes noundef attribute and other attributes imply noundef on param/arg. Differential Revision: https://reviews.llvm.org/D98899
This commit is contained in:
parent
4f5e92cc05
commit
3240910f00
|
@ -521,6 +521,12 @@ public:
|
||||||
return removeAttributes(C, ArgNo + FirstArgIndex, AttrsToRemove);
|
return removeAttributes(C, ArgNo + FirstArgIndex, AttrsToRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove noundef attribute and other attributes that imply undefined
|
||||||
|
/// behavior if a `undef` or `poison` value is passed from this attribute
|
||||||
|
/// list. Returns a new list because attribute lists are immutable.
|
||||||
|
LLVM_NODISCARD AttributeList
|
||||||
|
removeParamUndefImplyingAttributes(LLVMContext &C, unsigned ArgNo) const;
|
||||||
|
|
||||||
/// Remove all attributes at the specified arg index from this
|
/// Remove all attributes at the specified arg index from this
|
||||||
/// attribute list. Returns a new list because attribute lists are immutable.
|
/// attribute list. Returns a new list because attribute lists are immutable.
|
||||||
LLVM_NODISCARD AttributeList removeParamAttributes(LLVMContext &C,
|
LLVM_NODISCARD AttributeList removeParamAttributes(LLVMContext &C,
|
||||||
|
|
|
@ -426,6 +426,10 @@ public:
|
||||||
/// removes the attribute from the list of attributes.
|
/// removes the attribute from the list of attributes.
|
||||||
void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
|
void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
|
||||||
|
|
||||||
|
/// removes noundef and other attributes that imply undefined behavior if a
|
||||||
|
/// `undef` or `poison` value is passed from the list of attributes.
|
||||||
|
void removeParamUndefImplyingAttrs(unsigned ArgNo);
|
||||||
|
|
||||||
/// check if an attributes is in the list of attributes.
|
/// check if an attributes is in the list of attributes.
|
||||||
bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
|
bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
|
||||||
return getAttributes().hasAttribute(i, Kind);
|
return getAttributes().hasAttribute(i, Kind);
|
||||||
|
|
|
@ -1555,6 +1555,15 @@ public:
|
||||||
setAttributes(PAL);
|
setAttributes(PAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes noundef and other attributes that imply undefined behavior if a
|
||||||
|
/// `undef` or `poison` value is passed from the given argument.
|
||||||
|
void removeParamUndefImplyingAttrs(unsigned ArgNo) {
|
||||||
|
assert(ArgNo < getNumArgOperands() && "Out of bounds");
|
||||||
|
AttributeList PAL = getAttributes();
|
||||||
|
PAL = PAL.removeParamUndefImplyingAttributes(getContext(), ArgNo);
|
||||||
|
setAttributes(PAL);
|
||||||
|
}
|
||||||
|
|
||||||
/// adds the dereferenceable attribute to the list of attributes.
|
/// adds the dereferenceable attribute to the list of attributes.
|
||||||
void addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
void addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
||||||
AttributeList PAL = getAttributes();
|
AttributeList PAL = getAttributes();
|
||||||
|
|
|
@ -1454,6 +1454,17 @@ AttributeList AttributeList::removeAttributes(LLVMContext &C,
|
||||||
return getImpl(C, AttrSets);
|
return getImpl(C, AttrSets);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttributeList
|
||||||
|
AttributeList::removeParamUndefImplyingAttributes(LLVMContext &C,
|
||||||
|
unsigned ArgNo) const {
|
||||||
|
AttrBuilder B;
|
||||||
|
B.addAttribute(Attribute::NoUndef);
|
||||||
|
B.addAttribute(Attribute::NonNull);
|
||||||
|
B.addDereferenceableAttr(1);
|
||||||
|
B.addDereferenceableOrNullAttr(1);
|
||||||
|
return removeParamAttributes(C, ArgNo, B);
|
||||||
|
}
|
||||||
|
|
||||||
AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C,
|
AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C,
|
||||||
unsigned Index,
|
unsigned Index,
|
||||||
uint64_t Bytes) const {
|
uint64_t Bytes) const {
|
||||||
|
|
|
@ -562,6 +562,12 @@ void Function::removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs) {
|
||||||
setAttributes(PAL);
|
setAttributes(PAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Function::removeParamUndefImplyingAttrs(unsigned ArgNo) {
|
||||||
|
AttributeList PAL = getAttributes();
|
||||||
|
PAL = PAL.removeParamUndefImplyingAttributes(getContext(), ArgNo);
|
||||||
|
setAttributes(PAL);
|
||||||
|
}
|
||||||
|
|
||||||
void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
|
||||||
AttributeList PAL = getAttributes();
|
AttributeList PAL = getAttributes();
|
||||||
PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
|
PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);
|
||||||
|
|
|
@ -295,6 +295,7 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
|
||||||
Changed = true;
|
Changed = true;
|
||||||
}
|
}
|
||||||
UnusedArgs.push_back(Arg.getArgNo());
|
UnusedArgs.push_back(Arg.getArgNo());
|
||||||
|
Fn.removeParamUndefImplyingAttrs(Arg.getArgNo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +313,8 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
|
||||||
|
|
||||||
Value *Arg = CB->getArgOperand(ArgNo);
|
Value *Arg = CB->getArgOperand(ArgNo);
|
||||||
CB->setArgOperand(ArgNo, UndefValue::get(Arg->getType()));
|
CB->setArgOperand(ArgNo, UndefValue::get(Arg->getType()));
|
||||||
|
CB->removeParamUndefImplyingAttrs(ArgNo);
|
||||||
|
|
||||||
++NumArgumentsReplacedWithUndef;
|
++NumArgumentsReplacedWithUndef;
|
||||||
Changed = true;
|
Changed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
; RUN: opt -deadargelim -S < %s | FileCheck %s
|
||||||
|
|
||||||
|
; If caller is changed to pass in undef, noundef and related attributes
|
||||||
|
; should be deleted.
|
||||||
|
|
||||||
|
|
||||||
|
; CHECK: define i64 @bar(i64* %0, i64 %1)
|
||||||
|
define i64 @bar(i64* nonnull dereferenceable(8) %0, i64 %1) {
|
||||||
|
entry:
|
||||||
|
%2 = add i64 %1, 8
|
||||||
|
ret i64 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
define i64 @foo(i64* %p, i64 %v) {
|
||||||
|
; CHECK: %retval = call i64 @bar(i64* undef, i64 %v)
|
||||||
|
%retval = call i64 @bar(i64* nonnull dereferenceable(8) %p, i64 %v)
|
||||||
|
ret i64 %retval
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ done:
|
||||||
|
|
||||||
define i32 @compute(i8* noundef nonnull %ptr, i32 %x) #1 {
|
define i32 @compute(i8* noundef nonnull %ptr, i32 %x) #1 {
|
||||||
; CHECK-LABEL: define {{[^@]+}}@compute
|
; CHECK-LABEL: define {{[^@]+}}@compute
|
||||||
; CHECK-SAME: (i8* nocapture noundef nonnull readnone [[PTR:%.*]], i32 returned [[X:%.*]]) local_unnamed_addr #1
|
; CHECK-SAME: (i8* nocapture readnone [[PTR:%.*]], i32 returned [[X:%.*]]) local_unnamed_addr #1
|
||||||
; CHECK-NEXT: ret i32 [[X]]
|
; CHECK-NEXT: ret i32 [[X]]
|
||||||
;
|
;
|
||||||
ret i32 %x
|
ret i32 %x
|
||||||
|
|
Loading…
Reference in New Issue