mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-01 01:31:26 +00:00
[ConstraintElim] Store conditional facts as (Predicate, Op0, Op1).
This allows to add facts even if no corresponding ICmp instruction exists in the IR. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D158837
This commit is contained in:
parent
5b3f41c55d
commit
4a5bcbd560
@ -83,6 +83,16 @@ static Instruction *getContextInstForUse(Use &U) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Struct to express a condition of the form %Op0 Pred %Op1.
|
||||
struct ConditionTy {
|
||||
CmpInst::Predicate Pred;
|
||||
Value *Op0;
|
||||
Value *Op1;
|
||||
|
||||
ConditionTy(CmpInst::Predicate Pred, Value *Op0, Value *Op1)
|
||||
: Pred(Pred), Op0(Op0), Op1(Op1) {}
|
||||
};
|
||||
|
||||
/// Represents either
|
||||
/// * a condition that holds on entry to a block (=condition fact)
|
||||
/// * an assume (=assume fact)
|
||||
@ -101,29 +111,37 @@ struct FactOrCheck {
|
||||
union {
|
||||
Instruction *Inst;
|
||||
Use *U;
|
||||
ConditionTy Cond;
|
||||
};
|
||||
|
||||
unsigned NumIn;
|
||||
unsigned NumOut;
|
||||
EntryTy Ty;
|
||||
bool Not;
|
||||
|
||||
FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst, bool Not)
|
||||
FactOrCheck(EntryTy Ty, DomTreeNode *DTN, Instruction *Inst)
|
||||
: Inst(Inst), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
|
||||
Ty(Ty), Not(Not) {}
|
||||
Ty(Ty) {}
|
||||
|
||||
FactOrCheck(DomTreeNode *DTN, Use *U)
|
||||
: U(U), NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()),
|
||||
Ty(EntryTy::UseCheck), Not(false) {}
|
||||
Ty(EntryTy::UseCheck) {}
|
||||
|
||||
static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst *Inst,
|
||||
bool Not = false) {
|
||||
return FactOrCheck(EntryTy::ConditionFact, DTN, Inst, Not);
|
||||
FactOrCheck(DomTreeNode *DTN, CmpInst::Predicate Pred, Value *Op0, Value *Op1)
|
||||
: Cond(Pred, Op0, Op1), NumIn(DTN->getDFSNumIn()),
|
||||
NumOut(DTN->getDFSNumOut()), Ty(EntryTy::ConditionFact) {}
|
||||
|
||||
static FactOrCheck getConditionFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
|
||||
Value *Op0, Value *Op1) {
|
||||
return FactOrCheck(DTN, Pred, Op0, Op1);
|
||||
}
|
||||
|
||||
static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst,
|
||||
bool Not = false) {
|
||||
return FactOrCheck(EntryTy::InstFact, DTN, Inst, Not);
|
||||
static FactOrCheck getInstFact(DomTreeNode *DTN, Instruction *Inst) {
|
||||
return FactOrCheck(EntryTy::InstFact, DTN, Inst);
|
||||
}
|
||||
|
||||
static FactOrCheck getFact(DomTreeNode *DTN, CmpInst::Predicate Pred,
|
||||
Value *Op0, Value *Op1) {
|
||||
return FactOrCheck(DTN, Pred, Op0, Op1);
|
||||
}
|
||||
|
||||
static FactOrCheck getCheck(DomTreeNode *DTN, Use *U) {
|
||||
@ -131,7 +149,7 @@ struct FactOrCheck {
|
||||
}
|
||||
|
||||
static FactOrCheck getCheck(DomTreeNode *DTN, CallInst *CI) {
|
||||
return FactOrCheck(EntryTy::InstCheck, DTN, CI, false);
|
||||
return FactOrCheck(EntryTy::InstCheck, DTN, CI);
|
||||
}
|
||||
|
||||
bool isCheck() const {
|
||||
@ -188,19 +206,9 @@ struct StackEntry {
|
||||
ValuesToRelease(ValuesToRelease) {}
|
||||
};
|
||||
|
||||
/// 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;
|
||||
SmallVector<PreconditionTy, 2> Preconditions;
|
||||
SmallVector<ConditionTy, 2> Preconditions;
|
||||
|
||||
SmallVector<SmallVector<int64_t, 8>> ExtraInfo;
|
||||
|
||||
@ -346,7 +354,7 @@ struct Decomposition {
|
||||
} // namespace
|
||||
|
||||
static Decomposition decompose(Value *V,
|
||||
SmallVectorImpl<PreconditionTy> &Preconditions,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
bool IsSigned, const DataLayout &DL);
|
||||
|
||||
static bool canUseSExt(ConstantInt *CI) {
|
||||
@ -354,9 +362,9 @@ static bool canUseSExt(ConstantInt *CI) {
|
||||
return Val.sgt(MinSignedConstraintValue) && Val.slt(MaxConstraintValue);
|
||||
}
|
||||
|
||||
static Decomposition
|
||||
decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions,
|
||||
bool IsSigned, const DataLayout &DL) {
|
||||
static Decomposition decomposeGEP(GEPOperator &GEP,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
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.
|
||||
if (DL.getIndexTypeSizeInBits(GEP.getPointerOperand()->getType()) > 64)
|
||||
@ -417,7 +425,7 @@ decomposeGEP(GEPOperator &GEP, SmallVectorImpl<PreconditionTy> &Preconditions,
|
||||
// Variable } where Coefficient * Variable. The sum of the constant offset and
|
||||
// pairs equals \p V.
|
||||
static Decomposition decompose(Value *V,
|
||||
SmallVectorImpl<PreconditionTy> &Preconditions,
|
||||
SmallVectorImpl<ConditionTy> &Preconditions,
|
||||
bool IsSigned, const DataLayout &DL) {
|
||||
|
||||
auto MergeResults = [&Preconditions, IsSigned, &DL](Value *A, Value *B,
|
||||
@ -560,7 +568,7 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
|
||||
Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SLT)
|
||||
return {};
|
||||
|
||||
SmallVector<PreconditionTy, 4> Preconditions;
|
||||
SmallVector<ConditionTy, 4> Preconditions;
|
||||
bool IsSigned = CmpInst::isSigned(Pred);
|
||||
auto &Value2Index = getValue2Index(IsSigned);
|
||||
auto ADec = decompose(Op0->stripPointerCastsSameRepresentation(),
|
||||
@ -670,7 +678,7 @@ ConstraintTy ConstraintInfo::getConstraintForSolving(CmpInst::Predicate Pred,
|
||||
|
||||
bool ConstraintTy::isValid(const ConstraintInfo &Info) const {
|
||||
return Coefficients.size() > 0 &&
|
||||
all_of(Preconditions, [&Info](const PreconditionTy &C) {
|
||||
all_of(Preconditions, [&Info](const ConditionTy &C) {
|
||||
return Info.doesHold(C.Pred, C.Op0, C.Op1);
|
||||
});
|
||||
}
|
||||
@ -805,15 +813,16 @@ void State::addInfoFor(BasicBlock &BB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Value *Cond;
|
||||
Value *A, *B;
|
||||
CmpInst::Predicate Pred;
|
||||
// For now, just handle assumes with a single compare as condition.
|
||||
if (match(&I, m_Intrinsic<Intrinsic::assume>(m_Value(Cond))) &&
|
||||
isa<ICmpInst>(Cond)) {
|
||||
if (match(&I, m_Intrinsic<Intrinsic::assume>(
|
||||
m_ICmp(Pred, m_Value(A), m_Value(B))))) {
|
||||
if (GuaranteedToExecute) {
|
||||
// The assume is guaranteed to execute when BB is entered, hence Cond
|
||||
// holds on entry to BB.
|
||||
WorkList.emplace_back(FactOrCheck::getConditionFact(
|
||||
DT.getNode(I.getParent()), cast<CmpInst>(Cond)));
|
||||
DT.getNode(I.getParent()), Pred, A, B));
|
||||
} else {
|
||||
WorkList.emplace_back(
|
||||
FactOrCheck::getInstFact(DT.getNode(I.getParent()), &I));
|
||||
@ -853,8 +862,11 @@ void State::addInfoFor(BasicBlock &BB) {
|
||||
while (!CondWorkList.empty()) {
|
||||
Value *Cur = CondWorkList.pop_back_val();
|
||||
if (auto *Cmp = dyn_cast<ICmpInst>(Cur)) {
|
||||
WorkList.emplace_back(
|
||||
FactOrCheck::getConditionFact(DT.getNode(Successor), Cmp, IsOr));
|
||||
WorkList.emplace_back(FactOrCheck::getConditionFact(
|
||||
DT.getNode(Successor),
|
||||
IsOr ? CmpInst::getInversePredicate(Cmp->getPredicate())
|
||||
: Cmp->getPredicate(),
|
||||
Cmp->getOperand(0), Cmp->getOperand(1)));
|
||||
continue;
|
||||
}
|
||||
if (IsOr && match(Cur, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) {
|
||||
@ -876,11 +888,14 @@ void State::addInfoFor(BasicBlock &BB) {
|
||||
if (!CmpI)
|
||||
return;
|
||||
if (canAddSuccessor(BB, Br->getSuccessor(0)))
|
||||
WorkList.emplace_back(
|
||||
FactOrCheck::getConditionFact(DT.getNode(Br->getSuccessor(0)), CmpI));
|
||||
WorkList.emplace_back(FactOrCheck::getConditionFact(
|
||||
DT.getNode(Br->getSuccessor(0)), CmpI->getPredicate(),
|
||||
CmpI->getOperand(0), CmpI->getOperand(1)));
|
||||
if (canAddSuccessor(BB, Br->getSuccessor(1)))
|
||||
WorkList.emplace_back(FactOrCheck::getConditionFact(
|
||||
DT.getNode(Br->getSuccessor(1)), CmpI, true));
|
||||
DT.getNode(Br->getSuccessor(1)),
|
||||
CmpInst::getInversePredicate(CmpI->getPredicate()), CmpI->getOperand(0),
|
||||
CmpI->getOperand(1)));
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1312,8 +1327,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
|
||||
// transfer logic.
|
||||
stable_sort(S.WorkList, [](const FactOrCheck &A, const FactOrCheck &B) {
|
||||
auto HasNoConstOp = [](const FactOrCheck &B) {
|
||||
return !isa<ConstantInt>(B.Inst->getOperand(0)) &&
|
||||
!isa<ConstantInt>(B.Inst->getOperand(1));
|
||||
Value *V0 = B.isConditionFact() ? B.Cond.Op0 : B.Inst->getOperand(0);
|
||||
Value *V1 = B.isConditionFact() ? B.Cond.Op1 : B.Inst->getOperand(1);
|
||||
return !isa<ConstantInt>(V0) && !isa<ConstantInt>(V1);
|
||||
};
|
||||
// If both entries have the same In numbers, conditional facts come first.
|
||||
// Otherwise use the relative order in the basic block.
|
||||
@ -1386,7 +1402,6 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
|
||||
continue;
|
||||
}
|
||||
|
||||
LLVM_DEBUG(dbgs() << "fact to add to the system: " << *CB.Inst << "\n");
|
||||
auto AddFact = [&](CmpInst::Predicate Pred, Value *A, Value *B) {
|
||||
if (Info.getCS(CmpInst::isSigned(Pred)).size() > MaxRows) {
|
||||
LLVM_DEBUG(
|
||||
@ -1395,6 +1410,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
|
||||
return;
|
||||
}
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Processing fact to add to the system: " << Pred << " ";
|
||||
A->printAsOperand(dbgs());
|
||||
dbgs() << ", ";
|
||||
B->printAsOperand(dbgs(), false);
|
||||
dbgs() << "\n";
|
||||
});
|
||||
|
||||
Info.addFact(Pred, A, B, CB.NumIn, CB.NumOut, DFSInStack);
|
||||
if (ReproducerModule && DFSInStack.size() > ReproducerCondStack.size())
|
||||
ReproducerCondStack.emplace_back(Pred, A, B);
|
||||
@ -1413,23 +1436,27 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT,
|
||||
};
|
||||
|
||||
ICmpInst::Predicate Pred;
|
||||
if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
|
||||
Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
|
||||
AddFact(Pred, MinMax, MinMax->getLHS());
|
||||
AddFact(Pred, MinMax, MinMax->getRHS());
|
||||
continue;
|
||||
if (!CB.isConditionFact()) {
|
||||
if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
|
||||
Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
|
||||
AddFact(Pred, MinMax, MinMax->getLHS());
|
||||
AddFact(Pred, MinMax, MinMax->getRHS());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Value *A, *B;
|
||||
Value *Cmp = CB.Inst;
|
||||
match(Cmp, m_Intrinsic<Intrinsic::assume>(m_Value(Cmp)));
|
||||
if (match(Cmp, m_ICmp(Pred, m_Value(A), m_Value(B)))) {
|
||||
// Use the inverse predicate if required.
|
||||
if (CB.Not)
|
||||
Pred = CmpInst::getInversePredicate(Pred);
|
||||
|
||||
AddFact(Pred, A, B);
|
||||
Value *A = nullptr, *B = nullptr;
|
||||
if (CB.isConditionFact()) {
|
||||
Pred = CB.Cond.Pred;
|
||||
A = CB.Cond.Op0;
|
||||
B = CB.Cond.Op1;
|
||||
} else {
|
||||
bool Matched = match(CB.Inst, m_Intrinsic<Intrinsic::assume>(
|
||||
m_ICmp(Pred, m_Value(A), m_Value(B))));
|
||||
(void)Matched;
|
||||
assert(Matched && "Must have an assume intrinsic with a icmp operand");
|
||||
}
|
||||
AddFact(Pred, A, B);
|
||||
}
|
||||
|
||||
if (ReproducerModule && !ReproducerModule->functions().empty()) {
|
||||
|
@ -3,11 +3,11 @@
|
||||
; REQUIRES: asserts
|
||||
|
||||
define i1 @test_and_ule(i4 %x, i4 %y, i4 %z) {
|
||||
; CHECK: Processing fact to add to the system: %c.1 = icmp ule i4 %x, %y
|
||||
; CHECK: Processing fact to add to the system: ule i4 %x, %y
|
||||
; CHECK-NEXT: Adding 'ule %x, %y'
|
||||
; CHECK-NEXT: constraint: %x + -1 * %y <= 0
|
||||
|
||||
; CHECK: Processing fact to add to the system: %c.2 = icmp ule i4 %y, %z
|
||||
; CHECK: Processing fact to add to the system: ule i4 %y, %z
|
||||
; CHECK-NEXT: Adding 'ule %y, %z'
|
||||
; CHECK-NEXT: constraint: %y + -1 * %z <= 0
|
||||
|
||||
@ -33,11 +33,11 @@ exit:
|
||||
}
|
||||
|
||||
define i1 @test_and_ugt(i4 %x, i4 %y, i4 %z) {
|
||||
; CHECK: Processing fact to add to the system: %c.1 = icmp ugt i4 %x, %y
|
||||
; CHECK: Processing fact to add to the system: ugt i4 %x, %y
|
||||
; CHECK-NEXT: Adding 'ugt %x, %y'
|
||||
; CHECK-NEXT: constraint: -1 * %x + %y <= -1
|
||||
|
||||
; CHECK: Processing fact to add to the system: %c.2 = icmp ugt i4 %y, %z
|
||||
; CHECK: Processing fact to add to the system: ugt i4 %y, %z
|
||||
; CHECK-NEXT: Adding 'ugt %y, %z'
|
||||
; CHECK-NEXT: constraint: -1 * %y + %z <= -1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user