Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit decf72b

Browse files
author
Balaram Makam
committed
[InstCombine] Canonicalize icmp instructions based on dominating conditions.
Summary: This patch canonicalizes conditions based on the constant range information of the dominating branch condition. For example: %cmp = icmp slt i64 %a, 0 br i1 %cmp, label %land.lhs.true, label %lor.rhs lor.rhs: %cmp2 = icmp sgt i64 %a, 0 Would now be canonicalized into: %cmp = icmp slt i64 %a, 0 br i1 %cmp, label %land.lhs.true, label %lor.rhs lor.rhs: %cmp2 = icmp ne i64 %a, 0 Reviewers: mcrosier, gberry, t.p.northover, llvm-commits, reames, hfinkel, sanjoy, majnemer Subscribers: MatzeB, majnemer, mcrosier Differential Revision: http://reviews.llvm.org/D18841 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268521 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f7a03a4 commit decf72b

File tree

4 files changed

+185
-0
lines changed

4 files changed

+185
-0
lines changed

include/llvm/IR/ConstantRange.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ class ConstantRange {
8282
static ConstantRange makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
8383
const ConstantRange &Other);
8484

85+
/// Produce the exact range such that all values in the returned range satisfy
86+
/// the given predicate with any value contained within Other. Formally, this
87+
/// returns the exact answer when the superset of 'union over all y in Other
88+
/// is exactly same as the subset of intersection over all y in Other.
89+
/// { x : icmp op x y is true}'.
90+
///
91+
/// Example: Pred = ult and Other = i8 3 returns [0, 3)
92+
static ConstantRange makeExactICmpRegion(CmpInst::Predicate Pred,
93+
const APInt &Other);
94+
8595
/// Return the largest range containing all X such that "X BinOpC Y" is
8696
/// guaranteed not to wrap (overflow) for all Y in Other.
8797
///

lib/IR/ConstantRange.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@ ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
127127
.inverse();
128128
}
129129

130+
ConstantRange ConstantRange::makeExactICmpRegion(CmpInst::Predicate Pred,
131+
const APInt &C) {
132+
// Computes the exact range that is equal to both the constant ranges returned
133+
// by makeAllowedICmpRegion and makeSatisfyingICmpRegion. This is always true
134+
// when RHS is a singleton such as an APInt and so the assert is valid.
135+
// However for non-singleton RHS, for example ult [2,5) makeAllowedICmpRegion
136+
// returns [0,4) but makeSatisfyICmpRegion returns [0,2).
137+
//
138+
assert(makeAllowedICmpRegion(Pred, C) == makeSatisfyingICmpRegion(Pred, C));
139+
return makeAllowedICmpRegion(Pred, C);
140+
}
141+
130142
ConstantRange
131143
ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp,
132144
const ConstantRange &Other,

lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ static bool SubWithOverflow(Constant *&Result, Constant *In1,
114114
IsSigned);
115115
}
116116

