Skip to content

Commit af63aa7

Browse files
committed
Initial upstreaming of strlen8 LIR 1 out of 3
1 parent 49e3860 commit af63aa7

File tree

3 files changed

+445
-3
lines changed

3 files changed

+445
-3
lines changed

llvm/include/llvm/Transforms/Scalar/LoopIdiomRecognize.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ struct DisableLIRP {
3434

3535
/// When true, Memcpy is disabled.
3636
static bool Memcpy;
37+
38+
/// When true, Strlen is disabled.
39+
static bool Strlen;
3740
};
3841

3942
/// Performs Loop Idiom Recognize Pass.

llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp

Lines changed: 293 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ using namespace llvm;
9797
STATISTIC(NumMemSet, "Number of memset's formed from loop stores");
9898
STATISTIC(NumMemCpy, "Number of memcpy's formed from loop load+stores");
9999
STATISTIC(NumMemMove, "Number of memmove's formed from loop load+stores");
100+
STATISTIC(NumStrLen, "Number of strlen's formed from loop loads");
100101
STATISTIC(
101102
NumShiftUntilBitTest,
102103
"Number of uncountable loops recognized as 'shift until bitttest' idiom");
@@ -126,6 +127,14 @@ static cl::opt<bool, true>
126127
cl::location(DisableLIRP::Memcpy), cl::init(false),
127128
cl::ReallyHidden);
128129

