[ConstraintElim] Skip decomposition if precondition does not hold. (#212140)
Currently we fully decompose expressions, collect all preconditions and then bail out if any precondition is false. This means we miss out on simplifications in cases where the precondition does not hold, but we could still reason about the un-decomposed sub-expression. This patch updates `decompose` to take the constraint system as argument instead and eagerly check preconditions. If the precondition does not hold, we don't decompose the sub-expression and don't further recurse, but simply treat the sub-expression as variable. This improves results in some cases (https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/794) and is also slightly cheaper (or neutral) in most cases compile-time wise, as we cut off decomposition before recursing further. The number of queries for preconditions overall should stay the same PR: https://github.com/llvm/llvm-project/pull/212140
This commit is contained in:
parent
be2e6bc89a
commit
4fbefd6025
5 changed files with 82 additions and 101 deletions
|
|
@ -213,7 +213,6 @@ struct StackEntry {
|
|||
|
||||
struct ConstraintTy {
|
||||
SmallVector<int64_t, 8> Coefficients;
|
||||
SmallVector<ConditionTy, 2> Preconditions;
|
||||
|
||||
bool IsSigned = false;
|
||||
|
||||
|
|
@ -228,10 +227,6 @@ struct ConstraintTy {
|
|||
|
||||
unsigned empty() const { return Coefficients.empty(); }
|
||||
|
||||
/// Returns true if all preconditions for this list of constraints are
|
||||
/// satisfied given \p Info.
|
||||
bool isValid(const ConstraintInfo &Info) const;
|
||||
|
||||
bool isEq() const { return IsEq; }
|
||||
|
||||
bool isNe() const { return IsNe; }
|
||||
|
|
@ -438,8 +433,7 @@ static OffsetResult collectOffsets(GEPOperator &GEP, const DataLayout &DL) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
static Decomposition decompose(Value *V,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
static Decomposition decompose(Value *V, const ConstraintInfo &Info,
|
||||
bool IsSigned, const DataLayout &DL);
|
||||
|
||||
static bool canUseSExt(ConstantInt *CI) {
|
||||
|
|
@ -447,8 +441,14 @@ static bool canUseSExt(ConstantInt *CI) {
|
|||
return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);
|
||||
}
|
||||
|
||||
static Decomposition decomposeGEP(GEPOperator &GEP,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
/// Returns true if the pre-condition \p Op \p Pred \p RHS, required to look
|
||||
/// through an expression while decomposing it, is known to hold given \p Info.
|
||||
static bool preconditionHolds(const ConstraintInfo &Info,
|
||||
CmpInst::Predicate Pred, Value *Op, int64_t RHS) {
|
||||
return Info.doesHold(Pred, Op, ConstantInt::get(Op->getType(), RHS));
|
||||
}
|
||||
|
||||
static Decomposition decomposeGEP(GEPOperator &GEP, const ConstraintInfo &Info,
|
||||
bool IsSigned, const DataLayout &DL) {
|
||||
// Do not reason about pointers where the index size is larger than 64 bits,
|
||||
// as the coefficients used to encode constraints are 64 bit integers.
|
||||
|
|
@ -471,19 +471,20 @@ static Decomposition decomposeGEP(GEPOperator &GEP,
|
|||
|
||||
Decomposition Result(ConstantOffset.getSExtValue(), DecompEntry(1, BasePtr));
|
||||
for (auto [Index, Scale] : VariableOffsets) {
|
||||
auto IdxResult = decompose(Index, Preconditions, IsSigned, DL);
|
||||
if (!NW.hasNoUnsignedWrap()) {
|
||||
// Try to prove nuw from nusw and nneg. If the index cannot be proven
|
||||
// non-negative, keep the GEP as-is instead of decomposing it.
|
||||
assert(NW.hasNoUnsignedSignedWrap() && "Must have nusw flag");
|
||||
if (!isKnownNonNegative(Index, DL) &&
|
||||
!preconditionHolds(Info, CmpInst::ICMP_SGE, Index, 0))
|
||||
return &GEP;
|
||||
}
|
||||
|
||||
auto IdxResult = decompose(Index, Info, IsSigned, DL);
|
||||
if (IdxResult.mul(Scale.getSExtValue()))
|
||||
return &GEP;
|
||||
if (Result.add(IdxResult))
|
||||
return &GEP;
|
||||
|
||||
if (!NW.hasNoUnsignedWrap()) {
|
||||
// Try to prove nuw from nusw and nneg.
|
||||
assert(NW.hasNoUnsignedSignedWrap() && "Must have nusw flag");
|
||||
if (!isKnownNonNegative(Index, DL))
|
||||
Preconditions.emplace_back(CmpInst::ICMP_SGE, Index,
|
||||
ConstantInt::get(Index->getType(), 0));
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
|
@ -491,15 +492,16 @@ static Decomposition decomposeGEP(GEPOperator &GEP,
|
|||
// Decomposes \p V into a constant offset + list of pairs { Coefficient,
|
||||
// Variable } where Coefficient * Variable. The sum of the constant offset and
|
||||
// pairs equals \p V.
|
||||
static Decomposition decompose(Value *V,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
//
|
||||
// Looking through certain expressions is only valid if a pre-condition holds.
|
||||
// Pre-conditions are checked against \p Info as needed.
|
||||
static Decomposition decompose(Value *V, const ConstraintInfo &Info,
|
||||
bool IsSigned, const DataLayout &DL) {
|
||||
|
||||
auto MergeResults = [&Preconditions, IsSigned,
|
||||
auto MergeResults = [&Info, IsSigned,
|
||||
&DL](Value *A, Value *B,
|
||||
bool IsSignedB) -> std::optional<Decomposition> {
|
||||
auto ResA = decompose(A, Preconditions, IsSigned, DL);
|
||||
auto ResB = decompose(B, Preconditions, IsSignedB, DL);
|
||||
auto ResA = decompose(A, Info, IsSigned, DL);
|
||||
auto ResB = decompose(B, Info, IsSignedB, DL);
|
||||
if (ResA.add(ResB))
|
||||
return std::nullopt;
|
||||
return ResA;
|
||||
|
|
@ -508,7 +510,7 @@ static Decomposition decompose(Value *V,
|
|||
Type *Ty = V->getType()->getScalarType();
|
||||
if (Ty->isPointerTy() && !IsSigned) {
|
||||
if (auto *GEP = dyn_cast<GEPOperator>(V))
|
||||
return decomposeGEP(*GEP, Preconditions, IsSigned, DL);
|
||||
return decomposeGEP(*GEP, Info, IsSigned, DL);
|
||||
if (isa<ConstantPointerNull>(V))
|
||||
return int64_t(0);
|
||||
|
||||
|
|
@ -546,8 +548,8 @@ static Decomposition decompose(Value *V,
|
|||
}
|
||||
|
||||
if (match(V, m_NSWSub(m_Value(Op0), m_Value(Op1)))) {
|
||||
auto ResA = decompose(Op0, Preconditions, IsSigned, DL);
|
||||
auto ResB = decompose(Op1, Preconditions, IsSigned, DL);
|
||||
auto ResA = decompose(Op0, Info, IsSigned, DL);
|
||||
auto ResB = decompose(Op1, Info, IsSigned, DL);
|
||||
if (!ResA.sub(ResB))
|
||||
return ResA;
|
||||
return V;
|
||||
|
|
@ -555,7 +557,7 @@ static Decomposition decompose(Value *V,
|
|||
|
||||
ConstantInt *CI;
|
||||
if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) {
|
||||
auto Result = decompose(Op0, Preconditions, IsSigned, DL);
|
||||
auto Result = decompose(Op0, Info, IsSigned, DL);
|
||||
if (!Result.mul(CI->getSExtValue()))
|
||||
return Result;
|
||||
return V;
|
||||
|
|
@ -567,7 +569,7 @@ static Decomposition decompose(Value *V,
|
|||
uint64_t Shift = CI->getValue().getLimitedValue();
|
||||
if (Shift < Ty->getIntegerBitWidth() - 1) {
|
||||
assert(Shift < 64 && "Would overflow");
|
||||
auto Result = decompose(Op0, Preconditions, IsSigned, DL);
|
||||
auto Result = decompose(Op0, Info, IsSigned, DL);
|
||||
if (!Result.mul(int64_t(1) << Shift))
|
||||
return Result;
|
||||
return V;
|
||||
|
|
@ -587,17 +589,20 @@ static Decomposition decompose(Value *V,
|
|||
if (match(V, m_ZExt(m_Value(Op0)))) {
|
||||
V = Op0;
|
||||
} else if (match(V, m_SExt(m_Value(Op0)))) {
|
||||
// Looking through the sext is only valid if the operand is non-negative.
|
||||
if (!preconditionHolds(Info, CmpInst::ICMP_SGE, Op0, 0))
|
||||
return V;
|
||||
V = Op0;
|
||||
Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
|
||||
ConstantInt::get(Op0->getType(), 0));
|
||||
} else if (auto *Trunc = dyn_cast<TruncInst>(V)) {
|
||||
if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64) {
|
||||
if (Trunc->hasNoUnsignedWrap() || Trunc->hasNoSignedWrap()) {
|
||||
V = Trunc->getOperand(0);
|
||||
if (!Trunc->hasNoUnsignedWrap())
|
||||
Preconditions.emplace_back(CmpInst::ICMP_SGE, V,
|
||||
ConstantInt::get(V->getType(), 0));
|
||||
}
|
||||
if (Trunc->getSrcTy()->getScalarSizeInBits() <= 64 &&
|
||||
(Trunc->hasNoUnsignedWrap() || Trunc->hasNoSignedWrap())) {
|
||||
Value *Src = Trunc->getOperand(0);
|
||||
// A trunc nsw only truncates without unsigned wrap if its operand is
|
||||
// non-negative.
|
||||
if (!Trunc->hasNoUnsignedWrap() &&
|
||||
!preconditionHolds(Info, CmpInst::ICMP_SGE, Src, 0))
|
||||
return V;
|
||||
V = Src;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -611,21 +616,23 @@ static Decomposition decompose(Value *V,
|
|||
|
||||
if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&
|
||||
canUseSExt(CI)) {
|
||||
Preconditions.emplace_back(
|
||||
CmpInst::ICMP_UGE, Op0,
|
||||
ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));
|
||||
// Adding a negative constant only wraps if Op0 is smaller than it.
|
||||
if (!preconditionHolds(Info, CmpInst::ICMP_UGE, Op0,
|
||||
CI->getSExtValue() * -1))
|
||||
return V;
|
||||
if (auto Decomp = MergeResults(Op0, CI, true))
|
||||
return *Decomp;
|
||||
return V;
|
||||
}
|
||||
|
||||
if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
|
||||
if (!isKnownNonNegative(Op0, DL))
|
||||
Preconditions.emplace_back(CmpInst::ICMP_SGE, Op0,
|
||||
ConstantInt::get(Op0->getType(), 0));
|
||||
if (!isKnownNonNegative(Op1, DL))
|
||||
Preconditions.emplace_back(CmpInst::ICMP_SGE, Op1,
|
||||
ConstantInt::get(Op1->getType(), 0));
|
||||
// An add nsw only adds without unsigned wrap if both operands are
|
||||
// non-negative.
|
||||
if ((!isKnownNonNegative(Op0, DL) &&
|
||||
!preconditionHolds(Info, CmpInst::ICMP_SGE, Op0, 0)) ||
|
||||
(!isKnownNonNegative(Op1, DL) &&
|
||||
!preconditionHolds(Info, CmpInst::ICMP_SGE, Op1, 0)))
|
||||
return V;
|
||||
|
||||
if (auto Decomp = MergeResults(Op0, Op1, IsSigned))
|
||||
return *Decomp;
|
||||
|
|
@ -642,7 +649,7 @@ static Decomposition decompose(Value *V,
|
|||
if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
|
||||
if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
|
||||
return V;
|
||||
auto Result = decompose(Op1, Preconditions, IsSigned, DL);
|
||||
auto Result = decompose(Op1, Info, IsSigned, DL);
|
||||
if (!Result.mul(int64_t{1} << CI->getSExtValue()))
|
||||
return Result;
|
||||
return V;
|
||||
|
|
@ -650,15 +657,15 @@ static Decomposition decompose(Value *V,
|
|||
|
||||
if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&
|
||||
(!CI->isNegative())) {
|
||||
auto Result = decompose(Op1, Preconditions, IsSigned, DL);
|
||||
auto Result = decompose(Op1, Info, IsSigned, DL);
|
||||
if (!Result.mul(CI->getSExtValue()))
|
||||
return Result;
|
||||
return V;
|
||||
}
|
||||
|
||||
if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) {
|
||||
auto ResA = decompose(Op0, Preconditions, IsSigned, DL);
|
||||
auto ResB = decompose(Op1, Preconditions, IsSigned, DL);
|
||||
auto ResA = decompose(Op0, Info, IsSigned, DL);
|
||||
auto ResB = decompose(Op1, Info, IsSigned, DL);
|
||||
if (!ResA.sub(ResB))
|
||||
return ResA;
|
||||
return V;
|
||||
|
|
@ -713,13 +720,12 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
|
|||
Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
|
||||
return {};
|
||||
|
||||
SmallVector<ConditionTy, 4> Preconditions;
|
||||
bool IsSigned = ForceSignedSystem || CmpInst::isSigned(Pred);
|
||||
auto &Value2Index = getValue2Index(IsSigned);
|
||||
auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
|
||||
Preconditions, IsSigned, DL);
|
||||
auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(),
|
||||
Preconditions, IsSigned, DL);
|
||||
auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(), *this,
|
||||
IsSigned, DL);
|
||||
auto BDec = decompose(Op1->stripPointerCastsSameRepresentation(), *this,
|
||||
IsSigned, DL);
|
||||
int64_t Offset1 = ADec.Offset;
|
||||
int64_t Offset2 = BDec.Offset;
|
||||
Offset1 *= -1;
|
||||
|
|
@ -768,7 +774,6 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
|
|||
if (AddOverflow(OffsetSum, int64_t(-1), OffsetSum))
|
||||
return {};
|
||||
R[0] = OffsetSum;
|
||||
Res.Preconditions = std::move(Preconditions);
|
||||
|
||||
// Remove any (Coefficient, Variable) entry where the Coefficient is 0 for new
|
||||
// variables.
|
||||
|
|
@ -813,13 +818,6 @@ ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
|
|||
return R;
|
||||
}
|
||||
|
||||
bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
|
||||
return Coefficients.size() > 0 &&
|
||||
all_of(Preconditions, [&Info](const ConditionTy &C) {
|
||||
return Info.doesHold(C.Pred, C.Op0, C.Op1);
|
||||
});
|
||||
}
|
||||
|
||||
std::optional<bool>
|
||||
ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {
|
||||
const auto &[SubCS, NewCoefficients] = CS.getSubSystem(Coefficients);
|
||||
|
|
@ -869,7 +867,7 @@ ConstraintTy::isImpliedBy(const ConstraintSystem &CS) const {
|
|||
bool ConstraintInfo::doesHold(CmpInst::Predicate Pred, Value *A,
|
||||
Value *B) const {
|
||||
auto R = getConstraintForSolving(Pred, A, B);
|
||||
return R.isValid(*this) &&
|
||||
return !R.empty() &&
|
||||
getCS(R.IsSigned).isConditionImpliedInSubSystem(R.Coefficients);
|
||||
}
|
||||
|
||||
|
|
@ -1533,7 +1531,7 @@ static std::optional<bool> checkCondition(CmpInst::Predicate Pred, Value *A,
|
|||
LLVM_DEBUG(dbgs() << "Checking " << *CheckInst << "\n");
|
||||
|
||||
auto TryWithConstraint = [&](const ConstraintTy &R) -> std::optional<bool> {
|
||||
if (R.empty() || !R.isValid(Info)) {
|
||||
if (R.empty()) {
|
||||
LLVM_DEBUG(dbgs() << " failed to decompose condition\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
@ -1784,13 +1782,11 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
|
|||
unsigned NumIn, unsigned NumOut,
|
||||
SmallVectorImpl<StackEntry> &DFSInStack,
|
||||
bool ForceSignedSystem) {
|
||||
// If the constraint has a pre-condition, skip the constraint if it does not
|
||||
// hold.
|
||||
SmallVector<Value *> NewVariables;
|
||||
auto R = getConstraint(Pred, A, B, NewVariables, ForceSignedSystem);
|
||||
|
||||
// TODO: Support non-equality for facts as well.
|
||||
if (!R.isValid(*this) || R.isNe())
|
||||
if (R.empty() || R.isNe())
|
||||
return;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Adding '"; dumpUnpackedICmp(dbgs(), Pred, A, B);
|
||||
|
|
@ -1882,7 +1878,7 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
|
|||
auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,
|
||||
ConstraintInfo &Info) {
|
||||
auto R = Info.getConstraintForSolving(Pred, A, B);
|
||||
if (R.size() < 2 || !R.isValid(Info))
|
||||
if (R.size() < 2)
|
||||
return false;
|
||||
|
||||
auto &CSToUse = Info.getCS(R.IsSigned);
|
||||
|
|
|
|||
|
|
@ -177,10 +177,9 @@ define i1 @postinc_negative_step(i1 %c) {
|
|||
; CHECK-NEXT: [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], 0
|
||||
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
|
||||
; CHECK: [[LOOP_LATCH]]:
|
||||
; CHECK-NEXT: [[RES:%.*]] = icmp ugt i64 [[IV_NEXT]], 0
|
||||
; CHECK-NEXT: br i1 [[C]], label %[[EXIT_0:.*]], label %[[LOOP_HEADER]]
|
||||
; CHECK: [[EXIT_0]]:
|
||||
; CHECK-NEXT: ret i1 [[RES]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret i1 false
|
||||
;
|
||||
|
|
|
|||
|
|
@ -15,13 +15,11 @@ define void @test(i64 %x, ptr %y, ptr %z, ptr %w) {
|
|||
; CHECK-NEXT: [[TMP30:%.*]] = icmp ult ptr [[TMP29]], [[Z]]
|
||||
; CHECK-NEXT: br i1 [[TMP30]], label [[EARLY_EXIT]], label [[BB32:%.*]]
|
||||
; CHECK: bb32:
|
||||
; CHECK-NEXT: [[TMP33:%.*]] = icmp ult ptr [[TMP29]], [[Z]]
|
||||
; CHECK-NEXT: br i1 [[TMP33]], label [[BB35:%.*]], label [[EARLY_EXIT]]
|
||||
; CHECK-NEXT: br i1 false, label [[BB35:%.*]], label [[EARLY_EXIT]]
|
||||
; CHECK: bb35:
|
||||
; CHECK-NEXT: [[TMP36:%.*]] = icmp ult ptr [[Y]], [[Z]]
|
||||
; CHECK-NEXT: br i1 [[TMP36]], label [[EARLY_EXIT]], label [[BB38:%.*]]
|
||||
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB38:%.*]]
|
||||
; CHECK: bb38:
|
||||
; CHECK-NEXT: br i1 false, label [[EARLY_EXIT]], label [[BB43:%.*]]
|
||||
; CHECK-NEXT: br i1 true, label [[EARLY_EXIT]], label [[BB43:%.*]]
|
||||
; CHECK: bb43:
|
||||
; CHECK-NEXT: [[TMP47:%.*]] = getelementptr inbounds i8, ptr [[W:%.*]], i64 [[X]]
|
||||
; CHECK-NEXT: [[TMP48:%.*]] = icmp ult ptr [[TMP47]], [[Y]]
|
||||
|
|
@ -31,8 +29,7 @@ define void @test(i64 %x, ptr %y, ptr %z, ptr %w) {
|
|||
; CHECK-NEXT: [[TMP53:%.*]] = icmp ult ptr [[TMP52]], [[Y]]
|
||||
; CHECK-NEXT: br i1 [[TMP53]], label [[EARLY_EXIT]], label [[BB55:%.*]]
|
||||
; CHECK: bb55:
|
||||
; CHECK-NEXT: [[TMP57:%.*]] = icmp ult ptr [[W]], [[Y]]
|
||||
; CHECK-NEXT: br i1 [[TMP57]], label [[BB59:%.*]], label [[EARLY_EXIT]]
|
||||
; CHECK-NEXT: br i1 true, label [[BB59:%.*]], label [[EARLY_EXIT]]
|
||||
; CHECK: bb59:
|
||||
; CHECK-NEXT: call void @use(i1 true)
|
||||
; CHECK-NEXT: ret void
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ define i1 @precondition_unknown_operand_used_as_is(i16 %x, i16 %y, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[X]], [[Y]]
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp uge i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i16 %x, %y
|
||||
|
|
@ -57,8 +56,7 @@ define void @constants_folded_for_opaque_operand(i16 %x, i16 %y) {
|
|||
; CHECK-NEXT: [[C:%.*]] = icmp ult i16 [[ADD]], 100
|
||||
; CHECK-NEXT: br i1 [[C]], label %[[THEN:.*]], label %[[EXIT:.*]]
|
||||
; CHECK: [[THEN]]:
|
||||
; CHECK-NEXT: [[T_1:%.*]] = icmp ult i16 [[ADD]], 200
|
||||
; CHECK-NEXT: call void @use(i1 [[T_1]])
|
||||
; CHECK-NEXT: call void @use(i1 true)
|
||||
; CHECK-NEXT: [[T_2:%.*]] = icmp ult i16 [[ADD]], 50
|
||||
; CHECK-NEXT: call void @use(i1 [[T_2]])
|
||||
; CHECK-NEXT: ret void
|
||||
|
|
@ -92,8 +90,7 @@ define i1 @outer_offset_retained(i16 %x, i16 %y, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD_3:%.*]] = add nuw i16 [[ADD]], 3
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i16 [[ADD_3]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i16 %x, %y
|
||||
|
|
@ -115,8 +112,7 @@ define i1 @outer_offset_retained_nested(i16 %x, i16 %y, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD_8:%.*]] = add nuw i16 [[ADD_3]], 5
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp uge i16 [[Z]], [[ADD_8]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i16 [[Z]], [[ADD]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i16 %x, %y
|
||||
|
|
@ -138,8 +134,7 @@ define i1 @fact_partially_decomposed(i16 %x, i16 %y, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD_10:%.*]] = add nuw i16 [[ADD]], 10
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ule i16 [[ADD_10]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ule i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i16 %x, %y
|
||||
|
|
@ -160,8 +155,7 @@ define i1 @sext_operand_used_as_is(i16 %x, i32 %z) {
|
|||
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[EXT]], 4
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i32 [[EXT]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i32 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%ext = sext i16 %x to i32
|
||||
|
|
@ -181,8 +175,7 @@ define i1 @add_negative_constant_used_as_is(i16 %x, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD:%.*]] = add nuw i16 [[SUB]], 2
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i16 [[SUB]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%sub = add i16 %x, -4
|
||||
|
|
@ -202,8 +195,7 @@ define i1 @trunc_nsw_used_as_is(i32 %x, i16 %z) {
|
|||
; CHECK-NEXT: [[ADD:%.*]] = add nuw i16 [[TR]], 7
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i16 [[TR]], [[Z]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i16 [[ADD]], [[Z]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%tr = trunc nsw i32 %x to i16
|
||||
|
|
@ -226,8 +218,7 @@ define i1 @gep_nuw_index_used_as_is(ptr %p, i64 %x, i64 %y) {
|
|||
; CHECK-NEXT: call void @llvm.assume(i1 [[C_0]])
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[ADD]]
|
||||
; CHECK-NEXT: [[GEP_4:%.*]] = getelementptr nuw i8, ptr [[GEP]], i64 4
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt ptr [[GEP_4]], [[GEP]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i64 %x, %y
|
||||
|
|
@ -289,8 +280,7 @@ define i1 @only_one_side_used_as_is(i16 %x, i16 %y) {
|
|||
; CHECK-NEXT: [[Y_2:%.*]] = add nuw i16 [[Y]], 2
|
||||
; CHECK-NEXT: [[C:%.*]] = icmp ugt i16 [[ADD]], [[Y_2]]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
|
||||
; CHECK-NEXT: [[T:%.*]] = icmp ugt i16 [[ADD]], [[Y]]
|
||||
; CHECK-NEXT: ret i1 [[T]]
|
||||
; CHECK-NEXT: ret i1 true
|
||||
;
|
||||
entry:
|
||||
%add = add nsw i16 %x, %x
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ define void @uge_sext(i16 %x, i32 %y) {
|
|||
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
|
||||
; CHECK-NEXT: br i1 [[AND]], label [[BB1:%.*]], label [[BB2:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[T_1:%.*]] = icmp uge i32 [[X_EXT]], [[Y]]
|
||||
; CHECK-NEXT: call void @use(i1 [[T_1]])
|
||||
; CHECK-NEXT: call void @use(i1 true)
|
||||
; CHECK-NEXT: [[C_3:%.*]] = icmp uge i16 [[X]], -10
|
||||
; CHECK-NEXT: call void @use(i1 [[C_3]])
|
||||
; CHECK-NEXT: [[C_4:%.*]] = icmp uge i32 [[X_EXT]], -9
|
||||
|
|
|
|||
Loading…
Reference in a new issue