[llvm] 6c25eca - [Attributor] Add flag for undef value to the state of AAPotentialValues

Shinji Okumura via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 00:46:37 PDT 2020


Author: Shinji Okumura
Date: 2020-08-27T16:30:29+09:00
New Revision: 6c25eca6142cec0695016b6fd012df56b50ee01b

URL: https://github.com/llvm/llvm-project/commit/6c25eca6142cec0695016b6fd012df56b50ee01b
DIFF: https://github.com/llvm/llvm-project/commit/6c25eca6142cec0695016b6fd012df56b50ee01b.diff

LOG: [Attributor] Add flag for undef value to the state of AAPotentialValues

Currently, an undef value is reduced to 0 when it is added to a set of potential values.
This patch introduces a flag for under values. By this, for example, we can merge two states `{undef}`, `{1}` to `{1}` (because we can reduce the undef to 1).

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D85592

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Transforms/IPO/Attributor.cpp
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/potential.ll
    llvm/test/Transforms/Attributor/value-simplify.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 2dfb2b189046..43fd7cfe0bbb 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -3368,9 +3368,10 @@ template <typename MemberTy, typename KeyInfo = DenseMapInfo<MemberTy>>
 struct PotentialValuesState : AbstractState {
   using SetTy = DenseSet<MemberTy, KeyInfo>;
 
-  PotentialValuesState() : IsValidState(true) {}
+  PotentialValuesState() : IsValidState(true), UndefIsContained(false) {}
 
-  PotentialValuesState(bool IsValid) : IsValidState(IsValid) {}
+  PotentialValuesState(bool IsValid)
+      : IsValidState(IsValid), UndefIsContained(false) {}
 
   /// See AbstractState::isValidState(...)
   bool isValidState() const override { return IsValidState.isValidState(); }
@@ -3399,11 +3400,19 @@ struct PotentialValuesState : AbstractState {
     return Set;
   }
 
+  /// Returns whether this state contains an undef value or not.
+  bool undefIsContained() const {
+    assert(isValidState() && "This flag shoud not be used when it is invalid!");
+    return UndefIsContained;
+  }
+
   bool operator==(const PotentialValuesState &RHS) const {
     if (isValidState() != RHS.isValidState())
       return false;
     if (!isValidState() && !RHS.isValidState())
       return true;
+    if (undefIsContained() != RHS.undefIsContained())
+      return false;
     return Set == RHS.getAssumedSet();
   }
 
@@ -3431,6 +3440,9 @@ struct PotentialValuesState : AbstractState {
   /// Union assumed set with assumed set of the passed state \p PVS.
   void unionAssumed(const PotentialValuesState &PVS) { unionWith(PVS); }
 
+  /// Union assumed set with an undef value.
+  void unionAssumedWithUndef() { unionWithUndef(); }
+
   /// "Clamp" this state with \p PVS.
   PotentialValuesState operator^=(const PotentialValuesState &PVS) {
     IsValidState ^= PVS.IsValidState;
@@ -3452,6 +3464,10 @@ struct PotentialValuesState : AbstractState {
       indicatePessimisticFixpoint();
   }
 
+  /// If this state contains both undef and not undef, we can reduce
+  /// undef to the not undef value.
+  void reduceUndefValue() { UndefIsContained = UndefIsContained & Set.empty(); }
+
   /// Insert an element into this set.
   void insert(const MemberTy &C) {
     if (!isValidState())
@@ -3472,9 +3488,17 @@ struct PotentialValuesState : AbstractState {
     }
     for (const MemberTy &C : R.Set)
       Set.insert(C);
+    UndefIsContained |= R.undefIsContained();
+    reduceUndefValue();
     checkAndInvalidate();
   }
 
+  /// Take union with an undef value.
+  void unionWithUndef() {
+    UndefIsContained = true;
+    reduceUndefValue();
+  }
+
   /// Take intersection with R.
   void intersectWith(const PotentialValuesState &R) {
     /// If R is a full set, do nothing.
@@ -3491,6 +3515,8 @@ struct PotentialValuesState : AbstractState {
         IntersectSet.insert(C);
     }
     Set = IntersectSet;
+    UndefIsContained &= R.undefIsContained();
+    reduceUndefValue();
   }
 
   /// A helper state which indicate whether this state is valid or not.
@@ -3498,6 +3524,9 @@ struct PotentialValuesState : AbstractState {
 
   /// Container for potential values
   SetTy Set;
+
+  /// Flag for undef value
+  bool UndefIsContained;
 };
 
 using PotentialConstantIntValuesState = PotentialValuesState<APInt>;
@@ -3544,8 +3573,12 @@ struct AAPotentialValues
     if (getAssumedSet().size() == 1)
       return cast<ConstantInt>(ConstantInt::get(getAssociatedValue().getType(),
                                                 *(getAssumedSet().begin())));
-    if (getAssumedSet().size() == 0)
+    if (getAssumedSet().size() == 0) {
+      if (undefIsContained())
+        return cast<ConstantInt>(
+            ConstantInt::get(getAssociatedValue().getType(), 0));
       return llvm::None;
+    }
 
     return nullptr;
   }

diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index d34f4438d4c6..f4351ee11f9b 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -2165,9 +2165,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS,
   OS << "set-state(< {";
   if (!S.isValidState())
     OS << "full-set";
-  else
+  else {
     for (auto &it : S.getAssumedSet())
       OS << it << ", ";
+    if (S.undefIsContained())
+      OS << "undef ";
+  }
   OS << "} >)";
 
   return OS;

diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 33952a836e25..d96fa4189ab0 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -7353,10 +7353,7 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
     }
 
     if (isa<UndefValue>(&V)) {
-      // Collapse the undef state to 0.
-      unionAssumed(
-          APInt(/* numBits */ getAssociatedType()->getIntegerBitWidth(),
-                /* val */ 0));
+      unionAssumedWithUndef();
       indicateOptimisticFixpoint();
       return;
     }
@@ -7477,6 +7474,20 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
     }
   }
 
