xref: /freebsd/contrib/llvm-project/llvm/lib/Target/MSP430/MSP430BranchSelector.cpp (revision 5b27928474e6a4103d65b347544705c40c9618fd)
10b57cec5SDimitry Andric //===-- MSP430BranchSelector.cpp - Emit long conditional branches ---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a pass that scans a machine function to determine which
100b57cec5SDimitry Andric // conditional branches need more than 10 bits of displacement to reach their
110b57cec5SDimitry Andric // target basic block.  It does this in two passes; a calculation of basic block
120b57cec5SDimitry Andric // positions pass, and a branch pseudo op to machine branch opcode pass.  This
130b57cec5SDimitry Andric // pass should be run last, just before the assembly printer.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "MSP430.h"
180b57cec5SDimitry Andric #include "MSP430InstrInfo.h"
190b57cec5SDimitry Andric #include "MSP430Subtarget.h"
200b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
23*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
250b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "msp430-branch-select"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric static cl::opt<bool>
310b57cec5SDimitry Andric     BranchSelectEnabled("msp430-branch-select", cl::Hidden, cl::init(true),
320b57cec5SDimitry Andric                         cl::desc("Expand out of range branches"));
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric STATISTIC(NumSplit, "Number of machine basic blocks split");
350b57cec5SDimitry Andric STATISTIC(NumExpanded, "Number of branches expanded to long format");
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric namespace {
380b57cec5SDimitry Andric class MSP430BSel : public MachineFunctionPass {
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric   typedef SmallVector<int, 16> OffsetVector;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   MachineFunction *MF;
430b57cec5SDimitry Andric   const MSP430InstrInfo *TII;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   unsigned measureFunction(OffsetVector &BlockOffsets,
460b57cec5SDimitry Andric                            MachineBasicBlock *FromBB = nullptr);
470b57cec5SDimitry Andric   bool expandBranches(OffsetVector &BlockOffsets);
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric public:
500b57cec5SDimitry Andric   static char ID;
MSP430BSel()510b57cec5SDimitry Andric   MSP430BSel() : MachineFunctionPass(ID) {}
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
540b57cec5SDimitry Andric 
getRequiredProperties() const550b57cec5SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
560b57cec5SDimitry Andric     return MachineFunctionProperties().set(
570b57cec5SDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
getPassName() const600b57cec5SDimitry Andric   StringRef getPassName() const override { return "MSP430 Branch Selector"; }
610b57cec5SDimitry Andric };
620b57cec5SDimitry Andric char MSP430BSel::ID = 0;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
isInRage(int DistanceInBytes)650b57cec5SDimitry Andric static bool isInRage(int DistanceInBytes) {
660b57cec5SDimitry Andric   // According to CC430 Family User's Guide, Section 4.5.1.3, branch
670b57cec5SDimitry Andric   // instructions have the signed 10-bit word offset field, so first we need to
680b57cec5SDimitry Andric   // convert the distance from bytes to words, then check if it fits in 10-bit
690b57cec5SDimitry Andric   // signed integer.
700b57cec5SDimitry Andric   const int WordSize = 2;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   assert((DistanceInBytes % WordSize == 0) &&
730b57cec5SDimitry Andric          "Branch offset should be word aligned!");
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   int Words = DistanceInBytes / WordSize;
760b57cec5SDimitry Andric   return isInt<10>(Words);
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric /// Measure each basic block, fill the BlockOffsets, and return the size of
800b57cec5SDimitry Andric /// the function, starting with BB
measureFunction(OffsetVector & BlockOffsets,MachineBasicBlock * FromBB)810b57cec5SDimitry Andric unsigned MSP430BSel::measureFunction(OffsetVector &BlockOffsets,
820b57cec5SDimitry Andric                                      MachineBasicBlock *FromBB) {
830b57cec5SDimitry Andric   // Give the blocks of the function a dense, in-order, numbering.
840b57cec5SDimitry Andric   MF->RenumberBlocks(FromBB);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   MachineFunction::iterator Begin;
870b57cec5SDimitry Andric   if (FromBB == nullptr) {
880b57cec5SDimitry Andric     Begin = MF->begin();
890b57cec5SDimitry Andric   } else {
900b57cec5SDimitry Andric     Begin = FromBB->getIterator();
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   BlockOffsets.resize(MF->getNumBlockIDs());
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   unsigned TotalSize = BlockOffsets[Begin->getNumber()];
960b57cec5SDimitry Andric   for (auto &MBB : make_range(Begin, MF->end())) {
970b57cec5SDimitry Andric     BlockOffsets[MBB.getNumber()] = TotalSize;
980b57cec5SDimitry Andric     for (MachineInstr &MI : MBB) {
990b57cec5SDimitry Andric       TotalSize += TII->getInstSizeInBytes(MI);
1000b57cec5SDimitry Andric     }
1010b57cec5SDimitry Andric   }
1020b57cec5SDimitry Andric   return TotalSize;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric /// Do expand branches and split the basic blocks if necessary.
1060b57cec5SDimitry Andric /// Returns true if made any change.
expandBranches(OffsetVector & BlockOffsets)1070b57cec5SDimitry Andric bool MSP430BSel::expandBranches(OffsetVector &BlockOffsets) {
1080b57cec5SDimitry Andric   // For each conditional branch, if the offset to its destination is larger
1090b57cec5SDimitry Andric   // than the offset field allows, transform it into a long branch sequence
1100b57cec5SDimitry Andric   // like this:
1110b57cec5SDimitry Andric   //   short branch:
1120b57cec5SDimitry Andric   //     bCC MBB
1130b57cec5SDimitry Andric   //   long branch:
1140b57cec5SDimitry Andric   //     b!CC $PC+6
1150b57cec5SDimitry Andric   //     b MBB
1160b57cec5SDimitry Andric   //
1170b57cec5SDimitry Andric   bool MadeChange = false;
1180b57cec5SDimitry Andric   for (auto MBB = MF->begin(), E = MF->end(); MBB != E; ++MBB) {
1190b57cec5SDimitry Andric     unsigned MBBStartOffset = 0;
1200b57cec5SDimitry Andric     for (auto MI = MBB->begin(), EE = MBB->end(); MI != EE; ++MI) {
1210b57cec5SDimitry Andric       MBBStartOffset += TII->getInstSizeInBytes(*MI);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric       // If this instruction is not a short branch then skip it.
1240b57cec5SDimitry Andric       if (MI->getOpcode() != MSP430::JCC && MI->getOpcode() != MSP430::JMP) {
1250b57cec5SDimitry Andric         continue;
1260b57cec5SDimitry Andric       }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric       MachineBasicBlock *DestBB = MI->getOperand(0).getMBB();
1290b57cec5SDimitry Andric       // Determine the distance from the current branch to the destination
1300b57cec5SDimitry Andric       // block. MBBStartOffset already includes the size of the current branch
1310b57cec5SDimitry Andric       // instruction.
1320b57cec5SDimitry Andric       int BlockDistance =
1330b57cec5SDimitry Andric           BlockOffsets[DestBB->getNumber()] - BlockOffsets[MBB->getNumber()];
1340b57cec5SDimitry Andric       int BranchDistance = BlockDistance - MBBStartOffset;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric       // If this branch is in range, ignore it.
1370b57cec5SDimitry Andric       if (isInRage(BranchDistance)) {
1380b57cec5SDimitry Andric         continue;
1390b57cec5SDimitry Andric       }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "  Found a branch that needs expanding, "
1420b57cec5SDimitry Andric                         << printMBBReference(*DestBB) << ", Distance "
1430b57cec5SDimitry Andric                         << BranchDistance << "\n");
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric       // If JCC is not the last instruction we need to split the MBB.
1460b57cec5SDimitry Andric       if (MI->getOpcode() == MSP430::JCC && std::next(MI) != EE) {
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "  Found a basic block that needs to be split, "
1490b57cec5SDimitry Andric                           << printMBBReference(*MBB) << "\n");
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric         // Create a new basic block.
1520b57cec5SDimitry Andric         MachineBasicBlock *NewBB =
1530b57cec5SDimitry Andric             MF->CreateMachineBasicBlock(MBB->getBasicBlock());
1540b57cec5SDimitry Andric         MF->insert(std::next(MBB), NewBB);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric         // Splice the instructions following MI over to the NewBB.
1570b57cec5SDimitry Andric         NewBB->splice(NewBB->end(), &*MBB, std::next(MI), MBB->end());
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric         // Update the successor lists.
1600b57cec5SDimitry Andric         for (MachineBasicBlock *Succ : MBB->successors()) {
1610b57cec5SDimitry Andric           if (Succ == DestBB) {
1620b57cec5SDimitry Andric             continue;
1630b57cec5SDimitry Andric           }
1640b57cec5SDimitry Andric           MBB->replaceSuccessor(Succ, NewBB);
1650b57cec5SDimitry Andric           NewBB->addSuccessor(Succ);
1660b57cec5SDimitry Andric         }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric         // We introduced a new MBB so all following blocks should be numbered
1690b57cec5SDimitry Andric         // and measured again.
1700b57cec5SDimitry Andric         measureFunction(BlockOffsets, &*MBB);
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric         ++NumSplit;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric         // It may be not necessary to start all over at this point, but it's
1750b57cec5SDimitry Andric         // safer do this anyway.
1760b57cec5SDimitry Andric         return true;
1770b57cec5SDimitry Andric       }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric       MachineInstr &OldBranch = *MI;
1800b57cec5SDimitry Andric       DebugLoc dl = OldBranch.getDebugLoc();
1810b57cec5SDimitry Andric       int InstrSizeDiff = -TII->getInstSizeInBytes(OldBranch);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric       if (MI->getOpcode() == MSP430::JCC) {
1840b57cec5SDimitry Andric         MachineBasicBlock *NextMBB = &*std::next(MBB);
1850b57cec5SDimitry Andric         assert(MBB->isSuccessor(NextMBB) &&
1860b57cec5SDimitry Andric                "This block must have a layout successor!");
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric         // The BCC operands are:
1890b57cec5SDimitry Andric         // 0. Target MBB
1900b57cec5SDimitry Andric         // 1. MSP430 branch predicate
1910b57cec5SDimitry Andric         SmallVector<MachineOperand, 1> Cond;
1920b57cec5SDimitry Andric         Cond.push_back(MI->getOperand(1));
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric         // Jump over the long branch on the opposite condition
1950b57cec5SDimitry Andric         TII->reverseBranchCondition(Cond);
1960b57cec5SDimitry Andric         MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::JCC))
1970b57cec5SDimitry Andric                  .addMBB(NextMBB)
1980b57cec5SDimitry Andric                  .add(Cond[0]);
1990b57cec5SDimitry Andric         InstrSizeDiff += TII->getInstSizeInBytes(*MI);
2000b57cec5SDimitry Andric         ++MI;
2010b57cec5SDimitry Andric       }
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric       // Unconditional branch to the real destination.
2040b57cec5SDimitry Andric       MI = BuildMI(*MBB, MI, dl, TII->get(MSP430::Bi)).addMBB(DestBB);
2050b57cec5SDimitry Andric       InstrSizeDiff += TII->getInstSizeInBytes(*MI);
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric       // Remove the old branch from the function.
2080b57cec5SDimitry Andric       OldBranch.eraseFromParent();
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric       // The size of a new instruction is different from the old one, so we need
2110b57cec5SDimitry Andric       // to correct all block offsets.
2120b57cec5SDimitry Andric       for (int i = MBB->getNumber() + 1, e = BlockOffsets.size(); i < e; ++i) {
2130b57cec5SDimitry Andric         BlockOffsets[i] += InstrSizeDiff;
2140b57cec5SDimitry Andric       }
2150b57cec5SDimitry Andric       MBBStartOffset += InstrSizeDiff;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric       ++NumExpanded;
2180b57cec5SDimitry Andric       MadeChange = true;
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric   return MadeChange;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & mf)2240b57cec5SDimitry Andric bool MSP430BSel::runOnMachineFunction(MachineFunction &mf) {
2250b57cec5SDimitry Andric   MF = &mf;
2260b57cec5SDimitry Andric   TII = static_cast<const MSP430InstrInfo *>(MF->getSubtarget().getInstrInfo());
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   // If the pass is disabled, just bail early.
2290b57cec5SDimitry Andric   if (!BranchSelectEnabled)
2300b57cec5SDimitry Andric     return false;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "\n********** " << getPassName() << " **********\n");
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   // BlockOffsets - Contains the distance from the beginning of the function to
2350b57cec5SDimitry Andric   // the beginning of each basic block.
2360b57cec5SDimitry Andric   OffsetVector BlockOffsets;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   unsigned FunctionSize = measureFunction(BlockOffsets);
2390b57cec5SDimitry Andric   // If the entire function is smaller than the displacement of a branch field,
2400b57cec5SDimitry Andric   // we know we don't need to expand any branches in this
2410b57cec5SDimitry Andric   // function. This is a common case.
2420b57cec5SDimitry Andric   if (isInRage(FunctionSize)) {
2430b57cec5SDimitry Andric     return false;
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   // Iteratively expand branches until we reach a fixed point.
2470b57cec5SDimitry Andric   bool MadeChange = false;
2480b57cec5SDimitry Andric   while (expandBranches(BlockOffsets))
2490b57cec5SDimitry Andric     MadeChange = true;
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   return MadeChange;
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric /// Returns an instance of the Branch Selection Pass
createMSP430BranchSelectionPass()2550b57cec5SDimitry Andric FunctionPass *llvm::createMSP430BranchSelectionPass() {
2560b57cec5SDimitry Andric   return new MSP430BSel();
2570b57cec5SDimitry Andric }
258