[C++] Use 'nullptr'. Target edition.
[oota-llvm.git] / lib / Target / PowerPC / PPCBranchSelector.cpp
index 0c07d816218731da3c443680878dbc37703e2c65..8a851d85255b7934447e59e1802e2d844007d7b7 100644 (file)
-//===-- PowerPCBranchSelector.cpp - Emit long conditional branches-*- C++ -*-=//
+//===-- PPCBranchSelector.cpp - Emit long conditional branches ------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
-// This file was developed by Nate Baegeman and is distributed under the
-// University of Illinois Open Source License. See LICENSE.TXT for details.
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
 //
 //===----------------------------------------------------------------------===//
 //
 // This file contains a pass that scans a machine function to determine which
 // conditional branches need more than 16 bits of displacement to reach their
 // target basic block.  It does this in two passes; a calculation of basic block
-// positions pass, and a branch psuedo op to machine branch opcode pass.  This
+// positions pass, and a branch pseudo op to machine branch opcode pass.  This
 // pass should be run last, just before the assembly printer.
 //
 //===----------------------------------------------------------------------===//
 
-#define DEBUG_TYPE "bsel"
 #include "PPC.h"
+#include "MCTargetDesc/PPCPredicates.h"
 #include "PPCInstrBuilder.h"
 #include "PPCInstrInfo.h"
+#include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/Support/Debug.h"
-#include <map>
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Target/TargetMachine.h"
 using namespace llvm;
 
-namespace {
-  struct BSel : public MachineFunctionPass {
-    // OffsetMap - Mapping between BB and byte offset from start of function
-    std::map<MachineBasicBlock*, unsigned> OffsetMap;
-
-    /// bytesForOpcode - A convenience function for totalling up the number of
-    /// bytes in a basic block.
-    ///
-    static unsigned bytesForOpcode(unsigned opcode) {
-      switch (opcode) {
-      case PPC::COND_BRANCH:
-        // while this will be 4 most of the time, if we emit 12 it is just a
-        // minor pessimization that saves us from having to worry about
-        // keeping the offsets up to date later when we emit long branch glue.
-        return 12;
-      case PPC::IMPLICIT_DEF_GPR: // no asm emitted
-      case PPC::IMPLICIT_DEF_F4: // no asm emitted
-      case PPC::IMPLICIT_DEF_F8: // no asm emitted
-        return 0;
-      default:
-        break;
-      }
-      return 4; // PowerPC instructions are all 4 bytes
-    }
+#define DEBUG_TYPE "ppc-branch-select"
 
-    virtual bool runOnMachineFunction(MachineFunction &Fn) {
-      // Running total of instructions encountered since beginning of function
-      unsigned ByteCount = 0;
+STATISTIC(NumExpanded, "Number of branches expanded to long format");
 
-      // For each MBB, add its offset to the offset map, and count up its
-      // instructions
-      for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
-           ++MFI) {
-        MachineBasicBlock *MBB = MFI;
-        OffsetMap[MBB] = ByteCount;
+namespace llvm {
+  void initializePPCBSelPass(PassRegistry&);
+}
 
-        for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
-             MBBI != EE; ++MBBI)
-          ByteCount += bytesForOpcode(MBBI->getOpcode());
-      }
+namespace {
+  struct PPCBSel : public MachineFunctionPass {
+    static char ID;
+    PPCBSel() : MachineFunctionPass(ID) {
+      initializePPCBSelPass(*PassRegistry::getPassRegistry());
+    }
 
-      // We're about to run over the MBB's again, so reset the ByteCount
-      ByteCount = 0;
-
-      // For each MBB, find the conditional branch pseudo instructions, and
-      // calculate the difference between the target MBB and the current ICount
-      // to decide whether or not to emit a short or long branch.
-      //
-      // short branch:
-      // bCC .L_TARGET_MBB
-      //
-      // long branch:
-      // bInverseCC $PC+8
-      // b .L_TARGET_MBB
-      // b .L_FALLTHROUGH_MBB
-
-      for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
-           ++MFI) {
-        MachineBasicBlock *MBB = MFI;
-
-        for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
-             MBBI != EE; ++MBBI) {
-          // We may end up deleting the MachineInstr that MBBI points to, so
-          // remember its opcode now so we can refer to it after calling erase()
-          unsigned OpcodeToReplace = MBBI->getOpcode();
-
-          if (OpcodeToReplace == PPC::COND_BRANCH) {
-            MachineBasicBlock::iterator MBBJ = MBBI;
-            ++MBBJ;
-
-            // condbranch operands:
-            // 0. CR0 register
-            // 1. bc opcode
-            // 2. target MBB
-            // 3. fallthrough MBB
-            MachineBasicBlock *trueMBB =
-              MBBI->getOperand(2).getMachineBasicBlock();
-            MachineBasicBlock *falseMBB =
-              MBBI->getOperand(3).getMachineBasicBlock();
-
-            int Displacement = OffsetMap[trueMBB] - ByteCount;
-            unsigned Opcode = MBBI->getOperand(1).getImmedValue();
-            unsigned CRReg = MBBI->getOperand(0).getReg();
-            unsigned Inverted = PPC32InstrInfo::invertPPCBranchOpcode(Opcode);
-
-            if (Displacement >= -32768 && Displacement <= 32767) {
-              BuildMI(*MBB, MBBJ, Opcode, 2).addReg(CRReg).addMBB(trueMBB);
-            } else {
-              BuildMI(*MBB, MBBJ, Inverted, 2).addReg(CRReg).addSImm(8);
-              BuildMI(*MBB, MBBJ, PPC::B, 1).addMBB(trueMBB);
-              BuildMI(*MBB, MBBJ, PPC::B, 1).addMBB(falseMBB);
-            }
-
-            // Erase the psuedo COND_BRANCH instruction, and then back up the
-            // iterator so that when the for loop increments it, we end up in
-            // the correct place rather than iterating off the end.
-            MBB->erase(MBBI);
-            MBBI = --MBBJ;
-          }
-          ByteCount += bytesForOpcode(OpcodeToReplace);
-        }
-      }
+    /// BlockSizes - The sizes of the basic blocks in the function.
+    std::vector<unsigned> BlockSizes;
 
-      OffsetMap.clear();
-      return true;
-    }
+    virtual bool runOnMachineFunction(MachineFunction &Fn);
 
     virtual const char *getPassName() const {
-      return "PowerPC Branch Selection";
+      return "PowerPC Branch Selector";
     }
   };