+  bool calculateBinaryOperatorAndTakeUnion(const BinaryOperator *BinOp,
+                                           const APInt &LHS, const APInt &RHS) {
+    bool SkipOperation = false;
+    bool Unsupported = false;
+    APInt Result =
+        calculateBinaryOperator(BinOp, LHS, RHS, SkipOperation, Unsupported);
+    if (Unsupported)
+      return false;
+    // If SkipOperation is true, we can ignore this operand pair (L, R).
+    if (!SkipOperation)
+      unionAssumed(Result);
+    return isValidState();
+  }
+
   ChangeStatus updateWithICmpInst(Attributor &A, ICmpInst *ICI) {
     auto AssumedBefore = getAssumed();
     Value *LHS = ICI->getOperand(0);
@@ -7495,16 +7506,40 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
     const DenseSet<APInt> &LHSAAPVS = LHSAA.getAssumedSet();
     const DenseSet<APInt> &RHSAAPVS = RHSAA.getAssumedSet();
 
-    // TODO: Handle undef correctly.
+    // TODO: make use of undef flag to limit potential values aggressively.
     bool MaybeTrue = false, MaybeFalse = false;
-    for (const APInt &L : LHSAAPVS) {
+    const APInt Zero(RHS->getType()->getIntegerBitWidth(), 0);
+    if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) {
+      // The result of any comparison between undefs can be soundly replaced
+      // with undef.
+      unionAssumedWithUndef();
+    } else if (LHSAA.undefIsContained()) {
+      bool MaybeTrue = false, MaybeFalse = false;
       for (const APInt &R : RHSAAPVS) {
-        bool CmpResult = calculateICmpInst(ICI, L, R);
+        bool CmpResult = calculateICmpInst(ICI, Zero, R);
         MaybeTrue |= CmpResult;
         MaybeFalse |= !CmpResult;
         if (MaybeTrue & MaybeFalse)
           return indicatePessimisticFixpoint();
       }
+    } else if (RHSAA.undefIsContained()) {
+      for (const APInt &L : LHSAAPVS) {
+        bool CmpResult = calculateICmpInst(ICI, L, Zero);
+        MaybeTrue |= CmpResult;
+        MaybeFalse |= !CmpResult;
+        if (MaybeTrue & MaybeFalse)
+          return indicatePessimisticFixpoint();
+      }
+    } else {
+      for (const APInt &L : LHSAAPVS) {
+        for (const APInt &R : RHSAAPVS) {
+          bool CmpResult = calculateICmpInst(ICI, L, R);
+          MaybeTrue |= CmpResult;
+          MaybeFalse |= !CmpResult;
+          if (MaybeTrue & MaybeFalse)
+            return indicatePessimisticFixpoint();
+        }
+      }
     }
     if (MaybeTrue)
       unionAssumed(APInt(/* numBits */ 1, /* val */ 1));
@@ -7530,8 +7565,13 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
     if (!RHSAA.isValidState())
       return indicatePessimisticFixpoint();
 
-    unionAssumed(LHSAA);
-    unionAssumed(RHSAA);
+    if (LHSAA.undefIsContained() && RHSAA.undefIsContained())
+      // select i1 *, undef , undef => undef
+      unionAssumedWithUndef();
+    else {
+      unionAssumed(LHSAA);
+      unionAssumed(RHSAA);
+    }
     return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
                                          : ChangeStatus::CHANGED;
   }
