xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Mips/MipsBranchExpansion.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===----------------------- MipsBranchExpansion.cpp ----------------------===//
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 /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This pass do two things:
110b57cec5SDimitry Andric /// - it expands a branch or jump instruction into a long branch if its offset
120b57cec5SDimitry Andric ///   is too large to fit into its immediate field,
130b57cec5SDimitry Andric /// - it inserts nops to prevent forbidden slot hazards.
140b57cec5SDimitry Andric ///
150b57cec5SDimitry Andric /// The reason why this pass combines these two tasks is that one of these two
160b57cec5SDimitry Andric /// tasks can break the result of the previous one.
170b57cec5SDimitry Andric ///
180b57cec5SDimitry Andric /// Example of that is a situation where at first, no branch should be expanded,
190b57cec5SDimitry Andric /// but after adding at least one nop somewhere in the code to prevent a
200b57cec5SDimitry Andric /// forbidden slot hazard, offset of some branches may go out of range. In that
210b57cec5SDimitry Andric /// case it is necessary to check again if there is some branch that needs
220b57cec5SDimitry Andric /// expansion. On the other hand, expanding some branch may cause a control
230b57cec5SDimitry Andric /// transfer instruction to appear in the forbidden slot, which is a hazard that
240b57cec5SDimitry Andric /// should be fixed. This pass alternates between this two tasks untill no
250b57cec5SDimitry Andric /// changes are made. Only then we can be sure that all branches are expanded
260b57cec5SDimitry Andric /// properly, and no hazard situations exist.
270b57cec5SDimitry Andric ///
280b57cec5SDimitry Andric /// Regarding branch expanding:
290b57cec5SDimitry Andric ///
300b57cec5SDimitry Andric /// When branch instruction like beqzc or bnezc has offset that is too large
310b57cec5SDimitry Andric /// to fit into its immediate field, it has to be expanded to another
320b57cec5SDimitry Andric /// instruction or series of instructions.
330b57cec5SDimitry Andric ///
340b57cec5SDimitry Andric /// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries.
350b57cec5SDimitry Andric /// TODO: Handle out of range bc, b (pseudo) instructions.
360b57cec5SDimitry Andric ///
370b57cec5SDimitry Andric /// Regarding compact branch hazard prevention:
380b57cec5SDimitry Andric ///
3981ad6265SDimitry Andric /// Hazards handled: forbidden slots for MIPSR6, FPU slots for MIPS3 and below,
4081ad6265SDimitry Andric /// load delay slots for MIPS1.
410b57cec5SDimitry Andric ///
420b57cec5SDimitry Andric /// A forbidden slot hazard occurs when a compact branch instruction is executed
430b57cec5SDimitry Andric /// and the adjacent instruction in memory is a control transfer instruction
440b57cec5SDimitry Andric /// such as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.
450b57cec5SDimitry Andric ///
460b57cec5SDimitry Andric /// For example:
470b57cec5SDimitry Andric ///
480b57cec5SDimitry Andric /// 0x8004      bnec    a1,v0,<P+0x18>
490b57cec5SDimitry Andric /// 0x8008      beqc    a1,a2,<P+0x54>
500b57cec5SDimitry Andric ///
510b57cec5SDimitry Andric /// In such cases, the processor is required to signal a Reserved Instruction
520b57cec5SDimitry Andric /// exception.
530b57cec5SDimitry Andric ///
540b57cec5SDimitry Andric /// Here, if the instruction at 0x8004 is executed, the processor will raise an
550b57cec5SDimitry Andric /// exception as there is a control transfer instruction at 0x8008.
560b57cec5SDimitry Andric ///
570b57cec5SDimitry Andric /// There are two sources of forbidden slot hazards:
580b57cec5SDimitry Andric ///
590b57cec5SDimitry Andric /// A) A previous pass has created a compact branch directly.
600b57cec5SDimitry Andric /// B) Transforming a delay slot branch into compact branch. This case can be
610b57cec5SDimitry Andric ///    difficult to process as lookahead for hazards is insufficient, as
620b57cec5SDimitry Andric ///    backwards delay slot fillling can also produce hazards in previously
630b57cec5SDimitry Andric ///    processed instuctions.
640b57cec5SDimitry Andric ///
650b57cec5SDimitry Andric /// In future this pass can be extended (or new pass can be created) to handle
660b57cec5SDimitry Andric /// other pipeline hazards, such as various MIPS1 hazards, processor errata that
670b57cec5SDimitry Andric /// require instruction reorganization, etc.
680b57cec5SDimitry Andric ///
690b57cec5SDimitry Andric /// This pass has to run after the delay slot filler as that pass can introduce
700b57cec5SDimitry Andric /// pipeline hazards such as compact branch hazard, hence the existing hazard
710b57cec5SDimitry Andric /// recognizer is not suitable.
720b57cec5SDimitry Andric ///
730b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric #include "MCTargetDesc/MipsABIInfo.h"
760b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h"
770b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCNaCl.h"
780b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCTargetDesc.h"
790b57cec5SDimitry Andric #include "Mips.h"
800b57cec5SDimitry Andric #include "MipsInstrInfo.h"
810b57cec5SDimitry Andric #include "MipsMachineFunction.h"
820b57cec5SDimitry Andric #include "MipsSubtarget.h"
830b57cec5SDimitry Andric #include "MipsTargetMachine.h"
840b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
850b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
860b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
870b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
880b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
890b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
900b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
910b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
920b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
930b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
940b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
950b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
960b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
970b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
980b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
990b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
1000b57cec5SDimitry Andric #include <algorithm>
1010b57cec5SDimitry Andric #include <cassert>
1020b57cec5SDimitry Andric #include <cstdint>
1030b57cec5SDimitry Andric #include <iterator>
1040b57cec5SDimitry Andric #include <utility>
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric using namespace llvm;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric #define DEBUG_TYPE "mips-branch-expansion"
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric STATISTIC(NumInsertedNops, "Number of nops inserted");
1110b57cec5SDimitry Andric STATISTIC(LongBranches, "Number of long branches.");
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric static cl::opt<bool>
1140b57cec5SDimitry Andric     SkipLongBranch("skip-mips-long-branch", cl::init(false),
1150b57cec5SDimitry Andric                    cl::desc("MIPS: Skip branch expansion pass."), cl::Hidden);
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric static cl::opt<bool>
1180b57cec5SDimitry Andric     ForceLongBranch("force-mips-long-branch", cl::init(false),
1190b57cec5SDimitry Andric                     cl::desc("MIPS: Expand all branches to long format."),
1200b57cec5SDimitry Andric                     cl::Hidden);
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric namespace {
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric using Iter = MachineBasicBlock::iterator;
1250b57cec5SDimitry Andric using ReverseIter = MachineBasicBlock::reverse_iterator;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric struct MBBInfo {
1280b57cec5SDimitry Andric   uint64_t Size = 0;
1290b57cec5SDimitry Andric   bool HasLongBranch = false;
1300b57cec5SDimitry Andric   MachineInstr *Br = nullptr;
1310b57cec5SDimitry Andric   uint64_t Offset = 0;
1320b57cec5SDimitry Andric   MBBInfo() = default;
1330b57cec5SDimitry Andric };
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric class MipsBranchExpansion : public MachineFunctionPass {
1360b57cec5SDimitry Andric public:
1370b57cec5SDimitry Andric   static char ID;
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   MipsBranchExpansion() : MachineFunctionPass(ID), ABI(MipsABIInfo::Unknown()) {
1400b57cec5SDimitry Andric     initializeMipsBranchExpansionPass(*PassRegistry::getPassRegistry());
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   StringRef getPassName() const override {
1440b57cec5SDimitry Andric     return "Mips Branch Expansion Pass";
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &F) override;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   MachineFunctionProperties getRequiredProperties() const override {
1500b57cec5SDimitry Andric     return MachineFunctionProperties().set(
1510b57cec5SDimitry Andric         MachineFunctionProperties::Property::NoVRegs);
1520b57cec5SDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric private:
1550b57cec5SDimitry Andric   void splitMBB(MachineBasicBlock *MBB);
1560b57cec5SDimitry Andric   void initMBBInfo();
1570b57cec5SDimitry Andric   int64_t computeOffset(const MachineInstr *Br);
1580b57cec5SDimitry Andric   uint64_t computeOffsetFromTheBeginning(int MBB);
1590b57cec5SDimitry Andric   void replaceBranch(MachineBasicBlock &MBB, Iter Br, const DebugLoc &DL,
1600b57cec5SDimitry Andric                      MachineBasicBlock *MBBOpnd);
1610b57cec5SDimitry Andric   bool buildProperJumpMI(MachineBasicBlock *MBB,
1620b57cec5SDimitry Andric                          MachineBasicBlock::iterator Pos, DebugLoc DL);
1630b57cec5SDimitry Andric   void expandToLongBranch(MBBInfo &Info);
1640eae32dcSDimitry Andric   template <typename Pred, typename Safe>
1650eae32dcSDimitry Andric   bool handleSlot(Pred Predicate, Safe SafeInSlot);
1660b57cec5SDimitry Andric   bool handleForbiddenSlot();
1670eae32dcSDimitry Andric   bool handleFPUDelaySlot();
16881ad6265SDimitry Andric   bool handleLoadDelaySlot();
1690b57cec5SDimitry Andric   bool handlePossibleLongBranch();
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   const MipsSubtarget *STI;
1720b57cec5SDimitry Andric   const MipsInstrInfo *TII;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   MachineFunction *MFp;
1750b57cec5SDimitry Andric   SmallVector<MBBInfo, 16> MBBInfos;
1760b57cec5SDimitry Andric   bool IsPIC;
1770b57cec5SDimitry Andric   MipsABIInfo ABI;
1780b57cec5SDimitry Andric   bool ForceLongBranchFirstPass = false;
1790b57cec5SDimitry Andric };
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric } // end of anonymous namespace
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric char MipsBranchExpansion::ID = 0;
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric INITIALIZE_PASS(MipsBranchExpansion, DEBUG_TYPE,
1860b57cec5SDimitry Andric                 "Expand out of range branch instructions and fix forbidden"
1870b57cec5SDimitry Andric                 " slot hazards",
1880b57cec5SDimitry Andric                 false, false)
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric /// Returns a pass that clears pipeline hazards.
1910b57cec5SDimitry Andric FunctionPass *llvm::createMipsBranchExpansion() {
1920b57cec5SDimitry Andric   return new MipsBranchExpansion();
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric // Find the next real instruction from the current position in current basic
1960b57cec5SDimitry Andric // block.
1970b57cec5SDimitry Andric static Iter getNextMachineInstrInBB(Iter Position) {
1980b57cec5SDimitry Andric   Iter I = Position, E = Position->getParent()->end();
1990b57cec5SDimitry Andric   I = std::find_if_not(I, E,
2000b57cec5SDimitry Andric                        [](const Iter &Insn) { return Insn->isTransient(); });
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   return I;
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric // Find the next real instruction from the current position, looking through
2060b57cec5SDimitry Andric // basic block boundaries.
2070b57cec5SDimitry Andric static std::pair<Iter, bool> getNextMachineInstr(Iter Position,
2080b57cec5SDimitry Andric                                                  MachineBasicBlock *Parent) {
2090b57cec5SDimitry Andric   if (Position == Parent->end()) {
2100b57cec5SDimitry Andric     do {
2110b57cec5SDimitry Andric       MachineBasicBlock *Succ = Parent->getNextNode();
2120b57cec5SDimitry Andric       if (Succ != nullptr && Parent->isSuccessor(Succ)) {
2130b57cec5SDimitry Andric         Position = Succ->begin();
2140b57cec5SDimitry Andric         Parent = Succ;
2150b57cec5SDimitry Andric       } else {
2160b57cec5SDimitry Andric         return std::make_pair(Position, true);
2170b57cec5SDimitry Andric       }
2180b57cec5SDimitry Andric     } while (Parent->empty());
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   Iter Instr = getNextMachineInstrInBB(Position);
2220b57cec5SDimitry Andric   if (Instr == Parent->end()) {
2230b57cec5SDimitry Andric     return getNextMachineInstr(Instr, Parent);
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric   return std::make_pair(Instr, false);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric /// Iterate over list of Br's operands and search for a MachineBasicBlock
2290b57cec5SDimitry Andric /// operand.
2300b57cec5SDimitry Andric static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) {
2310b57cec5SDimitry Andric   for (unsigned I = 0, E = Br.getDesc().getNumOperands(); I < E; ++I) {
2320b57cec5SDimitry Andric     const MachineOperand &MO = Br.getOperand(I);
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric     if (MO.isMBB())
2350b57cec5SDimitry Andric       return MO.getMBB();
2360b57cec5SDimitry Andric   }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   llvm_unreachable("This instruction does not have an MBB operand.");
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric // Traverse the list of instructions backwards until a non-debug instruction is
2420b57cec5SDimitry Andric // found or it reaches E.
2430b57cec5SDimitry Andric static ReverseIter getNonDebugInstr(ReverseIter B, const ReverseIter &E) {
2440b57cec5SDimitry Andric   for (; B != E; ++B)
2450b57cec5SDimitry Andric     if (!B->isDebugInstr())
2460b57cec5SDimitry Andric       return B;
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric   return E;
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric // Split MBB if it has two direct jumps/branches.
2520b57cec5SDimitry Andric void MipsBranchExpansion::splitMBB(MachineBasicBlock *MBB) {
2530b57cec5SDimitry Andric   ReverseIter End = MBB->rend();
2540b57cec5SDimitry Andric   ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End);
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   // Return if MBB has no branch instructions.
2570b57cec5SDimitry Andric   if ((LastBr == End) ||
2580b57cec5SDimitry Andric       (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))
2590b57cec5SDimitry Andric     return;
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   ReverseIter FirstBr = getNonDebugInstr(std::next(LastBr), End);
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   // MBB has only one branch instruction if FirstBr is not a branch
2640b57cec5SDimitry Andric   // instruction.
2650b57cec5SDimitry Andric   if ((FirstBr == End) ||
2660b57cec5SDimitry Andric       (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))
2670b57cec5SDimitry Andric     return;
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   assert(!FirstBr->isIndirectBranch() && "Unexpected indirect branch found.");
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   // Create a new MBB. Move instructions in MBB to the newly created MBB.
2720b57cec5SDimitry Andric   MachineBasicBlock *NewMBB =
2730b57cec5SDimitry Andric       MFp->CreateMachineBasicBlock(MBB->getBasicBlock());
2740b57cec5SDimitry Andric 
2750b57cec5SDimitry Andric   // Insert NewMBB and fix control flow.
2760b57cec5SDimitry Andric   MachineBasicBlock *Tgt = getTargetMBB(*FirstBr);
2770b57cec5SDimitry Andric   NewMBB->transferSuccessors(MBB);
2780b57cec5SDimitry Andric   if (Tgt != getTargetMBB(*LastBr))
2790b57cec5SDimitry Andric     NewMBB->removeSuccessor(Tgt, true);
2800b57cec5SDimitry Andric   MBB->addSuccessor(NewMBB);
2810b57cec5SDimitry Andric   MBB->addSuccessor(Tgt);
2820b57cec5SDimitry Andric   MFp->insert(std::next(MachineFunction::iterator(MBB)), NewMBB);
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   NewMBB->splice(NewMBB->end(), MBB, LastBr.getReverse(), MBB->end());
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric // Fill MBBInfos.
2880b57cec5SDimitry Andric void MipsBranchExpansion::initMBBInfo() {
2890b57cec5SDimitry Andric   // Split the MBBs if they have two branches. Each basic block should have at
2900b57cec5SDimitry Andric   // most one branch after this loop is executed.
2910b57cec5SDimitry Andric   for (auto &MBB : *MFp)
2920b57cec5SDimitry Andric     splitMBB(&MBB);
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   MFp->RenumberBlocks();
2950b57cec5SDimitry Andric   MBBInfos.clear();
2960b57cec5SDimitry Andric   MBBInfos.resize(MFp->size());
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric   for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {
2990b57cec5SDimitry Andric     MachineBasicBlock *MBB = MFp->getBlockNumbered(I);
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric     // Compute size of MBB.
302*0fca6ea1SDimitry Andric     for (MachineInstr &MI : MBB->instrs())
303*0fca6ea1SDimitry Andric       MBBInfos[I].Size += TII->getInstSizeInBytes(MI);
3040b57cec5SDimitry Andric   }
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric // Compute offset of branch in number of bytes.
3080b57cec5SDimitry Andric int64_t MipsBranchExpansion::computeOffset(const MachineInstr *Br) {
3090b57cec5SDimitry Andric   int64_t Offset = 0;
3100b57cec5SDimitry Andric   int ThisMBB = Br->getParent()->getNumber();
3110b57cec5SDimitry Andric   int TargetMBB = getTargetMBB(*Br)->getNumber();
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // Compute offset of a forward branch.
3140b57cec5SDimitry Andric   if (ThisMBB < TargetMBB) {
3150b57cec5SDimitry Andric     for (int N = ThisMBB + 1; N < TargetMBB; ++N)
3160b57cec5SDimitry Andric       Offset += MBBInfos[N].Size;
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric     return Offset + 4;
3190b57cec5SDimitry Andric   }
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric   // Compute offset of a backward branch.
3220b57cec5SDimitry Andric   for (int N = ThisMBB; N >= TargetMBB; --N)
3230b57cec5SDimitry Andric     Offset += MBBInfos[N].Size;
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   return -Offset + 4;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric // Returns the distance in bytes up until MBB
3290b57cec5SDimitry Andric uint64_t MipsBranchExpansion::computeOffsetFromTheBeginning(int MBB) {
3300b57cec5SDimitry Andric   uint64_t Offset = 0;
3310b57cec5SDimitry Andric   for (int N = 0; N < MBB; ++N)
3320b57cec5SDimitry Andric     Offset += MBBInfos[N].Size;
3330b57cec5SDimitry Andric   return Offset;
3340b57cec5SDimitry Andric }
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric // Replace Br with a branch which has the opposite condition code and a
3370b57cec5SDimitry Andric // MachineBasicBlock operand MBBOpnd.
3380b57cec5SDimitry Andric void MipsBranchExpansion::replaceBranch(MachineBasicBlock &MBB, Iter Br,
3390b57cec5SDimitry Andric                                         const DebugLoc &DL,
3400b57cec5SDimitry Andric                                         MachineBasicBlock *MBBOpnd) {
3410b57cec5SDimitry Andric   unsigned NewOpc = TII->getOppositeBranchOpc(Br->getOpcode());
3420b57cec5SDimitry Andric   const MCInstrDesc &NewDesc = TII->get(NewOpc);
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, Br, DL, NewDesc);
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   for (unsigned I = 0, E = Br->getDesc().getNumOperands(); I < E; ++I) {
3470b57cec5SDimitry Andric     MachineOperand &MO = Br->getOperand(I);
3480b57cec5SDimitry Andric 
3495ffd83dbSDimitry Andric     switch (MO.getType()) {
3505ffd83dbSDimitry Andric     case MachineOperand::MO_Register:
3510b57cec5SDimitry Andric       MIB.addReg(MO.getReg());
3525ffd83dbSDimitry Andric       break;
3535ffd83dbSDimitry Andric     case MachineOperand::MO_Immediate:
3545ffd83dbSDimitry Andric       // Octeon BBIT family of branch has an immediate operand
3555ffd83dbSDimitry Andric       // (e.g. BBIT0 $v0, 3, %bb.1).
3565ffd83dbSDimitry Andric       if (!TII->isBranchWithImm(Br->getOpcode()))
3575ffd83dbSDimitry Andric         llvm_unreachable("Unexpected immediate in branch instruction");
3585ffd83dbSDimitry Andric       MIB.addImm(MO.getImm());
3595ffd83dbSDimitry Andric       break;
3605ffd83dbSDimitry Andric     case MachineOperand::MO_MachineBasicBlock:
3610b57cec5SDimitry Andric       MIB.addMBB(MBBOpnd);
3625ffd83dbSDimitry Andric       break;
3635ffd83dbSDimitry Andric     default:
3645ffd83dbSDimitry Andric       llvm_unreachable("Unexpected operand type in branch instruction");
3655ffd83dbSDimitry Andric     }
3665ffd83dbSDimitry Andric   }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   if (Br->hasDelaySlot()) {
3690b57cec5SDimitry Andric     // Bundle the instruction in the delay slot to the newly created branch
3700b57cec5SDimitry Andric     // and erase the original branch.
3710b57cec5SDimitry Andric     assert(Br->isBundledWithSucc());
3720b57cec5SDimitry Andric     MachineBasicBlock::instr_iterator II = Br.getInstrIterator();
3730b57cec5SDimitry Andric     MIBundleBuilder(&*MIB).append((++II)->removeFromBundle());
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric   Br->eraseFromParent();
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric bool MipsBranchExpansion::buildProperJumpMI(MachineBasicBlock *MBB,
3790b57cec5SDimitry Andric                                             MachineBasicBlock::iterator Pos,
3800b57cec5SDimitry Andric                                             DebugLoc DL) {
3810b57cec5SDimitry Andric   bool HasR6 = ABI.IsN64() ? STI->hasMips64r6() : STI->hasMips32r6();
3820b57cec5SDimitry Andric   bool AddImm = HasR6 && !STI->useIndirectJumpsHazard();
3830b57cec5SDimitry Andric 
3840b57cec5SDimitry Andric   unsigned JR = ABI.IsN64() ? Mips::JR64 : Mips::JR;
3850b57cec5SDimitry Andric   unsigned JIC = ABI.IsN64() ? Mips::JIC64 : Mips::JIC;
3860b57cec5SDimitry Andric   unsigned JR_HB = ABI.IsN64() ? Mips::JR_HB64 : Mips::JR_HB;
3870b57cec5SDimitry Andric   unsigned JR_HB_R6 = ABI.IsN64() ? Mips::JR_HB64_R6 : Mips::JR_HB_R6;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   unsigned JumpOp;
3900b57cec5SDimitry Andric   if (STI->useIndirectJumpsHazard())
3910b57cec5SDimitry Andric     JumpOp = HasR6 ? JR_HB_R6 : JR_HB;
3920b57cec5SDimitry Andric   else
3930b57cec5SDimitry Andric     JumpOp = HasR6 ? JIC : JR;
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   if (JumpOp == Mips::JIC && STI->inMicroMipsMode())
3960b57cec5SDimitry Andric     JumpOp = Mips::JIC_MMR6;
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   unsigned ATReg = ABI.IsN64() ? Mips::AT_64 : Mips::AT;
3990b57cec5SDimitry Andric   MachineInstrBuilder Instr =
4000b57cec5SDimitry Andric       BuildMI(*MBB, Pos, DL, TII->get(JumpOp)).addReg(ATReg);
4010b57cec5SDimitry Andric   if (AddImm)
4020b57cec5SDimitry Andric     Instr.addImm(0);
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   return !AddImm;
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric // Expand branch instructions to long branches.
4080b57cec5SDimitry Andric // TODO: This function has to be fixed for beqz16 and bnez16, because it
4090b57cec5SDimitry Andric // currently assumes that all branches have 16-bit offsets, and will produce
4100b57cec5SDimitry Andric // wrong code if branches whose allowed offsets are [-128, -126, ..., 126]
4110b57cec5SDimitry Andric // are present.
4120b57cec5SDimitry Andric void MipsBranchExpansion::expandToLongBranch(MBBInfo &I) {
4130b57cec5SDimitry Andric   MachineBasicBlock::iterator Pos;
4140b57cec5SDimitry Andric   MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br);
4150b57cec5SDimitry Andric   DebugLoc DL = I.Br->getDebugLoc();
4160b57cec5SDimitry Andric   const BasicBlock *BB = MBB->getBasicBlock();
4170b57cec5SDimitry Andric   MachineFunction::iterator FallThroughMBB = ++MachineFunction::iterator(MBB);
4180b57cec5SDimitry Andric   MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   MFp->insert(FallThroughMBB, LongBrMBB);
4210b57cec5SDimitry Andric   MBB->replaceSuccessor(TgtMBB, LongBrMBB);
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   if (IsPIC) {
4240b57cec5SDimitry Andric     MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);
4250b57cec5SDimitry Andric     MFp->insert(FallThroughMBB, BalTgtMBB);
4260b57cec5SDimitry Andric     LongBrMBB->addSuccessor(BalTgtMBB);
4270b57cec5SDimitry Andric     BalTgtMBB->addSuccessor(TgtMBB);
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric     // We must select between the MIPS32r6/MIPS64r6 BALC (which is a normal
4300b57cec5SDimitry Andric     // instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an
4310b57cec5SDimitry Andric     // pseudo-instruction wrapping BGEZAL).
4320b57cec5SDimitry Andric     const unsigned BalOp =
4330b57cec5SDimitry Andric         STI->hasMips32r6()
4340b57cec5SDimitry Andric             ? STI->inMicroMipsMode() ? Mips::BALC_MMR6 : Mips::BALC
4350b57cec5SDimitry Andric             : STI->inMicroMipsMode() ? Mips::BAL_BR_MM : Mips::BAL_BR;
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric     if (!ABI.IsN64()) {
4380b57cec5SDimitry Andric       // Pre R6:
4390b57cec5SDimitry Andric       // $longbr:
4400b57cec5SDimitry Andric       //  addiu $sp, $sp, -8
4410b57cec5SDimitry Andric       //  sw $ra, 0($sp)
4420b57cec5SDimitry Andric       //  lui $at, %hi($tgt - $baltgt)
4430b57cec5SDimitry Andric       //  bal $baltgt
4440b57cec5SDimitry Andric       //  addiu $at, $at, %lo($tgt - $baltgt)
4450b57cec5SDimitry Andric       // $baltgt:
4460b57cec5SDimitry Andric       //  addu $at, $ra, $at
4470b57cec5SDimitry Andric       //  lw $ra, 0($sp)
4480b57cec5SDimitry Andric       //  jr $at
4490b57cec5SDimitry Andric       //  addiu $sp, $sp, 8
4500b57cec5SDimitry Andric       // $fallthrough:
4510b57cec5SDimitry Andric       //
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric       // R6:
4540b57cec5SDimitry Andric       // $longbr:
4550b57cec5SDimitry Andric       //  addiu $sp, $sp, -8
4560b57cec5SDimitry Andric       //  sw $ra, 0($sp)
4570b57cec5SDimitry Andric       //  lui $at, %hi($tgt - $baltgt)
4580b57cec5SDimitry Andric       //  addiu $at, $at, %lo($tgt - $baltgt)
4590b57cec5SDimitry Andric       //  balc $baltgt
4600b57cec5SDimitry Andric       // $baltgt:
4610b57cec5SDimitry Andric       //  addu $at, $ra, $at
4620b57cec5SDimitry Andric       //  lw $ra, 0($sp)
4630b57cec5SDimitry Andric       //  addiu $sp, $sp, 8
4640b57cec5SDimitry Andric       //  jic $at, 0
4650b57cec5SDimitry Andric       // $fallthrough:
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric       Pos = LongBrMBB->begin();
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)
4700b57cec5SDimitry Andric           .addReg(Mips::SP)
4710b57cec5SDimitry Andric           .addImm(-8);
4720b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW))
4730b57cec5SDimitry Andric           .addReg(Mips::RA)
4740b57cec5SDimitry Andric           .addReg(Mips::SP)
4750b57cec5SDimitry Andric           .addImm(0);
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric       // LUi and ADDiu instructions create 32-bit offset of the target basic
4780b57cec5SDimitry Andric       // block from the target of BAL(C) instruction.  We cannot use immediate
4790b57cec5SDimitry Andric       // value for this offset because it cannot be determined accurately when
4800b57cec5SDimitry Andric       // the program has inline assembly statements.  We therefore use the
4810b57cec5SDimitry Andric       // relocation expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt) which
4820b57cec5SDimitry Andric       // are resolved during the fixup, so the values will always be correct.
4830b57cec5SDimitry Andric       //
4840b57cec5SDimitry Andric       // Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt)
4850b57cec5SDimitry Andric       // expressions at this point (it is possible only at the MC layer),
4860b57cec5SDimitry Andric       // we replace LUi and ADDiu with pseudo instructions
4870b57cec5SDimitry Andric       // LONG_BRANCH_LUi and LONG_BRANCH_ADDiu, and add both basic
4880b57cec5SDimitry Andric       // blocks as operands to these instructions.  When lowering these pseudo
4890b57cec5SDimitry Andric       // instructions to LUi and ADDiu in the MC layer, we will create
4900b57cec5SDimitry Andric       // %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as
4910b57cec5SDimitry Andric       // operands to lowered instructions.
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)
4940b57cec5SDimitry Andric           .addMBB(TgtMBB, MipsII::MO_ABS_HI)
4950b57cec5SDimitry Andric           .addMBB(BalTgtMBB);
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric       MachineInstrBuilder BalInstr =
4980b57cec5SDimitry Andric           BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
4990b57cec5SDimitry Andric       MachineInstrBuilder ADDiuInstr =
5000b57cec5SDimitry Andric           BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)
5010b57cec5SDimitry Andric               .addReg(Mips::AT)
5020b57cec5SDimitry Andric               .addMBB(TgtMBB, MipsII::MO_ABS_LO)
5030b57cec5SDimitry Andric               .addMBB(BalTgtMBB);
5040b57cec5SDimitry Andric       if (STI->hasMips32r6()) {
5050b57cec5SDimitry Andric         LongBrMBB->insert(Pos, ADDiuInstr);
5060b57cec5SDimitry Andric         LongBrMBB->insert(Pos, BalInstr);
5070b57cec5SDimitry Andric       } else {
5080b57cec5SDimitry Andric         LongBrMBB->insert(Pos, BalInstr);
5090b57cec5SDimitry Andric         LongBrMBB->insert(Pos, ADDiuInstr);
5100b57cec5SDimitry Andric         LongBrMBB->rbegin()->bundleWithPred();
5110b57cec5SDimitry Andric       }
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric       Pos = BalTgtMBB->begin();
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric       BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT)
5160b57cec5SDimitry Andric           .addReg(Mips::RA)
5170b57cec5SDimitry Andric           .addReg(Mips::AT);
5180b57cec5SDimitry Andric       BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA)
5190b57cec5SDimitry Andric           .addReg(Mips::SP)
5200b57cec5SDimitry Andric           .addImm(0);
5210b57cec5SDimitry Andric       if (STI->isTargetNaCl())
5220b57cec5SDimitry Andric         // Bundle-align the target of indirect branch JR.
5230b57cec5SDimitry Andric         TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric       // In NaCl, modifying the sp is not allowed in branch delay slot.
5260b57cec5SDimitry Andric       // For MIPS32R6, we can skip using a delay slot branch.
5270b57cec5SDimitry Andric       bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos, DL);
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric       if (STI->isTargetNaCl() || !hasDelaySlot) {
5300b57cec5SDimitry Andric         BuildMI(*BalTgtMBB, std::prev(Pos), DL, TII->get(Mips::ADDiu), Mips::SP)
5310b57cec5SDimitry Andric             .addReg(Mips::SP)
5320b57cec5SDimitry Andric             .addImm(8);
5330b57cec5SDimitry Andric       }
5340b57cec5SDimitry Andric       if (hasDelaySlot) {
5350b57cec5SDimitry Andric         if (STI->isTargetNaCl()) {
53681ad6265SDimitry Andric           TII->insertNop(*BalTgtMBB, Pos, DL);
5370b57cec5SDimitry Andric         } else {
5380b57cec5SDimitry Andric           BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)
5390b57cec5SDimitry Andric               .addReg(Mips::SP)
5400b57cec5SDimitry Andric               .addImm(8);
5410b57cec5SDimitry Andric         }
5420b57cec5SDimitry Andric         BalTgtMBB->rbegin()->bundleWithPred();
5430b57cec5SDimitry Andric       }
5440b57cec5SDimitry Andric     } else {
5450b57cec5SDimitry Andric       // Pre R6:
5460b57cec5SDimitry Andric       // $longbr:
5470b57cec5SDimitry Andric       //  daddiu $sp, $sp, -16
5480b57cec5SDimitry Andric       //  sd $ra, 0($sp)
5490b57cec5SDimitry Andric       //  daddiu $at, $zero, %hi($tgt - $baltgt)
5500b57cec5SDimitry Andric       //  dsll $at, $at, 16
5510b57cec5SDimitry Andric       //  bal $baltgt
5520b57cec5SDimitry Andric       //  daddiu $at, $at, %lo($tgt - $baltgt)
5530b57cec5SDimitry Andric       // $baltgt:
5540b57cec5SDimitry Andric       //  daddu $at, $ra, $at
5550b57cec5SDimitry Andric       //  ld $ra, 0($sp)
5560b57cec5SDimitry Andric       //  jr64 $at
5570b57cec5SDimitry Andric       //  daddiu $sp, $sp, 16
5580b57cec5SDimitry Andric       // $fallthrough:
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric       // R6:
5610b57cec5SDimitry Andric       // $longbr:
5620b57cec5SDimitry Andric       //  daddiu $sp, $sp, -16
5630b57cec5SDimitry Andric       //  sd $ra, 0($sp)
5640b57cec5SDimitry Andric       //  daddiu $at, $zero, %hi($tgt - $baltgt)
5650b57cec5SDimitry Andric       //  dsll $at, $at, 16
5660b57cec5SDimitry Andric       //  daddiu $at, $at, %lo($tgt - $baltgt)
5670b57cec5SDimitry Andric       //  balc $baltgt
5680b57cec5SDimitry Andric       // $baltgt:
5690b57cec5SDimitry Andric       //  daddu $at, $ra, $at
5700b57cec5SDimitry Andric       //  ld $ra, 0($sp)
5710b57cec5SDimitry Andric       //  daddiu $sp, $sp, 16
5720b57cec5SDimitry Andric       //  jic $at, 0
5730b57cec5SDimitry Andric       // $fallthrough:
5740b57cec5SDimitry Andric 
5750b57cec5SDimitry Andric       // We assume the branch is within-function, and that offset is within
5760b57cec5SDimitry Andric       // +/- 2GB.  High 32 bits will therefore always be zero.
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric       // Note that this will work even if the offset is negative, because
5790b57cec5SDimitry Andric       // of the +1 modification that's added in that case.  For example, if the
5800b57cec5SDimitry Andric       // offset is -1MB (0xFFFFFFFFFFF00000), the computation for %higher is
5810b57cec5SDimitry Andric       //
5820b57cec5SDimitry Andric       // 0xFFFFFFFFFFF00000 + 0x80008000 = 0x000000007FF08000
5830b57cec5SDimitry Andric       //
5840b57cec5SDimitry Andric       // and the bits [47:32] are zero.  For %highest
5850b57cec5SDimitry Andric       //
5860b57cec5SDimitry Andric       // 0xFFFFFFFFFFF00000 + 0x800080008000 = 0x000080007FF08000
5870b57cec5SDimitry Andric       //
5880b57cec5SDimitry Andric       // and the bits [63:48] are zero.
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric       Pos = LongBrMBB->begin();
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)
5930b57cec5SDimitry Andric           .addReg(Mips::SP_64)
5940b57cec5SDimitry Andric           .addImm(-16);
5950b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD))
5960b57cec5SDimitry Andric           .addReg(Mips::RA_64)
5970b57cec5SDimitry Andric           .addReg(Mips::SP_64)
5980b57cec5SDimitry Andric           .addImm(0);
5990b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu),
6000b57cec5SDimitry Andric               Mips::AT_64)
6010b57cec5SDimitry Andric           .addReg(Mips::ZERO_64)
6020b57cec5SDimitry Andric           .addMBB(TgtMBB, MipsII::MO_ABS_HI)
6030b57cec5SDimitry Andric           .addMBB(BalTgtMBB);
6040b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
6050b57cec5SDimitry Andric           .addReg(Mips::AT_64)
6060b57cec5SDimitry Andric           .addImm(16);
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric       MachineInstrBuilder BalInstr =
6090b57cec5SDimitry Andric           BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);
6100b57cec5SDimitry Andric       MachineInstrBuilder DADDiuInstr =
6110b57cec5SDimitry Andric           BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)
6120b57cec5SDimitry Andric               .addReg(Mips::AT_64)
6130b57cec5SDimitry Andric               .addMBB(TgtMBB, MipsII::MO_ABS_LO)
6140b57cec5SDimitry Andric               .addMBB(BalTgtMBB);
6150b57cec5SDimitry Andric       if (STI->hasMips32r6()) {
6160b57cec5SDimitry Andric         LongBrMBB->insert(Pos, DADDiuInstr);
6170b57cec5SDimitry Andric         LongBrMBB->insert(Pos, BalInstr);
6180b57cec5SDimitry Andric       } else {
6190b57cec5SDimitry Andric         LongBrMBB->insert(Pos, BalInstr);
6200b57cec5SDimitry Andric         LongBrMBB->insert(Pos, DADDiuInstr);
6210b57cec5SDimitry Andric         LongBrMBB->rbegin()->bundleWithPred();
6220b57cec5SDimitry Andric       }
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric       Pos = BalTgtMBB->begin();
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric       BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64)
6270b57cec5SDimitry Andric           .addReg(Mips::RA_64)
6280b57cec5SDimitry Andric           .addReg(Mips::AT_64);
6290b57cec5SDimitry Andric       BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64)
6300b57cec5SDimitry Andric           .addReg(Mips::SP_64)
6310b57cec5SDimitry Andric           .addImm(0);
6320b57cec5SDimitry Andric 
6330b57cec5SDimitry Andric       bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos, DL);
6340b57cec5SDimitry Andric       // If there is no delay slot, Insert stack adjustment before
6350b57cec5SDimitry Andric       if (!hasDelaySlot) {
6360b57cec5SDimitry Andric         BuildMI(*BalTgtMBB, std::prev(Pos), DL, TII->get(Mips::DADDiu),
6370b57cec5SDimitry Andric                 Mips::SP_64)
6380b57cec5SDimitry Andric             .addReg(Mips::SP_64)
6390b57cec5SDimitry Andric             .addImm(16);
6400b57cec5SDimitry Andric       } else {
6410b57cec5SDimitry Andric         BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)
6420b57cec5SDimitry Andric             .addReg(Mips::SP_64)
6430b57cec5SDimitry Andric             .addImm(16);
6440b57cec5SDimitry Andric         BalTgtMBB->rbegin()->bundleWithPred();
6450b57cec5SDimitry Andric       }
6460b57cec5SDimitry Andric     }
6470b57cec5SDimitry Andric   } else { // Not PIC
6480b57cec5SDimitry Andric     Pos = LongBrMBB->begin();
6490b57cec5SDimitry Andric     LongBrMBB->addSuccessor(TgtMBB);
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric     // Compute the position of the potentiall jump instruction (basic blocks
6520b57cec5SDimitry Andric     // before + 4 for the instruction)
6530b57cec5SDimitry Andric     uint64_t JOffset = computeOffsetFromTheBeginning(MBB->getNumber()) +
6540b57cec5SDimitry Andric                        MBBInfos[MBB->getNumber()].Size + 4;
6550b57cec5SDimitry Andric     uint64_t TgtMBBOffset = computeOffsetFromTheBeginning(TgtMBB->getNumber());
6560b57cec5SDimitry Andric     // If it's a forward jump, then TgtMBBOffset will be shifted by two
6570b57cec5SDimitry Andric     // instructions
6580b57cec5SDimitry Andric     if (JOffset < TgtMBBOffset)
6590b57cec5SDimitry Andric       TgtMBBOffset += 2 * 4;
6600b57cec5SDimitry Andric     // Compare 4 upper bits to check if it's the same segment
6610b57cec5SDimitry Andric     bool SameSegmentJump = JOffset >> 28 == TgtMBBOffset >> 28;
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric     if (STI->hasMips32r6() && TII->isBranchOffsetInRange(Mips::BC, I.Offset)) {
6640b57cec5SDimitry Andric       // R6:
6650b57cec5SDimitry Andric       // $longbr:
6660b57cec5SDimitry Andric       //  bc $tgt
6670b57cec5SDimitry Andric       // $fallthrough:
6680b57cec5SDimitry Andric       //
6690b57cec5SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL,
6700b57cec5SDimitry Andric               TII->get(STI->inMicroMipsMode() ? Mips::BC_MMR6 : Mips::BC))
6710b57cec5SDimitry Andric           .addMBB(TgtMBB);
6720b57cec5SDimitry Andric     } else if (SameSegmentJump) {
6730b57cec5SDimitry Andric       // Pre R6:
6740b57cec5SDimitry Andric       // $longbr:
6750b57cec5SDimitry Andric       //  j $tgt
6760b57cec5SDimitry Andric       //  nop
6770b57cec5SDimitry Andric       // $fallthrough:
6780b57cec5SDimitry Andric       //
67981ad6265SDimitry Andric       BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::J)).addMBB(TgtMBB);
68081ad6265SDimitry Andric       TII->insertNop(*LongBrMBB, Pos, DL)->bundleWithPred();
6810b57cec5SDimitry Andric     } else {
6820b57cec5SDimitry Andric       // At this point, offset where we need to branch does not fit into
6830b57cec5SDimitry Andric       // immediate field of the branch instruction and is not in the same
6840b57cec5SDimitry Andric       // segment as jump instruction. Therefore we will break it into couple
6850b57cec5SDimitry Andric       // instructions, where we first load the offset into register, and then we
6860b57cec5SDimitry Andric       // do branch register.
6870b57cec5SDimitry Andric       if (ABI.IsN64()) {
6880b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi2Op_64),
6890b57cec5SDimitry Andric                 Mips::AT_64)
6900b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_HIGHEST);
6910b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),
6920b57cec5SDimitry Andric                 Mips::AT_64)
6930b57cec5SDimitry Andric             .addReg(Mips::AT_64)
6940b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_HIGHER);
6950b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
6960b57cec5SDimitry Andric             .addReg(Mips::AT_64)
6970b57cec5SDimitry Andric             .addImm(16);
6980b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),
6990b57cec5SDimitry Andric                 Mips::AT_64)
7000b57cec5SDimitry Andric             .addReg(Mips::AT_64)
7010b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_ABS_HI);
7020b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)
7030b57cec5SDimitry Andric             .addReg(Mips::AT_64)
7040b57cec5SDimitry Andric             .addImm(16);
7050b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),
7060b57cec5SDimitry Andric                 Mips::AT_64)
7070b57cec5SDimitry Andric             .addReg(Mips::AT_64)
7080b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_ABS_LO);
7090b57cec5SDimitry Andric       } else {
7100b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi2Op),
7110b57cec5SDimitry Andric                 Mips::AT)
7120b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_ABS_HI);
7130b57cec5SDimitry Andric         BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_ADDiu2Op),
7140b57cec5SDimitry Andric                 Mips::AT)
7150b57cec5SDimitry Andric             .addReg(Mips::AT)
7160b57cec5SDimitry Andric             .addMBB(TgtMBB, MipsII::MO_ABS_LO);
7170b57cec5SDimitry Andric       }
7180b57cec5SDimitry Andric       buildProperJumpMI(LongBrMBB, Pos, DL);
7190b57cec5SDimitry Andric     }
7200b57cec5SDimitry Andric   }
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric   if (I.Br->isUnconditionalBranch()) {
7230b57cec5SDimitry Andric     // Change branch destination.
7240b57cec5SDimitry Andric     assert(I.Br->getDesc().getNumOperands() == 1);
72581ad6265SDimitry Andric     I.Br->removeOperand(0);
7260b57cec5SDimitry Andric     I.Br->addOperand(MachineOperand::CreateMBB(LongBrMBB));
7270b57cec5SDimitry Andric   } else
7280b57cec5SDimitry Andric     // Change branch destination and reverse condition.
7290b57cec5SDimitry Andric     replaceBranch(*MBB, I.Br, DL, &*FallThroughMBB);
7300b57cec5SDimitry Andric }
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {
7330b57cec5SDimitry Andric   MachineBasicBlock &MBB = F.front();
7340b57cec5SDimitry Andric   MachineBasicBlock::iterator I = MBB.begin();
7350b57cec5SDimitry Andric   DebugLoc DL = MBB.findDebugLoc(MBB.begin());
7360b57cec5SDimitry Andric   BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0)
7370b57cec5SDimitry Andric       .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
7380b57cec5SDimitry Andric   BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0)
7390b57cec5SDimitry Andric       .addReg(Mips::V0)
7400b57cec5SDimitry Andric       .addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
7410b57cec5SDimitry Andric   MBB.removeLiveIn(Mips::V0);
7420b57cec5SDimitry Andric }
7430b57cec5SDimitry Andric 
7440eae32dcSDimitry Andric template <typename Pred, typename Safe>
7450eae32dcSDimitry Andric bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {
7460b57cec5SDimitry Andric   bool Changed = false;
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric   for (MachineFunction::iterator FI = MFp->begin(); FI != MFp->end(); ++FI) {
7490b57cec5SDimitry Andric     for (Iter I = FI->begin(); I != FI->end(); ++I) {
7500b57cec5SDimitry Andric 
7510eae32dcSDimitry Andric       // Delay slot hazard handling. Use lookahead over state.
7520eae32dcSDimitry Andric       if (!Predicate(*I))
7530b57cec5SDimitry Andric         continue;
7540b57cec5SDimitry Andric 
7550eae32dcSDimitry Andric       Iter IInSlot;
7560b57cec5SDimitry Andric       bool LastInstInFunction =
7570b57cec5SDimitry Andric           std::next(I) == FI->end() && std::next(FI) == MFp->end();
7580b57cec5SDimitry Andric       if (!LastInstInFunction) {
7590b57cec5SDimitry Andric         std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI);
7600b57cec5SDimitry Andric         LastInstInFunction |= Res.second;
7610eae32dcSDimitry Andric         IInSlot = Res.first;
7620b57cec5SDimitry Andric       }
7630b57cec5SDimitry Andric 
7640eae32dcSDimitry Andric       if (LastInstInFunction || !SafeInSlot(*IInSlot, *I)) {
7650b57cec5SDimitry Andric         MachineBasicBlock::instr_iterator Iit = I->getIterator();
7660b57cec5SDimitry Andric         if (std::next(Iit) == FI->end() ||
7670b57cec5SDimitry Andric             std::next(Iit)->getOpcode() != Mips::NOP) {
7680b57cec5SDimitry Andric           Changed = true;
76981ad6265SDimitry Andric           TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())
77081ad6265SDimitry Andric               ->bundleWithPred();
7710b57cec5SDimitry Andric           NumInsertedNops++;
7720b57cec5SDimitry Andric         }
7730b57cec5SDimitry Andric       }
7740b57cec5SDimitry Andric     }
7750b57cec5SDimitry Andric   }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   return Changed;
7780b57cec5SDimitry Andric }
7790b57cec5SDimitry Andric 
7800eae32dcSDimitry Andric bool MipsBranchExpansion::handleForbiddenSlot() {
7810eae32dcSDimitry Andric   // Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.
7820eae32dcSDimitry Andric   if (!STI->hasMips32r6() || STI->inMicroMipsMode())
7830eae32dcSDimitry Andric     return false;
7840eae32dcSDimitry Andric 
7850eae32dcSDimitry Andric   return handleSlot(
7860eae32dcSDimitry Andric       [this](auto &I) -> bool { return TII->HasForbiddenSlot(I); },
7870eae32dcSDimitry Andric       [this](auto &IInSlot, auto &I) -> bool {
7880eae32dcSDimitry Andric         return TII->SafeInForbiddenSlot(IInSlot);
7890eae32dcSDimitry Andric       });
7900eae32dcSDimitry Andric }
7910eae32dcSDimitry Andric 
7920eae32dcSDimitry Andric bool MipsBranchExpansion::handleFPUDelaySlot() {
7930eae32dcSDimitry Andric   // FPU delay slots are only defined for MIPS3 and below.
7940eae32dcSDimitry Andric   if (STI->hasMips32() || STI->hasMips4())
7950eae32dcSDimitry Andric     return false;
7960eae32dcSDimitry Andric 
7970eae32dcSDimitry Andric   return handleSlot([this](auto &I) -> bool { return TII->HasFPUDelaySlot(I); },
7980eae32dcSDimitry Andric                     [this](auto &IInSlot, auto &I) -> bool {
7990eae32dcSDimitry Andric                       return TII->SafeInFPUDelaySlot(IInSlot, I);
8000eae32dcSDimitry Andric                     });
8010eae32dcSDimitry Andric }
8020eae32dcSDimitry Andric 
80381ad6265SDimitry Andric bool MipsBranchExpansion::handleLoadDelaySlot() {
80481ad6265SDimitry Andric   // Load delay slot hazards are only for MIPS1.
80581ad6265SDimitry Andric   if (STI->hasMips2())
80681ad6265SDimitry Andric     return false;
80781ad6265SDimitry Andric 
80881ad6265SDimitry Andric   return handleSlot(
80981ad6265SDimitry Andric       [this](auto &I) -> bool { return TII->HasLoadDelaySlot(I); },
81081ad6265SDimitry Andric       [this](auto &IInSlot, auto &I) -> bool {
81181ad6265SDimitry Andric         return TII->SafeInLoadDelaySlot(IInSlot, I);
81281ad6265SDimitry Andric       });
81381ad6265SDimitry Andric }
81481ad6265SDimitry Andric 
8150b57cec5SDimitry Andric bool MipsBranchExpansion::handlePossibleLongBranch() {
8160b57cec5SDimitry Andric   if (STI->inMips16Mode() || !STI->enableLongBranchPass())
8170b57cec5SDimitry Andric     return false;
8180b57cec5SDimitry Andric 
8190b57cec5SDimitry Andric   if (SkipLongBranch)
8200b57cec5SDimitry Andric     return false;
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   bool EverMadeChange = false, MadeChange = true;
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   while (MadeChange) {
8250b57cec5SDimitry Andric     MadeChange = false;
8260b57cec5SDimitry Andric 
8270b57cec5SDimitry Andric     initMBBInfo();
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric     for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {
8300b57cec5SDimitry Andric       MachineBasicBlock *MBB = MFp->getBlockNumbered(I);
8310b57cec5SDimitry Andric       // Search for MBB's branch instruction.
8320b57cec5SDimitry Andric       ReverseIter End = MBB->rend();
8330b57cec5SDimitry Andric       ReverseIter Br = getNonDebugInstr(MBB->rbegin(), End);
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric       if ((Br != End) && Br->isBranch() && !Br->isIndirectBranch() &&
8360b57cec5SDimitry Andric           (Br->isConditionalBranch() ||
8370b57cec5SDimitry Andric            (Br->isUnconditionalBranch() && IsPIC))) {
8380b57cec5SDimitry Andric         int64_t Offset = computeOffset(&*Br);
8390b57cec5SDimitry Andric 
8400b57cec5SDimitry Andric         if (STI->isTargetNaCl()) {
8410b57cec5SDimitry Andric           // The offset calculation does not include sandboxing instructions
8420b57cec5SDimitry Andric           // that will be added later in the MC layer.  Since at this point we
8430b57cec5SDimitry Andric           // don't know the exact amount of code that "sandboxing" will add, we
8440b57cec5SDimitry Andric           // conservatively estimate that code will not grow more than 100%.
8450b57cec5SDimitry Andric           Offset *= 2;
8460b57cec5SDimitry Andric         }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric         if (ForceLongBranchFirstPass ||
8490b57cec5SDimitry Andric             !TII->isBranchOffsetInRange(Br->getOpcode(), Offset)) {
8500b57cec5SDimitry Andric           MBBInfos[I].Offset = Offset;
8510b57cec5SDimitry Andric           MBBInfos[I].Br = &*Br;
8520b57cec5SDimitry Andric         }
8530b57cec5SDimitry Andric       }
8540b57cec5SDimitry Andric     } // End for
8550b57cec5SDimitry Andric 
8560b57cec5SDimitry Andric     ForceLongBranchFirstPass = false;
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric     SmallVectorImpl<MBBInfo>::iterator I, E = MBBInfos.end();
8590b57cec5SDimitry Andric 
8600b57cec5SDimitry Andric     for (I = MBBInfos.begin(); I != E; ++I) {
8610b57cec5SDimitry Andric       // Skip if this MBB doesn't have a branch or the branch has already been
8620b57cec5SDimitry Andric       // converted to a long branch.
8630b57cec5SDimitry Andric       if (!I->Br)
8640b57cec5SDimitry Andric         continue;
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric       expandToLongBranch(*I);
8670b57cec5SDimitry Andric       ++LongBranches;
8680b57cec5SDimitry Andric       EverMadeChange = MadeChange = true;
8690b57cec5SDimitry Andric     }
8700b57cec5SDimitry Andric 
8710b57cec5SDimitry Andric     MFp->RenumberBlocks();
8720b57cec5SDimitry Andric   }
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric   return EverMadeChange;
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {
8780b57cec5SDimitry Andric   const TargetMachine &TM = MF.getTarget();
8790b57cec5SDimitry Andric   IsPIC = TM.isPositionIndependent();
8800b57cec5SDimitry Andric   ABI = static_cast<const MipsTargetMachine &>(TM).getABI();
88181ad6265SDimitry Andric   STI = &MF.getSubtarget<MipsSubtarget>();
8820b57cec5SDimitry Andric   TII = static_cast<const MipsInstrInfo *>(STI->getInstrInfo());
8830b57cec5SDimitry Andric 
8840b57cec5SDimitry Andric   if (IsPIC && ABI.IsO32() &&
8850b57cec5SDimitry Andric       MF.getInfo<MipsFunctionInfo>()->globalBaseRegSet())
8860b57cec5SDimitry Andric     emitGPDisp(MF, TII);
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric   MFp = &MF;
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric   ForceLongBranchFirstPass = ForceLongBranch;
89181ad6265SDimitry Andric   // Run these at least once.
8920b57cec5SDimitry Andric   bool longBranchChanged = handlePossibleLongBranch();
8930b57cec5SDimitry Andric   bool forbiddenSlotChanged = handleForbiddenSlot();
8940eae32dcSDimitry Andric   bool fpuDelaySlotChanged = handleFPUDelaySlot();
89581ad6265SDimitry Andric   bool loadDelaySlotChanged = handleLoadDelaySlot();
8960b57cec5SDimitry Andric 
89781ad6265SDimitry Andric   bool Changed = longBranchChanged || forbiddenSlotChanged ||
89881ad6265SDimitry Andric                  fpuDelaySlotChanged || loadDelaySlotChanged;
8990b57cec5SDimitry Andric 
90081ad6265SDimitry Andric   // Then run them alternatively while there are changes.
9010b57cec5SDimitry Andric   while (forbiddenSlotChanged) {
9020b57cec5SDimitry Andric     longBranchChanged = handlePossibleLongBranch();
9030eae32dcSDimitry Andric     fpuDelaySlotChanged = handleFPUDelaySlot();
90481ad6265SDimitry Andric     loadDelaySlotChanged = handleLoadDelaySlot();
90581ad6265SDimitry Andric     if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged)
9060b57cec5SDimitry Andric       break;
9070b57cec5SDimitry Andric     forbiddenSlotChanged = handleForbiddenSlot();
9080b57cec5SDimitry Andric   }
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric   return Changed;
9110b57cec5SDimitry Andric }
912