Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MipsBranchExpansion.cpp
35294 views
//===----------------------- MipsBranchExpansion.cpp ----------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8///9/// This pass do two things:10/// - it expands a branch or jump instruction into a long branch if its offset11/// is too large to fit into its immediate field,12/// - it inserts nops to prevent forbidden slot hazards.13///14/// The reason why this pass combines these two tasks is that one of these two15/// tasks can break the result of the previous one.16///17/// Example of that is a situation where at first, no branch should be expanded,18/// but after adding at least one nop somewhere in the code to prevent a19/// forbidden slot hazard, offset of some branches may go out of range. In that20/// case it is necessary to check again if there is some branch that needs21/// expansion. On the other hand, expanding some branch may cause a control22/// transfer instruction to appear in the forbidden slot, which is a hazard that23/// should be fixed. This pass alternates between this two tasks untill no24/// changes are made. Only then we can be sure that all branches are expanded25/// properly, and no hazard situations exist.26///27/// Regarding branch expanding:28///29/// When branch instruction like beqzc or bnezc has offset that is too large30/// to fit into its immediate field, it has to be expanded to another31/// instruction or series of instructions.32///33/// FIXME: Fix pc-region jump instructions which cross 256MB segment boundaries.34/// TODO: Handle out of range bc, b (pseudo) instructions.35///36/// Regarding compact branch hazard prevention:37///38/// Hazards handled: forbidden slots for MIPSR6, FPU slots for MIPS3 and below,39/// load delay slots for MIPS1.40///41/// A forbidden slot hazard occurs when a compact branch instruction is executed42/// and the adjacent instruction in memory is a control transfer instruction43/// such as a branch or jump, ERET, ERETNC, DERET, WAIT and PAUSE.44///45/// For example:46///47/// 0x8004 bnec a1,v0,<P+0x18>48/// 0x8008 beqc a1,a2,<P+0x54>49///50/// In such cases, the processor is required to signal a Reserved Instruction51/// exception.52///53/// Here, if the instruction at 0x8004 is executed, the processor will raise an54/// exception as there is a control transfer instruction at 0x8008.55///56/// There are two sources of forbidden slot hazards:57///58/// A) A previous pass has created a compact branch directly.59/// B) Transforming a delay slot branch into compact branch. This case can be60/// difficult to process as lookahead for hazards is insufficient, as61/// backwards delay slot fillling can also produce hazards in previously62/// processed instuctions.63///64/// In future this pass can be extended (or new pass can be created) to handle65/// other pipeline hazards, such as various MIPS1 hazards, processor errata that66/// require instruction reorganization, etc.67///68/// This pass has to run after the delay slot filler as that pass can introduce69/// pipeline hazards such as compact branch hazard, hence the existing hazard70/// recognizer is not suitable.71///72//===----------------------------------------------------------------------===//7374#include "MCTargetDesc/MipsABIInfo.h"75#include "MCTargetDesc/MipsBaseInfo.h"76#include "MCTargetDesc/MipsMCNaCl.h"77#include "MCTargetDesc/MipsMCTargetDesc.h"78#include "Mips.h"79#include "MipsInstrInfo.h"80#include "MipsMachineFunction.h"81#include "MipsSubtarget.h"82#include "MipsTargetMachine.h"83#include "llvm/ADT/SmallVector.h"84#include "llvm/ADT/Statistic.h"85#include "llvm/ADT/StringRef.h"86#include "llvm/CodeGen/MachineBasicBlock.h"87#include "llvm/CodeGen/MachineFunction.h"88#include "llvm/CodeGen/MachineFunctionPass.h"89#include "llvm/CodeGen/MachineInstr.h"90#include "llvm/CodeGen/MachineInstrBuilder.h"91#include "llvm/CodeGen/MachineModuleInfo.h"92#include "llvm/CodeGen/MachineOperand.h"93#include "llvm/CodeGen/TargetSubtargetInfo.h"94#include "llvm/IR/DebugLoc.h"95#include "llvm/Support/CommandLine.h"96#include "llvm/Support/ErrorHandling.h"97#include "llvm/Support/MathExtras.h"98#include "llvm/Target/TargetMachine.h"99#include <algorithm>100#include <cassert>101#include <cstdint>102#include <iterator>103#include <utility>104105using namespace llvm;106107#define DEBUG_TYPE "mips-branch-expansion"108109STATISTIC(NumInsertedNops, "Number of nops inserted");110STATISTIC(LongBranches, "Number of long branches.");111112static cl::opt<bool>113SkipLongBranch("skip-mips-long-branch", cl::init(false),114cl::desc("MIPS: Skip branch expansion pass."), cl::Hidden);115116static cl::opt<bool>117ForceLongBranch("force-mips-long-branch", cl::init(false),118cl::desc("MIPS: Expand all branches to long format."),119cl::Hidden);120121namespace {122123using Iter = MachineBasicBlock::iterator;124using ReverseIter = MachineBasicBlock::reverse_iterator;125126struct MBBInfo {127uint64_t Size = 0;128bool HasLongBranch = false;129MachineInstr *Br = nullptr;130uint64_t Offset = 0;131MBBInfo() = default;132};133134class MipsBranchExpansion : public MachineFunctionPass {135public:136static char ID;137138MipsBranchExpansion() : MachineFunctionPass(ID), ABI(MipsABIInfo::Unknown()) {139initializeMipsBranchExpansionPass(*PassRegistry::getPassRegistry());140}141142StringRef getPassName() const override {143return "Mips Branch Expansion Pass";144}145146bool runOnMachineFunction(MachineFunction &F) override;147148MachineFunctionProperties getRequiredProperties() const override {149return MachineFunctionProperties().set(150MachineFunctionProperties::Property::NoVRegs);151}152153private:154void splitMBB(MachineBasicBlock *MBB);155void initMBBInfo();156int64_t computeOffset(const MachineInstr *Br);157uint64_t computeOffsetFromTheBeginning(int MBB);158void replaceBranch(MachineBasicBlock &MBB, Iter Br, const DebugLoc &DL,159MachineBasicBlock *MBBOpnd);160bool buildProperJumpMI(MachineBasicBlock *MBB,161MachineBasicBlock::iterator Pos, DebugLoc DL);162void expandToLongBranch(MBBInfo &Info);163template <typename Pred, typename Safe>164bool handleSlot(Pred Predicate, Safe SafeInSlot);165bool handleForbiddenSlot();166bool handleFPUDelaySlot();167bool handleLoadDelaySlot();168bool handlePossibleLongBranch();169170const MipsSubtarget *STI;171const MipsInstrInfo *TII;172173MachineFunction *MFp;174SmallVector<MBBInfo, 16> MBBInfos;175bool IsPIC;176MipsABIInfo ABI;177bool ForceLongBranchFirstPass = false;178};179180} // end of anonymous namespace181182char MipsBranchExpansion::ID = 0;183184INITIALIZE_PASS(MipsBranchExpansion, DEBUG_TYPE,185"Expand out of range branch instructions and fix forbidden"186" slot hazards",187false, false)188189/// Returns a pass that clears pipeline hazards.190FunctionPass *llvm::createMipsBranchExpansion() {191return new MipsBranchExpansion();192}193194// Find the next real instruction from the current position in current basic195// block.196static Iter getNextMachineInstrInBB(Iter Position) {197Iter I = Position, E = Position->getParent()->end();198I = std::find_if_not(I, E,199[](const Iter &Insn) { return Insn->isTransient(); });200201return I;202}203204// Find the next real instruction from the current position, looking through205// basic block boundaries.206static std::pair<Iter, bool> getNextMachineInstr(Iter Position,207MachineBasicBlock *Parent) {208if (Position == Parent->end()) {209do {210MachineBasicBlock *Succ = Parent->getNextNode();211if (Succ != nullptr && Parent->isSuccessor(Succ)) {212Position = Succ->begin();213Parent = Succ;214} else {215return std::make_pair(Position, true);216}217} while (Parent->empty());218}219220Iter Instr = getNextMachineInstrInBB(Position);221if (Instr == Parent->end()) {222return getNextMachineInstr(Instr, Parent);223}224return std::make_pair(Instr, false);225}226227/// Iterate over list of Br's operands and search for a MachineBasicBlock228/// operand.229static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) {230for (unsigned I = 0, E = Br.getDesc().getNumOperands(); I < E; ++I) {231const MachineOperand &MO = Br.getOperand(I);232233if (MO.isMBB())234return MO.getMBB();235}236237llvm_unreachable("This instruction does not have an MBB operand.");238}239240// Traverse the list of instructions backwards until a non-debug instruction is241// found or it reaches E.242static ReverseIter getNonDebugInstr(ReverseIter B, const ReverseIter &E) {243for (; B != E; ++B)244if (!B->isDebugInstr())245return B;246247return E;248}249250// Split MBB if it has two direct jumps/branches.251void MipsBranchExpansion::splitMBB(MachineBasicBlock *MBB) {252ReverseIter End = MBB->rend();253ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End);254255// Return if MBB has no branch instructions.256if ((LastBr == End) ||257(!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))258return;259260ReverseIter FirstBr = getNonDebugInstr(std::next(LastBr), End);261262// MBB has only one branch instruction if FirstBr is not a branch263// instruction.264if ((FirstBr == End) ||265(!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))266return;267268assert(!FirstBr->isIndirectBranch() && "Unexpected indirect branch found.");269270// Create a new MBB. Move instructions in MBB to the newly created MBB.271MachineBasicBlock *NewMBB =272MFp->CreateMachineBasicBlock(MBB->getBasicBlock());273274// Insert NewMBB and fix control flow.275MachineBasicBlock *Tgt = getTargetMBB(*FirstBr);276NewMBB->transferSuccessors(MBB);277if (Tgt != getTargetMBB(*LastBr))278NewMBB->removeSuccessor(Tgt, true);279MBB->addSuccessor(NewMBB);280MBB->addSuccessor(Tgt);281MFp->insert(std::next(MachineFunction::iterator(MBB)), NewMBB);282283NewMBB->splice(NewMBB->end(), MBB, LastBr.getReverse(), MBB->end());284}285286// Fill MBBInfos.287void MipsBranchExpansion::initMBBInfo() {288// Split the MBBs if they have two branches. Each basic block should have at289// most one branch after this loop is executed.290for (auto &MBB : *MFp)291splitMBB(&MBB);292293MFp->RenumberBlocks();294MBBInfos.clear();295MBBInfos.resize(MFp->size());296297for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {298MachineBasicBlock *MBB = MFp->getBlockNumbered(I);299300// Compute size of MBB.301for (MachineInstr &MI : MBB->instrs())302MBBInfos[I].Size += TII->getInstSizeInBytes(MI);303}304}305306// Compute offset of branch in number of bytes.307int64_t MipsBranchExpansion::computeOffset(const MachineInstr *Br) {308int64_t Offset = 0;309int ThisMBB = Br->getParent()->getNumber();310int TargetMBB = getTargetMBB(*Br)->getNumber();311312// Compute offset of a forward branch.313if (ThisMBB < TargetMBB) {314for (int N = ThisMBB + 1; N < TargetMBB; ++N)315Offset += MBBInfos[N].Size;316317return Offset + 4;318}319320// Compute offset of a backward branch.321for (int N = ThisMBB; N >= TargetMBB; --N)322Offset += MBBInfos[N].Size;323324return -Offset + 4;325}326327// Returns the distance in bytes up until MBB328uint64_t MipsBranchExpansion::computeOffsetFromTheBeginning(int MBB) {329uint64_t Offset = 0;330for (int N = 0; N < MBB; ++N)331Offset += MBBInfos[N].Size;332return Offset;333}334335// Replace Br with a branch which has the opposite condition code and a336// MachineBasicBlock operand MBBOpnd.337void MipsBranchExpansion::replaceBranch(MachineBasicBlock &MBB, Iter Br,338const DebugLoc &DL,339MachineBasicBlock *MBBOpnd) {340unsigned NewOpc = TII->getOppositeBranchOpc(Br->getOpcode());341const MCInstrDesc &NewDesc = TII->get(NewOpc);342343MachineInstrBuilder MIB = BuildMI(MBB, Br, DL, NewDesc);344345for (unsigned I = 0, E = Br->getDesc().getNumOperands(); I < E; ++I) {346MachineOperand &MO = Br->getOperand(I);347348switch (MO.getType()) {349case MachineOperand::MO_Register:350MIB.addReg(MO.getReg());351break;352case MachineOperand::MO_Immediate:353// Octeon BBIT family of branch has an immediate operand354// (e.g. BBIT0 $v0, 3, %bb.1).355if (!TII->isBranchWithImm(Br->getOpcode()))356llvm_unreachable("Unexpected immediate in branch instruction");357MIB.addImm(MO.getImm());358break;359case MachineOperand::MO_MachineBasicBlock:360MIB.addMBB(MBBOpnd);361break;362default:363llvm_unreachable("Unexpected operand type in branch instruction");364}365}366367if (Br->hasDelaySlot()) {368// Bundle the instruction in the delay slot to the newly created branch369// and erase the original branch.370assert(Br->isBundledWithSucc());371MachineBasicBlock::instr_iterator II = Br.getInstrIterator();372MIBundleBuilder(&*MIB).append((++II)->removeFromBundle());373}374Br->eraseFromParent();375}376377bool MipsBranchExpansion::buildProperJumpMI(MachineBasicBlock *MBB,378MachineBasicBlock::iterator Pos,379DebugLoc DL) {380bool HasR6 = ABI.IsN64() ? STI->hasMips64r6() : STI->hasMips32r6();381bool AddImm = HasR6 && !STI->useIndirectJumpsHazard();382383unsigned JR = ABI.IsN64() ? Mips::JR64 : Mips::JR;384unsigned JIC = ABI.IsN64() ? Mips::JIC64 : Mips::JIC;385unsigned JR_HB = ABI.IsN64() ? Mips::JR_HB64 : Mips::JR_HB;386unsigned JR_HB_R6 = ABI.IsN64() ? Mips::JR_HB64_R6 : Mips::JR_HB_R6;387388unsigned JumpOp;389if (STI->useIndirectJumpsHazard())390JumpOp = HasR6 ? JR_HB_R6 : JR_HB;391else392JumpOp = HasR6 ? JIC : JR;393394if (JumpOp == Mips::JIC && STI->inMicroMipsMode())395JumpOp = Mips::JIC_MMR6;396397unsigned ATReg = ABI.IsN64() ? Mips::AT_64 : Mips::AT;398MachineInstrBuilder Instr =399BuildMI(*MBB, Pos, DL, TII->get(JumpOp)).addReg(ATReg);400if (AddImm)401Instr.addImm(0);402403return !AddImm;404}405406// Expand branch instructions to long branches.407// TODO: This function has to be fixed for beqz16 and bnez16, because it408// currently assumes that all branches have 16-bit offsets, and will produce409// wrong code if branches whose allowed offsets are [-128, -126, ..., 126]410// are present.411void MipsBranchExpansion::expandToLongBranch(MBBInfo &I) {412MachineBasicBlock::iterator Pos;413MachineBasicBlock *MBB = I.Br->getParent(), *TgtMBB = getTargetMBB(*I.Br);414DebugLoc DL = I.Br->getDebugLoc();415const BasicBlock *BB = MBB->getBasicBlock();416MachineFunction::iterator FallThroughMBB = ++MachineFunction::iterator(MBB);417MachineBasicBlock *LongBrMBB = MFp->CreateMachineBasicBlock(BB);418419MFp->insert(FallThroughMBB, LongBrMBB);420MBB->replaceSuccessor(TgtMBB, LongBrMBB);421422if (IsPIC) {423MachineBasicBlock *BalTgtMBB = MFp->CreateMachineBasicBlock(BB);424MFp->insert(FallThroughMBB, BalTgtMBB);425LongBrMBB->addSuccessor(BalTgtMBB);426BalTgtMBB->addSuccessor(TgtMBB);427428// We must select between the MIPS32r6/MIPS64r6 BALC (which is a normal429// instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an430// pseudo-instruction wrapping BGEZAL).431const unsigned BalOp =432STI->hasMips32r6()433? STI->inMicroMipsMode() ? Mips::BALC_MMR6 : Mips::BALC434: STI->inMicroMipsMode() ? Mips::BAL_BR_MM : Mips::BAL_BR;435436if (!ABI.IsN64()) {437// Pre R6:438// $longbr:439// addiu $sp, $sp, -8440// sw $ra, 0($sp)441// lui $at, %hi($tgt - $baltgt)442// bal $baltgt443// addiu $at, $at, %lo($tgt - $baltgt)444// $baltgt:445// addu $at, $ra, $at446// lw $ra, 0($sp)447// jr $at448// addiu $sp, $sp, 8449// $fallthrough:450//451452// R6:453// $longbr:454// addiu $sp, $sp, -8455// sw $ra, 0($sp)456// lui $at, %hi($tgt - $baltgt)457// addiu $at, $at, %lo($tgt - $baltgt)458// balc $baltgt459// $baltgt:460// addu $at, $ra, $at461// lw $ra, 0($sp)462// addiu $sp, $sp, 8463// jic $at, 0464// $fallthrough:465466Pos = LongBrMBB->begin();467468BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)469.addReg(Mips::SP)470.addImm(-8);471BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SW))472.addReg(Mips::RA)473.addReg(Mips::SP)474.addImm(0);475476// LUi and ADDiu instructions create 32-bit offset of the target basic477// block from the target of BAL(C) instruction. We cannot use immediate478// value for this offset because it cannot be determined accurately when479// the program has inline assembly statements. We therefore use the480// relocation expressions %hi($tgt-$baltgt) and %lo($tgt-$baltgt) which481// are resolved during the fixup, so the values will always be correct.482//483// Since we cannot create %hi($tgt-$baltgt) and %lo($tgt-$baltgt)484// expressions at this point (it is possible only at the MC layer),485// we replace LUi and ADDiu with pseudo instructions486// LONG_BRANCH_LUi and LONG_BRANCH_ADDiu, and add both basic487// blocks as operands to these instructions. When lowering these pseudo488// instructions to LUi and ADDiu in the MC layer, we will create489// %hi($tgt-$baltgt) and %lo($tgt-$baltgt) expressions and add them as490// operands to lowered instructions.491492BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi), Mips::AT)493.addMBB(TgtMBB, MipsII::MO_ABS_HI)494.addMBB(BalTgtMBB);495496MachineInstrBuilder BalInstr =497BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);498MachineInstrBuilder ADDiuInstr =499BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_ADDiu), Mips::AT)500.addReg(Mips::AT)501.addMBB(TgtMBB, MipsII::MO_ABS_LO)502.addMBB(BalTgtMBB);503if (STI->hasMips32r6()) {504LongBrMBB->insert(Pos, ADDiuInstr);505LongBrMBB->insert(Pos, BalInstr);506} else {507LongBrMBB->insert(Pos, BalInstr);508LongBrMBB->insert(Pos, ADDiuInstr);509LongBrMBB->rbegin()->bundleWithPred();510}511512Pos = BalTgtMBB->begin();513514BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDu), Mips::AT)515.addReg(Mips::RA)516.addReg(Mips::AT);517BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LW), Mips::RA)518.addReg(Mips::SP)519.addImm(0);520if (STI->isTargetNaCl())521// Bundle-align the target of indirect branch JR.522TgtMBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);523524// In NaCl, modifying the sp is not allowed in branch delay slot.525// For MIPS32R6, we can skip using a delay slot branch.526bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos, DL);527528if (STI->isTargetNaCl() || !hasDelaySlot) {529BuildMI(*BalTgtMBB, std::prev(Pos), DL, TII->get(Mips::ADDiu), Mips::SP)530.addReg(Mips::SP)531.addImm(8);532}533if (hasDelaySlot) {534if (STI->isTargetNaCl()) {535TII->insertNop(*BalTgtMBB, Pos, DL);536} else {537BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::ADDiu), Mips::SP)538.addReg(Mips::SP)539.addImm(8);540}541BalTgtMBB->rbegin()->bundleWithPred();542}543} else {544// Pre R6:545// $longbr:546// daddiu $sp, $sp, -16547// sd $ra, 0($sp)548// daddiu $at, $zero, %hi($tgt - $baltgt)549// dsll $at, $at, 16550// bal $baltgt551// daddiu $at, $at, %lo($tgt - $baltgt)552// $baltgt:553// daddu $at, $ra, $at554// ld $ra, 0($sp)555// jr64 $at556// daddiu $sp, $sp, 16557// $fallthrough:558559// R6:560// $longbr:561// daddiu $sp, $sp, -16562// sd $ra, 0($sp)563// daddiu $at, $zero, %hi($tgt - $baltgt)564// dsll $at, $at, 16565// daddiu $at, $at, %lo($tgt - $baltgt)566// balc $baltgt567// $baltgt:568// daddu $at, $ra, $at569// ld $ra, 0($sp)570// daddiu $sp, $sp, 16571// jic $at, 0572// $fallthrough:573574// We assume the branch is within-function, and that offset is within575// +/- 2GB. High 32 bits will therefore always be zero.576577// Note that this will work even if the offset is negative, because578// of the +1 modification that's added in that case. For example, if the579// offset is -1MB (0xFFFFFFFFFFF00000), the computation for %higher is580//581// 0xFFFFFFFFFFF00000 + 0x80008000 = 0x000000007FF08000582//583// and the bits [47:32] are zero. For %highest584//585// 0xFFFFFFFFFFF00000 + 0x800080008000 = 0x000080007FF08000586//587// and the bits [63:48] are zero.588589Pos = LongBrMBB->begin();590591BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)592.addReg(Mips::SP_64)593.addImm(-16);594BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::SD))595.addReg(Mips::RA_64)596.addReg(Mips::SP_64)597.addImm(0);598BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu),599Mips::AT_64)600.addReg(Mips::ZERO_64)601.addMBB(TgtMBB, MipsII::MO_ABS_HI)602.addMBB(BalTgtMBB);603BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)604.addReg(Mips::AT_64)605.addImm(16);606607MachineInstrBuilder BalInstr =608BuildMI(*MFp, DL, TII->get(BalOp)).addMBB(BalTgtMBB);609MachineInstrBuilder DADDiuInstr =610BuildMI(*MFp, DL, TII->get(Mips::LONG_BRANCH_DADDiu), Mips::AT_64)611.addReg(Mips::AT_64)612.addMBB(TgtMBB, MipsII::MO_ABS_LO)613.addMBB(BalTgtMBB);614if (STI->hasMips32r6()) {615LongBrMBB->insert(Pos, DADDiuInstr);616LongBrMBB->insert(Pos, BalInstr);617} else {618LongBrMBB->insert(Pos, BalInstr);619LongBrMBB->insert(Pos, DADDiuInstr);620LongBrMBB->rbegin()->bundleWithPred();621}622623Pos = BalTgtMBB->begin();624625BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDu), Mips::AT_64)626.addReg(Mips::RA_64)627.addReg(Mips::AT_64);628BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::LD), Mips::RA_64)629.addReg(Mips::SP_64)630.addImm(0);631632bool hasDelaySlot = buildProperJumpMI(BalTgtMBB, Pos, DL);633// If there is no delay slot, Insert stack adjustment before634if (!hasDelaySlot) {635BuildMI(*BalTgtMBB, std::prev(Pos), DL, TII->get(Mips::DADDiu),636Mips::SP_64)637.addReg(Mips::SP_64)638.addImm(16);639} else {640BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::DADDiu), Mips::SP_64)641.addReg(Mips::SP_64)642.addImm(16);643BalTgtMBB->rbegin()->bundleWithPred();644}645}646} else { // Not PIC647Pos = LongBrMBB->begin();648LongBrMBB->addSuccessor(TgtMBB);649650// Compute the position of the potentiall jump instruction (basic blocks651// before + 4 for the instruction)652uint64_t JOffset = computeOffsetFromTheBeginning(MBB->getNumber()) +653MBBInfos[MBB->getNumber()].Size + 4;654uint64_t TgtMBBOffset = computeOffsetFromTheBeginning(TgtMBB->getNumber());655// If it's a forward jump, then TgtMBBOffset will be shifted by two656// instructions657if (JOffset < TgtMBBOffset)658TgtMBBOffset += 2 * 4;659// Compare 4 upper bits to check if it's the same segment660bool SameSegmentJump = JOffset >> 28 == TgtMBBOffset >> 28;661662if (STI->hasMips32r6() && TII->isBranchOffsetInRange(Mips::BC, I.Offset)) {663// R6:664// $longbr:665// bc $tgt666// $fallthrough:667//668BuildMI(*LongBrMBB, Pos, DL,669TII->get(STI->inMicroMipsMode() ? Mips::BC_MMR6 : Mips::BC))670.addMBB(TgtMBB);671} else if (SameSegmentJump) {672// Pre R6:673// $longbr:674// j $tgt675// nop676// $fallthrough:677//678BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::J)).addMBB(TgtMBB);679TII->insertNop(*LongBrMBB, Pos, DL)->bundleWithPred();680} else {681// At this point, offset where we need to branch does not fit into682// immediate field of the branch instruction and is not in the same683// segment as jump instruction. Therefore we will break it into couple684// instructions, where we first load the offset into register, and then we685// do branch register.686if (ABI.IsN64()) {687BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi2Op_64),688Mips::AT_64)689.addMBB(TgtMBB, MipsII::MO_HIGHEST);690BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),691Mips::AT_64)692.addReg(Mips::AT_64)693.addMBB(TgtMBB, MipsII::MO_HIGHER);694BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)695.addReg(Mips::AT_64)696.addImm(16);697BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),698Mips::AT_64)699.addReg(Mips::AT_64)700.addMBB(TgtMBB, MipsII::MO_ABS_HI);701BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::DSLL), Mips::AT_64)702.addReg(Mips::AT_64)703.addImm(16);704BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_DADDiu2Op),705Mips::AT_64)706.addReg(Mips::AT_64)707.addMBB(TgtMBB, MipsII::MO_ABS_LO);708} else {709BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_LUi2Op),710Mips::AT)711.addMBB(TgtMBB, MipsII::MO_ABS_HI);712BuildMI(*LongBrMBB, Pos, DL, TII->get(Mips::LONG_BRANCH_ADDiu2Op),713Mips::AT)714.addReg(Mips::AT)715.addMBB(TgtMBB, MipsII::MO_ABS_LO);716}717buildProperJumpMI(LongBrMBB, Pos, DL);718}719}720721if (I.Br->isUnconditionalBranch()) {722// Change branch destination.723assert(I.Br->getDesc().getNumOperands() == 1);724I.Br->removeOperand(0);725I.Br->addOperand(MachineOperand::CreateMBB(LongBrMBB));726} else727// Change branch destination and reverse condition.728replaceBranch(*MBB, I.Br, DL, &*FallThroughMBB);729}730731static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {732MachineBasicBlock &MBB = F.front();733MachineBasicBlock::iterator I = MBB.begin();734DebugLoc DL = MBB.findDebugLoc(MBB.begin());735BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0)736.addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);737BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0)738.addReg(Mips::V0)739.addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);740MBB.removeLiveIn(Mips::V0);741}742743template <typename Pred, typename Safe>744bool MipsBranchExpansion::handleSlot(Pred Predicate, Safe SafeInSlot) {745bool Changed = false;746747for (MachineFunction::iterator FI = MFp->begin(); FI != MFp->end(); ++FI) {748for (Iter I = FI->begin(); I != FI->end(); ++I) {749750// Delay slot hazard handling. Use lookahead over state.751if (!Predicate(*I))752continue;753754Iter IInSlot;755bool LastInstInFunction =756std::next(I) == FI->end() && std::next(FI) == MFp->end();757if (!LastInstInFunction) {758std::pair<Iter, bool> Res = getNextMachineInstr(std::next(I), &*FI);759LastInstInFunction |= Res.second;760IInSlot = Res.first;761}762763if (LastInstInFunction || !SafeInSlot(*IInSlot, *I)) {764MachineBasicBlock::instr_iterator Iit = I->getIterator();765if (std::next(Iit) == FI->end() ||766std::next(Iit)->getOpcode() != Mips::NOP) {767Changed = true;768TII->insertNop(*(I->getParent()), std::next(I), I->getDebugLoc())769->bundleWithPred();770NumInsertedNops++;771}772}773}774}775776return Changed;777}778779bool MipsBranchExpansion::handleForbiddenSlot() {780// Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6.781if (!STI->hasMips32r6() || STI->inMicroMipsMode())782return false;783784return handleSlot(785[this](auto &I) -> bool { return TII->HasForbiddenSlot(I); },786[this](auto &IInSlot, auto &I) -> bool {787return TII->SafeInForbiddenSlot(IInSlot);788});789}790791bool MipsBranchExpansion::handleFPUDelaySlot() {792// FPU delay slots are only defined for MIPS3 and below.793if (STI->hasMips32() || STI->hasMips4())794return false;795796return handleSlot([this](auto &I) -> bool { return TII->HasFPUDelaySlot(I); },797[this](auto &IInSlot, auto &I) -> bool {798return TII->SafeInFPUDelaySlot(IInSlot, I);799});800}801802bool MipsBranchExpansion::handleLoadDelaySlot() {803// Load delay slot hazards are only for MIPS1.804if (STI->hasMips2())805return false;806807return handleSlot(808[this](auto &I) -> bool { return TII->HasLoadDelaySlot(I); },809[this](auto &IInSlot, auto &I) -> bool {810return TII->SafeInLoadDelaySlot(IInSlot, I);811});812}813814bool MipsBranchExpansion::handlePossibleLongBranch() {815if (STI->inMips16Mode() || !STI->enableLongBranchPass())816return false;817818if (SkipLongBranch)819return false;820821bool EverMadeChange = false, MadeChange = true;822823while (MadeChange) {824MadeChange = false;825826initMBBInfo();827828for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {829MachineBasicBlock *MBB = MFp->getBlockNumbered(I);830// Search for MBB's branch instruction.831ReverseIter End = MBB->rend();832ReverseIter Br = getNonDebugInstr(MBB->rbegin(), End);833834if ((Br != End) && Br->isBranch() && !Br->isIndirectBranch() &&835(Br->isConditionalBranch() ||836(Br->isUnconditionalBranch() && IsPIC))) {837int64_t Offset = computeOffset(&*Br);838839if (STI->isTargetNaCl()) {840// The offset calculation does not include sandboxing instructions841// that will be added later in the MC layer. Since at this point we842// don't know the exact amount of code that "sandboxing" will add, we843// conservatively estimate that code will not grow more than 100%.844Offset *= 2;845}846847if (ForceLongBranchFirstPass ||848!TII->isBranchOffsetInRange(Br->getOpcode(), Offset)) {849MBBInfos[I].Offset = Offset;850MBBInfos[I].Br = &*Br;851}852}853} // End for854855ForceLongBranchFirstPass = false;856857SmallVectorImpl<MBBInfo>::iterator I, E = MBBInfos.end();858859for (I = MBBInfos.begin(); I != E; ++I) {860// Skip if this MBB doesn't have a branch or the branch has already been861// converted to a long branch.862if (!I->Br)863continue;864865expandToLongBranch(*I);866++LongBranches;867EverMadeChange = MadeChange = true;868}869870MFp->RenumberBlocks();871}872873return EverMadeChange;874}875876bool MipsBranchExpansion::runOnMachineFunction(MachineFunction &MF) {877const TargetMachine &TM = MF.getTarget();878IsPIC = TM.isPositionIndependent();879ABI = static_cast<const MipsTargetMachine &>(TM).getABI();880STI = &MF.getSubtarget<MipsSubtarget>();881TII = static_cast<const MipsInstrInfo *>(STI->getInstrInfo());882883if (IsPIC && ABI.IsO32() &&884MF.getInfo<MipsFunctionInfo>()->globalBaseRegSet())885emitGPDisp(MF, TII);886887MFp = &MF;888889ForceLongBranchFirstPass = ForceLongBranch;890// Run these at least once.891bool longBranchChanged = handlePossibleLongBranch();892bool forbiddenSlotChanged = handleForbiddenSlot();893bool fpuDelaySlotChanged = handleFPUDelaySlot();894bool loadDelaySlotChanged = handleLoadDelaySlot();895896bool Changed = longBranchChanged || forbiddenSlotChanged ||897fpuDelaySlotChanged || loadDelaySlotChanged;898899// Then run them alternatively while there are changes.900while (forbiddenSlotChanged) {901longBranchChanged = handlePossibleLongBranch();902fpuDelaySlotChanged = handleFPUDelaySlot();903loadDelaySlotChanged = handleLoadDelaySlot();904if (!longBranchChanged && !fpuDelaySlotChanged && !loadDelaySlotChanged)905break;906forbiddenSlotChanged = handleForbiddenSlot();907}908909return Changed;910}911912913