[ConstraintElimination] Allow adding pre-conditions for constraints.
authorFlorian Hahn <flo@fhahn.com>
Fri, 4 Feb 2022 11:45:07 +0000 (11:45 +0000)
committerFlorian Hahn <flo@fhahn.com>
Fri, 4 Feb 2022 11:45:07 +0000 (11:45 +0000)
With this patch pre-conditions can be added to a list of constraints.
Constraints with pre-conditions can only be used if all pre-conditions
are satisfied when the constraint is used.

The pre-conditions at the moment are specified as a list of
(Predicate, Value *,Value *) tuples. This allow easily checking them
like any other condition, using the existing infrastructure.

This then is used to limit GEP decomposition to cases where we can
prove that offsets are signed positive.

This fixes a couple of incorrect transforms where GEP offsets where
assumed to be signed positive, but they were not.

Note that this effectively disables GEP decomposition, as there's no
support for reasoning about signed predicates. D118806 adds initial
signed support.

Fixes PR49624.

Reviewed By: reames

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

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/gep-arithmetic.ll
llvm/test/Transforms/ConstraintElimination/geps-unsigned-predicates.ll
llvm/test/Transforms/ConstraintElimination/large-system-growth.ll
llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-pointer-cmps.ll
llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll

index 063d91b..d27a987 100644 (file)
@@ -44,6 +44,17 @@ DEBUG_COUNTER(EliminatedCounter, "conds-eliminated",
 static int64_t MaxConstraintValue = std::numeric_limits<int64_t>::max();
 
 namespace {
+
+/// Struct to express a pre-condition of the form %Op0 Pred %Op1.
+struct PreconditionTy {
+  CmpInst::Predicate Pred;
+  Value *Op0;
+  Value *Op1;
+
+  PreconditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
+      : Pred(Pred), Op0(Op0), Op1(Op1) {}
+};
+
 struct ConstraintTy {
   SmallVector<int64_t, 8> Coefficients;
 
@@ -53,17 +64,23 @@ struct ConstraintTy {
   unsigned size() const { return Coefficients.size(); }
 };
 
-/// Struct to manage a list of constraints.
+/// Struct to manage a list of constraints with pre-conditions that must be
+/// satisfied before using the constraints.
 struct ConstraintListTy {
   SmallVector<ConstraintTy, 4> Constraints;
+  SmallVector<PreconditionTy, 4> Preconditions;
 
   ConstraintListTy() {}
 
-  ConstraintListTy(const SmallVector<ConstraintTy, 4> &Constraints)
-      : Constraints(Constraints) {}
+  ConstraintListTy(ArrayRef<ConstraintTy> Constraints,
+                   ArrayRef<PreconditionTy> Preconditions)
+      : Constraints(Constraints.begin(), Constraints.end()),
+        Preconditions(Preconditions.begin(), Preconditions.end()) {}
 
   void mergeIn(const ConstraintListTy &Other) {
     append_range(Constraints, Other.Constraints);
+    // TODO: Do smarter merges here, e.g. exclude duplicates.
+    append_range(Preconditions, Other.Preconditions);
   }
 
   unsigned size() const { return Constraints.size(); }
@@ -84,6 +101,17 @@ struct ConstraintListTy {
   }
 
   ConstraintTy &get(unsigned I) { return Constraints[I]; }
+
+  /// Returns true if all preconditions for this list of constraints are
+  /// satisfied given \p CS and the corresponding \p Value2Index mapping.
+  bool isValid(const ConstraintSystem &CS,
+               DenseMap<Value *, unsigned> &Value2Index) const;
+  /// Returns true if there is exactly one constraint in the list and isValid is
+  /// also true.
+  bool isValidSingle(const ConstraintSystem &CS,
+                     DenseMap<Value *, unsigned> &Value2Index) const {
+    return size() == 1 && isValid(CS, Value2Index);
+  }
 };
 
 } // namespace
@@ -92,7 +120,8 @@ struct ConstraintListTy {
 // sum of the pairs equals \p V.  The first pair is the constant-factor and X
 // must be nullptr. If the expression cannot be decomposed, returns an empty
 // vector.
-static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
+static SmallVector<std::pair<int64_t, Value *>, 4>
+decompose(Value *V, SmallVector<PreconditionTy, 4> &Preconditions) {
   if (auto *CI = dyn_cast<ConstantInt>(V)) {
     if (CI->isNegative() || CI->uge(MaxConstraintValue))
       return {};
@@ -136,6 +165,10 @@ static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
       Op0 = GEP->getOperand(GEP->getNumOperands() - 1);
       Result = {{0, nullptr}, {1, GEP->getPointerOperand()}, {1, Op0}};
     }
+    // If Op0 is signed non-negative, the GEP is increasing monotonically and
+    // can be de-composed.
+    Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
+                               ConstantInt::get(Op0->getType(), 0));
     return Result;
   }
 
@@ -168,6 +201,7 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
   int64_t Offset1 = 0;
   int64_t Offset2 = 0;
 
+  SmallVector<PreconditionTy, 4> Preconditions;
   // First try to look up \p V in Value2Index and NewIndices. Otherwise add a
   // new entry to NewIndices.
   auto GetOrAddIndex = [&Value2Index, &NewIndices](Value *V) -> unsigned {
@@ -207,8 +241,10 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
   if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT)
     return {};
 
-  auto ADec = decompose(Op0->stripPointerCastsSameRepresentation());
-  auto BDec = decompose(Op1->stripPointerCastsSameRepresentation());
+  auto ADec =
+      decompose(Op0->stripPointerCastsSameRepresentation(), Preconditions);
+  auto BDec =
+      decompose(Op1->stripPointerCastsSameRepresentation(), Preconditions);
   // Skip if decomposing either of the values failed.
   if (ADec.empty() || BDec.empty())
     return {};
@@ -240,16 +276,27 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     R[GetOrAddIndex(KV.second)] -= KV.first;
 
   R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0);
-  return {{R}};
+  return {{R}, Preconditions};
 }
 
