summaryrefslogtreecommitdiff
path: root/lib/Target/PowerPC/PPCBranchSelector.cpp
blob: 543c390037140715f7ba8429d83719e9798111b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//===-- 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.
//
//===----------------------------------------------------------------------===//

#include "PPC.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include <map>
using namespace llvm;

namespace {
  struct PPCBSel : public MachineFunctionPass {
    // OffsetMap - Mapping between BB and byte offset from start of function
    std::map<MachineBasicBlock*, unsigned> OffsetMap;

    virtual bool runOnMachineFunction(MachineFunction &Fn);

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

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

/// getNumBytesForInstruction - Return the number of bytes of code the specified
/// instruction may be.  This returns the maximum number of bytes.
///
static unsigned getNumBytesForInstruction(MachineInstr *MI) {
  switch (MI->getOpcode()) {
  case PPC::COND_BRANCH:
    // while this will be 4 most of the time, if we emit 8 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 8;
  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;
  case PPC::INLINEASM:    // Inline Asm: Variable size.
    for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
      if (MI->getOperand(i).isExternalSymbol()) {
        const char *AsmStr = MI->getOperand(i).getSymbolName();
        // Count the number of newline's in the asm string.
        unsigned NumInstrs = 0;
        for (; *AsmStr; ++AsmStr)
          NumInstrs += *AsmStr == '\n';
        return NumInstrs*4;
      }
    assert(0 && "INLINEASM didn't have format string??");
  default:
    return 4; // PowerPC instructions are all 4 bytes
  }
}


bool PPCBSel::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 += getNumBytesForInstruction(MBBI);
  }
  
  // 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
  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 ByteSize = getNumBytesForInstruction(MBBI);
      if (MBBI->getOpcode() == 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();
        
        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);
        }
        
        // 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 += ByteSize;
    }
  }
  
  OffsetMap.clear();
  return true;
}