<div style="font-family: arial, helvetica, sans-serif"><font size="2"><div class="gmail_quote">On Wed, Jun 13, 2012 at 6:22 PM, Akira Hatanaka <span dir="ltr"><<a href="mailto:ahatanaka@mips.com" target="_blank">ahatanaka@mips.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ahatanak<br>
Date: Wed Jun 13 20:22:24 2012<br>
New Revision: 158436<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=158436&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=158436&view=rev</a><br>
Log:<br>
Add file MipsLongBranch.cpp.<br></blockquote><div><br></div><div>When doing a delayed push of commits, I think it would be better if you could merge together those that merely fix bugs or oversights in previous commits. This reduces the strain on the build bots considerably.</div>
<div><br></div><div>Of course, pushing commits more incrementally is always ideal. =] Anyways, cool to see the new support for this!</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Added:<br>
llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp<br>
<br>
Added: llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp?rev=158436&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp?rev=158436&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp (added)<br>
+++ llvm/trunk/lib/Target/Mips/MipsLongBranch.cpp Wed Jun 13 20:22:24 2012<br>
@@ -0,0 +1,416 @@<br>
+//===-- MipsLongBranch.cpp - Emit long branches ---------------------------===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This pass expands a branch or jump instruction into a long branch if its<br>
+// offset is too large to fit into its immediate field.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#define DEBUG_TYPE "mips-long-branch"<br>
+<br>
+#include "Mips.h"<br>
+#include "MipsTargetMachine.h"<br>
+#include "MCTargetDesc/MipsBaseInfo.h"<br>
+#include "llvm/ADT/Statistic.h"<br>
+#include "llvm/CodeGen/MachineFunctionPass.h"<br>
+#include "llvm/CodeGen/MachineInstrBuilder.h"<br>
+#include "llvm/Function.h"<br>
+#include "llvm/Support/CommandLine.h"<br>
+#include "llvm/Support/MathExtras.h"<br>
+#include "llvm/Target/TargetInstrInfo.h"<br>
+#include "llvm/Target/TargetMachine.h"<br>
+#include "llvm/Target/TargetRegisterInfo.h"<br>
+<br>
+using namespace llvm;<br>
+<br>
+STATISTIC(LongBranches, "Number of long branches.");<br>
+<br>
+static cl::opt<bool> SkipLongBranch(<br>
+ "skip-mips-long-branch",<br>
+ cl::init(false),<br>
+ cl::desc("MIPS: Skip long branch pass."),<br>
+ cl::Hidden);<br>
+<br>
+static cl::opt<bool> ForceLongBranch(<br>
+ "force-mips-long-branch",<br>
+ cl::init(false),<br>
+ cl::desc("MIPS: Expand all branches to long format."),<br>
+ cl::Hidden);<br>
+<br>
+namespace {<br>
+ typedef MachineBasicBlock::iterator Iter;<br>
+ typedef MachineBasicBlock::reverse_iterator ReverseIter;<br>
+<br>
+ struct MBBInfo {<br>
+ uint64_t Size;<br>
+ bool HasLongBranch;<br>
+ MachineInstr *Br;<br>
+<br>
+ MBBInfo() : Size(0), HasLongBranch(false), Br(0) {}<br>
+ };<br>
+<br>
+ class MipsLongBranch : public MachineFunctionPass {<br>
+<br>
+ public:<br>
+ static char ID;<br>
+ MipsLongBranch(TargetMachine &tm)<br>
+ : MachineFunctionPass(ID), TM(tm),<br>
+ TII(static_cast<const MipsInstrInfo*>(tm.getInstrInfo())) {}<br>
+<br>
+ virtual const char *getPassName() const {<br>
+ return "Mips Long Branch";<br>
+ }<br>
+<br>
+ bool runOnMachineFunction(MachineFunction &F);<br>
+<br>
+ private:<br>
+ void splitMBB(MachineBasicBlock *MBB);<br>
+ void initMBBInfo();<br>
+ int64_t computeOffset(const MachineInstr *Br);<br>
+ bool offsetFitsIntoField(const MachineInstr *Br);<br>
+ unsigned addLongBranch(MachineBasicBlock &MBB, Iter Pos,<br>
+ MachineBasicBlock *Tgt, DebugLoc DL, bool Nop);<br>
+ void replaceBranch(MachineBasicBlock &MBB, Iter Br, DebugLoc DL,<br>
+ MachineBasicBlock *MBBOpnd);<br>
+ void expandToLongBranch(MBBInfo &Info);<br>
+<br>
+ const TargetMachine &TM;<br>
+ const MipsInstrInfo *TII;<br>
+ MachineFunction *MF;<br>
+ SmallVector<MBBInfo, 16> MBBInfos;<br>
+ };<br>
+<br>
+ char MipsLongBranch::ID = 0;<br>
+} // end of anonymous namespace<br>
+<br>
+/// createMipsLongBranchPass - Returns a pass that converts branches to long<br>
+/// branches.<br>
+FunctionPass *llvm::createMipsLongBranchPass(MipsTargetMachine &tm) {<br>
+ return new MipsLongBranch(tm);<br>
+}<br>
+<br>
+/// Iterate over list of Br's operands and search for a MachineBasicBlock<br>
+/// operand.<br>
+static MachineBasicBlock *getTargetMBB(const MachineInstr &Br) {<br>
+ for (unsigned I = 0, E = Br.getDesc().getNumOperands(); I < E; ++I) {<br>
+ const MachineOperand &MO = Br.getOperand(I);<br>
+<br>
+ if (MO.isMBB())<br>
+ return MO.getMBB();<br>
+ }<br>
+<br>
+ assert(false && "This instruction does not have an MBB operand.");<br>
+ return 0;<br>
+}<br>
+<br>
+// Traverse the list of instructions backwards until a non-debug instruction is<br>
+// found or it reaches E.<br>
+static ReverseIter getNonDebugInstr(ReverseIter B, ReverseIter E) {<br>
+ for (; B != E; ++B)<br>
+ if (!B->isDebugValue())<br>
+ return B;<br>
+<br>
+ return E;<br>
+}<br>
+<br>
+// Split MBB if it has two direct jumps/branches.<br>
+void MipsLongBranch::splitMBB(MachineBasicBlock *MBB) {<br>
+ ReverseIter End = MBB->rend();<br>
+ ReverseIter LastBr = getNonDebugInstr(MBB->rbegin(), End);<br>
+<br>
+ // Return if MBB has no branch instructions.<br>
+ if ((LastBr == End) ||<br>
+ (!LastBr->isConditionalBranch() && !LastBr->isUnconditionalBranch()))<br>
+ return;<br>
+<br>
+ ReverseIter FirstBr = getNonDebugInstr(next(LastBr), End);<br>
+<br>
+ // MBB has only one branch instruction if FirstBr is not a branch<br>
+ // instruction.<br>
+ if ((FirstBr == End) ||<br>
+ (!FirstBr->isConditionalBranch() && !FirstBr->isUnconditionalBranch()))<br>
+ return;<br>
+<br>
+ assert(!FirstBr->isIndirectBranch() && "Unexpected indirect branch found.");<br>
+<br>
+ // Create a new MBB. Move instructions in MBB to the newly created MBB.<br>
+ MachineBasicBlock *NewMBB =<br>
+ MF->CreateMachineBasicBlock(MBB->getBasicBlock());<br>
+<br>
+ // Insert NewMBB and fix control flow.<br>
+ MachineBasicBlock *Tgt = getTargetMBB(*FirstBr);<br>
+ NewMBB->transferSuccessors(MBB);<br>
+ NewMBB->removeSuccessor(Tgt);<br>
+ MBB->addSuccessor(NewMBB);<br>
+ MBB->addSuccessor(Tgt);<br>
+ MF->insert(next(MachineFunction::iterator(MBB)), NewMBB);<br>
+<br>
+ NewMBB->splice(NewMBB->end(), MBB, (++LastBr).base(), MBB->end());<br>
+}<br>
+<br>
+// Fill MBBInfos.<br>
+void MipsLongBranch::initMBBInfo() {<br>
+ // Split the MBBs if they have two branches. Each basic block should have at<br>
+ // most one branch after this loop is executed.<br>
+ for (MachineFunction::iterator I = MF->begin(), E = MF->end(); I != E;)<br>
+ splitMBB(I++);<br>
+<br>
+ MF->RenumberBlocks();<br>
+ MBBInfos.clear();<br>
+ MBBInfos.resize(MF->size());<br>
+<br>
+ for (unsigned I = 0, E = MBBInfos.size(); I < E; ++I) {<br>
+ MachineBasicBlock *MBB = MF->getBlockNumbered(I);<br>
+<br>
+ // Compute size of MBB.<br>
+ for (MachineBasicBlock::instr_iterator MI = MBB->instr_begin();<br>
+ MI != MBB->instr_end(); ++MI)<br>
+ MBBInfos[I].Size += TII->GetInstSizeInBytes(&*MI);<br>
+<br>
+ // Search for MBB's branch instruction.<br>
+ ReverseIter End = MBB->rend();<br>
+ ReverseIter Br = getNonDebugInstr(MBB->rbegin(), End);<br>
+<br>
+ if ((Br != End) && !Br->isIndirectBranch() &&<br>
+ (Br->isConditionalBranch() || Br->isUnconditionalBranch()))<br>
+ MBBInfos[I].Br = (++Br).base();<br>
+ }<br>
+}<br>
+<br>
+// Compute offset of branch in number of bytes.<br>
+int64_t MipsLongBranch::computeOffset(const MachineInstr *Br) {<br>
+ int64_t Offset = 0;<br>
+ int ThisMBB = Br->getParent()->getNumber();<br>
+ int TargetMBB = getTargetMBB(*Br)->getNumber();<br>
+<br>
+ // Compute offset of a forward branch.<br>
+ if (ThisMBB < TargetMBB) {<br>
+ for (int N = ThisMBB + 1; N < TargetMBB; ++N)<br>
+ Offset += MBBInfos[N].Size;<br>
+<br>
+ return Offset + 4;<br>
+ }<br>
+<br>
+ // Compute offset of a backward branch.<br>
+ for (int N = ThisMBB; N >= TargetMBB; --N)<br>
+ Offset += MBBInfos[N].Size;<br>
+<br>
+ return -Offset + 4;<br>
+}<br>
+<br>
+// Insert the following sequence:<br>
+// (pic or N64)<br>
+// lw $at, global_reg_slot<br>
+// lw $at, got($L1)($at)<br>
+// addiu $at, $at, lo($L1)<br>
+// jr $at<br>
+// noop<br>
+// (static and !N64)<br>
+// lui $at, hi($L1)<br>
+// addiu $at, $at, lo($L1)<br>
+// jr $at<br>
+// noop<br>
+unsigned MipsLongBranch::addLongBranch(MachineBasicBlock &MBB, Iter Pos,<br>
+ MachineBasicBlock *Tgt, DebugLoc DL,<br>
+ bool Nop) {<br>
+ MF->getInfo<MipsFunctionInfo>()->setEmitNOAT();<br>
+ bool IsPIC = (TM.getRelocationModel() == Reloc::PIC_);<br>
+ unsigned ABI = TM.getSubtarget<MipsSubtarget>().getTargetABI();<br>
+ bool N64 = (ABI == MipsSubtarget::N64);<br>
+ unsigned NumInstrs;<br>
+<br>
+ if (IsPIC || N64) {<br>
+ bool HasMips64 = TM.getSubtarget<MipsSubtarget>().hasMips64();<br>
+ unsigned AT = N64 ? Mips::AT_64 : Mips::AT;<br>
+ unsigned Load = N64 ? Mips::LD_P8 : Mips::LW;<br>
+ unsigned ADDiu = N64 ? Mips::DADDiu : Mips::ADDiu;<br>
+ unsigned JR = N64 ? Mips::JR64 : Mips::JR;<br>
+ unsigned GOTFlag = HasMips64 ? MipsII::MO_GOT_PAGE : MipsII::MO_GOT;<br>
+ unsigned OFSTFlag = HasMips64 ? MipsII::MO_GOT_OFST : MipsII::MO_ABS_LO;<br>
+ const MipsRegisterInfo *MRI =<br>
+ static_cast<const MipsRegisterInfo*>(TM.getRegisterInfo());<br>
+ unsigned SP = MRI->getFrameRegister(*MF);<br>
+ unsigned GlobalRegFI = MF->getInfo<MipsFunctionInfo>()->getGlobalRegFI();<br>
+ int64_t Offset = MF->getFrameInfo()->getObjectOffset(GlobalRegFI);<br>
+<br>
+ if (isInt<16>(Offset)) {<br>
+ BuildMI(MBB, Pos, DL, TII->get(Load), AT).addReg(SP).addImm(Offset);<br>
+ NumInstrs = 1;<br>
+ } else {<br>
+ unsigned ADDu = N64 ? Mips::DADDu : Mips::ADDu;<br>
+ MipsAnalyzeImmediate::Inst LastInst(0, 0);<br>
+<br>
+ MF->getInfo<MipsFunctionInfo>()->setEmitNOAT();<br>
+ NumInstrs = Mips::loadImmediate(Offset, N64, *TII, MBB, Pos, DL, true,<br>
+ &LastInst) + 2;<br>
+ BuildMI(MBB, Pos, DL, TII->get(ADDu), AT).addReg(SP).addReg(AT);<br>
+ BuildMI(MBB, Pos, DL, TII->get(Load), AT).addReg(AT)<br>
+ .addImm(SignExtend64<16>(LastInst.ImmOpnd));<br>
+ }<br>
+<br>
+ BuildMI(MBB, Pos, DL, TII->get(Load), AT).addReg(AT).addMBB(Tgt, GOTFlag);<br>
+ BuildMI(MBB, Pos, DL, TII->get(ADDiu), AT).addReg(AT).addMBB(Tgt, OFSTFlag);<br>
+ BuildMI(MBB, Pos, DL, TII->get(JR)).addReg(Mips::AT, RegState::Kill);<br>
+ NumInstrs += 3;<br>
+ } else {<br>
+ BuildMI(MBB, Pos, DL, TII->get(Mips::LUi), Mips::AT)<br>
+ .addMBB(Tgt, MipsII::MO_ABS_HI);<br>
+ BuildMI(MBB, Pos, DL, TII->get(Mips::ADDiu), Mips::AT)<br>
+ .addReg(Mips::AT).addMBB(Tgt, MipsII::MO_ABS_LO);<br>
+ BuildMI(MBB, Pos, DL, TII->get(Mips::JR)).addReg(Mips::AT, RegState::Kill);<br>
+ NumInstrs = 3;<br>
+ }<br>
+<br>
+ if (Nop) {<br>
+ BuildMI(MBB, Pos, DL, TII->get(Mips::NOP))->setIsInsideBundle();<br>
+ ++NumInstrs;<br>
+ }<br>
+<br>
+ return NumInstrs;<br>
+}<br>
+<br>
+// Replace Br with a branch which has the opposite condition code and a<br>
+// MachineBasicBlock operand MBBOpnd.<br>
+void MipsLongBranch::replaceBranch(MachineBasicBlock &MBB, Iter Br,<br>
+ DebugLoc DL, MachineBasicBlock *MBBOpnd) {<br>
+ unsigned NewOpc = Mips::GetOppositeBranchOpc(Br->getOpcode());<br>
+ const MCInstrDesc &NewDesc = TII->get(NewOpc);<br>
+<br>
+ MachineInstrBuilder MIB = BuildMI(MBB, Br, DL, NewDesc);<br>
+<br>
+ for (unsigned I = 0, E = Br->getDesc().getNumOperands(); I < E; ++I) {<br>
+ MachineOperand &MO = Br->getOperand(I);<br>
+<br>
+ if (!MO.isReg()) {<br>
+ assert(MO.isMBB() && "MBB operand expected.");<br>
+ break;<br>
+ }<br>
+<br>
+ MIB.addReg(MO.getReg());<br>
+ }<br>
+<br>
+ MIB.addMBB(MBBOpnd);<br>
+<br>
+ Br->eraseFromParent();<br>
+}<br>
+<br>
+// Expand branch instructions to long branches.<br>
+void MipsLongBranch::expandToLongBranch(MBBInfo &I) {<br>
+ I.HasLongBranch = true;<br>
+<br>
+ MachineBasicBlock *MBB = I.Br->getParent(), *Tgt = getTargetMBB(*I.Br);<br>
+ DebugLoc DL = I.Br->getDebugLoc();<br>
+<br>
+ if (I.Br->isUnconditionalBranch()) {<br>
+ // Unconditional branch before transformation:<br>
+ // b $tgt<br>
+ // delay-slot-instr<br>
+ //<br>
+ // after transformation:<br>
+ // delay-slot-instr<br>
+ // lw $at, global_reg_slot<br>
+ // lw $at, %got($tgt)($at)<br>
+ // addiu $at, $at, %lo($tgt)<br>
+ // jr $at<br>
+ // nop<br>
+ I.Size += (addLongBranch(*MBB, next(Iter(I.Br)), Tgt, DL, true) - 1) * 4;<br>
+<br>
+ // Remove branch and clear InsideBundle bit of the next instruction.<br>
+ next(MachineBasicBlock::instr_iterator(I.Br))->setIsInsideBundle(false);<br>
+ I.Br->eraseFromParent();<br>
+ return;<br>
+ }<br>
+<br>
+ assert(I.Br->isConditionalBranch() && "Conditional branch expected.");<br>
+<br>
+ // Conditional branch before transformation:<br>
+ // b cc, $tgt<br>
+ // delay-slot-instr<br>
+ // FallThrough:<br>
+ //<br>
+ // after transformation:<br>
+ // b !cc, FallThrough<br>
+ // delay-slot-instr<br>
+ // NewMBB:<br>
+ // lw $at, global_reg_slot<br>
+ // lw $at, %got($tgt)($at)<br>
+ // addiu $at, $at, %lo($tgt)<br>
+ // jr $at<br>
+ // noop<br>
+ // FallThrough:<br>
+<br>
+ MachineBasicBlock *NewMBB = MF->CreateMachineBasicBlock(MBB->getBasicBlock());<br>
+ MF->insert(next(MachineFunction::iterator(MBB)), NewMBB);<br>
+ MBB->removeSuccessor(Tgt);<br>
+ MBB->addSuccessor(NewMBB);<br>
+ NewMBB->addSuccessor(Tgt);<br>
+<br>
+ I.Size += addLongBranch(*NewMBB, NewMBB->begin(), Tgt, DL, true) * 4;<br>
+ replaceBranch(*MBB, I.Br, DL, *MBB->succ_begin());<br>
+}<br>
+<br>
+static void emitGPDisp(MachineFunction &F, const MipsInstrInfo *TII) {<br>
+ MachineBasicBlock &MBB = F.front();<br>
+ MachineBasicBlock::iterator I = MBB.begin();<br>
+ DebugLoc DL = MBB.findDebugLoc(MBB.begin());<br>
+ BuildMI(MBB, I, DL, TII->get(Mips::LUi), Mips::V0)<br>
+ .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);<br>
+ BuildMI(MBB, I, DL, TII->get(Mips::ADDiu), Mips::V0)<br>
+ .addReg(Mips::V0).addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);<br>
+ MBB.removeLiveIn(Mips::V0);<br>
+}<br>
+<br>
+bool MipsLongBranch::runOnMachineFunction(MachineFunction &F) {<br>
+ if ((TM.getRelocationModel() == Reloc::PIC_) &&<br>
+ TM.getSubtarget<MipsSubtarget>().isABI_O32() &&<br>
+ F.getInfo<MipsFunctionInfo>()->globalBaseRegSet())<br>
+ emitGPDisp(F, TII);<br>
+<br>
+ if (SkipLongBranch)<br>
+ return false;<br>
+<br>
+ MF = &F;<br>
+ initMBBInfo();<br>
+<br>
+ bool IsPIC = (TM.getRelocationModel() == Reloc::PIC_);<br>
+ SmallVector<MBBInfo, 16>::iterator I, E = MBBInfos.end();<br>
+ bool EverMadeChange = false, MadeChange = true;<br>
+<br>
+ while (MadeChange) {<br>
+ MadeChange = false;<br>
+<br>
+ for (I = MBBInfos.begin(); I != E; ++I) {<br>
+ // Skip if this MBB doesn't have a branch or the branch has already been<br>
+ // converted to a long branch.<br>
+ if (!I->Br || I->HasLongBranch)<br>
+ continue;<br>
+<br>
+ int64_t Offset = computeOffset(I->Br);<br>
+<br>
+ if (!ForceLongBranch) {<br>
+ // Check if offset fits into 16-bit immediate field of branches.<br>
+ if ((I->Br->isConditionalBranch() || IsPIC) && isInt<16>(Offset / 4))<br>
+ continue;<br>
+<br>
+ // Check if offset fits into 26-bit immediate field of jumps (J).<br>
+ if (I->Br->isUnconditionalBranch() && !IsPIC && isInt<26>(Offset / 4))<br>
+ continue;<br>
+ }<br>
+<br>
+ expandToLongBranch(*I);<br>
+ ++LongBranches;<br>
+ EverMadeChange = MadeChange = true;<br>
+ }<br>
+ }<br>
+<br>
+ if (EverMadeChange)<br>
+ MF->RenumberBlocks();<br>
+<br>
+ return EverMadeChange;<br>
+}<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></font></div>