-static ConstraintListTy
-getConstraint(CmpInst *Cmp, const DenseMap<Value *, unsigned> &Value2Index,
-              DenseMap<Value *, unsigned> &NewIndices) {
+static ConstraintListTy getConstraint(CmpInst *Cmp,
+                                      DenseMap<Value *, unsigned> &Value2Index,
+                                      DenseMap<Value *, unsigned> &NewIndices) {
   return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0),
                        Cmp->getOperand(1), Value2Index, NewIndices);
 }
 
+bool ConstraintListTy::isValid(const ConstraintSystem &CS,
+                               DenseMap<Value *, unsigned> &Value2Index) const {
+  return all_of(Preconditions, [&CS, &Value2Index](const PreconditionTy &C) {
+    DenseMap<Value *, unsigned> NewIndices;
+    auto R = getConstraint(C.Pred, C.Op0, C.Op1, Value2Index, NewIndices);
+    // TODO: properly check NewIndices.
+    return NewIndices.empty() && R.Preconditions.empty() && R.size() == 1 &&
+           CS.isConditionImplied(R.get(0).Coefficients);
+  });
+}
+
 namespace {
 /// Represents either a condition that holds on entry to a block or a basic
 /// block, with their respective Dominator DFS in and out numbers.
@@ -437,10 +484,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
 
         DenseMap<Value *, unsigned> NewIndices;
         auto R = getConstraint(Cmp, Value2Index, NewIndices);
-        if (R.size() != 1)
-          continue;
 
-        if (R.needsNewIndices(NewIndices))
+        if (!R.isValidSingle(CS, Value2Index) || R.needsNewIndices(NewIndices))
           continue;
 
         if (CS.isConditionImplied(R.get(0).Coefficients)) {
@@ -503,7 +548,7 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
     // it into a constraint.
     DenseMap<Value *, unsigned> NewIndices;
     auto R = getConstraint(CB.Condition, Value2Index, NewIndices);
-    if (R.empty())
+    if (!R.isValid(CS, Value2Index))
       continue;
 
     for (auto &KV : NewIndices)
index 56e5f1a..f66c1e9 100644 (file)
@@ -85,7 +85,7 @@ define i1 @gep_constant_negative_index(i8* %dst, i8* %lower, i8* %upper) {
 ; CHECK-NEXT:    [[CMP_DST_SUB_4_LOWER:%.*]] = icmp uge i8* [[DST_SUB_4]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_DST_SUB_4_UPPER:%.*]] = icmp ult i8* [[DST_SUB_4]], [[UPPER]]
 ; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[CMP_DST_SUB_4_LOWER]]
-; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], true
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], [[CMP_DST_SUB_4_UPPER]]
 ; CHECK-NEXT:    [[DST_SUB_5:%.*]] = getelementptr inbounds i8, i8* [[DST]], i64 -5
 ; CHECK-NEXT:    [[CMP_DST_SUB_5_LOWER:%.*]] = icmp uge i8* [[DST_SUB_5]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_DST_SUB_5_UPPER:%.*]] = icmp ult i8* [[DST_SUB_5]], [[UPPER]]
