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