Skip to content

Commit 90f99c4

Browse files
committed
[InstCombine] Try optimizing with knownbits which determined from SelectInst Cond
ICmpInst of SelectInst is not included in the calculation of KnownBits so we are missing the opportunity to optimize the Value of the True or False Condition via ICmpInst with KnownBits. Consider: %or = or i32 %x, %y %or0 = icmp eq i32 %or, 0 %and = and i32 %x, %y %cond = select i1 %or0, i32 %and, i32 %or ret i32 %cond Expect: %or = or i32 %x, %y ret i32 %or We could know what bit was enabled for %x, %y by ICmpInst in SelectInst. This patch is an implementation that calculates the known bits over ICmp and optimizes them where possible. Proof : https://alive2.llvm.org/ce/z/kJ4YBF
1 parent 35c6ad2 commit 90f99c4

File tree

2 files changed

+163
-0
lines changed

2 files changed

+163
-0
lines changed

llvm/include/llvm/Transforms/InstCombine/InstCombiner.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,13 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
438438
return llvm::computeKnownBits(V, Depth, SQ.getWithInstruction(CxtI));
439439
}
440440

441+
void computeKnownBitsFromCond(const Value *V, ICmpInst *Cmp, KnownBits &Known,
442+
unsigned Depth, const Instruction *CxtI,
443+
bool Invert) const {
444+
llvm::computeKnownBitsFromCond(V, Cmp, Known, Depth,
445+
SQ.getWithInstruction(CxtI), Invert);
446+
}
447+
441448
bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero = false,
442449
unsigned Depth = 0,
443450
const Instruction *CxtI = nullptr) {

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,158 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
17901790
return nullptr;
17911791
}
17921792

