38 #include "llvm/Config/llvm-config.h" 59 #define DEBUG_TYPE "arm-cp-islands" 61 #define ARM_CP_ISLANDS_OPT_NAME \ 62 "ARM constant island placement and branch shortening pass" 63 STATISTIC(NumCPEs,
"Number of constpool entries");
64 STATISTIC(NumSplit,
"Number of uncond branches inserted");
65 STATISTIC(NumCBrFixed,
"Number of cond branches fixed");
66 STATISTIC(NumUBrFixed,
"Number of uncond branches fixed");
67 STATISTIC(NumTBs,
"Number of table branches generated");
68 STATISTIC(NumT2CPShrunk,
"Number of Thumb2 constantpool instructions shrunk");
69 STATISTIC(NumT2BrShrunk,
"Number of Thumb2 immediate branches shrunk");
70 STATISTIC(NumCBZ,
"Number of CBZ / CBNZ formed");
71 STATISTIC(NumJTMoved,
"Number of jump table destination blocks moved");
72 STATISTIC(NumJTInserted,
"Number of jump table intermediate blocks inserted");
76 cl::desc(
"Adjust basic block layout to better use TB[BH]"));
80 cl::desc(
"The max number of iteration for converge"));
84 cl::desc(
"Use compressed jump tables in Thumb-1 by synthesizing an " 85 "equivalent to the TBB/TBH instructions"));
101 std::vector<BasicBlockInfo> BBInfo;
106 std::vector<MachineBasicBlock*> WaterList;
112 using water_iterator = std::vector<MachineBasicBlock *>::iterator;
133 bool KnownAlignment =
false;
136 bool neg,
bool soimm)
137 : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm) {
144 unsigned getMaxDisp()
const {
145 return (KnownAlignment ? MaxDisp : MaxDisp - 2) - 2;
151 std::vector<CPUser> CPUsers;
162 : CPEMI(cpemi), CPI(cpi), RefCount(
rc) {}
174 std::vector<std::vector<CPEntry>> CPEntries;
190 unsigned MaxDisp : 31;
194 ImmBranch(
MachineInstr *mi,
unsigned maxdisp,
bool cond,
unsigned ubr)
195 : MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {}
199 std::vector<ImmBranch> ImmBranches;
219 bool isPositionIndependentOrROPI;
238 void doInitialConstPlacement(std::vector<MachineInstr *> &CPEMIs);
239 void doInitialJumpTablePlacement(std::vector<MachineInstr *> &CPEMIs);
241 CPEntry *findConstPoolEntry(
unsigned CPI,
const MachineInstr *CPEMI);
243 void scanFunctionJumpTables();
244 void initializeFunctionInfo(
const std::vector<MachineInstr*> &CPEMIs);
248 bool decrementCPEReferenceCount(
unsigned CPI,
MachineInstr* CPEMI);
250 int findInRangeCPEntry(CPUser& U,
unsigned UserOffset);
251 bool findAvailableWater(CPUser&U,
unsigned UserOffset,
252 water_iterator &WaterIter,
bool CloserWater);
253 void createNewWater(
unsigned CPUserIndex,
unsigned UserOffset,
255 bool handleConstantPoolUser(
unsigned CPUserIndex,
bool CloserWater);
257 bool removeUnusedCPEntries();
258 bool isCPEntryInRange(
MachineInstr *MI,
unsigned UserOffset,
260 bool DoDump =
false);
262 CPUser &U,
unsigned &Growth);
264 bool fixupImmediateBr(ImmBranch &Br);
265 bool fixupConditionalBr(ImmBranch &Br);
266 bool fixupUnconditionalBr(ImmBranch &Br);
267 bool undoLRSpillRestore();
268 bool optimizeThumb2Instructions();
269 bool optimizeThumb2Branches();
270 bool reorderThumb2JumpTables();
272 unsigned &DeadSize,
bool &CanDeleteLEA,
274 bool optimizeThumb2JumpTables();
279 unsigned getUserOffset(CPUser&)
const;
283 bool isOffsetInRange(
unsigned UserOffset,
unsigned TrialOffset,
284 unsigned Disp,
bool NegativeOK,
bool IsSoImm =
false);
285 bool isOffsetInRange(
unsigned UserOffset,
unsigned TrialOffset,
287 return isOffsetInRange(UserOffset, TrialOffset,
288 U.getMaxDisp(), U.NegOk, U.IsSoImm);
302 return BBInfo[LHS.
getNumber()].postOffset() <
303 BBInfo[RHS.getNumber()].postOffset();
305 LLVM_DEBUG(
dbgs() <<
"Verifying " << CPUsers.size() <<
" CP users.\n");
306 for (
unsigned i = 0, e = CPUsers.size(); i != e; ++i) {
307 CPUser &U = CPUsers[i];
308 unsigned UserOffset = getUserOffset(U);
311 if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, U.getMaxDisp()+2, U.NegOk,
324 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 328 for (
unsigned J = 0,
E = BBInfo.size(); J !=
E; ++J) {
345 << MCP->
getConstants().size() <<
" CP entries, aligned to " 349 TII = STI->getInstrInfo();
350 isPositionIndependentOrROPI =
351 STI->getTargetLowering()->isPositionIndependent() || STI->isROPI();
370 bool MadeChange =
false;
372 scanFunctionJumpTables();
373 MadeChange |= reorderThumb2JumpTables();
375 T2JumpTables.
clear();
382 std::vector<MachineInstr*> CPEMIs;
384 doInitialConstPlacement(CPEMIs);
387 doInitialJumpTablePlacement(CPEMIs);
395 initializeFunctionInfo(CPEMIs);
401 if (!T2JumpTables.
empty())
405 MadeChange |= removeUnusedCPEntries();
409 unsigned NoCPIters = 0, NoBRIters = 0;
411 LLVM_DEBUG(
dbgs() <<
"Beginning CP iteration #" << NoCPIters <<
'\n');
412 bool CPChange =
false;
413 for (
unsigned i = 0, e = CPUsers.size(); i != e; ++i)
417 CPChange |= handleConstantPoolUser(i, NoCPIters >=
CPMaxIteration / 2);
424 NewWaterList.
clear();
426 LLVM_DEBUG(
dbgs() <<
"Beginning BR iteration #" << NoBRIters <<
'\n');
427 bool BRChange =
false;
428 for (
unsigned i = 0, e = ImmBranches.size(); i != e; ++i)
429 BRChange |= fixupImmediateBr(ImmBranches[i]);
430 if (BRChange && ++NoBRIters > 30)
434 if (!CPChange && !BRChange)
440 if (isThumb2 && !STI->prefers32BitThumb())
441 MadeChange |= optimizeThumb2Instructions();
444 if (isThumb && STI->hasV8MBaselineOps())
445 MadeChange |= optimizeThumb2Branches();
448 if (GenerateTBB && !STI->genExecuteOnly())
449 MadeChange |= optimizeThumb2JumpTables();
457 MadeChange |= undoLRSpillRestore();
460 for (
unsigned i = 0, e = CPEntries.size(); i != e; ++i) {
461 for (
unsigned j = 0, je = CPEntries[i].
size(); j != je; ++j) {
462 const CPEntry & CPE = CPEntries[i][j];
463 if (CPE.CPEMI && CPE.CPEMI->getOperand(1).isCPI())
474 JumpTableEntryIndices.
clear();
475 JumpTableUserIndices.
clear();
478 T2JumpTables.
clear();
486 ARMConstantIslands::doInitialConstPlacement(std::vector<MachineInstr*> &CPEMIs) {
509 const std::vector<MachineConstantPoolEntry> &CPs = MCP->
getConstants();
512 for (
unsigned i = 0, e = CPs.
size(); i != e; ++i) {
514 unsigned Align = CPs[i].getAlignment();
518 assert((Size % Align) == 0 &&
"CP Entry not multiple of 4 bytes!");
521 unsigned LogAlign =
Log2_32(Align);
526 CPEMIs.push_back(CPEMI);
530 for (
unsigned a = LogAlign + 1; a <= MaxAlign; ++a)
531 if (InsPoint[a] == InsAt)
535 CPEntries.emplace_back(1, CPEntry(CPEMI, i));
537 LLVM_DEBUG(
dbgs() <<
"Moved CPI#" << i <<
" to end of function, size = " 538 << Size <<
", align = " << Align <<
'\n');
548 void ARMConstantIslands::doInitialJumpTablePlacement(
549 std::vector<MachineInstr *> &CPEMIs) {
550 unsigned i = CPEntries.size();
552 const std::vector<MachineJumpTableEntry> &
JT = MJTI->getJumpTables();
556 auto MI = MBB.getLastNonDebugInstr();
567 case ARM::BR_JTm_i12:
569 JTOpcode = ARM::JUMPTABLE_ADDRS;
572 JTOpcode = ARM::JUMPTABLE_INSTS;
576 JTOpcode = ARM::JUMPTABLE_TBB;
580 JTOpcode = ARM::JUMPTABLE_TBH;
588 unsigned Size = JT[JTI].MBBs.size() *
sizeof(
uint32_t);
596 CPEMIs.push_back(CPEMI);
597 CPEntries.emplace_back(1, CPEntry(CPEMI, JTI));
598 JumpTableEntryIndices.
insert(std::make_pair(JTI, CPEntries.size() - 1));
599 if (!LastCorrectlyNumberedBB)
600 LastCorrectlyNumberedBB = &MBB;
604 if (LastCorrectlyNumberedBB)
605 MF->RenumberBlocks(LastCorrectlyNumberedBB);
625 bool TooDifficult = TII->
analyzeBranch(*MBB, TBB, FBB, Cond);
626 return TooDifficult || FBB ==
nullptr;
631 ARMConstantIslands::CPEntry *
632 ARMConstantIslands::findConstPoolEntry(
unsigned CPI,
634 std::vector<CPEntry> &CPEs = CPEntries[CPI];
637 for (
unsigned i = 0, e = CPEs.size(); i != e; ++i) {
638 if (CPEs[i].CPEMI == CPEMI)
646 unsigned ARMConstantIslands::getCPELogAlign(
const MachineInstr *CPEMI) {
648 case ARM::CONSTPOOL_ENTRY:
650 case ARM::JUMPTABLE_TBB:
651 return isThumb1 ? 2 : 0;
652 case ARM::JUMPTABLE_TBH:
653 return isThumb1 ? 2 : 1;
654 case ARM::JUMPTABLE_INSTS:
656 case ARM::JUMPTABLE_ADDRS:
662 unsigned CPI = getCombinedIndex(CPEMI);
663 assert(CPI < MCP->getConstants().
size() &&
"Invalid constant pool index.");
664 unsigned Align = MCP->
getConstants()[CPI].getAlignment();
672 void ARMConstantIslands::scanFunctionJumpTables() {
676 (
I.getOpcode() == ARM::t2BR_JT ||
I.getOpcode() == ARM::tBR_JTr))
684 void ARMConstantIslands::
685 initializeFunctionInfo(
const std::vector<MachineInstr*> &CPEMIs) {
691 BBInfo.front().KnownBits = MF->getAlignment();
694 adjustBBOffsetsAfter(&MF->front());
701 WaterList.push_back(&MBB);
704 if (
I.isDebugInstr())
707 unsigned Opc =
I.getOpcode();
751 unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
752 ImmBranches.push_back(ImmBranch(&
I, MaxOffs, isCond, UOpc));
755 if (Opc == ARM::tPUSH || Opc == ARM::tPOP_RET)
758 if (Opc == ARM::CONSTPOOL_ENTRY || Opc == ARM::JUMPTABLE_ADDRS ||
759 Opc == ARM::JUMPTABLE_INSTS || Opc == ARM::JUMPTABLE_TBB ||
760 Opc == ARM::JUMPTABLE_TBH)
764 for (
unsigned op = 0, e =
I.getNumOperands();
op != e; ++
op)
765 if (
I.getOperand(
op).isCPI() ||
I.getOperand(
op).isJTI()) {
773 bool IsSoImm =
false;
781 case ARM::LEApcrelJT:
791 case ARM::t2LEApcrel:
792 case ARM::t2LEApcrelJT:
797 case ARM::tLEApcrelJT:
836 unsigned CPI =
I.getOperand(
op).getIndex();
837 if (
I.getOperand(
op).isJTI()) {
838 JumpTableUserIndices.
insert(std::make_pair(CPI, CPUsers.size()));
839 CPI = JumpTableEntryIndices[CPI];
843 unsigned MaxOffs = ((1 <<
Bits)-1) * Scale;
844 CPUsers.push_back(CPUser(&
I, CPEMI, MaxOffs, NegOk, IsSoImm));
847 CPEntry *CPE = findConstPoolEntry(CPI, CPEMI);
848 assert(CPE &&
"Cannot find a corresponding CPEntry!");
862 unsigned ARMConstantIslands::getOffsetOf(
MachineInstr *MI)
const {
872 assert(
I != MBB->
end() &&
"Didn't find MI in its own basic block?");
901 WaterList.insert(IP, NewBB);
914 MF->insert(MBBI, NewBB);
923 unsigned Opc = isThumb ? (isThumb2 ? ARM::t2B : ARM::tB) :
ARM::B;
941 MF->RenumberBlocks(NewBB);
955 if (WaterBB == OrigBB)
956 WaterList.
insert(std::next(IP), NewBB);
958 WaterList.insert(IP, OrigBB);
959 NewWaterList.
insert(OrigBB);
973 adjustBBOffsetsAfter(OrigBB);
981 unsigned ARMConstantIslands::getUserOffset(CPUser &U)
const {
982 unsigned UserOffset = getOffsetOf(U.MI);
983 const BasicBlockInfo &BBI = BBInfo[U.MI->getParent()->getNumber()];
987 UserOffset += (isThumb ? 4 : 8);
991 U.KnownAlignment = (KnownBits >= 2);
996 if (isThumb && U.KnownAlignment)
1008 bool ARMConstantIslands::isOffsetInRange(
unsigned UserOffset,
1009 unsigned TrialOffset,
unsigned MaxDisp,
1010 bool NegativeOK,
bool IsSoImm) {
1011 if (UserOffset <= TrialOffset) {
1013 if (TrialOffset - UserOffset <= MaxDisp)
1016 }
else if (NegativeOK) {
1017 if (UserOffset - TrialOffset <= MaxDisp)
1028 bool ARMConstantIslands::isWaterInRange(
unsigned UserOffset,
1031 unsigned CPELogAlign = getCPELogAlign(U.CPEMI);
1032 unsigned CPEOffset = BBInfo[Water->
getNumber()].postOffset(CPELogAlign);
1033 unsigned NextBlockOffset, NextBlockAlignment;
1035 if (++NextBlock == MF->end()) {
1036 NextBlockOffset = BBInfo[Water->
getNumber()].postOffset();
1037 NextBlockAlignment = 0;
1039 NextBlockOffset = BBInfo[NextBlock->getNumber()].Offset;
1040 NextBlockAlignment = NextBlock->getAlignment();
1042 unsigned Size = U.CPEMI->getOperand(2).getImm();
1043 unsigned CPEEnd = CPEOffset +
Size;
1048 if (CPEEnd > NextBlockOffset) {
1049 Growth = CPEEnd - NextBlockOffset;
1057 if (CPEOffset < UserOffset)
1058 UserOffset += Growth +
UnknownPadding(MF->getAlignment(), CPELogAlign);
1063 return isOffsetInRange(UserOffset, CPEOffset, U);
1068 bool ARMConstantIslands::isCPEntryInRange(
MachineInstr *MI,
unsigned UserOffset,
1070 bool NegOk,
bool DoDump) {
1071 unsigned CPEOffset = getOffsetOf(CPEMI);
1078 <<
" max delta=" << MaxDisp
1079 <<
format(
" insn address=%#x", UserOffset) <<
" in " 1082 <<
format(
"CPE address=%#x offset=%+d: ", CPEOffset,
1083 int(CPEOffset - UserOffset));
1087 return isOffsetInRange(UserOffset, CPEOffset, MaxDisp, NegOk);
1109 for(
unsigned i = BBNum + 1, e = MF->getNumBlockIDs(); i < e; ++i) {
1112 unsigned LogAlign = MF->getBlockNumbered(i)->getAlignment();
1113 unsigned Offset = BBInfo[i - 1].postOffset(LogAlign);
1114 unsigned KnownBits = BBInfo[i - 1].postKnownBits(LogAlign);
1119 if (i > BBNum + 2 &&
1120 BBInfo[i].Offset == Offset &&
1121 BBInfo[i].KnownBits == KnownBits)
1124 BBInfo[i].Offset =
Offset;
1125 BBInfo[i].KnownBits = KnownBits;
1133 bool ARMConstantIslands::decrementCPEReferenceCount(
unsigned CPI,
1136 CPEntry *CPE = findConstPoolEntry(CPI, CPEMI);
1137 assert(CPE &&
"Unexpected!");
1138 if (--CPE->RefCount == 0) {
1139 removeDeadCPEMI(CPEMI);
1140 CPE->CPEMI =
nullptr;
1147 unsigned ARMConstantIslands::getCombinedIndex(
const MachineInstr *CPEMI) {
1160 int ARMConstantIslands::findInRangeCPEntry(CPUser& U,
unsigned UserOffset) {
1165 if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk,
1172 unsigned CPI = getCombinedIndex(CPEMI);
1173 std::vector<CPEntry> &CPEs = CPEntries[CPI];
1174 for (
unsigned i = 0, e = CPEs.size(); i != e; ++i) {
1176 if (CPEs[i].CPEMI == CPEMI)
1179 if (CPEs[i].CPEMI ==
nullptr)
1181 if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(),
1184 << CPEs[i].CPI <<
"\n");
1186 U.CPEMI = CPEs[i].CPEMI;
1197 return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1;
1208 return ((1<<10)-1)*2;
1210 return ((1<<23)-1)*2;
1215 return ((1<<23)-1)*4;
1226 bool ARMConstantIslands::findAvailableWater(CPUser &U,
unsigned UserOffset,
1227 water_iterator &WaterIter,
1229 if (WaterList.empty())
1232 unsigned BestGrowth = ~0u;
1244 unsigned MinNoSplitDisp =
1245 BBInfo[UserBB->
getNumber()].postOffset(getCPELogAlign(U.CPEMI));
1246 if (CloserWater && MinNoSplitDisp > U.getMaxDisp() / 2)
1248 for (water_iterator IP = std::prev(WaterList.end()),
B = WaterList.begin();;
1262 if (isWaterInRange(UserOffset, WaterBB, U, Growth) &&
1263 (WaterBB->
getNumber() < U.HighWaterMark->getNumber() ||
1264 NewWaterList.
count(WaterBB) || WaterBB == U.MI->getParent()) &&
1265 Growth < BestGrowth) {
1267 BestGrowth = Growth;
1270 <<
" Growth=" << Growth <<
'\n');
1272 if (CloserWater && WaterBB == U.MI->getParent())
1276 if (!CloserWater && BestGrowth == 0)
1282 return BestGrowth != ~0u;
1292 void ARMConstantIslands::createNewWater(
unsigned CPUserIndex,
1293 unsigned UserOffset,
1295 CPUser &U = CPUsers[CPUserIndex];
1298 unsigned CPELogAlign = getCPELogAlign(CPEMI);
1308 unsigned Delta = isThumb1 ? 2 : 4;
1310 unsigned CPEOffset = UserBBI.
postOffset(CPELogAlign) + Delta;
1312 if (isOffsetInRange(UserOffset, CPEOffset, U)) {
1314 <<
format(
", expected CPE offset %#x\n", CPEOffset));
1321 int UncondBr = isThumb ? ((isThumb2) ? ARM::t2B : ARM::tB) :
ARM::B;
1329 ImmBranches.push_back(ImmBranch(&UserMBB->
back(),
1330 MaxDisp,
false, UncondBr));
1332 adjustBBOffsetsAfter(UserMBB);
1352 unsigned LogAlign = MF->getAlignment();
1353 assert(LogAlign >= CPELogAlign &&
"Over-aligned constant pool entry");
1356 unsigned BaseInsertOffset = UserOffset + U.getMaxDisp() - UPad;
1363 BaseInsertOffset -= 4;
1366 <<
" la=" << LogAlign <<
" kb=" << KnownBits
1367 <<
" up=" << UPad <<
'\n');
1373 if (BaseInsertOffset + 8 >= UserBBI.
postOffset()) {
1382 unsigned EndInsertOffset = BaseInsertOffset + 4 + UPad +
1386 unsigned CPUIndex = CPUserIndex+1;
1387 unsigned NumCPUsers = CPUsers.size();
1390 Offset < BaseInsertOffset;
1392 assert(MI != UserMBB->
end() &&
"Fell off end of block");
1393 if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == &*MI) {
1394 CPUser &U = CPUsers[CPUIndex];
1395 if (!isOffsetInRange(Offset, EndInsertOffset, U)) {
1397 BaseInsertOffset -= 1u << LogAlign;
1398 EndInsertOffset -= 1u << LogAlign;
1404 EndInsertOffset += U.CPEMI->getOperand(2).getImm();
1409 if (MI->getOpcode() == ARM::t2IT)
1417 unsigned PredReg = 0;
1430 if (STI->isTargetWindows() && isThumb && MI->getOpcode() == ARM::t2MOVTi16 &&
1434 assert(MI->getOpcode() == ARM::t2MOVi16 &&
1443 NewMBB = splitBlockBeforeInstr(&*MI);
1450 bool ARMConstantIslands::handleConstantPoolUser(
unsigned CPUserIndex,
1452 CPUser &U = CPUsers[CPUserIndex];
1455 unsigned CPI = getCombinedIndex(CPEMI);
1458 unsigned UserOffset = getUserOffset(U);
1462 int result = findInRangeCPEntry(U, UserOffset);
1463 if (result==1)
return false;
1464 else if (result==2)
return true;
1474 if (findAvailableWater(U, UserOffset, IP, CloserWater)) {
1481 if (NewWaterList.
erase(WaterBB))
1482 NewWaterList.
insert(NewIsland);
1489 createNewWater(CPUserIndex, UserOffset, NewMBB);
1497 IP =
find(WaterList, WaterBB);
1498 if (IP != WaterList.end())
1499 NewWaterList.
erase(WaterBB);
1502 NewWaterList.
insert(NewIsland);
1507 const unsigned Align = isThumb ? 1 : 2;
1515 if (IP != WaterList.end())
1516 WaterList.erase(IP);
1522 updateForInsertedWaterBlock(NewIsland);
1526 U.HighWaterMark = NewIsland;
1531 CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1));
1535 decrementCPEReferenceCount(CPI, CPEMI);
1542 adjustBBOffsetsAfter(&*--NewIsland->
getIterator());
1552 dbgs() <<
" Moved CPE to #" << ID <<
" CPI=" << CPI
1560 void ARMConstantIslands::removeDeadCPEMI(
MachineInstr *CPEMI) {
1566 if (CPEBB->
empty()) {
1575 adjustBBOffsetsAfter(CPEBB);
1585 bool ARMConstantIslands::removeUnusedCPEntries() {
1586 unsigned MadeChange =
false;
1587 for (
unsigned i = 0, e = CPEntries.size(); i != e; ++i) {
1588 std::vector<CPEntry> &CPEs = CPEntries[i];
1589 for (
unsigned j = 0, ee = CPEs.size(); j != ee; ++j) {
1590 if (CPEs[j].RefCount == 0 && CPEs[j].CPEMI) {
1591 removeDeadCPEMI(CPEs[j].CPEMI);
1592 CPEs[j].CPEMI =
nullptr;
1604 unsigned PCAdj = isThumb ? 4 : 8;
1605 unsigned BrOffset = getOffsetOf(MI) + PCAdj;
1606 unsigned DestOffset = BBInfo[DestBB->
getNumber()].Offset;
1610 <<
" max delta=" << MaxDisp <<
" from " << getOffsetOf(MI)
1611 <<
" to " << DestOffset <<
" offset " 1612 << int(DestOffset - BrOffset) <<
"\t" << *
MI);
1614 if (BrOffset <= DestOffset) {
1616 if (DestOffset-BrOffset <= MaxDisp)
1619 if (BrOffset-DestOffset <= MaxDisp)
1627 bool ARMConstantIslands::fixupImmediateBr(ImmBranch &Br) {
1632 if (isBBInRange(MI, DestBB, Br.MaxDisp))
1636 return fixupUnconditionalBr(Br);
1637 return fixupConditionalBr(Br);
1645 ARMConstantIslands::fixupUnconditionalBr(ImmBranch &Br) {
1652 Br.MaxDisp = (1 << 21) * 2;
1653 MI->
setDesc(TII->get(ARM::tBfar));
1655 adjustBBOffsetsAfter(MBB);
1668 ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
1702 if (isBBInRange(MI, NewDest, Br.MaxDisp)) {
1704 dbgs() <<
" Invert Bcc condition and swap its destination with " 1715 splitBlockBeforeInstr(MI);
1725 std::next(MBB->
getIterator())->removeSuccessor(DestBB);
1732 <<
" also invert condition and change dest. to " 1739 Br.MI = &MBB->
back();
1749 ImmBranches.push_back(ImmBranch(&MBB->
back(), MaxDisp,
false, Br.UncondBr));
1754 adjustBBOffsetsAfter(MBB);
1761 bool ARMConstantIslands::undoLRSpillRestore() {
1762 bool MadeChange =
false;
1763 for (
unsigned i = 0, e = PushPopMIs.
size(); i != e; ++i) {
1775 }
else if (MI->
getOpcode() == ARM::tPUSH &&
1786 bool ARMConstantIslands::optimizeThumb2Instructions() {
1787 bool MadeChange =
false;
1790 for (
unsigned i = 0, e = CPUsers.size(); i != e; ++i) {
1791 CPUser &U = CPUsers[i];
1792 unsigned Opcode = U.MI->getOpcode();
1793 unsigned NewOpc = 0;
1798 case ARM::t2LEApcrel:
1800 NewOpc = ARM::tLEApcrel;
1807 NewOpc = ARM::tLDRpci;
1817 unsigned UserOffset = getUserOffset(U);
1818 unsigned MaxOffs = ((1 <<
Bits) - 1) * Scale;
1821 if (!U.KnownAlignment)
1825 if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, MaxOffs,
false,
true)) {
1827 U.MI->setDesc(TII->get(NewOpc));
1830 adjustBBOffsetsAfter(MBB);
1839 bool ARMConstantIslands::optimizeThumb2Branches() {
1840 bool MadeChange =
false;
1847 for (
unsigned i = ImmBranches.size(); i != 0; --i) {
1848 ImmBranch &Br = ImmBranches[i-1];
1849 unsigned Opcode = Br.MI->getOpcode();
1850 unsigned NewOpc = 0;
1867 unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
1869 if (isBBInRange(Br.MI, DestBB, MaxOffs)) {
1871 Br.MI->setDesc(TII->get(NewOpc));
1874 adjustBBOffsetsAfter(MBB);
1880 Opcode = Br.MI->getOpcode();
1881 if (Opcode != ARM::tBcc)
1886 if (!Br.MI->killsRegister(ARM::CPSR))
1890 unsigned PredReg = 0;
1895 NewOpc = ARM::tCBNZ;
1901 unsigned BrOffset = getOffsetOf(Br.MI) + 4 - 2;
1902 unsigned DestOffset = BBInfo[DestBB->
getNumber()].Offset;
1903 if (BrOffset < DestOffset && (DestOffset - BrOffset) <= 126) {
1905 if (CmpMI != Br.MI->getParent()->begin()) {
1907 if (CmpMI->getOpcode() == ARM::tCMPi8) {
1908 unsigned Reg = CmpMI->getOperand(0).getReg();
1911 CmpMI->getOperand(1).getImm() == 0 &&
1916 BuildMI(*MBB, CmpMI, Br.MI->getDebugLoc(), TII->get(NewOpc))
1917 .addReg(Reg).
addMBB(DestBB,Br.MI->getOperand(0).getTargetFlags());
1918 CmpMI->eraseFromParent();
1919 Br.MI->eraseFromParent();
1922 adjustBBOffsetsAfter(MBB);
1955 bool ARMConstantIslands::preserveBaseRegister(
MachineInstr *JumpMI,
1959 bool &BaseRegKill) {
1982 CanDeleteLEA =
true;
1983 BaseRegKill =
false;
1986 for (++I; &*I != JumpMI; ++
I) {
1992 for (
unsigned K = 0,
E = I->getNumOperands(); K !=
E; ++K) {
1999 BaseRegKill = BaseRegKill || MO.
isKill();
2000 CanDeleteLEA =
false;
2010 for (++I; &*I != JumpMI; ++
I) {
2011 for (
unsigned K = 0,
E = I->getNumOperands(); K !=
E; ++K) {
2018 RemovableAdd =
nullptr;
2024 DeadSize += isThumb2 ? 4 : 2;
2025 }
else if (BaseReg == EntryReg) {
2046 return MBB != MF->
end() && MBB->begin() != MBB->end() &&
2047 &*MBB->begin() == CPEMI;
2052 unsigned &DeadSize) {
2061 for (++I; &*I != JumpMI; ++
I) {
2062 if (I->getOpcode() == ARM::t2ADDrs && I->getOperand(0).getReg() == EntryReg)
2071 for (++J; &*J != JumpMI; ++J) {
2072 for (
unsigned K = 0,
E = J->getNumOperands(); K !=
E; ++K) {
2092 for (
auto I = From;
I != To; ++
I)
2093 if (
I->modifiesRegister(Reg, TRI))
2100 bool ARMConstantIslands::optimizeThumb2JumpTables() {
2101 bool MadeChange =
false;
2106 if (!MJTI)
return false;
2108 const std::vector<MachineJumpTableEntry> &JT = MJTI->
getJumpTables();
2109 for (
unsigned i = 0, e = T2JumpTables.
size(); i != e; ++i) {
2113 unsigned JTOpIdx = NumOps - (MI->
isPredicable() ? 2 : 1);
2115 unsigned JTI = JTOP.getIndex();
2119 bool HalfWordOk =
true;
2120 unsigned JTOffset = getOffsetOf(MI) + 4;
2121 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
2122 for (
unsigned j = 0, ee = JTBBs.size(); j != ee; ++j) {
2124 unsigned DstOffset = BBInfo[MBB->
getNumber()].Offset;
2127 if (ByteOk && (DstOffset - JTOffset) > ((1<<8)-1)*2)
2129 unsigned TBHLimit = ((1<<16)-1)*2;
2130 if (HalfWordOk && (DstOffset - JTOffset) > TBHLimit)
2132 if (!ByteOk && !HalfWordOk)
2136 if (!ByteOk && !HalfWordOk)
2139 CPUser &
User = CPUsers[JumpTableUserIndices[JTI]];
2144 unsigned DeadSize = 0;
2145 bool CanDeleteLEA =
false;
2146 bool BaseRegKill =
false;
2148 unsigned IdxReg = ~0U;
2149 bool IdxRegKill =
true;
2154 bool PreservedBaseReg =
2155 preserveBaseRegister(MI, User.MI, DeadSize, CanDeleteLEA, BaseRegKill);
2163 unsigned BaseReg = User.MI->getOperand(0).getReg();
2165 if (User.MI->getIterator() == User.MI->getParent()->begin())
2168 if (Shift->
getOpcode() != ARM::tLSLri ||
2190 auto *
TRI = STI->getRegisterInfo();
2200 if (isPositionIndependentOrROPI) {
2223 CanDeleteLEA =
true;
2231 unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT;
2233 Opc = ByteOk ? ARM::tTBB_JT : ARM::tTBH_JT;
2238 .addReg(User.MI->getOperand(0).getReg(),
2241 .addJumpTableIndex(JTI, JTOP.getTargetFlags())
2245 unsigned JTOpc = ByteOk ? ARM::JUMPTABLE_TBB : ARM::JUMPTABLE_TBH;
2246 CPEMI->
setDesc(TII->get(JTOpc));
2256 User.MI->eraseFromParent();
2257 DeadSize += isThumb2 ? 4 : 2;
2264 User.IsSoImm =
false;
2265 User.KnownAlignment =
false;
2269 int CPEntryIdx = JumpTableEntryIndices[JTI];
2270 auto &CPEs = CPEntries[CPEntryIdx];
2272 find_if(CPEs, [&](CPEntry &
E) {
return E.CPEMI == User.CPEMI; });
2274 CPUsers.emplace_back(CPUser(NewJTMI, User.CPEMI, 4,
false,
false));
2282 int Delta = OrigSize - NewSize + DeadSize;
2284 adjustBBOffsetsAfter(MBB);
2295 bool ARMConstantIslands::reorderThumb2JumpTables() {
2296 bool MadeChange =
false;
2299 if (!MJTI)
return false;
2301 const std::vector<MachineJumpTableEntry> &JT = MJTI->
getJumpTables();
2302 for (
unsigned i = 0, e = T2JumpTables.
size(); i != e; ++i) {
2306 unsigned JTOpIdx = NumOps - (MI->
isPredicable() ? 2 : 1);
2308 unsigned JTI = JTOP.getIndex();
2315 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
2316 for (
unsigned j = 0, ee = JTBBs.size(); j != ee; ++j) {
2320 if (DTNumber < JTNumber) {
2324 adjustJTTargetBlockForward(MBB, MI->
getParent());
2353 if (!B && Cond.
empty() && BB != &MF->
front() &&
2356 OldPrior->updateTerminator();
2359 MF->RenumberBlocks();
2368 MF->insert(MBBI, NewBB);
2383 MF->RenumberBlocks(NewBB);
2396 return new ARMConstantIslands();
const MachineInstrBuilder & add(const MachineOperand &MO) const
A parsed version of the target data layout string in and methods for querying it. ...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
The MachineConstantPool class keeps track of constants referenced by a function which must be spilled...
const std::vector< MachineJumpTableEntry > & getJumpTables() const
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
MachineBasicBlock * getMBB() const
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
bool isEmpty() const
isEmpty - Return true if this constant pool contains no constants.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
This class represents lattice values for constants.
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them...
void push_back(const T &Elt)
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
Describe properties that are true of each instruction in the target description file.
unsigned getReg() const
getReg - Returns the register number.
void transferSuccessors(MachineBasicBlock *FromMBB)
Transfers all the successors from MBB to this machine basic block (i.e., copies all the successors Fr...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
bool isPredicable(QueryType Type=AllInBundle) const
Return true if this instruction has a predicate operand that controls execution.
unsigned Offset
Offset - Distance from the beginning of the function to the beginning of this basic block...
STATISTIC(NumFunctions, "Total number of functions")
void moveAfter(MachineBasicBlock *NewBefore)
unsigned const TargetRegisterInfo * TRI
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
void dump() const
dump - Print the current MachineFunction to cerr, useful for debugger use.
void computeBlockSize(MachineFunction *MF, MachineBasicBlock *MBB, BasicBlockInfo &BBI)
unsigned createPICLabelUId()
static bool isThumb(const MCSubtargetInfo &STI)
void setAlignment(unsigned Align)
Set alignment of the basic block.
bool ReplaceMBBInJumpTable(unsigned Idx, MachineBasicBlock *Old, MachineBasicBlock *New)
ReplaceMBBInJumpTable - If Old is a target of the jump tables, update the jump table to branch to New...
BasicBlockInfo - Information about the offset and size of a single basic block.
static bool CompareMBBNumbers(const MachineBasicBlock *LHS, const MachineBasicBlock *RHS)
CompareMBBNumbers - Little predicate function to sort the WaterList by MBB ID.
static bool isSimpleIndexCalc(MachineInstr &I, unsigned EntryReg, unsigned BaseReg)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
const HexagonInstrInfo * TII
Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
unsigned getNumOperands() const
Retuns the total number of operands.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
#define ARM_CP_ISLANDS_OPT_NAME
FunctionPass * createARMConstantIslandPass()
createARMConstantIslandPass - returns an instance of the constpool island pass.
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
static std::array< MachineOperand, 2 > predOps(ARMCC::CondCodes Pred, unsigned PredReg=0)
Get the operands corresponding to the given Pred value.
static cl::opt< bool > SynthesizeThumb1TBB("arm-synthesize-thumb-1-tbb", cl::Hidden, cl::init(true), cl::desc("Use compressed jump tables in Thumb-1 by synthesizing an " "equivalent to the TBB/TBH instructions"))
bool isLRSpilledForFarJump() const
bool isThumb2Function() const
auto lower_bound(R &&Range, ForwardIt I) -> decltype(adl_begin(Range))
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *bb=nullptr)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
unsigned getKillRegState(bool B)
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
initializer< Ty > init(const Ty &Val)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
unsigned getConstantPoolAlignment() const
getConstantPoolAlignment - Return the alignment required by the whole constant pool, of which the first element must be aligned.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
unsigned postOffset(unsigned LogAlign=0) const
Compute the offset immediately following this block.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
static bool registerDefinedBetween(unsigned Reg, MachineBasicBlock::iterator From, MachineBasicBlock::iterator To, const TargetRegisterInfo *TRI)
unsigned getInstSizeInBytes(const MachineInstr &MI) const override
GetInstSize - Returns the size of the specified MachineInstr.
unsigned getAlignment() const
Return alignment of the basic block.
void ensureAlignment(unsigned A)
ensureAlignment - Make sure the function is at least 1 << A bytes aligned.
void setMBB(MachineBasicBlock *MBB)
static bool BBIsJumpedOver(MachineBasicBlock *MBB)
BBIsJumpedOver - Return true of the specified basic block's only predecessor unconditionally branches...
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
void setImm(int64_t immVal)
void initPICLabelUId(unsigned UId)
FunctionPass class - This class is used to implement most global optimizations.
self_iterator getIterator()
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
unsigned internalKnownBits() const
Compute the number of known offset bits internally to this block.
bool isThumb1OnlyFunction() const
succ_iterator succ_begin()
ARMCC::CondCodes getInstrPredicate(const MachineInstr &MI, unsigned &PredReg)
getInstrPredicate - If instruction is predicated, returns its predicate condition, otherwise returns AL.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
pred_iterator pred_begin()
static wasm::ValType getType(const TargetRegisterClass *RC)
auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
MO_LO16 - On a symbol operand, this represents a relocation containing lower 16 bit of the address...
unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
void setIsKill(bool Val=true)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
const std::vector< MachineConstantPoolEntry > & getConstants() const
Iterator for intrusive lists based on ilist_node.
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
void setDesc(const MCInstrDesc &tid)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one...
auto size(R &&Range, typename std::enable_if< std::is_same< typename std::iterator_traits< decltype(Range.begin())>::iterator_category, std::random_access_iterator_tag >::value, void >::type *=nullptr) -> decltype(std::distance(Range.begin(), Range.end()))
Get the size of a range.
BlockVerifier::State From
ARMCC::CondCodes getITInstrPredicate(const MachineInstr &MI, unsigned &PredReg)
getITInstrPredicate - Valid only in Thumb2 mode.
unsigned UnknownPadding(unsigned LogAlign, unsigned KnownBits)
UnknownPadding - Return the worst case padding that could result from unknown offset bits...
MachineOperand class - Representation of each machine instruction operand.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify=false) const override
void updateTerminator()
Update the terminator instructions in block to account for changes to the layout. ...
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned char TargetFlags=0) const
APFloat neg(APFloat X)
Returns the negated value of the argument.
static cl::opt< bool > AdjustJumpTableBlocks("arm-adjust-jump-tables", cl::Hidden, cl::init(true), cl::desc("Adjust basic block layout to better use TB[BH]"))
void invalidateLiveness()
invalidateLiveness - Indicates that register liveness is no longer being tracked accurately.
unsigned pred_size() const
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
void replaceSuccessor(MachineBasicBlock *Old, MachineBasicBlock *New)
Replace successor OLD with NEW and update probability info.
unsigned succ_size() const
const MachineBasicBlock * getParent() const
MachineFunctionProperties & set(Property P)
void recordCPEClone(unsigned CPIdx, unsigned CPCloneIdx)
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
static bool isARMLowRegister(unsigned Reg)
isARMLowRegister - Returns true if the register is a low register (r0-r7).
Representation of each machine instruction.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
static CondCodes getOppositeCondition(CondCodes CC)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
uint8_t Unalign
Unalign - When non-zero, the block contains instructions (inline asm) of unknown size.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
LLVM_NODISCARD bool empty() const
static bool BBHasFallthrough(MachineBasicBlock *MBB)
BBHasFallthrough - Return true if the specified basic block can fallthrough into the block immediatel...
ARMFunctionInfo - This class is derived from MachineFunctionInfo and contains private ARM-specific in...
void setReg(unsigned Reg)
Change the register this operand corresponds to.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
MO_OPTION_MASK - Most flags are mutually exclusive; this mask selects just that part of the flag set...
uint8_t KnownBits
KnownBits - The number of low bits in Offset that are known to be exact.
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
static unsigned getUnconditionalBrDisp(int Opc)
getUnconditionalBrDisp - Returns the maximum displacement that can fit in the specific unconditional ...
bool isReg() const
isReg - Tests if this is a MO_Register operand.
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned char TargetFlags=0) const
static cl::opt< unsigned > CPMaxIteration("arm-constant-island-max-iteration", cl::Hidden, cl::init(30), cl::desc("The max number of iteration for converge"))
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool jumpTableFollowsTB(MachineInstr *JTMI, MachineInstr *CPEMI)
Returns whether CPEMI is the first instruction in the block immediately following JTMI (assumed to be...
void push_back(MachineBasicBlock *MBB)
uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align)
Returns the offset to the next integer (mod 2**64) that is greater than or equal to Value and is a mu...
StringRef - Represent a constant reference to a string, i.e.
static void RemoveDeadAddBetweenLEAAndJT(MachineInstr *LEAMI, MachineInstr *JumpMI, unsigned &DeadSize)
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned char TargetFlags=0) const
const MachineJumpTableInfo * getJumpTableInfo() const
getJumpTableInfo - Return the jump table info object for the current function.
const MachineOperand & getOperand(unsigned i) const
bool isThumbFunction() const
uint8_t PostAlign
PostAlign - When non-zero, the block terminator contains a .align directive, so the end of the block ...
MO_HI16 - On a symbol operand, this represents a relocation containing higher 16 bit of the address...
Properties which a MachineFunction may have at a given point in time.
std::vector< BasicBlockInfo > computeAllBlockSizes(MachineFunction *MF)
size_type count(const T &V) const
count - Return 1 if the element is in the set, 0 otherwise.