+  char PPCBSel::ID = 0;
 }
 
+INITIALIZE_PASS(PPCBSel, "ppc-branch-select", "PowerPC Branch Selector",
+                false, false)
+
 /// createPPCBranchSelectionPass - returns an instance of the Branch Selection
 /// Pass
 ///
 FunctionPass *llvm::createPPCBranchSelectionPass() {
-  return new BSel();
+  return new PPCBSel();
 }
+
+bool PPCBSel::runOnMachineFunction(MachineFunction &Fn) {
+  const PPCInstrInfo *TII =
+                static_cast<const PPCInstrInfo*>(Fn.getTarget().getInstrInfo());
+  // Give the blocks of the function a dense, in-order, numbering.
+  Fn.RenumberBlocks();
+  BlockSizes.resize(Fn.getNumBlockIDs());
+
+  // Measure each MBB and compute a size for the entire function.
+  unsigned FuncSize = 0;
+  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
+       ++MFI) {
+    MachineBasicBlock *MBB = MFI;
+
+    unsigned BlockSize = 0;
+    for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
+         MBBI != EE; ++MBBI)
+      BlockSize += TII->GetInstSizeInBytes(MBBI);
+    
+    BlockSizes[MBB->getNumber()] = BlockSize;
+    FuncSize += BlockSize;
+  }
+  
+  // If the entire function is smaller than the displacement of a branch field,
+  // we know we don't need to shrink any branches in this function.  This is a
+  // common case.
+  if (FuncSize < (1 << 15)) {
+    BlockSizes.clear();
+    return false;
+  }
+  
+  // For each conditional branch, if the offset to its destination is larger
+  // than the offset field allows, transform it into a long branch sequence
+  // like this:
+  //   short branch:
+  //     bCC MBB
+  //   long branch:
+  //     b!CC $PC+8
+  //     b MBB
+  //
+  bool MadeChange = true;
+  bool EverMadeChange = false;
+  while (MadeChange) {
+    // Iteratively expand branches until we reach a fixed point.
+    MadeChange = false;
+  
+    for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
+         ++MFI) {
+      MachineBasicBlock &MBB = *MFI;
+      unsigned MBBStartOffset = 0;
+      for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
+           I != E; ++I) {
+        MachineBasicBlock *Dest = nullptr;
+        if (I->getOpcode() == PPC::BCC && !I->getOperand(2).isImm())
+          Dest = I->getOperand(2).getMBB();
+        else if ((I->getOpcode() == PPC::BC || I->getOpcode() == PPC::BCn) &&
+                 !I->getOperand(1).isImm())
+          Dest = I->getOperand(1).getMBB();
+        else if ((I->getOpcode() == PPC::BDNZ8 || I->getOpcode() == PPC::BDNZ ||
+                  I->getOpcode() == PPC::BDZ8  || I->getOpcode() == PPC::BDZ) &&
+                 !I->getOperand(0).isImm())
+          Dest = I->getOperand(0).getMBB();
+
+        if (!Dest) {
+          MBBStartOffset += TII->GetInstSizeInBytes(I);
+          continue;
+        }
+        
+        // Determine the offset from the current branch to the destination
+        // block.
+        int BranchSize;
+        if (Dest->getNumber() <= MBB.getNumber()) {
+          // If this is a backwards branch, the delta is the offset from the
+          // start of this block to this branch, plus the sizes of all blocks
+          // from this block to the dest.
+          BranchSize = MBBStartOffset;
+          
+          for (unsigned i = Dest->getNumber(), e = MBB.getNumber(); i != e; ++i)
+            BranchSize += BlockSizes[i];
+        } else {
+          // Otherwise, add the size of the blocks between this block and the
+          // dest to the number of bytes left in this block.
+          BranchSize = -MBBStartOffset;
+
+          for (unsigned i = MBB.getNumber(), e = Dest->getNumber(); i != e; ++i)
+            BranchSize += BlockSizes[i];
+        }
+
+        // If this branch is in range, ignore it.
+        if (isInt<16>(BranchSize)) {
+          MBBStartOffset += 4;
+          continue;
+        }
+
+        // Otherwise, we have to expand it to a long branch.
+        MachineInstr *OldBranch = I;
+        DebugLoc dl = OldBranch->getDebugLoc();
+        if (I->getOpcode() == PPC::BCC) {
+          // The BCC operands are:
+          // 0. PPC branch predicate
+          // 1. CR register
+          // 2. Target MBB
+          PPC::Predicate Pred = (PPC::Predicate)I->getOperand(0).getImm();
+          unsigned CRReg = I->getOperand(1).getReg();
+       
+          // Jump over the uncond branch inst (i.e. $PC+8) on opposite condition.
+          BuildMI(MBB, I, dl, TII->get(PPC::BCC))
+            .addImm(PPC::InvertPredicate(Pred)).addReg(CRReg).addImm(2);
+        } else if (I->getOpcode() == PPC::BC) {
+          unsigned CRBit = I->getOperand(0).getReg();
+          BuildMI(MBB, I, dl, TII->get(PPC::BCn)).addReg(CRBit).addImm(2);
+        } else if (I->getOpcode() == PPC::BCn) {
+          unsigned CRBit = I->getOperand(0).getReg();
+          BuildMI(MBB, I, dl, TII->get(PPC::BC)).addReg(CRBit).addImm(2);
+        } else if (I->getOpcode() == PPC::BDNZ) {
+          BuildMI(MBB, I, dl, TII->get(PPC::BDZ)).addImm(2);
+        } else if (I->getOpcode() == PPC::BDNZ8) {
+          BuildMI(MBB, I, dl, TII->get(PPC::BDZ8)).addImm(2);
+        } else if (I->getOpcode() == PPC::BDZ) {
+          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ)).addImm(2);
+        } else if (I->getOpcode() == PPC::BDZ8) {
+          BuildMI(MBB, I, dl, TII->get(PPC::BDNZ8)).addImm(2);
+        } else {
+           llvm_unreachable("Unhandled branch type!");
+        }
+        
+        // Uncond branch to the real destination.
+        I = BuildMI(MBB, I, dl, TII->get(PPC::B)).addMBB(Dest);
+
+        // Remove the old branch from the function.
+        OldBranch->eraseFromParent();
+        
+        // Remember that this instruction is 8-bytes, increase the size of the
+        // block by 4, remember to iterate.
+        BlockSizes[MBB.getNumber()] += 4;
+        MBBStartOffset += 8;
+        ++NumExpanded;
+        MadeChange = true;
+      }
+    }
+    EverMadeChange |= MadeChange;
+  }
+  
+  BlockSizes.clear();
+  return true;
+}
+