Skip to content

Commit 3240910

Browse files
committed
[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
1 parent 4f5e92c commit 3240910

File tree

8 files changed

+58
-1
lines changed

8 files changed

+58
-1
lines changed

llvm/include/llvm/IR/Attributes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,12 @@ class AttributeList {
521521
return removeAttributes(C, ArgNo + FirstArgIndex, AttrsToRemove);
522522
}
523523

524+
/// Remove noundef attribute and other attributes that imply undefined
525+
/// behavior if a `undef` or `poison` value is passed from this attribute
526+
/// list. Returns a new list because attribute lists are immutable.
527+
LLVM_NODISCARD AttributeList
528+
removeParamUndefImplyingAttributes(LLVMContext &C, unsigned ArgNo) const;
529+
524530
/// Remove all attributes at the specified arg index from this
525531
/// attribute list. Returns a new list because attribute lists are immutable.
526532
LLVM_NODISCARD AttributeList removeParamAttributes(LLVMContext &C,

llvm/include/llvm/IR/Function.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ class Function : public GlobalObject, public ilist_node<Function> {
426426
/// removes the attribute from the list of attributes.
427427
void removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs);
428428

429+
/// removes noundef and other attributes that imply undefined behavior if a
430+
/// `undef` or `poison` value is passed from the list of attributes.
431+
void removeParamUndefImplyingAttrs(unsigned ArgNo);
432+
429433
/// check if an attributes is in the list of attributes.
430434
bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
431435
return getAttributes().hasAttribute(i, Kind);

llvm/include/llvm/IR/InstrTypes.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,15 @@ class CallBase : public Instruction {
15551555
setAttributes(PAL);
15561556
}
15571557

1558+
/// Removes noundef and other attributes that imply undefined behavior if a
1559+
/// `undef` or `poison` value is passed from the given argument.
1560+
void removeParamUndefImplyingAttrs(unsigned ArgNo) {
1561+
assert(ArgNo < getNumArgOperands() && "Out of bounds");
1562+
AttributeList PAL = getAttributes();
1563+
PAL = PAL.removeParamUndefImplyingAttributes(getContext(), ArgNo);
1564+
setAttributes(PAL);
1565+
}
1566+
15581567
/// adds the dereferenceable attribute to the list of attributes.
15591568
void addDereferenceableAttr(unsigned i, uint64_t Bytes) {
15601569
AttributeList PAL = getAttributes();

llvm/lib/IR/Attributes.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,17 @@ AttributeList AttributeList::removeAttributes(LLVMContext &C,
14541454
return getImpl(C, AttrSets);
14551455
}
14561456

1457+
AttributeList
1458+
AttributeList::removeParamUndefImplyingAttributes(LLVMContext &C,
1459+
unsigned ArgNo) const {
1460+
AttrBuilder B;
1461+
B.addAttribute(Attribute::NoUndef);
1462+
B.addAttribute(Attribute::NonNull);
1463+
B.addDereferenceableAttr(1);
1464+
B.addDereferenceableOrNullAttr(1);
1465+
return removeParamAttributes(C, ArgNo, B);
1466+
}
1467+
14571468
AttributeList AttributeList::addDereferenceableAttr(LLVMContext &C,
14581469
unsigned Index,
14591470
uint64_t Bytes) const {

llvm/lib/IR/Function.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,12 @@ void Function::removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs) {
562562
setAttributes(PAL);
563563
}
564564

565+
void Function::removeParamUndefImplyingAttrs(unsigned ArgNo) {
566+
AttributeList PAL = getAttributes();
567+
PAL = PAL.removeParamUndefImplyingAttributes(getContext(), ArgNo);
568+
setAttributes(PAL);
569+
}
570+
565571
void Function::addDereferenceableAttr(unsigned i, uint64_t Bytes) {
566572
AttributeList PAL = getAttributes();
567573
PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);

llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
295295
Changed = true;
296296
}
297297
UnusedArgs.push_back(Arg.getArgNo());
298+
Fn.removeParamUndefImplyingAttrs(Arg.getArgNo());
298299
}
299300
}
300301

@@ -312,6 +313,8 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
312313

313314
Value *Arg = CB->getArgOperand(ArgNo);
314315
CB->setArgOperand(ArgNo, UndefValue::get(Arg->getType()));
316+
CB->removeParamUndefImplyingAttrs(ArgNo);
317+
315318
++NumArgumentsReplacedWithUndef;
316319
Changed = true;
317320
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: opt -deadargelim -S < %s | FileCheck %s
2+
3+
; If caller is changed to pass in undef, noundef and related attributes
4+
; should be deleted.
5+
6+
7+
; CHECK: define i64 @bar(i64* %0, i64 %1)
8+
define i64 @bar(i64* nonnull dereferenceable(8) %0, i64 %1) {
9+
entry:
10+
%2 = add i64 %1, 8
11+
ret i64 %2
12+
}
13+
14+
define i64 @foo(i64* %p, i64 %v) {
15+
; CHECK: %retval = call i64 @bar(i64* undef, i64 %v)
16+
%retval = call i64 @bar(i64* nonnull dereferenceable(8) %p, i64 %v)
17+
ret i64 %retval
18+
}

llvm/test/Transforms/InstCombine/unused-nonnull.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ done:
3737

3838
define i32 @compute(i8* noundef nonnull %ptr, i32 %x) #1 {
3939
; CHECK-LABEL: define {{[^@]+}}@compute
40-
; CHECK-SAME: (i8* nocapture noundef nonnull readnone [[PTR:%.*]], i32 returned [[X:%.*]]) local_unnamed_addr #1
40+
; CHECK-SAME: (i8* nocapture readnone [[PTR:%.*]], i32 returned [[X:%.*]]) local_unnamed_addr #1
4141
; CHECK-NEXT: ret i32 [[X]]
4242
;
4343
ret i32 %x

0 commit comments

Comments
 (0)