Skip to content

Commit eed9965

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/CT7WFW
1 parent deeef25 commit eed9965

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-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: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1809,6 +1809,156 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
18091809
return nullptr;
18101810
}
18111811

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

2104+
if (Instruction *NewSel = foldSelectICmpBinOp(SI, ICI, CmpLHS, CmpRHS,
2105+
TrueVal, FalseVal, *this))
2106+
return NewSel;
2107+
19542108
return Changed ? &SI : nullptr;
19552109
}
19562110

0 commit comments

Comments
 (0)