@@ -7547,11 +7587,14 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
     if (!SrcAA.isValidState())
       return indicatePessimisticFixpoint();
     const DenseSet<APInt> &SrcAAPVS = SrcAA.getAssumedSet();
-    for (const APInt &S : SrcAAPVS) {
-      APInt T = calculateCastInst(CI, S, ResultBitWidth);
-      unionAssumed(T);
+    if (SrcAA.undefIsContained())
+      unionAssumedWithUndef();
+    else {
+      for (const APInt &S : SrcAAPVS) {
+        APInt T = calculateCastInst(CI, S, ResultBitWidth);
+        unionAssumed(T);
+      }
     }
-    // TODO: Handle undef correctly.
     return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
                                          : ChangeStatus::CHANGED;
   }
@@ -7573,19 +7616,28 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
 
     const DenseSet<APInt> &LHSAAPVS = LHSAA.getAssumedSet();
     const DenseSet<APInt> &RHSAAPVS = RHSAA.getAssumedSet();
+    const APInt Zero = APInt(LHS->getType()->getIntegerBitWidth(), 0);
 
-    // TODO: Handle undef correctly
-    for (const APInt &L : LHSAAPVS) {
+    // TODO: make use of undef flag to limit potential values aggressively.
+    if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) {
+      if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))
+        return indicatePessimisticFixpoint();
+    } else if (LHSAA.undefIsContained()) {
       for (const APInt &R : RHSAAPVS) {
-        bool SkipOperation = false;
-        bool Unsupported = false;
-        APInt Result =
-            calculateBinaryOperator(BinOp, L, R, SkipOperation, Unsupported);
-        if (Unsupported)
+        if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))
+          return indicatePessimisticFixpoint();
+      }
+    } else if (RHSAA.undefIsContained()) {
+      for (const APInt &L : LHSAAPVS) {
+        if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))
           return indicatePessimisticFixpoint();
-        // If SkipOperation is true, we can ignore this operand pair (L, R).
-        if (!SkipOperation)
-          unionAssumed(Result);
+      }
+    } else {
+      for (const APInt &L : LHSAAPVS) {
+        for (const APInt &R : RHSAAPVS) {
+          if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))
+            return indicatePessimisticFixpoint();
+        }
       }
     }
     return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
@@ -7600,7 +7652,10 @@ struct AAPotentialValuesFloating : AAPotentialValuesImpl {
           *this, IRPosition::value(*IncomingValue));
       if (!PotentialValuesAA.isValidState())
         return indicatePessimisticFixpoint();
-      unionAssumed(PotentialValuesAA.getAssumed());
+      if (PotentialValuesAA.undefIsContained())
+        unionAssumedWithUndef();
+      else
+        unionAssumed(PotentialValuesAA.getAssumed());
     }
     return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED
                                          : ChangeStatus::CHANGED;
@@ -7688,10 +7743,7 @@ struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {
     }
 
     if (isa<UndefValue>(&V)) {
-      // Collapse the undef state to 0.
-      unionAssumed(
-          APInt(/* numBits */ getAssociatedType()->getIntegerBitWidth(),
-                /* val */ 0));
+      unionAssumedWithUndef();
       indicateOptimisticFixpoint();
       return;
     }