117+
/// Given an icmp instruction, return true if any use of this comparison is a
118+
/// branch on sign bit comparison.
119+
static bool isBranchOnSignBitCheck(ICmpInst &I, bool isSignBit) {
120+
for (auto *U : I.users())
121+
if (isa<BranchInst>(U))
122+
return isSignBit;
123+
return false;
124+
}
125+
117126
/// isSignBitCheck - Given an exploded icmp instruction, return true if the
118127
/// comparison only checks the sign bit. If it only checks the sign bit, set
119128
/// TrueIfSigned if the result of the comparison is true when the input value is
@@ -3284,6 +3293,42 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) {
32843293
// bits, if it is a sign bit comparison, it only demands the sign bit.
32853294
bool UnusedBit;
32863295
isSignBit = isSignBitCheck(I.getPredicate(), CI, UnusedBit);
3296+
3297+
// Canonicalize icmp instructions based on dominating conditions.
3298+
BasicBlock *Parent = I.getParent();
3299+
BasicBlock *Dom = Parent->getSinglePredecessor();
3300+
auto *BI = Dom ? dyn_cast<BranchInst>(Dom->getTerminator()) : nullptr;
3301+
ICmpInst::Predicate Pred;
3302+
BasicBlock *TrueBB, *FalseBB;
3303+
ConstantInt *CI2;
3304+
if (BI && match(BI, m_Br(m_ICmp(Pred, m_Specific(Op0), m_ConstantInt(CI2)),
3305+
TrueBB, FalseBB)) &&
3306+
TrueBB != FalseBB) {
3307+
ConstantRange CR = ConstantRange::makeAllowedICmpRegion(I.getPredicate(),
3308+
CI->getValue());
3309+
ConstantRange DominatingCR =
3310+
(Parent == TrueBB)
3311+
? ConstantRange::makeExactICmpRegion(Pred, CI2->getValue())
3312+
: ConstantRange::makeExactICmpRegion(
3313+
CmpInst::getInversePredicate(Pred), CI2->getValue());
3314+
ConstantRange Intersection = DominatingCR.intersectWith(CR);
3315+
ConstantRange Difference = DominatingCR.difference(CR);
3316+
if (Intersection.isEmptySet())
3317+
return replaceInstUsesWith(I, Builder->getFalse());
3318+
if (Difference.isEmptySet())
3319+
return replaceInstUsesWith(I, Builder->getTrue());
3320+
// Canonicalizing a sign bit comparison that gets used in a branch,
3321+
// pessimizes codegen by generating branch on zero instruction instead
3322+
// of a test and branch. So we avoid canonicalizing in such situations
3323+
// because test and branch instruction has better branch displacement
3324+
// than compare and branch instruction.
3325+
if (!isBranchOnSignBitCheck(I, isSignBit) && !I.isEquality()) {
3326+
if (auto *AI = Intersection.getSingleElement())
3327+
return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Builder->getInt(*AI));
3328+
if (auto *AD = Difference.getSingleElement())
3329+
return new ICmpInst(ICmpInst::ICMP_NE, Op0, Builder->getInt(*AD));
3330+
}
3331+
}
32873332
}
32883333

32893334
// See if we can fold the comparison based on range information we can get

test/Transforms/InstCombine/icmp.ll

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,3 +1979,121 @@ define i1 @cmp_inverse_mask_bits_set_ne(i32 %x) {
19791979
ret i1 %cmp
19801980
}
19811981

