<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>