diff  --git a/llvm/test/Transforms/Attributor/potential.ll b/llvm/test/Transforms/Attributor/potential.ll
index 41818fc95924..99e2a71ddc85 100644
--- a/llvm/test/Transforms/Attributor/potential.ll
+++ b/llvm/test/Transforms/Attributor/potential.ll
@@ -493,20 +493,6 @@ end:
 ;        and returned value of @potential_test10 can be simplified to 0(false)
 
 define internal i32 @may_return_undef(i32 %c) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@may_return_undef
-; IS__TUNIT____-SAME: (i32 [[C:%.*]])
-; IS__TUNIT____-NEXT:    switch i32 [[C]], label [[OTHERWISE:%.*]] [
-; IS__TUNIT____-NEXT:    i32 1, label [[A:%.*]]
-; IS__TUNIT____-NEXT:    i32 -1, label [[B:%.*]]
-; IS__TUNIT____-NEXT:    ]
-; IS__TUNIT____:       a:
-; IS__TUNIT____-NEXT:    ret i32 1
-; IS__TUNIT____:       b:
-; IS__TUNIT____-NEXT:    ret i32 -1
-; IS__TUNIT____:       otherwise:
-; IS__TUNIT____-NEXT:    ret i32 undef
-;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@may_return_undef
 ; IS__CGSCC____-SAME: (i32 [[C:%.*]])