@@ -259,7 +259,7 @@ define i4 @ptr_N_signed_positive_explicit_check_constant_step(i8* %src, i8* %low
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i16 1
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
@@ -374,7 +374,7 @@ define i4 @ptr_N_and_step_signed_positive_explicit_check_constant_step(i8* %src,
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i16 1
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
@@ -435,7 +435,7 @@ define i4 @ptr_N_and_step_signed_positive_unsigned_checks_only(i8* %src, i8* %lo
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i16 1
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
@@ -545,7 +545,7 @@ define i4 @ptr_N_could_be_negative(i8* %src, i8* %lower, i8* %upper, i8 %N, i8 %
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[STEP]]
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
@@ -652,7 +652,7 @@ define i4 @inc_ptr_N_could_be_negative(i8* %src, i8* %lower, i8* %upper, i8 %N,
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[STEP]]
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
@@ -912,7 +912,7 @@ define i4 @ptr_N_signed_positive_assume(i8* %src, i8* %lower, i8* %upper, i16 %N
 ; CHECK-NEXT:    [[SRC_STEP:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i16 [[STEP]]
 ; CHECK-NEXT:    [[CMP_STEP_START:%.*]] = icmp ult i8* [[SRC_STEP]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_STEP_END:%.*]] = icmp uge i8* [[SRC_STEP]], [[UPPER]]
-; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_CHECK:%.*]] = or i1 [[CMP_STEP_START]], [[CMP_STEP_END]]
 ; CHECK-NEXT:    br i1 [[OR_CHECK]], label [[TRAP_BB]], label [[EXIT]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret i4 3
index 4ac15ac..54aef43 100644 (file)
@@ -480,7 +480,7 @@ define void @test.not.uge.uge.nonconst(i8* %start, i8* %low, i8* %high, i8 %off)
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[START_OFF_2:%.*]] = getelementptr inbounds i8, i8* [[START]], i8 [[OFF]]
 ; CHECK-NEXT:    [[T_0:%.*]] = icmp uge i8* [[START_OFF_2]], [[HIGH]]
-; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 [[T_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.end:
 ; CHECK-NEXT:    [[START_1:%.*]] = getelementptr inbounds i8, i8* [[START]], i64 1
@@ -488,7 +488,7 @@ define void @test.not.uge.uge.nonconst(i8* %start, i8* %low, i8* %high, i8 %off)
 ; CHECK-NEXT:    call void @use(i1 [[C_0]])
 ; CHECK-NEXT:    [[START_OFF:%.*]] = getelementptr inbounds i8, i8* [[START]], i8 [[OFF]]
 ; CHECK-NEXT:    [[F_0:%.*]] = icmp uge i8* [[START_OFF]], [[HIGH]]
-; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 [[F_0]])
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -531,7 +531,7 @@ define void @test.ult.gep.shl(i32* readonly %src, i32* readnone %max, i8 %idx) {
 ; CHECK-NEXT:    [[IDX_SHL_1:%.*]] = shl nuw i8 [[IDX]], 1
 ; CHECK-NEXT:    [[ADD_PTR_SHL_1:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i8 [[IDX_SHL_1]]
 ; CHECK-NEXT:    [[C_MAX_0:%.*]] = icmp ult i32* [[ADD_PTR_SHL_1]], [[MAX]]
-; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 [[C_MAX_0]])
 ; CHECK-NEXT:    [[IDX_SHL_2:%.*]] = shl nuw i8 [[IDX]], 2
 ; CHECK-NEXT:    [[ADD_PTR_SHL_2:%.*]] = getelementptr inbounds i32, i32* [[SRC]], i8 [[IDX_SHL_2]]
 ; CHECK-NEXT:    [[C_MAX_1:%.*]] = icmp ult i32* [[ADD_PTR_SHL_2]], [[MAX]]
index db9113d..8ea8824 100644 (file)
@@ -13,16 +13,16 @@ define void @test(i64 %x, i8* %y, i8* %z, i8* %w) {
 ; CHECK:       bb28:
 ; CHECK-NEXT:    [[TMP29:%.*]] = getelementptr inbounds i8, i8* [[Y]], i64 [[X]]
 ; CHECK-NEXT:    [[TMP30:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
-; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB32:%.*]]
+; CHECK-NEXT:    br i1 [[TMP30]], label [[EARLY_EXIT]], label [[BB32:%.*]]
 ; CHECK:       bb32:
 ; CHECK-NEXT:    [[TMP33:%.*]] = icmp ult i8* [[TMP29]], [[Z]]
-; CHECK-NEXT:    br i1 true, label [[BB35:%.*]], label [[EARLY_EXIT]]
+; CHECK-NEXT:    br i1 [[TMP33]], label [[BB35:%.*]], label [[EARLY_EXIT]]
 ; CHECK:       bb35:
 ; CHECK-NEXT:    [[TMP36:%.*]] = icmp ult i8* [[Y]], [[Z]]
-; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB38:%.*]]
+; CHECK-NEXT:    br i1 [[TMP36]], label [[EARLY_EXIT]], label [[BB38:%.*]]
 ; CHECK:       bb38:
 ; CHECK-NEXT:    [[TMP41:%.*]] = icmp ult i8* [[Y]], [[Z]]
-; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB43:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EARLY_EXIT]], label [[BB43:%.*]]
 ; CHECK:       bb43:
 ; CHECK-NEXT:    [[TMP47:%.*]] = getelementptr inbounds i8, i8* [[W:%.*]], i64 [[X]]
 ; CHECK-NEXT:    [[TMP48:%.*]] = icmp ult i8* [[TMP47]], [[Y]]
@@ -30,10 +30,10 @@ define void @test(i64 %x, i8* %y, i8* %z, i8* %w) {
 ; CHECK:       bb50:
 ; CHECK-NEXT:    [[TMP52:%.*]] = getelementptr inbounds i8, i8* [[W]], i64 [[X]]
 ; CHECK-NEXT:    [[TMP53:%.*]] = icmp ult i8* [[TMP52]], [[Y]]
-; CHECK-NEXT:    br i1 true, label [[EARLY_EXIT]], label [[BB55:%.*]]
+; CHECK-NEXT:    br i1 [[TMP53]], label [[EARLY_EXIT]], label [[BB55:%.*]]
 ; CHECK:       bb55:
 ; CHECK-NEXT:    [[TMP57:%.*]] = icmp ult i8* [[W]], [[Y]]
-; CHECK-NEXT:    br i1 true, label [[BB59:%.*]], label [[EARLY_EXIT]]
+; CHECK-NEXT:    br i1 [[TMP57]], label [[BB59:%.*]], label [[EARLY_EXIT]]
 ; CHECK:       bb59:
 ; CHECK-NEXT:    [[TMP60:%.*]] = icmp ult i8* [[W]], [[Y]]
 ; CHECK-NEXT:    call void @use(i1 true)
index ca03cee..d1e7d6d 100644 (file)
@@ -94,7 +94,7 @@ define void @some_checks_in_loops_removable(i8* %ptr, i8* %lower, i8* %upper, i8
 ; CHECK-NEXT:    [[PTR_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV_1]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV_1]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV_1]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_PTR_IV_1_UPPER]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_PTR_IV_1_LOWER]], [[CMP_PTR_IV_1_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    store i8 0, i8* [[PTR_IV]], align 4
@@ -173,7 +173,7 @@ define void @no_checks_in_loops_removable(i8* %ptr, i8* %lower, i8* %upper, i8 %
 ; CHECK-NEXT:    [[PTR_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[IV_1]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[PTR_IV_1]]
 ; CHECK-NEXT:    [[CMP_PTR_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[PTR_IV_1]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_PTR_IV_1_UPPER]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_PTR_IV_1_LOWER]], [[CMP_PTR_IV_1_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[TRAP]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    store i8 0, i8* [[PTR_IV]], align 4
index e7f248b..ba15c60 100644 (file)
@@ -21,7 +21,7 @@ define void @test1(i8* %src, i8* noundef %lower, i8* noundef %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[IV]]
 ; CHECK-NEXT:    [[CMP_IV_START:%.*]] = icmp ult i8* [[SRC_IV]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_END:%.*]] = icmp uge i8* [[SRC_IV]], [[UPPER]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_IV_START]], false
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_IV_START]], [[CMP_IV_END]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
 ; CHECK:       loop.body.1:
 ; CHECK-NEXT:    [[PTR_SRC_IV:%.*]] = bitcast i8* [[SRC_IV]] to i32*
@@ -30,7 +30,7 @@ define void @test1(i8* %src, i8* noundef %lower, i8* noundef %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV_1:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_START:%.*]] = icmp ult i8* [[SRC_IV_1]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_1_END:%.*]] = icmp uge i8* [[SRC_IV_1]], [[UPPER]]
-; CHECK-NEXT:    [[OR_2:%.*]] = or i1 false, false
+; CHECK-NEXT:    [[OR_2:%.*]] = or i1 [[CMP_IV_1_START]], [[CMP_IV_1_END]]
 ; CHECK-NEXT:    br i1 [[OR_2]], label [[TRAP_BB]], label [[LOOP_BODY_2:%.*]]
 ; CHECK:       loop.body.2:
 ; CHECK-NEXT:    [[PTR_SRC_IV_1:%.*]] = bitcast i8* [[SRC_IV_1]] to i32*
@@ -39,7 +39,7 @@ define void @test1(i8* %src, i8* noundef %lower, i8* noundef %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV_2:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_2]]
 ; CHECK-NEXT:    [[CMP_IV_2_START:%.*]] = icmp ult i8* [[SRC_IV_2]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_2_END:%.*]] = icmp uge i8* [[SRC_IV_2]], [[UPPER]]
