[llvm] 3240910 - [DAE] Adjust param/arg attributes when changing parameter to undef

Guozhi Wei via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 25 14:54:18 PDT 2021


Author: Guozhi Wei
Date: 2021-03-25T14:53:22-07:00
New Revision: 3240910f000625957a6a01ff8758c892f72a3a0d

URL: https://github.com/llvm/llvm-project/commit/3240910f000625957a6a01ff8758c892f72a3a0d
DIFF: https://github.com/llvm/llvm-project/commit/3240910f000625957a6a01ff8758c892f72a3a0d.diff

LOG: [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

Added: 
    llvm/test/Transforms/DeadArgElim/NoundefAttrs.ll

Modified: 
    llvm/include/llvm/IR/Attributes.h
    llvm/include/llvm/IR/Function.h
    llvm/include/llvm/IR/InstrTypes.h
    llvm/lib/IR/Attributes.cpp
    llvm/lib/IR/Function.cpp
    llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
    llvm/test/Transforms/InstCombine/unused-nonnull.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/Attributes.h b/llvm/include/llvm/IR/Attributes.h
index 1e43d903360e..d21d65bc4e79 100644
--- a/llvm/include/llvm/IR/Attributes.h
+++ b/llvm/include/llvm/IR/Attributes.h
@@ -521,6 +521,12 @@ class AttributeList {
     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
   /// attribute list. Returns a new list because attribute lists are immutable.
   LLVM_NODISCARD AttributeList removeParamAttributes(LLVMContext &C,

diff  --git a/llvm/include/llvm/IR/Function.h b/llvm/include/llvm/IR/Function.h
index b3a1b6c03618..ab20cc4b68c8 100644
--- a/llvm/include/llvm/IR/Function.h
+++ b/llvm/include/llvm/IR/Function.h
@@ -426,6 +426,10 @@ class Function : public GlobalObject, public ilist_node<Function> {
   /// removes the attribute from the list of attributes.
   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.
   bool hasAttribute(unsigned i, Attribute::AttrKind Kind) const {
     return getAttributes().hasAttribute(i, Kind);

diff  --git a/llvm/include/llvm/IR/InstrTypes.h b/llvm/include/llvm/IR/InstrTypes.h
index 86e86c454d8f..f218bc4cd36f 100644
--- a/llvm/include/llvm/IR/InstrTypes.h
+++ b/llvm/include/llvm/IR/InstrTypes.h
@@ -1555,6 +1555,15 @@ class CallBase : public Instruction {
     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.
   void addDereferenceableAttr(unsigned i, uint64_t Bytes) {
     AttributeList PAL = getAttributes();

diff  --git a/llvm/lib/IR/Attributes.cpp b/llvm/lib/IR/Attributes.cpp
index 4c087c967b01..831186a49fca 100644
--- a/llvm/lib/IR/Attributes.cpp
+++ b/llvm/lib/IR/Attributes.cpp
@@ -1454,6 +1454,17 @@ AttributeList AttributeList::removeAttributes(LLVMContext &C,
   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,
                                                     unsigned Index,
                                                     uint64_t Bytes) const {

diff  --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index ab8d425ef44c..7389ec6858ed 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -562,6 +562,12 @@ void Function::removeParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs) {
   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) {
   AttributeList PAL = getAttributes();
   PAL = PAL.addDereferenceableAttr(getContext(), i, Bytes);

diff  --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
index 0b763e423fe0..3154d2468c64 100644
--- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -295,6 +295,7 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
         Changed = true;
       }
       UnusedArgs.push_back(Arg.getArgNo());
+      Fn.removeParamUndefImplyingAttrs(Arg.getArgNo());
     }
   }
 
@@ -312,6 +313,8 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) {
 
       Value *Arg = CB->getArgOperand(ArgNo);
       CB->setArgOperand(ArgNo, UndefValue::get(Arg->getType()));
+      CB->removeParamUndefImplyingAttrs(ArgNo);
+
       ++NumArgumentsReplacedWithUndef;
       Changed = true;
     }

diff  --git a/llvm/test/Transforms/DeadArgElim/NoundefAttrs.ll b/llvm/test/Transforms/DeadArgElim/NoundefAttrs.ll
new file mode 100644
index 000000000000..576f972fc87a
--- /dev/null
+++ b/llvm/test/Transforms/DeadArgElim/NoundefAttrs.ll
@@ -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
+}

diff  --git a/llvm/test/Transforms/InstCombine/unused-nonnull.ll b/llvm/test/Transforms/InstCombine/unused-nonnull.ll
index 74173ad4592d..0f6ef7299980 100644
--- a/llvm/test/Transforms/InstCombine/unused-nonnull.ll
+++ b/llvm/test/Transforms/InstCombine/unused-nonnull.ll
@@ -37,7 +37,7 @@ done:
 
 define i32 @compute(i8* noundef nonnull %ptr, i32 %x) #1 {
 ; 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]]
 ;
   ret i32 %x


        


More information about the llvm-commits mailing list