39 #define DEBUG_TYPE "arm-cp-islands"
41 STATISTIC(NumCPEs,
"Number of constpool entries");
42 STATISTIC(NumSplit,
"Number of uncond branches inserted");
43 STATISTIC(NumCBrFixed,
"Number of cond branches fixed");
44 STATISTIC(NumUBrFixed,
"Number of uncond branches fixed");
45 STATISTIC(NumTBs,
"Number of table branches generated");
46 STATISTIC(NumT2CPShrunk,
"Number of Thumb2 constantpool instructions shrunk");
47 STATISTIC(NumT2BrShrunk,
"Number of Thumb2 immediate branches shrunk");
48 STATISTIC(NumCBZ,
"Number of CBZ / CBNZ formed");
49 STATISTIC(NumJTMoved,
"Number of jump table destination blocks moved");
50 STATISTIC(NumJTInserted,
"Number of jump table intermediate blocks inserted");
55 cl::desc(
"Adjust basic block layout to better use TB[BH]"));
59 cl::desc(
"The max number of iteration for converge"));
63 cl::desc(
"Use compressed jump tables in Thumb-1 by synthesizing an "
64 "equivalent to the TBB/TBH instructions"));
80 std::vector<BasicBlockInfo> BBInfo;
85 std::vector<MachineBasicBlock*> WaterList;
91 typedef std::vector<MachineBasicBlock*>::iterator water_iterator;
114 bool neg,
bool soimm)
115 :
MI(mi), CPEMI(cpemi), MaxDisp(maxdisp), NegOk(neg), IsSoImm(soimm),
116 KnownAlignment(
false) {
117 HighWaterMark = CPEMI->getParent();
122 unsigned getMaxDisp()
const {
123 return (KnownAlignment ? MaxDisp : MaxDisp - 2) - 2;
129 std::vector<CPUser> CPUsers;
139 : CPEMI(cpemi), CPI(cpi), RefCount(
rc) {}
151 std::vector<std::vector<CPEntry> > CPEntries;
167 unsigned MaxDisp : 31;
170 ImmBranch(
MachineInstr *mi,
unsigned maxdisp,
bool cond,
unsigned ubr)
171 :
MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {}
176 std::vector<ImmBranch> ImmBranches;
197 bool isPositionIndependentOrROPI;
210 return "ARM constant island placement and branch shortening pass";
214 void doInitialConstPlacement(std::vector<MachineInstr *> &CPEMIs);
215 void doInitialJumpTablePlacement(std::vector<MachineInstr *> &CPEMIs);
217 CPEntry *findConstPoolEntry(
unsigned CPI,
const MachineInstr *CPEMI);
219 void scanFunctionJumpTables();
220 void initializeFunctionInfo(
const std::vector<MachineInstr*> &CPEMIs);
224 bool decrementCPEReferenceCount(
unsigned CPI,
MachineInstr* CPEMI);
226 int findInRangeCPEntry(CPUser& U,
unsigned UserOffset);
227 bool findAvailableWater(CPUser&U,
unsigned UserOffset,
228 water_iterator &WaterIter,
bool CloserWater);
229 void createNewWater(
unsigned CPUserIndex,
unsigned UserOffset,
231 bool handleConstantPoolUser(
unsigned CPUserIndex,
bool CloserWater);
233 bool removeUnusedCPEntries();
236 bool DoDump =
false);
238 CPUser &U,
unsigned &Growth);
240 bool fixupImmediateBr(ImmBranch &Br);
241 bool fixupConditionalBr(ImmBranch &Br);
242 bool fixupUnconditionalBr(ImmBranch &Br);
243 bool undoLRSpillRestore();
244 bool optimizeThumb2Instructions();
245 bool optimizeThumb2Branches();
246 bool reorderThumb2JumpTables();
248 unsigned &DeadSize,
bool &CanDeleteLEA,
250 bool optimizeThumb2JumpTables();
255 unsigned getUserOffset(CPUser&)
const;
259 bool isOffsetInRange(
unsigned UserOffset,
unsigned TrialOffset,
260 unsigned Disp,
bool NegativeOK,
bool IsSoImm =
false);
261 bool isOffsetInRange(
unsigned UserOffset,
unsigned TrialOffset,
263 return isOffsetInRange(UserOffset, TrialOffset,
264 U.getMaxDisp(), U.NegOk, U.IsSoImm);
273 assert(std::is_sorted(MF->begin(), MF->end(),
276 return BBInfo[LHS.
getNumber()].postOffset() <
277 BBInfo[RHS.getNumber()].postOffset();
279 DEBUG(
dbgs() <<
"Verifying " << CPUsers.size() <<
" CP users.\n");
280 for (
unsigned i = 0, e = CPUsers.size();
i != e; ++
i) {
281 CPUser &U = CPUsers[
i];
282 unsigned UserOffset = getUserOffset(U);
285 if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, U.getMaxDisp()+2, U.NegOk,
299 void ARMConstantIslands::dumpBBs() {
301 for (
unsigned J = 0,
E = BBInfo.size(); J !=
E; ++J) {
307 <<
format(
" size=%#x\n", BBInfo[J].Size);
315 return new ARMConstantIslands();
322 DEBUG(
dbgs() <<
"***** ARMConstantIslands: "
323 << MCP->getConstants().size() <<
" CP entries, aligned to "
324 << MCP->getConstantPoolAlignment() <<
" bytes *****\n");
326 STI = &
static_cast<const ARMSubtarget &
>(MF->getSubtarget());
327 TII = STI->getInstrInfo();
328 isPositionIndependentOrROPI =
329 STI->getTargetLowering()->isPositionIndependent() || STI->isROPI();
332 isThumb = AFI->isThumbFunction();
333 isThumb1 = AFI->isThumb1OnlyFunction();
334 isThumb2 = AFI->isThumb2Function();
340 MF->getRegInfo().invalidateLiveness();
344 MF->RenumberBlocks();
348 bool MadeChange =
false;
350 scanFunctionJumpTables();
351 MadeChange |= reorderThumb2JumpTables();
353 T2JumpTables.clear();
355 MF->RenumberBlocks();
360 std::vector<MachineInstr*> CPEMIs;
362 doInitialConstPlacement(CPEMIs);
364 if (MF->getJumpTableInfo())
365 doInitialJumpTablePlacement(CPEMIs);
368 AFI->initPICLabelUId(CPEMIs.size());
373 initializeFunctionInfo(CPEMIs);
379 if (!T2JumpTables.empty())
380 MF->ensureAlignment(2);
383 MadeChange |= removeUnusedCPEntries();
387 unsigned NoCPIters = 0, NoBRIters = 0;
389 DEBUG(
dbgs() <<
"Beginning CP iteration #" << NoCPIters <<
'\n');
390 bool CPChange =
false;
391 for (
unsigned i = 0, e = CPUsers.size();
i != e; ++
i)
395 CPChange |= handleConstantPoolUser(
i, NoCPIters >=
CPMaxIteration / 2);
402 NewWaterList.clear();
404 DEBUG(
dbgs() <<
"Beginning BR iteration #" << NoBRIters <<
'\n');
405 bool BRChange =
false;
406 for (
unsigned i = 0, e = ImmBranches.size();
i != e; ++
i)
407 BRChange |= fixupImmediateBr(ImmBranches[
i]);
408 if (BRChange && ++NoBRIters > 30)
412 if (!CPChange && !BRChange)
418 if (isThumb2 && !STI->prefers32BitThumb())
419 MadeChange |= optimizeThumb2Instructions();
422 if (isThumb && STI->hasV8MBaselineOps())
423 MadeChange |= optimizeThumb2Branches();
426 if (GenerateTBB && !STI->genExecuteOnly())
427 MadeChange |= optimizeThumb2JumpTables();
435 MadeChange |= undoLRSpillRestore();
438 for (
unsigned i = 0, e = CPEntries.size(); i != e; ++
i) {
439 for (
unsigned j = 0, je = CPEntries[i].size(); j != je; ++j) {
440 const CPEntry & CPE = CPEntries[
i][j];
441 if (CPE.CPEMI && CPE.CPEMI->getOperand(1).isCPI())
442 AFI->recordCPEClone(i, CPE.CPI);
452 JumpTableEntryIndices.clear();
453 JumpTableUserIndices.clear();
456 T2JumpTables.clear();
464 ARMConstantIslands::doInitialConstPlacement(std::vector<MachineInstr*> &CPEMIs) {
470 unsigned MaxAlign =
Log2_32(MCP->getConstantPoolAlignment());
487 const std::vector<MachineConstantPoolEntry> &CPs = MCP->getConstants();
490 for (
unsigned i = 0, e = CPs.
size(); i != e; ++
i) {
492 assert(Size >= 4 &&
"Too small constant pool entry");
493 unsigned Align = CPs[
i].getAlignment();
497 assert((Size % Align) == 0 &&
"CP Entry not multiple of 4 bytes!");
500 unsigned LogAlign =
Log2_32(Align);
505 CPEMIs.push_back(CPEMI);
509 for (
unsigned a = LogAlign + 1; a <= MaxAlign; ++a)
510 if (InsPoint[a] == InsAt)
514 CPEntries.emplace_back(1, CPEntry(CPEMI, i));
516 DEBUG(
dbgs() <<
"Moved CPI#" << i <<
" to end of function, size = "
517 << Size <<
", align = " << Align <<
'\n');
527 void ARMConstantIslands::doInitialJumpTablePlacement(
528 std::vector<MachineInstr *> &CPEMIs) {
529 unsigned i = CPEntries.size();
530 auto MJTI = MF->getJumpTableInfo();
531 const std::vector<MachineJumpTableEntry> &
JT = MJTI->getJumpTables();
540 switch (
MI->getOpcode()) {
547 JTOpcode = ARM::JUMPTABLE_ADDRS;
550 JTOpcode = ARM::JUMPTABLE_INSTS;
554 JTOpcode = ARM::JUMPTABLE_TBB;
558 JTOpcode = ARM::JUMPTABLE_TBH;
562 unsigned NumOps =
MI->getDesc().getNumOperands();
564 MI->getOperand(NumOps - (
MI->isPredicable() ? 2 : 1));
566 unsigned Size = JT[JTI].MBBs.size() *
sizeof(
uint32_t);
574 CPEMIs.push_back(CPEMI);
575 CPEntries.emplace_back(1, CPEntry(CPEMI, JTI));
576 JumpTableEntryIndices.insert(std::make_pair(JTI, CPEntries.size() - 1));
577 if (!LastCorrectlyNumberedBB)
578 LastCorrectlyNumberedBB = &
MBB;
582 if (LastCorrectlyNumberedBB)
583 MF->RenumberBlocks(LastCorrectlyNumberedBB);
604 return TooDifficult || FBB ==
nullptr;
609 ARMConstantIslands::CPEntry
610 *ARMConstantIslands::findConstPoolEntry(
unsigned CPI,
612 std::vector<CPEntry> &CPEs = CPEntries[CPI];
615 for (
unsigned i = 0, e = CPEs.size(); i != e; ++
i) {
616 if (CPEs[i].CPEMI == CPEMI)
624 unsigned ARMConstantIslands::getCPELogAlign(
const MachineInstr *CPEMI) {
626 case ARM::CONSTPOOL_ENTRY:
628 case ARM::JUMPTABLE_TBB:
629 return isThumb1 ? 2 : 0;
630 case ARM::JUMPTABLE_TBH:
631 return isThumb1 ? 2 : 1;
632 case ARM::JUMPTABLE_INSTS:
634 case ARM::JUMPTABLE_ADDRS:
640 unsigned CPI = getCombinedIndex(CPEMI);
641 assert(CPI < MCP->getConstants().size() &&
"Invalid constant pool index.");
642 unsigned Align = MCP->getConstants()[CPI].getAlignment();
650 void ARMConstantIslands::scanFunctionJumpTables() {
654 (
I.getOpcode() == ARM::t2BR_JT ||
I.getOpcode() == ARM::tBR_JTr))
655 T2JumpTables.push_back(&
I);
662 void ARMConstantIslands::
663 initializeFunctionInfo(
const std::vector<MachineInstr*> &CPEMIs) {
669 BBInfo.front().KnownBits = MF->getAlignment();
672 adjustBBOffsetsAfter(&MF->front());
679 WaterList.push_back(&MBB);
682 if (
I.isDebugValue())
685 unsigned Opc =
I.getOpcode();
696 T2JumpTables.push_back(&
I);
729 unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
730 ImmBranches.push_back(ImmBranch(&
I, MaxOffs, isCond, UOpc));
733 if (Opc == ARM::tPUSH || Opc == ARM::tPOP_RET)
734 PushPopMIs.push_back(&
I);
736 if (Opc == ARM::CONSTPOOL_ENTRY || Opc == ARM::JUMPTABLE_ADDRS ||
737 Opc == ARM::JUMPTABLE_INSTS || Opc == ARM::JUMPTABLE_TBB ||
738 Opc == ARM::JUMPTABLE_TBH)
742 for (
unsigned op = 0, e =
I.getNumOperands();
op != e; ++
op)
743 if (
I.getOperand(
op).isCPI() ||
I.getOperand(
op).isJTI()) {
751 bool IsSoImm =
false;
759 case ARM::LEApcrelJT:
769 case ARM::t2LEApcrel:
770 case ARM::t2LEApcrelJT:
775 case ARM::tLEApcrelJT:
808 unsigned CPI =
I.getOperand(
op).getIndex();
809 if (
I.getOperand(
op).isJTI()) {
810 JumpTableUserIndices.insert(std::make_pair(CPI, CPUsers.size()));
811 CPI = JumpTableEntryIndices[CPI];
815 unsigned MaxOffs = ((1 <<
Bits)-1) * Scale;
816 CPUsers.push_back(CPUser(&
I, CPEMI, MaxOffs, NegOk, IsSoImm));
819 CPEntry *CPE = findConstPoolEntry(CPI, CPEMI);
820 assert(CPE &&
"Cannot find a corresponding CPEntry!");
834 unsigned ARMConstantIslands::getOffsetOf(
MachineInstr *
MI)
const {
844 assert(
I != MBB->
end() &&
"Didn't find MI in its own basic block?");
845 Offset +=
TII->getInstSizeInBytes(*
I);
871 std::lower_bound(WaterList.begin(), WaterList.end(), NewBB,
873 WaterList.insert(IP, NewBB);
887 MF->insert(MBBI, NewBB);
896 unsigned Opc = isThumb ? (isThumb2 ? ARM::t2B : ARM::tB) :
ARM::B;
913 MF->RenumberBlocks(NewBB);
924 std::lower_bound(WaterList.begin(), WaterList.end(), OrigBB,
927 if (WaterBB == OrigBB)
928 WaterList.
insert(std::next(IP), NewBB);
930 WaterList.insert(IP, OrigBB);
931 NewWaterList.insert(OrigBB);
945 adjustBBOffsetsAfter(OrigBB);
953 unsigned ARMConstantIslands::getUserOffset(CPUser &U)
const {
954 unsigned UserOffset = getOffsetOf(U.MI);
955 const BasicBlockInfo &BBI = BBInfo[U.MI->getParent()->getNumber()];
959 UserOffset += (isThumb ? 4 : 8);
963 U.KnownAlignment = (KnownBits >= 2);
968 if (isThumb && U.KnownAlignment)
980 bool ARMConstantIslands::isOffsetInRange(
unsigned UserOffset,
981 unsigned TrialOffset,
unsigned MaxDisp,
982 bool NegativeOK,
bool IsSoImm) {
983 if (UserOffset <= TrialOffset) {
985 if (TrialOffset - UserOffset <= MaxDisp)
988 }
else if (NegativeOK) {
989 if (UserOffset - TrialOffset <= MaxDisp)
1000 bool ARMConstantIslands::isWaterInRange(
unsigned UserOffset,
1003 unsigned CPELogAlign = getCPELogAlign(U.CPEMI);
1004 unsigned CPEOffset = BBInfo[Water->
getNumber()].postOffset(CPELogAlign);
1005 unsigned NextBlockOffset, NextBlockAlignment;
1007 if (++NextBlock == MF->end()) {
1008 NextBlockOffset = BBInfo[Water->
getNumber()].postOffset();
1009 NextBlockAlignment = 0;
1011 NextBlockOffset = BBInfo[NextBlock->getNumber()].Offset;
1012 NextBlockAlignment = NextBlock->getAlignment();
1014 unsigned Size = U.CPEMI->getOperand(2).getImm();
1015 unsigned CPEEnd = CPEOffset + Size;
1020 if (CPEEnd > NextBlockOffset) {
1021 Growth = CPEEnd - NextBlockOffset;
1029 if (CPEOffset < UserOffset)
1030 UserOffset += Growth +
UnknownPadding(MF->getAlignment(), CPELogAlign);
1035 return isOffsetInRange(UserOffset, CPEOffset, U);
1040 bool ARMConstantIslands::isCPEntryInRange(
MachineInstr *MI,
unsigned UserOffset,
1042 bool NegOk,
bool DoDump) {
1043 unsigned CPEOffset = getOffsetOf(CPEMI);
1050 <<
" max delta=" << MaxDisp
1051 <<
format(
" insn address=%#x", UserOffset)
1052 <<
" in BB#" << Block <<
": "
1054 <<
format(
"CPE address=%#x offset=%+d: ", CPEOffset,
1055 int(CPEOffset-UserOffset));
1059 return isOffsetInRange(UserOffset, CPEOffset, MaxDisp, NegOk);
1081 for(
unsigned i = BBNum + 1, e = MF->getNumBlockIDs(); i < e; ++
i) {
1084 unsigned LogAlign = MF->getBlockNumbered(i)->getAlignment();
1085 unsigned Offset = BBInfo[i - 1].postOffset(LogAlign);
1086 unsigned KnownBits = BBInfo[i - 1].postKnownBits(LogAlign);
1091 if (i > BBNum + 2 &&
1092 BBInfo[i].Offset == Offset &&
1093 BBInfo[i].KnownBits == KnownBits)
1097 BBInfo[
i].KnownBits = KnownBits;
1106 bool ARMConstantIslands::decrementCPEReferenceCount(
unsigned CPI,
1109 CPEntry *CPE = findConstPoolEntry(CPI, CPEMI);
1110 assert(CPE &&
"Unexpected!");
1111 if (--CPE->RefCount == 0) {
1112 removeDeadCPEMI(CPEMI);
1113 CPE->CPEMI =
nullptr;
1120 unsigned ARMConstantIslands::getCombinedIndex(
const MachineInstr *CPEMI) {
1133 int ARMConstantIslands::findInRangeCPEntry(CPUser& U,
unsigned UserOffset)
1139 if (isCPEntryInRange(UserMI, UserOffset, CPEMI, U.getMaxDisp(), U.NegOk,
1146 unsigned CPI = getCombinedIndex(CPEMI);
1147 std::vector<CPEntry> &CPEs = CPEntries[CPI];
1148 for (
unsigned i = 0, e = CPEs.size(); i != e; ++
i) {
1150 if (CPEs[i].CPEMI == CPEMI)
1153 if (CPEs[i].CPEMI ==
nullptr)
1155 if (isCPEntryInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.getMaxDisp(),
1157 DEBUG(
dbgs() <<
"Replacing CPE#" << CPI <<
" with CPE#"
1158 << CPEs[i].CPI <<
"\n");
1160 U.CPEMI = CPEs[
i].CPEMI;
1171 return decrementCPEReferenceCount(CPI, CPEMI) ? 2 : 1;
1182 return ((1<<10)-1)*2;
1184 return ((1<<23)-1)*2;
1189 return ((1<<23)-1)*4;
1200 bool ARMConstantIslands::findAvailableWater(CPUser &U,
unsigned UserOffset,
1201 water_iterator &WaterIter,
1203 if (WaterList.empty())
1206 unsigned BestGrowth = ~0u;
1218 unsigned MinNoSplitDisp =
1219 BBInfo[UserBB->
getNumber()].postOffset(getCPELogAlign(U.CPEMI));
1220 if (CloserWater && MinNoSplitDisp > U.getMaxDisp() / 2)
1222 for (water_iterator IP = std::prev(WaterList.end()),
B = WaterList.begin();;
1236 if (isWaterInRange(UserOffset, WaterBB, U, Growth) &&
1237 (WaterBB->
getNumber() < U.HighWaterMark->getNumber() ||
1238 NewWaterList.count(WaterBB) || WaterBB == U.MI->getParent()) &&
1239 Growth < BestGrowth) {
1241 BestGrowth = Growth;
1244 <<
" Growth=" << Growth <<
'\n');
1246 if (CloserWater && WaterBB == U.MI->getParent())
1250 if (!CloserWater && BestGrowth == 0)
1256 return BestGrowth != ~0u;
1266 void ARMConstantIslands::createNewWater(
unsigned CPUserIndex,
1267 unsigned UserOffset,
1269 CPUser &U = CPUsers[CPUserIndex];
1272 unsigned CPELogAlign = getCPELogAlign(CPEMI);
1282 unsigned Delta = isThumb1 ? 2 : 4;
1284 unsigned CPEOffset = UserBBI.
postOffset(CPELogAlign) + Delta;
1286 if (isOffsetInRange(UserOffset, CPEOffset, U)) {
1288 <<
format(
", expected CPE offset %#x\n", CPEOffset));
1295 int UncondBr = isThumb ? ((isThumb2) ? ARM::t2B : ARM::tB) :
ARM::
B;
1302 ImmBranches.push_back(ImmBranch(&UserMBB->
back(),
1303 MaxDisp,
false, UncondBr));
1305 adjustBBOffsetsAfter(UserMBB);
1325 unsigned LogAlign = MF->getAlignment();
1326 assert(LogAlign >= CPELogAlign &&
"Over-aligned constant pool entry");
1329 unsigned BaseInsertOffset = UserOffset + U.getMaxDisp() - UPad;
1336 BaseInsertOffset -= 4;
1339 <<
" la=" << LogAlign
1340 <<
" kb=" << KnownBits
1341 <<
" up=" << UPad <<
'\n');
1347 if (BaseInsertOffset + 8 >= UserBBI.
postOffset()) {
1353 UserOffset +
TII->getInstSizeInBytes(*UserMI) + 1);
1354 DEBUG(
dbgs() <<
format(
"Move inside block: %#x\n", BaseInsertOffset));
1356 unsigned EndInsertOffset = BaseInsertOffset + 4 + UPad +
1360 unsigned CPUIndex = CPUserIndex+1;
1361 unsigned NumCPUsers = CPUsers.size();
1363 for (
unsigned Offset = UserOffset +
TII->getInstSizeInBytes(*UserMI);
1364 Offset < BaseInsertOffset;
1365 Offset +=
TII->getInstSizeInBytes(*MI), MI = std::next(MI)) {
1366 assert(MI != UserMBB->
end() &&
"Fell off end of block");
1367 if (CPUIndex < NumCPUsers && CPUsers[CPUIndex].MI == &*MI) {
1368 CPUser &U = CPUsers[CPUIndex];
1369 if (!isOffsetInRange(Offset, EndInsertOffset, U)) {
1371 BaseInsertOffset -= 1u << LogAlign;
1372 EndInsertOffset -= 1u << LogAlign;
1378 EndInsertOffset += U.CPEMI->getOperand(2).getImm();
1383 if (MI->getOpcode() == ARM::t2IT)
1391 unsigned PredReg = 0;
1398 DEBUG(
unsigned PredReg;
1401 NewMBB = splitBlockBeforeInstr(&*MI);
1408 bool ARMConstantIslands::handleConstantPoolUser(
unsigned CPUserIndex,
1410 CPUser &U = CPUsers[CPUserIndex];
1413 unsigned CPI = getCombinedIndex(CPEMI);
1416 unsigned UserOffset = getUserOffset(U);
1420 int result = findInRangeCPEntry(U, UserOffset);
1421 if (result==1)
return false;
1422 else if (result==2)
return true;
1426 unsigned ID = AFI->createPICLabelUId();
1432 if (findAvailableWater(U, UserOffset, IP, CloserWater)) {
1433 DEBUG(
dbgs() <<
"Found water in range\n");
1439 if (NewWaterList.erase(WaterBB))
1440 NewWaterList.
insert(NewIsland);
1447 createNewWater(CPUserIndex, UserOffset, NewMBB);
1455 IP =
find(WaterList, WaterBB);
1456 if (IP != WaterList.end())
1457 NewWaterList.erase(WaterBB);
1460 NewWaterList.insert(NewIsland);
1467 if (IP != WaterList.end())
1468 WaterList.erase(IP);
1474 updateForInsertedWaterBlock(NewIsland);
1478 U.HighWaterMark = NewIsland;
1481 CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1));
1485 decrementCPEReferenceCount(CPI, CPEMI);
1491 BBInfo[NewIsland->
getNumber()].Size += Size;
1492 adjustBBOffsetsAfter(&*--NewIsland->
getIterator());
1501 DEBUG(
dbgs() <<
" Moved CPE to #" << ID <<
" CPI=" << CPI
1509 void ARMConstantIslands::removeDeadCPEMI(
MachineInstr *CPEMI) {
1513 BBInfo[CPEBB->
getNumber()].Size -= Size;
1515 if (CPEBB->
empty()) {
1524 adjustBBOffsetsAfter(CPEBB);
1534 bool ARMConstantIslands::removeUnusedCPEntries() {
1535 unsigned MadeChange =
false;
1536 for (
unsigned i = 0, e = CPEntries.size(); i != e; ++
i) {
1537 std::vector<CPEntry> &CPEs = CPEntries[
i];
1538 for (
unsigned j = 0, ee = CPEs.size(); j != ee; ++j) {
1539 if (CPEs[j].RefCount == 0 && CPEs[j].CPEMI) {
1540 removeDeadCPEMI(CPEs[j].CPEMI);
1541 CPEs[j].CPEMI =
nullptr;
1553 unsigned PCAdj = isThumb ? 4 : 8;
1554 unsigned BrOffset = getOffsetOf(MI) + PCAdj;
1555 unsigned DestOffset = BBInfo[DestBB->
getNumber()].Offset;
1559 <<
" max delta=" << MaxDisp
1560 <<
" from " << getOffsetOf(MI) <<
" to " << DestOffset
1561 <<
" offset " << int(DestOffset-BrOffset) <<
"\t" << *
MI);
1563 if (BrOffset <= DestOffset) {
1565 if (DestOffset-BrOffset <= MaxDisp)
1568 if (BrOffset-DestOffset <= MaxDisp)
1576 bool ARMConstantIslands::fixupImmediateBr(ImmBranch &Br) {
1581 if (isBBInRange(MI, DestBB, Br.MaxDisp))
1585 return fixupUnconditionalBr(Br);
1586 return fixupConditionalBr(Br);
1594 ARMConstantIslands::fixupUnconditionalBr(ImmBranch &Br) {
1601 Br.MaxDisp = (1 << 21) * 2;
1604 adjustBBOffsetsAfter(MBB);
1608 DEBUG(
dbgs() <<
" Changed B to long jump " << *MI);
1617 ARMConstantIslands::fixupConditionalBr(ImmBranch &Br) {
1651 if (isBBInRange(MI, NewDest, Br.MaxDisp)) {
1652 DEBUG(
dbgs() <<
" Invert Bcc condition and swap its destination with "
1663 splitBlockBeforeInstr(MI);
1666 int delta =
TII->getInstSizeInBytes(MBB->
back());
1674 <<
" also invert condition and change dest. to BB#"
1681 Br.MI = &MBB->
back();
1690 ImmBranches.push_back(ImmBranch(&MBB->
back(), MaxDisp,
false, Br.UncondBr));
1695 adjustBBOffsetsAfter(MBB);
1702 bool ARMConstantIslands::undoLRSpillRestore() {
1703 bool MadeChange =
false;
1704 for (
unsigned i = 0, e = PushPopMIs.size(); i != e; ++
i) {
1721 bool ARMConstantIslands::optimizeThumb2Instructions() {
1722 bool MadeChange =
false;
1725 for (
unsigned i = 0, e = CPUsers.size(); i != e; ++
i) {
1726 CPUser &U = CPUsers[
i];
1727 unsigned Opcode = U.MI->getOpcode();
1728 unsigned NewOpc = 0;
1733 case ARM::t2LEApcrel:
1735 NewOpc = ARM::tLEApcrel;
1742 NewOpc = ARM::tLDRpci;
1752 unsigned UserOffset = getUserOffset(U);
1753 unsigned MaxOffs = ((1 <<
Bits) - 1) * Scale;
1756 if (!U.KnownAlignment)
1760 if (isCPEntryInRange(U.MI, UserOffset, U.CPEMI, MaxOffs,
false,
true)) {
1762 U.MI->setDesc(
TII->get(NewOpc));
1765 adjustBBOffsetsAfter(MBB);
1774 bool ARMConstantIslands::optimizeThumb2Branches() {
1775 bool MadeChange =
false;
1782 for (
unsigned i = ImmBranches.size(); i != 0; --
i) {
1783 ImmBranch &Br = ImmBranches[i-1];
1784 unsigned Opcode = Br.MI->getOpcode();
1785 unsigned NewOpc = 0;
1803 unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale;
1805 if (isBBInRange(Br.MI, DestBB, MaxOffs)) {
1806 DEBUG(
dbgs() <<
"Shrink branch: " << *Br.MI);
1807 Br.MI->setDesc(
TII->get(NewOpc));
1810 adjustBBOffsetsAfter(MBB);
1816 Opcode = Br.MI->getOpcode();
1817 if (Opcode != ARM::tBcc)
1822 if (!Br.MI->killsRegister(ARM::CPSR))
1826 unsigned PredReg = 0;
1831 NewOpc = ARM::tCBNZ;
1837 unsigned BrOffset = getOffsetOf(Br.MI) + 4 - 2;
1838 unsigned DestOffset = BBInfo[DestBB->
getNumber()].Offset;
1839 if (BrOffset < DestOffset && (DestOffset - BrOffset) <= 126) {
1841 if (CmpMI != Br.MI->getParent()->begin()) {
1843 if (CmpMI->getOpcode() == ARM::tCMPi8) {
1844 unsigned Reg = CmpMI->getOperand(0).getReg();
1847 CmpMI->getOperand(1).getImm() == 0 &&
1850 DEBUG(
dbgs() <<
"Fold: " << *CmpMI <<
" and: " << *Br.MI);
1852 BuildMI(*MBB, CmpMI, Br.MI->getDebugLoc(),
TII->get(NewOpc))
1853 .addReg(Reg).
addMBB(DestBB,Br.MI->getOperand(0).getTargetFlags());
1854 CmpMI->eraseFromParent();
1855 Br.MI->eraseFromParent();
1858 adjustBBOffsetsAfter(MBB);
1891 bool ARMConstantIslands::preserveBaseRegister(
MachineInstr *JumpMI,
1895 bool &BaseRegKill) {
1918 CanDeleteLEA =
true;
1919 BaseRegKill =
false;
1922 for (++
I; &*
I != JumpMI; ++
I) {
1928 for (
unsigned K = 0,
E =
I->getNumOperands(); K !=
E; ++K) {
1935 BaseRegKill = BaseRegKill || MO.
isKill();
1936 CanDeleteLEA =
false;
1946 for (++
I; &*
I != JumpMI; ++
I) {
1947 for (
unsigned K = 0,
E =
I->getNumOperands(); K !=
E; ++K) {
1954 RemovableAdd =
nullptr;
1960 DeadSize += isThumb2 ? 4 : 2;
1961 }
else if (BaseReg == EntryReg) {
1982 return MBB != MF->
end() && MBB->begin() != MBB->end() &&
1983 &*MBB->begin() == CPEMI;
1988 bool ARMConstantIslands::optimizeThumb2JumpTables() {
1989 bool MadeChange =
false;
1994 if (!MJTI)
return false;
1996 const std::vector<MachineJumpTableEntry> &JT = MJTI->
getJumpTables();
1997 for (
unsigned i = 0, e = T2JumpTables.size(); i != e; ++
i) {
2001 unsigned JTOpIdx = NumOps - (MI->
isPredicable() ? 2 : 1);
2003 unsigned JTI = JTOP.getIndex();
2007 bool HalfWordOk =
true;
2008 unsigned JTOffset = getOffsetOf(MI) + 4;
2009 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
2010 for (
unsigned j = 0, ee = JTBBs.size(); j != ee; ++j) {
2012 unsigned DstOffset = BBInfo[MBB->
getNumber()].Offset;
2015 if (ByteOk && (DstOffset - JTOffset) > ((1<<8)-1)*2)
2017 unsigned TBHLimit = ((1<<16)-1)*2;
2018 if (HalfWordOk && (DstOffset - JTOffset) > TBHLimit)
2020 if (!ByteOk && !HalfWordOk)
2024 if (!ByteOk && !HalfWordOk)
2027 CPUser &
User = CPUsers[JumpTableUserIndices[JTI]];
2032 unsigned DeadSize = 0;
2033 bool CanDeleteLEA =
false;
2034 bool BaseRegKill =
false;
2036 unsigned IdxReg = ~0U;
2037 bool IdxRegKill =
true;
2042 bool PreservedBaseReg =
2043 preserveBaseRegister(MI, User.MI, DeadSize, CanDeleteLEA, BaseRegKill);
2051 unsigned BaseReg = User.MI->getOperand(0).getReg();
2053 if (User.MI->getIterator() == User.MI->getParent()->begin())
2056 if (Shift->
getOpcode() != ARM::tLSLri ||
2072 if (isPositionIndependentOrROPI) {
2091 CanDeleteLEA =
true;
2099 unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT;
2101 Opc = ByteOk ? ARM::tTBB_JT : ARM::tTBH_JT;
2106 .addReg(User.MI->getOperand(0).getReg(),
2109 .addJumpTableIndex(JTI, JTOP.getTargetFlags())
2113 unsigned JTOpc = ByteOk ? ARM::JUMPTABLE_TBB : ARM::JUMPTABLE_TBH;
2121 User.MI->eraseFromParent();
2122 DeadSize += isThumb2 ? 4 : 2;
2129 User.IsSoImm =
false;
2130 User.KnownAlignment =
false;
2134 int CPEntryIdx = JumpTableEntryIndices[JTI];
2135 auto &CPEs = CPEntries[CPEntryIdx];
2137 find_if(CPEs, [&](CPEntry &
E) {
return E.CPEMI == User.CPEMI; });
2139 CPUsers.emplace_back(CPUser(NewJTMI, User.CPEMI, 4,
false,
false));
2143 unsigned NewSize =
TII->getInstSizeInBytes(*NewJTMI);
2144 unsigned OrigSize =
TII->getInstSizeInBytes(*MI);
2147 int Delta = OrigSize - NewSize + DeadSize;
2149 adjustBBOffsetsAfter(MBB);
2160 bool ARMConstantIslands::reorderThumb2JumpTables() {
2161 bool MadeChange =
false;
2164 if (!MJTI)
return false;
2166 const std::vector<MachineJumpTableEntry> &JT = MJTI->
getJumpTables();
2167 for (
unsigned i = 0, e = T2JumpTables.size(); i != e; ++
i) {
2171 unsigned JTOpIdx = NumOps - (MI->
isPredicable() ? 2 : 1);
2173 unsigned JTI = JTOP.getIndex();
2180 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
2181 for (
unsigned j = 0, ee = JTBBs.size(); j != ee; ++j) {
2185 if (DTNumber < JTNumber) {
2189 adjustJTTargetBlockForward(MBB, MI->
getParent());
2218 if (!B && Cond.
empty() && BB != &MF->
front() &&
2221 OldPrior->updateTerminator();
2224 MF->RenumberBlocks();
2233 MF->insert(MBBI, NewBB);
2250 MF->RenumberBlocks(NewBB);
unsigned succ_size() const
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
A parsed version of the target data layout string in and methods for querying it. ...
The MachineConstantPool class keeps track of constants referenced by a function which must be spilled...
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
STATISTIC(NumFunctions,"Total number of functions")
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them...
MachineBasicBlock * getMBB() const
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
Describe properties that are true of each instruction in the target description file.
void transferSuccessors(MachineBasicBlock *FromMBB)
Transfers all the successors from MBB to this machine basic block (i.e., copies all the successors Fr...
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...
const MCInstrDesc & getDesc() const
Returns the target instruction descriptor of this MachineInstr.
void moveAfter(MachineBasicBlock *NewBefore)
FunctionType * getType(LLVMContext &Context, ID id, ArrayRef< Type * > Tys=None)
Return the function type for an intrinsic.
void computeBlockSize(MachineFunction *MF, MachineBasicBlock *MBB, BasicBlockInfo &BBI)
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.
bool isLRSpilledForFarJump() const
static bool CompareMBBNumbers(const MachineBasicBlock *LHS, const MachineBasicBlock *RHS)
CompareMBBNumbers - Little predicate function to sort the WaterList by MBB ID.
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
static bool isSimpleIndexCalc(MachineInstr &I, unsigned EntryReg, unsigned BaseReg)
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e...
const std::vector< MachineJumpTableEntry > & getJumpTables() const
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...
const HexagonInstrInfo * TII
bool isReg() const
isReg - Tests if this is a MO_Register operand.
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Reg
All possible values of the reg field in the ModR/M byte.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
LLVM_NODISCARD bool empty() const
unsigned getNumOperands() const
Access to explicit operands of the instruction.
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
FunctionPass * createARMConstantIslandPass()
createARMConstantIslandPass - returns an instance of the constpool island pass.
Function Alias Analysis false
iterator getLastNonDebugInstr()
Returns an iterator to the last non-debug instruction in the basic block, or end().
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
unsigned getKillRegState(bool B)
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
const MachineBasicBlock * getParent() const
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
initializer< Ty > init(const Ty &Val)
constexpr bool isPowerOf2_32(uint32_t Value)
isPowerOf2_32 - This function returns true if the argument is a power of two > 0. ...
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
const MachineOperand & getOperand(unsigned i) const
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"))
void setMBB(MachineBasicBlock *MBB)
unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
void neg(uint64_t &Value)
static bool BBIsJumpedOver(MachineBasicBlock *MBB)
BBIsJumpedOver - Return true of the specified basic block's only predecessor unconditionally branches...
void setImm(int64_t immVal)
FunctionPass class - This class is used to implement most global optimizations.
self_iterator getIterator()
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
succ_iterator succ_begin()
ARMCC::CondCodes getInstrPredicate(const MachineInstr &MI, unsigned &PredReg)
getInstrPredicate - If instruction is predicated, returns its predicate condition, otherwise returns AL.
pred_iterator pred_begin()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setIsKill(bool Val=true)
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 find(R &&Range, const T &Val) -> decltype(std::begin(Range))
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly...
ARMCC::CondCodes getITInstrPredicate(const MachineInstr &MI, unsigned &PredReg)
getITInstrPredicate - Valid only in Thumb2 mode.
uint64_t getTypeAllocSize(Type *Ty) const
Returns the offset in bytes between successive objects of the specified type, including alignment pad...
unsigned UnknownPadding(unsigned LogAlign, unsigned KnownBits)
UnknownPadding - Return the worst case padding that could result from unknown offset bits...
const MachineInstrBuilder & addJumpTableIndex(unsigned Idx, unsigned char TargetFlags=0) const
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
void updateTerminator()
Update the terminator instructions in block to account for changes to the layout. ...
bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
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]"))
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
unsigned Log2_32(uint32_t Value)
Log2_32 - This function returns 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.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
MachineFunctionProperties & set(Property P)
static bool isARMLowRegister(unsigned Reg)
isARMLowRegister - Returns true if the register is a low register (r0-r7).
Representation of each machine instruction.
static CondCodes getOppositeCondition(CondCodes CC)
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 '...
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 MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned char TargetFlags=0) const
void push_back(MachineInstr *MI)
LLVM_ATTRIBUTE_ALWAYS_INLINE size_type size() const
uint8_t KnownBits
KnownBits - The number of low bits in Offset that are known to be exact.
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
unsigned internalKnownBits() const
Compute the number of known offset bits internally to this block.
static unsigned getUnconditionalBrDisp(int Opc)
getUnconditionalBrDisp - Returns the maximum displacement that can fit in the specific unconditional ...
unsigned getReg() const
getReg - Returns the register number.
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...
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned char TargetFlags=0) const
#define LLVM_FALLTHROUGH
LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
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...
const MachineInstrBuilder & addOperand(const MachineOperand &MO) const
StringRef - Represent a constant reference to a string, i.e.
auto find_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
const MachineInstrBuilder & addReg(unsigned RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
unsigned pred_size() const
uint8_t PostAlign
PostAlign - When non-zero, the block terminator contains a .align directive, so the end of the block ...
Properties which a MachineFunction may have at a given point in time.
unsigned postOffset(unsigned LogAlign=0) const
Compute the offset immediately following this block.
std::vector< BasicBlockInfo > computeAllBlockSizes(MachineFunction *MF)
unsigned getAlignment() const
Return alignment of the basic block.