-; CHECK-NEXT:    [[OR_3:%.*]] = or i1 false, [[CMP_IV_2_END]]
+; CHECK-NEXT:    [[OR_3:%.*]] = or i1 [[CMP_IV_2_START]], [[CMP_IV_2_END]]
 ; CHECK-NEXT:    br i1 [[OR_3]], label [[TRAP_BB]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[PTR_SRC_IV_2:%.*]] = bitcast i8* [[SRC_IV_2]] to i32*
@@ -130,14 +130,14 @@ define void @test2(i8* %src, i8* %lower, i8* %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV_1:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_START:%.*]] = icmp ult i8* [[SRC_IV_1]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_1_END:%.*]] = icmp uge i8* [[SRC_IV_1]], [[UPPER]]
-; CHECK-NEXT:    [[OR_2:%.*]] = or i1 false, [[CMP_IV_1_END]]
+; CHECK-NEXT:    [[OR_2:%.*]] = or i1 [[CMP_IV_1_START]], [[CMP_IV_1_END]]
 ; CHECK-NEXT:    br i1 [[OR_2]], label [[TRAP_BB]], label [[LOOP_BODY_2:%.*]]
 ; CHECK:       loop.body.2:
 ; CHECK-NEXT:    [[ADD_2:%.*]] = add nuw nsw i8 [[IV]], 2
 ; CHECK-NEXT:    [[SRC_IV_2:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_2]]
 ; CHECK-NEXT:    [[CMP_IV_2_START:%.*]] = icmp ult i8* [[SRC_IV_2]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_2_END:%.*]] = icmp uge i8* [[SRC_IV_2]], [[UPPER]]