@@ -532,19 +518,10 @@ otherwise:
 }
 
 define i1 @potential_test10(i32 %c) {
-; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test10
-; IS__TUNIT_OPM-SAME: (i32 [[C:%.*]])
-; IS__TUNIT_OPM-NEXT:    [[RET:%.*]] = call i32 @may_return_undef(i32 [[C]]) [[ATTR0]], [[RNG2:!range !.*]]
-; IS__TUNIT_OPM-NEXT:    [[CMP:%.*]] = icmp eq i32 [[RET]], 0
-; IS__TUNIT_OPM-NEXT:    ret i1 [[CMP]]
-;
-; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test10
-; IS__TUNIT_NPM-SAME: (i32 [[C:%.*]])
-; IS__TUNIT_NPM-NEXT:    [[RET:%.*]] = call i32 @may_return_undef(i32 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
-; IS__TUNIT_NPM-NEXT:    [[CMP:%.*]] = icmp eq i32 [[RET]], 0
-; IS__TUNIT_NPM-NEXT:    ret i1 [[CMP]]
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test10
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT:    ret i1 false
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test10
@@ -558,15 +535,350 @@ define i1 @potential_test10(i32 %c) {
   ret i1 %cmp
 }
 
+define i32 @optimize_undef_1(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_1
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____:       t:
+; IS__TUNIT____-NEXT:    ret i32 0
+; IS__TUNIT____:       f:
+; IS__TUNIT____-NEXT:    ret i32 1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_1
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____:       t:
+; IS__CGSCC____-NEXT:    ret i32 0
+; IS__CGSCC____:       f:
+; IS__CGSCC____-NEXT:    ret i32 1
+;
+  br i1 %c, label %t, label %f
+t:
+  ret i32 0
+f:
+  %undef = add i32 undef, 1
+  ret i32 %undef
+}
+
+define i32 @optimize_undef_2(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_2
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____:       t:
+; IS__TUNIT____-NEXT:    ret i32 0
+; IS__TUNIT____:       f:
+; IS__TUNIT____-NEXT:    ret i32 -1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_2
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____:       t:
+; IS__CGSCC____-NEXT:    ret i32 0
+; IS__CGSCC____:       f:
+; IS__CGSCC____-NEXT:    ret i32 -1
+;
+  br i1 %c, label %t, label %f
+t:
+  ret i32 0
+f:
+  %undef = sub i32 undef, 1
+  ret i32 %undef
+}
+
+define i32 @optimize_undef_3(i1 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@optimize_undef_3
+; IS__TUNIT____-SAME: (i1 [[C:%.*]])
+; IS__TUNIT____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT____:       t:
+; IS__TUNIT____-NEXT:    ret i32 0
+; IS__TUNIT____:       f:
+; IS__TUNIT____-NEXT:    ret i32 1
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@optimize_undef_3
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC____:       t:
+; IS__CGSCC____-NEXT:    ret i32 0
+; IS__CGSCC____:       f:
+; IS__CGSCC____-NEXT:    ret i32 1
+;
+  br i1 %c, label %t, label %f
+t:
+  ret i32 0
+f:
+  %undef = icmp eq i32 undef, 0
+  %undef2 = zext i1 %undef to i32
+  ret i32 %undef2
+}
+
+
+; FIXME: returned value can be simplified to 0
+define i32 @potential_test11(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test11
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT:    [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) [[ATTR0]], [[RNG2:!range !.*]]
+; IS__TUNIT_OPM-NEXT:    [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
+; IS__TUNIT_OPM-NEXT:    [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__TUNIT_OPM-NEXT:    [[ACC2:%.*]] = add i32 [[ACC1]], 0
+; IS__TUNIT_OPM-NEXT:    ret i32 [[ACC2]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test11
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT:    [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]]) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT:    [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]]) [[ATTR0]], [[RNG3:!range !.*]]
+; IS__TUNIT_NPM-NEXT:    [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__TUNIT_NPM-NEXT:    [[ACC2:%.*]] = add i32 [[ACC1]], 0
+; IS__TUNIT_NPM-NEXT:    ret i32 [[ACC2]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test11
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT:    [[ZERO1:%.*]] = call i32 @optimize_undef_1(i1 [[C]])
+; IS__CGSCC____-NEXT:    [[ZERO2:%.*]] = call i32 @optimize_undef_2(i1 [[C]])
+; IS__CGSCC____-NEXT:    [[ZERO3:%.*]] = call i32 @optimize_undef_3(i1 [[C]])
+; IS__CGSCC____-NEXT:    [[ACC1:%.*]] = add i32 [[ZERO1]], [[ZERO2]]
+; IS__CGSCC____-NEXT:    [[ACC2:%.*]] = add i32 [[ACC1]], [[ZERO3]]
+; IS__CGSCC____-NEXT:    ret i32 [[ACC2]]
+;
+  %zero1 = call i32 @optimize_undef_1(i1 %c)
+  %zero2 = call i32 @optimize_undef_2(i1 %c)
+  %zero3 = call i32 @optimize_undef_3(i1 %c)
+  %acc1 = add i32 %zero1, %zero2
+  %acc2 = add i32 %acc1, %zero3
+  ret i32 %acc2
+}
+
+define i32 @optimize_poison_1(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT_OPM:       t:
+; IS__TUNIT_OPM-NEXT:    ret i32 0
+; IS__TUNIT_OPM:       f:
+; IS__TUNIT_OPM-NEXT:    ret i32 -1
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__TUNIT_NPM:       t:
+; IS__TUNIT_NPM-NEXT:    ret i32 0
+; IS__TUNIT_NPM:       f:
+; IS__TUNIT_NPM-NEXT:    ret i32 undef
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]])
+; IS__CGSCC_OPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_OPM:       t:
+; IS__CGSCC_OPM-NEXT:    ret i32 0
+; IS__CGSCC_OPM:       f:
+; IS__CGSCC_OPM-NEXT:    ret i32 -1
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@optimize_poison_1
+; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]])
+; IS__CGSCC_NPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_NPM:       t:
+; IS__CGSCC_NPM-NEXT:    ret i32 0
+; IS__CGSCC_NPM:       f:
+; IS__CGSCC_NPM-NEXT:    ret i32 undef
+;
+  br i1 %c, label %t, label %f
+t:
+  ret i32 0
+f:
+  %poison = sub nuw i32 0, 1
+  ret i32 %poison
+}
+
+; FIXME: returned value can be simplified to 0
+define i32 @potential_test12(i1 %c) {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test12
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_OPM-NEXT:    [[ZERO:%.*]] = call i32 @optimize_poison_1(i1 [[C]]) [[ATTR0]], [[RNG3]]
+; IS__TUNIT_OPM-NEXT:    ret i32 [[ZERO]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test12
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]])
+; IS__TUNIT_NPM-NEXT:    ret i32 0
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test12
+; IS__CGSCC____-SAME: (i1 [[C:%.*]])
+; IS__CGSCC____-NEXT:    [[ZERO:%.*]] = call i32 @optimize_poison_1(i1 [[C]])
+; IS__CGSCC____-NEXT:    ret i32 [[ZERO]]
+;
+  %zero = call i32 @optimize_poison_1(i1 %c)
+  ret i32 %zero
+}
+
+; Test 13
+; Do not simplify %ret in the callee to `%c`.
+; The potential value of %c is {0, 1} (undef is merged).
+; However, we should not simplify `and i32 %c, 3` to `%c`
+
+define internal i32 @potential_test13_callee(i32 %c) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test13_callee
+; IS__TUNIT____-SAME: (i32 [[C:%.*]])
+; IS__TUNIT____-NEXT:    [[RET:%.*]] = and i32 [[C]], 3
+; IS__TUNIT____-NEXT:    ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_callee
+; IS__CGSCC____-SAME: (i32 [[C:%.*]])
+; IS__CGSCC____-NEXT:    [[RET:%.*]] = and i32 [[C]], 3
+; IS__CGSCC____-NEXT:    ret i32 [[RET]]
+;
+  %ret = and i32 %c, 3
+  ret i32 %ret
+}
+
+define i32 @potential_test13_caller1() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__TUNIT_OPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 0) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT:    ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__TUNIT_NPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 0) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT:    ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller1()
+; IS__CGSCC____-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 0)
+; IS__CGSCC____-NEXT:    ret i32 [[RET]]
+;
+  %ret = call i32 @potential_test13_callee(i32 0)
+  ret i32 %ret
+}
+
+define i32 @potential_test13_caller2() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__TUNIT_OPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 1) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT:    ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__TUNIT_NPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 1) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT:    ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller2()
+; IS__CGSCC____-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 1)
+; IS__CGSCC____-NEXT:    ret i32 [[RET]]
+;
+  %ret = call i32 @potential_test13_callee(i32 1)
+  ret i32 %ret
+}
+
+define i32 @potential_test13_caller3() {
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__TUNIT_OPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) [[ATTR0]], [[RNG2]]
+; IS__TUNIT_OPM-NEXT:    ret i32 [[RET]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__TUNIT_NPM-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef) [[ATTR0]], [[RNG0]]
+; IS__TUNIT_NPM-NEXT:    ret i32 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test13_caller3()
+; IS__CGSCC____-NEXT:    [[RET:%.*]] = call i32 @potential_test13_callee(i32 undef)
+; IS__CGSCC____-NEXT:    ret i32 [[RET]]
+;
+  %ret = call i32 @potential_test13_callee(i32 undef)
+  ret i32 %ret
+}
+
+define i1 @potential_test14(i1 %c0, i1 %c1, i1 %c2, i1 %c3) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test14
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
+; IS__TUNIT____-NEXT:    [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
+; IS__TUNIT____-NEXT:    [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
+; IS__TUNIT____-NEXT:    [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7
+; IS__TUNIT____-NEXT:    [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]]
+; IS__TUNIT____-NEXT:    [[RET:%.*]] = icmp slt i32 [[Z3]], 7
+; IS__TUNIT____-NEXT:    ret i1 [[RET]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test14
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]])
+; IS__CGSCC____-NEXT:    [[X0:%.*]] = select i1 [[C0]], i32 0, i32 1
+; IS__CGSCC____-NEXT:    [[X1:%.*]] = select i1 [[C1]], i32 [[X0]], i32 undef
+; IS__CGSCC____-NEXT:    [[Y2:%.*]] = select i1 [[C2]], i32 0, i32 7
+; IS__CGSCC____-NEXT:    [[Z3:%.*]] = select i1 [[C3]], i32 [[X1]], i32 [[Y2]]
+; IS__CGSCC____-NEXT:    [[RET:%.*]] = icmp slt i32 [[Z3]], 7
+; IS__CGSCC____-NEXT:    ret i1 [[RET]]
+;
+  %x0 = select i1 %c0, i32 0, i32 1
+  %x1 = select i1 %c1, i32 %x0, i32 undef
+  %y2 = select i1 %c2, i32 0, i32 7
+  %z3 = select i1 %c3, i32 %x1, i32 %y2
+  %ret = icmp slt i32 %z3, 7
+  ret i1 %ret
+}
+
+define i1 @potential_test15(i1 %c0, i1 %c1) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test15
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__TUNIT____-NEXT:    ret i1 false
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test15
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__CGSCC____-NEXT:    ret i1 false
+;
+  %x0 = select i1 %c0, i32 0, i32 1
+  %x1 = select i1 %c1, i32 %x0, i32 undef
+  %ret = icmp eq i32 %x1, 7
+  ret i1 %ret
+}
+
+define i1 @potential_test16(i1 %c0, i1 %c1) {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@potential_test16
+; IS__TUNIT____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__TUNIT____-NEXT:    ret i1 false
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@potential_test16
+; IS__CGSCC____-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]])
+; IS__CGSCC____-NEXT:    ret i1 false
+;
+  %x0 = select i1 %c0, i32 0, i32 undef
+  %x1 = select i1 %c1, i32 %x0, i32 1
+  %ret = icmp eq i32 %x1, 7
+  ret i1 %ret
+}
+
 ; IS__TUNIT_NPM: !0 = !{i32 0, i32 2}
 ; IS__TUNIT_NPM: !1 = !{i32 1, i32 4}
 ; IS__TUNIT_NPM: !2 = !{i32 3, i32 5}
