//===-- PPCBranchSelector.cpp - Emit long conditional branches-----*- C++ -*-=//
//
//                     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 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
// pass should be run last, just before the assembly printer.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "bsel"
#include "PPC.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/Debug.h"
#include <map>
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
    }

    virtual bool runOnMachineFunction(MachineFunction &Fn) {
      // Running total of instructions encountered since beginning of function
      unsigned ByteCount = 0;

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

        for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end();
             MBBI != EE; ++MBBI)
          ByteCount += bytesForOpcode(MBBI->getOpcode());
      }

      // 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 = PPCInstrInfo::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);
        }
      }

      OffsetMap.clear();
      return true;
    }

    virtual const char *getPassName() const {
      return "PowerPC Branch Selection";
    }
  };
}

/// createPPCBranchSelectionPass - returns an instance of the Branch Selection
/// Pass
///
FunctionPass *llvm::createPPCBranchSelectionPass() {
  return new BSel();
}