1793+
// ICmpInst of SelectInst is not included in the calculation of KnownBits
1794+
// so we are missing the opportunity to optimize the Value of the True or
1795+
// False Condition via ICmpInst with KnownBits.
1796+
//
1797+
// Consider:
1798+
// %or = or i32 %x, %y
1799+
// %or0 = icmp eq i32 %or, 0
1800+
// %and = and i32 %x, %y
1801+
// %cond = select i1 %or0, i32 %and, i32 %or
1802+
// ret i32 %cond
1803+
//
1804+
// Expect:
1805+
// %or = or i32 %x, %y
1806+
// ret i32 %or
1807+
//
1808+
// We could know what bit was enabled for %x, %y by ICmpInst in SelectInst.
1809+
static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
1810+
Value *CmpLHS, Value *CmpRHS,
1811+
Value *TVal, Value *FVal,
1812+
InstCombinerImpl &IC) {
1813+
Value *X, *Y;
1814+
const APInt *C;
1815+
1816+
if (!((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
1817+
match(CmpRHS, m_APInt(C))) &&
1818+
(match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
1819+
match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))))
1820+
return nullptr;
1821+
1822+
enum SpecialKnownBits {
1823+
NothingSpecial = 0,
1824+
NoCommonBits = 1 << 1,
1825+
AllCommonBits = 1 << 2,
1826+
AllBitsEnabled = 1 << 3,
1827+
};
1828+
1829+
// We cannot know exactly what bits is known in X Y.
1830+
// Instead, we just know what relationship exist for.
1831+
auto isSpecialKnownBitsFor = [&](const Instruction *CmpLHS,
1832+
const APInt *CmpRHS) -> unsigned {
1833+
unsigned Opc = CmpLHS->getOpcode();
1834+
if (Opc == Instruction::And) {
1835+
if (CmpRHS->isZero())
1836+
return NoCommonBits;
1837+
} else if (Opc == Instruction::Xor) {
1838+
if (CmpRHS->isAllOnes())
1839+
return NoCommonBits | AllBitsEnabled;
1840+
if (CmpRHS->isZero())
1841+
return AllCommonBits;
1842+
}
1843+
1844+
return NothingSpecial;
1845+
};
1846+
1847+
auto hasOperandAt = [&](Instruction *I, Value *Op) -> int {
1848+
for (unsigned Idx = 0; Idx < I->getNumOperands(); Idx++) {
1849+
if (I->getOperand(Idx) == Op)
1850+
return Idx + 1;
1851+
}
1852+
return 0;
1853+
};
1854+
1855+
Type *TValTy = TVal->getType();
1856+
unsigned BitWidth = TVal->getType()->getScalarSizeInBits();
1857+
auto TValBop = cast<BinaryOperator>(TVal);
1858+
auto CmpLHSBop = cast<BinaryOperator>(CmpLHS);
1859+
unsigned XOrder = hasOperandAt(TValBop, X);
1860+
unsigned YOrder = hasOperandAt(TValBop, Y);
1861+
unsigned SKB = isSpecialKnownBitsFor(CmpLHSBop, C);
1862+
1863+
KnownBits Known;
1864+
if (TValBop->isBitwiseLogicOp()) {
1865+
if (SKB != SpecialKnownBits::NothingSpecial && XOrder && YOrder) {
1866+
if (SKB & SpecialKnownBits::NoCommonBits) {
1867+
if (SKB & (SpecialKnownBits::AllBitsEnabled)) {
1868+
if (TValBop->getOpcode() == Instruction::Xor)
1869+
Known = KnownBits::makeConstant(APInt(BitWidth, -1));
1870+
}
1871+
if (TValBop->getOpcode() == Instruction::And)
1872+
Known = KnownBits::makeConstant(APInt(BitWidth, 0));
1873+
else if ((match(TVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
1874+
match(FVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) ||
1875+
(match(TVal, m_c_Xor(m_Specific(X), m_Specific(Y))) &&
1876+
match(FVal, m_c_Or(m_Specific(X), m_Specific(Y)))))
1877+
return IC.replaceInstUsesWith(SI, FVal);
1878+
} else if (SKB & SpecialKnownBits::AllCommonBits) {
1879+
if (TValBop->getOpcode() == Instruction::And ||
1880+
TValBop->getOpcode() == Instruction::Or)
1881+
if (TValBop->hasOneUse())
1882+
return IC.replaceOperand(SI, 1, X);
1883+
} else if (SKB & SpecialKnownBits::AllBitsEnabled) {
1884+
if (TValBop->getOpcode() == Instruction::Or)
1885+
Known = KnownBits::makeConstant(APInt(BitWidth, -1));
1886+
}
1887+
} else {
1888+
KnownBits XKnown, YKnown, Temp;
1889+
KnownBits TValBop0KB, TValBop1KB;
1890+
XKnown = IC.computeKnownBits(X, 0, &SI);
1891+
IC.computeKnownBitsFromCond(X, ICI, XKnown, 0, &SI, false);
1892+
YKnown = IC.computeKnownBits(Y, 0, &SI);
1893+
IC.computeKnownBitsFromCond(Y, ICI, YKnown, 0, &SI, false);
1894+
1895+
// Estimate additional KnownBits from the relationship between X and Y
1896+
CmpInst::Predicate Pred = ICI->getPredicate();
1897+
if (Pred == ICmpInst::ICMP_EQ) {
1898+
if (CmpLHSBop->getOpcode() == Instruction::And) {
1899+
XKnown.Zero |= ~*C & YKnown.One;
1900+
YKnown.Zero |= ~*C & XKnown.One;
1901+
}
1902+
if (CmpLHSBop->getOpcode() == Instruction::Or) {
1903+
XKnown.One |= *C & YKnown.Zero;
1904+
YKnown.One |= *C & XKnown.Zero;
1905+
}
1906+
if (CmpLHSBop->getOpcode() == Instruction::Xor) {
1907+
XKnown.One |= *C & YKnown.Zero;
1908+
XKnown.Zero |= *C & YKnown.One;
1909+
YKnown.One |= *C & XKnown.Zero;
1910+
YKnown.Zero |= *C & XKnown.One;
1911+
XKnown.Zero |= ~*C & YKnown.Zero;
1912+
XKnown.One |= ~*C & YKnown.One;
1913+
YKnown.Zero |= ~*C & XKnown.Zero;
1914+
YKnown.One |= ~*C & XKnown.One;
1915+
}
1916+
}
1917+
1918+
auto getTValBopKB = [&](unsigned OpNum) -> KnownBits {
1919+
unsigned Order = OpNum + 1;
1920+
if (Order == XOrder)
1921+
return XKnown;
1922+
else if (Order == YOrder)
1923+
return YKnown;
1924+
1925+
Value *V = TValBop->getOperand(OpNum);
1926+
KnownBits Known = IC.computeKnownBits(V, 0, &SI);
1927+
return Known;
1928+
};
1929+
TValBop0KB = getTValBopKB(0);
1930+
TValBop1KB = getTValBopKB(1);
1931+
Known = analyzeKnownBitsFromAndXorOr(
1932+
cast<Operator>(TValBop), TValBop0KB, TValBop1KB, 0,
1933+
IC.getSimplifyQuery().getWithInstruction(&SI));
1934+
}
1935+
}
1936+
1937+
if (Known.isConstant()) {
1938+
auto Const = ConstantInt::get(TValTy, Known.getConstant());
1939+
return IC.replaceOperand(SI, 1, Const);
1940+
}
1941+
1942+
return nullptr;
1943+
}
1944+
17931945
/// Visit a SelectInst that has an ICmpInst as its first operand.
17941946
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
17951947
ICmpInst *ICI) {
@@ -1932,6 +2084,10 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
19322084
if (Value *V = foldAbsDiff(ICI, TrueVal, FalseVal, Builder))
19332085
return replaceInstUsesWith(SI, V);
19342086

2087+
if (Instruction *NewSel = foldSelectICmpBinOp(SI, ICI, CmpLHS, CmpRHS,
2088+
TrueVal, FalseVal, *this))
2089+
return NewSel;
2090+
19352091
return Changed ? &SI : nullptr;
19362092
}
19372093

0 commit comments

Comments
 (0)