130+
bool DisableLIRP::Strlen;
131+
static cl::opt<bool, true>
132+
DisableLIRPStrlen("disable-" DEBUG_TYPE "-strlen",
133+
cl::desc("Proceed with loop idiom recognize pass, but do "
134+
"not convert loop(s) to strlen."),
135+
cl::location(DisableLIRP::Strlen), cl::init(false),
136+
cl::ReallyHidden);
137+
129138
static cl::opt<bool> UseLIRCodeSizeHeurs(
130139
"use-lir-code-size-heurs",
131140
cl::desc("Use loop idiom recognition code size heuristics when compiling"
@@ -246,6 +255,7 @@ class LoopIdiomRecognize {
246255

247256
bool recognizeShiftUntilBitTest();
248257
bool recognizeShiftUntilZero();
258+
bool recognizeAndInsertStrLen();
249259

250260
/// @}
251261
};
@@ -1507,9 +1517,11 @@ static Value *matchCondition(BranchInst *BI, BasicBlock *LoopEntry,
15071517
if (!Cond)
15081518
return nullptr;
15091519

1510-
ConstantInt *CmpZero = dyn_cast<ConstantInt>(Cond->getOperand(1));
1511-
if (!CmpZero || !CmpZero->isZero())
1512-
return nullptr;
1520+
if (!isa<ConstantPointerNull>(Cond->getOperand(1))) {
1521+
ConstantInt *CmpZero = dyn_cast<ConstantInt>(Cond->getOperand(1));
1522+
if (!CmpZero || !CmpZero->isZero())
1523+
return nullptr;
1524+
}
15131525

15141526
BasicBlock *TrueSucc = BI->getSuccessor(0);
15151527
BasicBlock *FalseSucc = BI->getSuccessor(1);
@@ -1524,6 +1536,284 @@ static Value *matchCondition(BranchInst *BI, BasicBlock *LoopEntry,
15241536
return nullptr;
15251537
}
15261538

1539+
/// getCandidateResInstr - If there is strlen calculated, return the Result
1540+
/// instruction based on the \p OpWidth passed, else return nullptr
1541+
static Instruction *getCandidateResInstr(Instruction *EndAddress,
1542+
Value *StartAddress,
1543+
unsigned OpWidth) {
1544+
using namespace llvm::PatternMatch;
1545+
1546+
assert(StartAddress && "Valid start address required.");
1547+
1548+
// lambda expression to check that the instruction has a single user
1549+
auto GetSingleUser = [](Instruction *I) -> User * {
1550+
if (I->hasOneUse())
1551+
return *I->user_begin();
1552+
return nullptr;
1553+
};
1554+
1555+
// The pointer to the end address should only have one use which is a pointer
1556+
// to int instruction.
1557+
auto *TmpUser = GetSingleUser(EndAddress);
1558+
if (!TmpUser)
1559+
return nullptr;
1560+
1561+
if (PtrToIntInst *PToI = dyn_cast<PtrToIntInst>(TmpUser)) {
1562+
// The only user of the PtrToIntInst should be the sub instruction that
1563+
// calculates the difference b/w the two pointer operands.
1564+
TmpUser = GetSingleUser(PToI);
1565+
if (!TmpUser)
1566+
return nullptr;
1567+
Instruction *Inst = dyn_cast<Instruction>(TmpUser);
1568+
1569+
if (!Inst || Inst->getOpcode() != Instruction::Sub ||
1570+
Inst->getOperand(0) != PToI)
1571+
return nullptr;
1572+
Value *MatchAddr;
1573+
if (match(Inst->getOperand(1), m_PtrToInt(m_Value(MatchAddr)))) {
1574+
if (MatchAddr != StartAddress)
1575+
return nullptr;
1576+
1577+
// We found the candidate sub instruction
1578+
switch (OpWidth) {
1579+
case 8:
1580+
return Inst;
1581+
default:
1582+
return nullptr;
1583+
}
1584+
}
1585+
}
1586+
1587+
return nullptr;
1588+
}
1589+
1590+
/// Recognizes a strlen idiom by checking for loops that increment
1591+
/// a char pointer and then subtract with the base pointer.
1592+
///
1593+
/// If detected, transforms the relevant code to a strlen function
1594+
/// call, and returns true; otherwise, returns false.
1595+
///
1596+
/// The core idiom we are trying to detect is:
1597+
/// \code
1598+
/// if (str == NULL)
1599+
/// goto loop-exit // the precondition of the loop
1600+
/// start = str;
1601+
/// do {
1602+
/// str++;
1603+
/// } while(*str!='\0');
1604+
/// return (str - start);
1605+
/// loop-exit:
1606+
/// \endcode
1607+
///
1608+
/// The transformed output is similar to below c-code:
1609+
/// \code
1610+
/// if (str == NULL)
1611+
/// goto loop-exit // the precondition of the loop
1612+
/// return strlen(str);
1613+
/// \endcode
1614+
bool LoopIdiomRecognize::recognizeAndInsertStrLen() {
1615+
if (DisableLIRPStrlen)
1616+
return false;
1617+
1618+
// Give up if the loop has multiple blocks or multiple backedges.
1619+
if (CurLoop->getNumBackEdges() != 1 || CurLoop->getNumBlocks() != 1)
1620+
return false;
1621+
1622+
// It should have a preheader containing nothing but an unconditional branch.
1623+
auto *Pre = CurLoop->getLoopPreheader();
1624+
if (!Pre || &Pre->front() != Pre->getTerminator())
1625+
return false;
1626+
1627+
auto *EntryBI = dyn_cast<BranchInst>(Pre->getTerminator());
1628+
if (!EntryBI || EntryBI->isConditional())
1629+
return false;
1630+
1631+
// It should have a precondition block
1632+
auto *PreCondBB = Pre->getSinglePredecessor();
1633+
if (!PreCondBB)
1634+
return false;
1635+
1636+
// The precondition terminator instruction should skip the loop body based on
1637+
// an icmp with zero/null.
1638+
if (!matchCondition(dyn_cast<BranchInst>(PreCondBB->getTerminator()), Pre))
1639+
return false;
1640+
1641+
// The loop exit must be conditioned on an icmp with 0.
1642+
// The icmp operand has to be a load on some SSA reg that increments
1643+
// by 1 in the loop.
1644+
auto *LoopBody = *(CurLoop->block_begin());
1645+
auto *LoopTerm = dyn_cast<BranchInst>(LoopBody->getTerminator());
1646+
auto *LoopCond = matchCondition(LoopTerm, LoopBody);
1647+
1648+
if (!LoopCond)
1649+
return false;
1650+
1651+
auto *LoopLoad = dyn_cast<LoadInst>(LoopCond);
1652+
if (!LoopLoad || LoopLoad->getPointerAddressSpace() != 0)
1653+
return false;
1654+
1655+
Type *OperandType = LoopLoad->getType();
1656+
if (!OperandType || !OperandType->isIntegerTy())
1657+
return false;
1658+
1659+
// See if the pointer expression is an AddRec with step 1 ({n,+,1}) on
1660+
// the loop, indicating strlen calculation.
1661+
auto *IncPtr = LoopLoad->getPointerOperand();
1662+
const SCEVAddRecExpr *LoadEv = dyn_cast<SCEVAddRecExpr>(SE->getSCEV(IncPtr));
1663+
if (!LoadEv || LoadEv->getLoop() != CurLoop || !LoadEv->isAffine())
1664+
return false;
1665+
1666+
const SCEVConstant *Step =
1667+
dyn_cast<SCEVConstant>(LoadEv->getStepRecurrence(*SE));
1668+
if (!Step)
1669+
return false;
1670+
1671+
unsigned int ConstIntValue = 0;
1672+
if (ConstantInt *CI = dyn_cast<ConstantInt>(Step->getValue()))
1673+
ConstIntValue = CI->getZExtValue();
1674+
1675+
unsigned OpWidth = OperandType->getIntegerBitWidth();
1676+
if (OpWidth != ConstIntValue * 8)
1677+
return false;
1678+
if (OpWidth != 8)
1679+
return false;
1680+
1681+
// Scan every instruction in the loop to ensure there are no side effects.
1682+
for (auto &I : *LoopBody)
1683+
if (I.mayHaveSideEffects())
1684+
return false;
1685+
1686+
auto *LoopExitBB = CurLoop->getExitBlock();
1687+
if (!LoopExitBB)
1688+
return false;
1689+
1690+
// Check that the loop exit block is valid:
1691+
// It needs to have exactly one LCSSA Phi which is an AddRec.
1692+
PHINode *LCSSAPhi = nullptr;
1693+
for (PHINode &PN : LoopExitBB->phis()) {
1694+
if (!LCSSAPhi && PN.getNumIncomingValues() == 1)
1695+
LCSSAPhi = &PN;
1696+
else
1697+
return false;
1698+
}
1699+
1700+
if (!LCSSAPhi || !SE->isSCEVable(LCSSAPhi->getType()))
1701+
return false;
1702+
1703+
if (LCSSAPhi->getIncomingValueForBlock(LoopBody) !=
1704+
LoopLoad->getPointerOperand())
1705+
return false;
1706+
1707+
const SCEVAddRecExpr *LCSSAEv =
1708+
dyn_cast<SCEVAddRecExpr>(SE->getSCEV(LCSSAPhi->getIncomingValue(0)));
1709+
1710+
if (!LCSSAEv || !dyn_cast<SCEVUnknown>(SE->getPointerBase(LCSSAEv)) ||
1711+
!LCSSAEv->isAffine())
1712+
return false;
1713+
1714+
// We can now expand the base of the str
1715+
IRBuilder<> Builder(Pre->getTerminator());
1716+
1717+
PHINode *LoopPhi = &*LoopBody->phis().begin();
1718+
if (!LoopPhi || ++LoopBody->phis().begin() != LoopBody->phis().end())
1719+
return false;
1720+
Value *PreVal = LoopBody->phis().begin()->getIncomingValueForBlock(Pre);
1721+
if (!PreVal)
1722+
return false;
1723+
1724+
Value *Expanded = nullptr;
1725+
if (auto *GEP = dyn_cast<GetElementPtrInst>(LoopLoad->getPointerOperand())) {
1726+
if (GEP->getPointerOperand() != LoopPhi)
1727+
return false;
1728+
GetElementPtrInst *NewGEP =
1729+
GetElementPtrInst::Create(GEP->getSourceElementType(), PreVal,
1730+
SmallVector<Value *, 4>(GEP->indices()),
1731+
"newgep", Pre->getTerminator());
1732+
Expanded = NewGEP;
1733+
} else if (LoopLoad->getPointerOperand() == LoopPhi)
1734+
Expanded = PreVal;
1735+
if (!Expanded)
1736+
return false;
1737+
1738+
// Check that the LoopExitBB is calculating the string length and identify
1739+
// the instruction that has the string length calculation
1740+
Instruction *ResInst = getCandidateResInstr(LCSSAPhi, PreVal, OpWidth);
1741+
if (!ResInst)
1742+
return false;
1743+
1744+
// Ensure that the GEP has the correct index if the pointer was modified.
1745+
// This can happen when the pointer in the user code, outside the loop,
1746+
// walks past a certain pre-checked index of the string.
1747+
if (auto *GEP = dyn_cast<GEPOperator>(Expanded)) {
1748+
if (GEP->getNumOperands() != 2)
1749+
return false;
1750+
1751+
ConstantInt *I0 = dyn_cast<ConstantInt>(GEP->getOperand(1));
1752+
if (!I0)
1753+
return false;
1754+
1755+
int64_t Index = I0->getSExtValue(); // GEP index
1756+
auto *SAdd = dyn_cast<SCEVAddExpr>(LoadEv->getStart());
1757+
if (!SAdd || SAdd->getNumOperands() != 2)
1758+
return false;
1759+
1760+
auto *SAdd0 = dyn_cast<SCEVConstant>(SAdd->getOperand(0));
1761+
if (!SAdd0)
1762+
return false;
1763+
1764+
ConstantInt *CInt = SAdd0->getValue(); // SCEV index
1765+
assert(CInt && "Expecting CInt to be valid.");
1766+
int64_t Offset = CInt->getSExtValue();
1767+
1768+
// Update the index based on the Offset
1769+
assert((Offset * 8) % GEP->getSourceElementType()->getIntegerBitWidth() ==
1770+
0 &&
1771+
"Invalid offset");
1772+
int64_t NewIndex =
1773+
(Offset * 8) / GEP->getSourceElementType()->getIntegerBitWidth() -
1774+
Index;
1775+
Value *NewIndexVal =
1776+
ConstantInt::get(GEP->getOperand(1)->getType(), NewIndex);
1777+
GEP->setOperand(1, NewIndexVal);
1778+
}
1779+
1780+
Value *StrLenFunc = nullptr;
1781+
switch (OpWidth) {
1782+
case 8:
1783+
StrLenFunc = emitStrLen(Expanded, Builder, *DL, TLI);
1784+
break;
1785+
}
1786+
1787+
assert(StrLenFunc && "Failed to emit strlen function.");
1788+
1789+
// Replace the subtraction instruction by the result of strlen
1790+
ResInst->replaceAllUsesWith(StrLenFunc);
1791+
1792+
// Remove the loop-exit branch and delete dead instructions
1793+
RecursivelyDeleteTriviallyDeadInstructions(ResInst, TLI);
1794+
1795+
ConstantInt *NewLoopCond = LoopTerm->getSuccessor(0) == LoopBody
1796+
? Builder.getFalse()
1797+
: Builder.getTrue();
1798+
LoopTerm->setCondition(NewLoopCond);
1799+
1800+
deleteDeadInstruction(cast<Instruction>(LoopCond));
1801+
deleteDeadInstruction(cast<Instruction>(IncPtr));
1802+
SE->forgetLoop(CurLoop);
1803+
1804+
LLVM_DEBUG(dbgs() << " Formed strlen: " << *StrLenFunc << "\n");
1805+
1806+
ORE.emit([&]() {
1807+
return OptimizationRemark(DEBUG_TYPE, "recognizeAndInsertStrLen",
1808+
CurLoop->getStartLoc(), Pre)
1809+
<< "Transformed pointer difference into a call to strlen() function";
1810+
});
1811+
1812+
++NumStrLen;
1813+
1814+
return true;
1815+
}
1816+
15271817
/// Check if the given conditional branch is based on an unsigned less-than
15281818
/// comparison between a variable and a constant, and if the comparison is false
15291819
/// the control yields to the loop entry. If the branch matches the behaviour,

0 commit comments

Comments
 (0)