-; CHECK-NEXT:    [[OR_3:%.*]] = or i1 false, [[CMP_IV_2_END]]
+; CHECK-NEXT:    [[OR_3:%.*]] = or i1 [[CMP_IV_2_START]], [[CMP_IV_2_END]]
 ; CHECK-NEXT:    br i1 [[OR_3]], label [[TRAP_BB]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[PTR:%.*]] = bitcast i8* [[SRC_IV]] to i32*
@@ -226,14 +226,14 @@ define void @test2_with_ne(i8* %src, i8* %lower, i8* %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV_1:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_START:%.*]] = icmp ult i8* [[SRC_IV_1]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_1_END:%.*]] = icmp uge i8* [[SRC_IV_1]], [[UPPER]]
-; CHECK-NEXT:    [[OR_2:%.*]] = or i1 false, [[CMP_IV_1_END]]
+; CHECK-NEXT:    [[OR_2:%.*]] = or i1 [[CMP_IV_1_START]], [[CMP_IV_1_END]]
 ; CHECK-NEXT:    br i1 [[OR_2]], label [[TRAP_BB]], label [[LOOP_BODY_2:%.*]]
 ; CHECK:       loop.body.2:
 ; CHECK-NEXT:    [[ADD_2:%.*]] = add nuw nsw i8 [[IV]], 2
 ; CHECK-NEXT:    [[SRC_IV_2:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_2]]
 ; CHECK-NEXT:    [[CMP_IV_2_START:%.*]] = icmp ult i8* [[SRC_IV_2]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_2_END:%.*]] = icmp uge i8* [[SRC_IV_2]], [[UPPER]]