-; IS__TUNIT_NPM: !3 = !{i32 -1, i32 2}
+; IS__TUNIT_NPM: !3 = !{i32 -1, i32 1}
 ; IS__TUNIT_NPM-NOT: !4
 
 ; IS__TUNIT_OPM: !0 = !{i32 1, i32 4}
 ; IS__TUNIT_OPM: !1 = !{i32 3, i32 5}
-; IS__TUNIT_OPM: !2 = !{i32 -1, i32 2}
-; IS__TUNIT_OPM-NOT: !3
+; IS__TUNIT_OPM: !2 = !{i32 0, i32 2}
+; IS__TUNIT_OPM: !3 = !{i32 -1, i32 1}
+; IS__TUNIT_OPM-NOT: !4
 
 ; IS__CGSCC____-NOT: !0

diff  --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
index 7ae8cd378011..125d76926d09 100644
--- a/llvm/test/Transforms/Attributor/value-simplify.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify.ll
@@ -644,12 +644,10 @@ for.end:
 }
 
 ; Check we merge undef and a constant properly.
-; FIXME fold the addition and return the constant.
 define i8 @caller0() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller0()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller0()
@@ -662,8 +660,7 @@ define i8 @caller0() {
 define i8 @caller1() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller1()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller1()
@@ -676,8 +673,7 @@ define i8 @caller1() {
 define i8 @caller2() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller2()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller2()
@@ -690,8 +686,7 @@ define i8 @caller2() {
 define i8 @caller_middle() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller_middle()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller_middle()
@@ -704,8 +699,7 @@ define i8 @caller_middle() {
 define i8 @caller3() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller3()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller3()
@@ -718,8 +712,7 @@ define i8 @caller3() {
 define i8 @caller4() {
 ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__TUNIT____-LABEL: define {{[^@]+}}@caller4()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = call i8 @callee()
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
+; IS__TUNIT____-NEXT:    ret i8 49
 ;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@caller4()
@@ -730,15 +723,9 @@ define i8 @caller4() {
   ret i8 %c
 }
 define internal i8 @callee(i8 %a) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@callee()
-; IS__TUNIT____-NEXT:    [[C:%.*]] = add i8 42, 7
-; IS__TUNIT____-NEXT:    ret i8 [[C]]
-;
 ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@callee()
-; IS__CGSCC____-NEXT:    [[C:%.*]] = add i8 42, 7
-; IS__CGSCC____-NEXT:    ret i8 [[C]]
+; IS__CGSCC____-NEXT:    ret i8 49
 ;
   %c = add i8 %a, 7
   ret i8 %c


        


More information about the llvm-commits mailing list