1982+
; CHECK-LABEL: @idom_sign_bit_check_edge_dominates
1983+
define void @idom_sign_bit_check_edge_dominates(i64 %a) {
1984+
entry:
1985+
%cmp = icmp slt i64 %a, 0
1986+
br i1 %cmp, label %land.lhs.true, label %lor.rhs
1987+
1988+
land.lhs.true: ; preds = %entry
1989+
br label %lor.end
1990+
1991+
; CHECK-LABEL: lor.rhs:
1992+
; CHECK-NOT: icmp sgt i64 %a, 0
1993+
; CHECK: icmp eq i64 %a, 0
1994+
lor.rhs: ; preds = %entry
1995+
%cmp2 = icmp sgt i64 %a, 0
1996+
br i1 %cmp2, label %land.rhs, label %lor.end
1997+
1998+
land.rhs: ; preds = %lor.rhs
1999+
br label %lor.end
2000+
2001+
lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true
2002+
ret void
2003+
}
2004+
2005+
; CHECK-LABEL: @idom_sign_bit_check_edge_not_dominates
2006+
define void @idom_sign_bit_check_edge_not_dominates(i64 %a) {
2007+
entry:
2008+
%cmp = icmp slt i64 %a, 0
2009+
br i1 %cmp, label %land.lhs.true, label %lor.rhs
2010+
2011+
land.lhs.true: ; preds = %entry
2012+
br i1 undef, label %lor.end, label %lor.rhs
2013+
2014+
; CHECK-LABEL: lor.rhs:
2015+
; CHECK: icmp sgt i64 %a, 0
2016+
; CHECK-NOT: icmp eq i64 %a, 0
2017+
lor.rhs: ; preds = %land.lhs.true, %entry
2018+
%cmp2 = icmp sgt i64 %a, 0
2019+
br i1 %cmp2, label %land.rhs, label %lor.end
2020+
2021+
land.rhs: ; preds = %lor.rhs
2022+
br label %lor.end
2023+
2024+
lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true
2025+
ret void
2026+
}
2027+
2028+
; CHECK-LABEL: @idom_sign_bit_check_edge_dominates_select
2029+
define void @idom_sign_bit_check_edge_dominates_select(i64 %a, i64 %b) {
2030+
entry:
2031+
%cmp = icmp slt i64 %a, 5
2032+
br i1 %cmp, label %land.lhs.true, label %lor.rhs
2033+
2034+
land.lhs.true: ; preds = %entry
2035+
br label %lor.end
2036+
2037+
; CHECK-LABEL: lor.rhs:
2038+
; CHECK-NOT: [[B:%.*]] = icmp sgt i64 %a, 5
2039+
; CHECK: [[C:%.*]] = icmp eq i64 %a, %b
2040+
; CHECK-NOT: [[D:%.*]] = select i1 [[B]], i64 %a, i64 5
2041+
; CHECK-NOT: icmp ne i64 [[D]], %b
2042+
; CHECK-NEXT: br i1 [[C]], label %lor.end, label %land.rhs
2043+
lor.rhs: ; preds = %entry
2044+
%cmp2 = icmp sgt i64 %a, 5
2045+
%select = select i1 %cmp2, i64 %a, i64 5
2046+
%cmp3 = icmp ne i64 %select, %b
2047+
br i1 %cmp3, label %land.rhs, label %lor.end
2048+
2049+
land.rhs: ; preds = %lor.rhs
2050+
br label %lor.end
2051+
2052+
lor.end: ; preds = %land.rhs, %lor.rhs, %land.lhs.true
2053+
ret void
2054+
}
2055+
2056+
; CHECK-LABEL: @idom_zbranch
2057+
define void @idom_zbranch(i64 %a) {
2058+
entry:
2059+
%cmp = icmp sgt i64 %a, 0
2060+
br i1 %cmp, label %lor.end, label %lor.rhs
2061+
2062+
; CHECK-LABEL: lor.rhs:
2063+
; CHECK: icmp slt i64 %a, 0
2064+
; CHECK-NOT: icmp eq i64 %a, 0
2065+
lor.rhs: ; preds = %entry
2066+
%cmp2 = icmp slt i64 %a, 0
2067+
br i1 %cmp2, label %land.rhs, label %lor.end
2068+
2069+
land.rhs: ; preds = %lor.rhs
2070+
br label %lor.end
2071+
2072+
lor.end: ; preds = %land.rhs, %lor.rhs
2073+
ret void
2074+
}
2075+
2076+
; CHECK-LABEL: @idom_not_zbranch
2077+
define void @idom_not_zbranch(i32 %a, i32 %b) {
2078+
entry:
2079+
%cmp = icmp sgt i32 %a, 0
2080+
br i1 %cmp, label %return, label %if.end
2081+
2082+
; CHECK-LABEL: if.end:
2083+
; CHECK-NOT: [[B:%.*]] = icmp slt i32 %a, 0
2084+
; CHECK: [[C:%.*]] = icmp eq i32 %a, %b
2085+
; CHECK-NOT: [[D:%.*]] = select i1 [[B]], i32 %a, i32 0
2086+
; CHECK-NOT: icmp ne i32 [[D]], %b
2087+
; CHECK-NEXT: br i1 [[C]], label %return, label %if.then3
2088+
if.end: ; preds = %entry
2089+
%cmp1 = icmp slt i32 %a, 0
2090+
%a. = select i1 %cmp1, i32 %a, i32 0
2091+
%cmp2 = icmp ne i32 %a., %b
2092+
br i1 %cmp2, label %if.then3, label %return
2093+
2094+
if.then3: ; preds = %if.end
2095+
br label %return
2096+
2097+
return: ; preds = %if.end, %entry, %if.then3
2098+
ret void
2099+
}

0 commit comments

Comments
 (0)