-; CHECK-NEXT:    [[OR_3:%.*]] = or i1 false, [[CMP_IV_2_END]]
+; CHECK-NEXT:    [[OR_3:%.*]] = or i1 [[CMP_IV_2_START]], [[CMP_IV_2_END]]
 ; CHECK-NEXT:    br i1 [[OR_3]], label [[TRAP_BB]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[PTR:%.*]] = bitcast i8* [[SRC_IV]] to i32*
@@ -329,7 +329,7 @@ define void @test3(i8* %src, i8* %lower, i8* %upper, i8 %N) {
 ; CHECK-NEXT:    [[SRC_IV_2:%.*]] = getelementptr inbounds i8, i8* [[SRC]], i8 [[ADD_2]]
 ; CHECK-NEXT:    [[CMP_IV_2_START:%.*]] = icmp ult i8* [[SRC_IV_2]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_2_END:%.*]] = icmp uge i8* [[SRC_IV_2]], [[UPPER]]
-; CHECK-NEXT:    [[OR_3:%.*]] = or i1 false, [[CMP_IV_2_END]]
+; CHECK-NEXT:    [[OR_3:%.*]] = or i1 [[CMP_IV_2_START]], [[CMP_IV_2_END]]
 ; CHECK-NEXT:    br i1 [[OR_3]], label [[TRAP_BB]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[PTR:%.*]] = bitcast i8* [[SRC_IV]] to i32*
@@ -418,7 +418,7 @@ define void @ne_check_in_loop_no_zext_n_may_be_negative(i8* %ptr, i8* %lower, i8
 ; CHECK-NEXT:    [[GEP_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[ADD]]
 ; CHECK-NEXT:    [[CMP_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[GEP_IV_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[GEP_IV_1]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_1_UPPER]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_IV_1_LOWER]], [[CMP_IV_1_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP]], label [[FOR_LATCH]]
 ; CHECK:       for.latch:
 ; CHECK-NEXT:    store i8 0, i8* [[GEP_IV]], align 4
@@ -502,7 +502,7 @@ define void @ne_check_in_loop_no_zext_n_positive_check(i8* %ptr, i8* %lower, i8*
 ; CHECK-NEXT:    [[GEP_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[ADD]]
 ; CHECK-NEXT:    [[CMP_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[GEP_IV_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[GEP_IV_1]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_1_UPPER]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_IV_1_LOWER]], [[CMP_IV_1_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP]], label [[FOR_LATCH]]
 ; CHECK:       for.latch:
 ; CHECK-NEXT:    store i8 0, i8* [[GEP_IV]], align 4
@@ -588,7 +588,7 @@ define void @ne_check_in_loop_with_zext(i8* %ptr, i8* %lower, i8* %upper, i8 %n)
 ; CHECK-NEXT:    [[GEP_IV_1:%.*]] = getelementptr inbounds i8, i8* [[PTR]], i16 [[ADD]]
 ; CHECK-NEXT:    [[CMP_IV_1_LOWER:%.*]] = icmp ugt i8* [[LOWER]], [[GEP_IV_1]]
 ; CHECK-NEXT:    [[CMP_IV_1_UPPER:%.*]] = icmp ule i8* [[UPPER]], [[GEP_IV_1]]
-; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_1_UPPER]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 [[CMP_IV_1_LOWER]], [[CMP_IV_1_UPPER]]
 ; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP]], label [[FOR_LATCH]]
 ; CHECK:       for.latch:
 ; CHECK-NEXT:    store i8 0, i8* [[GEP_IV]], align 4