| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 1 | //===-- ARMConstantIslandPass.cpp - ARM constant islands --------*- C++ -*-===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file was developed by Chris Lattner and is distributed under the | 
|  | 6 | // University of Illinois Open Source License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | // This file contains a pass that splits the constant pool up into 'islands' | 
|  | 11 | // which are scattered through-out the function.  This is required due to the | 
|  | 12 | // limited pc-relative displacements that ARM has. | 
|  | 13 | // | 
|  | 14 | //===----------------------------------------------------------------------===// | 
|  | 15 |  | 
|  | 16 | #define DEBUG_TYPE "arm-cp-islands" | 
|  | 17 | #include "ARM.h" | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 18 | #include "ARMMachineFunctionInfo.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 19 | #include "ARMInstrInfo.h" | 
|  | 20 | #include "llvm/CodeGen/MachineConstantPool.h" | 
|  | 21 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | 22 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 23 | #include "llvm/Target/TargetData.h" | 
|  | 24 | #include "llvm/Target/TargetMachine.h" | 
|  | 25 | #include "llvm/Support/Compiler.h" | 
|  | 26 | #include "llvm/Support/Debug.h" | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 27 | #include "llvm/ADT/SmallVector.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 28 | #include "llvm/ADT/STLExtras.h" | 
|  | 29 | #include "llvm/ADT/Statistic.h" | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 30 | using namespace llvm; | 
|  | 31 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 32 | STATISTIC(NumCPEs,     "Number of constpool entries"); | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 33 | STATISTIC(NumSplit,    "Number of uncond branches inserted"); | 
|  | 34 | STATISTIC(NumCBrFixed, "Number of cond branches fixed"); | 
|  | 35 | STATISTIC(NumUBrFixed, "Number of uncond branches fixed"); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 36 |  | 
|  | 37 | namespace { | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 38 | /// ARMConstantIslands - Due to limited PC-relative displacements, ARM | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 39 | /// requires constant pool entries to be scattered among the instructions | 
|  | 40 | /// inside a function.  To do this, it completely ignores the normal LLVM | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 41 | /// constant pool; instead, it places constants wherever it feels like with | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 42 | /// special instructions. | 
|  | 43 | /// | 
|  | 44 | /// The terminology used in this pass includes: | 
|  | 45 | ///   Islands - Clumps of constants placed in the function. | 
|  | 46 | ///   Water   - Potential places where an island could be formed. | 
|  | 47 | ///   CPE     - A constant pool entry that has been placed somewhere, which | 
|  | 48 | ///             tracks a list of users. | 
|  | 49 | class VISIBILITY_HIDDEN ARMConstantIslands : public MachineFunctionPass { | 
|  | 50 | /// NextUID - Assign unique ID's to CPE's. | 
|  | 51 | unsigned NextUID; | 
|  | 52 |  | 
|  | 53 | /// BBSizes - The size of each MachineBasicBlock in bytes of code, indexed | 
|  | 54 | /// by MBB Number. | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 55 | std::vector<unsigned> BBSizes; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 56 |  | 
|  | 57 | /// WaterList - A sorted list of basic blocks where islands could be placed | 
|  | 58 | /// (i.e. blocks that don't fall through to the following block, due | 
|  | 59 | /// to a return, unreachable, or unconditional branch). | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 60 | std::vector<MachineBasicBlock*> WaterList; | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 61 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 62 | // WaterListOffsets - the offset of the beginning of each WaterList block. | 
|  | 63 | // This is computed as needed in HandleConstantPoolUser; not necessarily | 
|  | 64 | // valid at arbitrary times. | 
|  | 65 | std::vector<unsigned> WaterListOffsets; | 
|  | 66 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 67 | /// CPUser - One user of a constant pool, keeping the machine instruction | 
|  | 68 | /// pointer, the constant pool being referenced, and the max displacement | 
|  | 69 | /// allowed from the instruction to the CP. | 
|  | 70 | struct CPUser { | 
|  | 71 | MachineInstr *MI; | 
|  | 72 | MachineInstr *CPEMI; | 
|  | 73 | unsigned MaxDisp; | 
|  | 74 | CPUser(MachineInstr *mi, MachineInstr *cpemi, unsigned maxdisp) | 
|  | 75 | : MI(mi), CPEMI(cpemi), MaxDisp(maxdisp) {} | 
|  | 76 | }; | 
|  | 77 |  | 
|  | 78 | /// CPUsers - Keep track of all of the machine instructions that use various | 
|  | 79 | /// constant pools and their max displacement. | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 80 | std::vector<CPUser> CPUsers; | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 81 |  | 
|  | 82 | /// CPEntry - One per constant pool entry, keeping the machine instruction | 
|  | 83 | /// pointer, the constpool index, and the number of CPUser's which | 
|  | 84 | /// reference this entry. | 
|  | 85 | struct CPEntry { | 
|  | 86 | MachineInstr *CPEMI; | 
|  | 87 | unsigned CPI; | 
|  | 88 | unsigned RefCount; | 
|  | 89 | CPEntry(MachineInstr *cpemi, unsigned cpi, unsigned rc = 0) | 
|  | 90 | : CPEMI(cpemi), CPI(cpi), RefCount(rc) {} | 
|  | 91 | }; | 
|  | 92 |  | 
|  | 93 | /// CPEntries - Keep track of all of the constant pool entry machine | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 94 | /// instructions. For each original constpool index (i.e. those that | 
|  | 95 | /// existed upon entry to this pass), it keeps a vector of entries. | 
|  | 96 | /// Original elements are cloned as we go along; the clones are | 
|  | 97 | /// put in the vector of the original element, but have distinct CPIs. | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 98 | std::vector<std::vector<CPEntry> > CPEntries; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 99 |  | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 100 | /// ImmBranch - One per immediate branch, keeping the machine instruction | 
|  | 101 | /// pointer, conditional or unconditional, the max displacement, | 
|  | 102 | /// and (if isCond is true) the corresponding unconditional branch | 
|  | 103 | /// opcode. | 
|  | 104 | struct ImmBranch { | 
|  | 105 | MachineInstr *MI; | 
| Evan Cheng | c285414 | 2007-01-25 23:18:59 +0000 | [diff] [blame] | 106 | unsigned MaxDisp : 31; | 
|  | 107 | bool isCond : 1; | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 108 | int UncondBr; | 
| Evan Cheng | c285414 | 2007-01-25 23:18:59 +0000 | [diff] [blame] | 109 | ImmBranch(MachineInstr *mi, unsigned maxdisp, bool cond, int ubr) | 
|  | 110 | : MI(mi), MaxDisp(maxdisp), isCond(cond), UncondBr(ubr) {} | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 111 | }; | 
|  | 112 |  | 
| Evan Cheng | c285414 | 2007-01-25 23:18:59 +0000 | [diff] [blame] | 113 | /// Branches - Keep track of all the immediate branch instructions. | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 114 | /// | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 115 | std::vector<ImmBranch> ImmBranches; | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 116 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 117 | /// PushPopMIs - Keep track of all the Thumb push / pop instructions. | 
|  | 118 | /// | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 119 | SmallVector<MachineInstr*, 4> PushPopMIs; | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 120 |  | 
|  | 121 | /// HasFarJump - True if any far jump instruction has been emitted during | 
|  | 122 | /// the branch fix up pass. | 
|  | 123 | bool HasFarJump; | 
|  | 124 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 125 | const TargetInstrInfo *TII; | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 126 | const ARMFunctionInfo *AFI; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 127 | public: | 
|  | 128 | virtual bool runOnMachineFunction(MachineFunction &Fn); | 
|  | 129 |  | 
|  | 130 | virtual const char *getPassName() const { | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 131 | return "ARM constant island placement and branch shortening pass"; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 132 | } | 
|  | 133 |  | 
|  | 134 | private: | 
|  | 135 | void DoInitialPlacement(MachineFunction &Fn, | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 136 | std::vector<MachineInstr*> &CPEMIs); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 137 | CPEntry *findConstPoolEntry(unsigned CPI, const MachineInstr *CPEMI); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 138 | void InitialFunctionScan(MachineFunction &Fn, | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 139 | const std::vector<MachineInstr*> &CPEMIs); | 
| Evan Cheng | 0c61584 | 2007-01-31 02:22:22 +0000 | [diff] [blame] | 140 | MachineBasicBlock *SplitBlockBeforeInstr(MachineInstr *MI); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 141 | void UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB); | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 142 | bool DecrementOldEntry(unsigned CPI, MachineInstr* CPEMI, unsigned Size); | 
|  | 143 | void ComputeWaterListOffsets(MachineFunction &Fn); | 
|  | 144 | int LookForExistingCPEntry(CPUser& U, unsigned UserOffset); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 145 | bool HandleConstantPoolUser(MachineFunction &Fn, CPUser &U); | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 146 | bool CPEIsInRange(MachineInstr *MI, unsigned UserOffset, | 
|  | 147 | MachineInstr *CPEMI, unsigned Disp, | 
|  | 148 | bool DoDump); | 
|  | 149 | bool WaterIsInRange(unsigned UserOffset, | 
|  | 150 | std::vector<MachineBasicBlock*>::iterator IP, | 
|  | 151 | unsigned Disp); | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 152 | bool BBIsInRange(MachineInstr *MI, MachineBasicBlock *BB, unsigned Disp); | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 153 | bool FixUpImmediateBr(MachineFunction &Fn, ImmBranch &Br); | 
|  | 154 | bool FixUpConditionalBr(MachineFunction &Fn, ImmBranch &Br); | 
|  | 155 | bool FixUpUnconditionalBr(MachineFunction &Fn, ImmBranch &Br); | 
|  | 156 | bool UndoLRSpillRestore(); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 157 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 158 | unsigned GetOffsetOf(MachineInstr *MI) const; | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 159 | unsigned GetOffsetOf(MachineBasicBlock *MBB) const; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 160 | }; | 
|  | 161 | } | 
|  | 162 |  | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 163 | /// createARMConstantIslandPass - returns an instance of the constpool | 
|  | 164 | /// island pass. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 165 | FunctionPass *llvm::createARMConstantIslandPass() { | 
|  | 166 | return new ARMConstantIslands(); | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | bool ARMConstantIslands::runOnMachineFunction(MachineFunction &Fn) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 170 | MachineConstantPool &MCP = *Fn.getConstantPool(); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 171 |  | 
|  | 172 | TII = Fn.getTarget().getInstrInfo(); | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 173 | AFI = Fn.getInfo<ARMFunctionInfo>(); | 
|  | 174 |  | 
|  | 175 | HasFarJump = false; | 
|  | 176 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 177 | // Renumber all of the machine basic blocks in the function, guaranteeing that | 
|  | 178 | // the numbers agree with the position of the block in the function. | 
|  | 179 | Fn.RenumberBlocks(); | 
|  | 180 |  | 
|  | 181 | // Perform the initial placement of the constant pool entries.  To start with, | 
|  | 182 | // we put them all at the end of the function. | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 183 | std::vector<MachineInstr*> CPEMIs; | 
| Evan Cheng | 7755fac | 2007-01-26 01:04:44 +0000 | [diff] [blame] | 184 | if (!MCP.isEmpty()) | 
|  | 185 | DoInitialPlacement(Fn, CPEMIs); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 186 |  | 
|  | 187 | /// The next UID to take is the first unused one. | 
|  | 188 | NextUID = CPEMIs.size(); | 
|  | 189 |  | 
|  | 190 | // Do the initial scan of the function, building up information about the | 
|  | 191 | // sizes of each block, the location of all the water, and finding all of the | 
|  | 192 | // constant pool users. | 
|  | 193 | InitialFunctionScan(Fn, CPEMIs); | 
|  | 194 | CPEMIs.clear(); | 
|  | 195 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 196 | // Iteratively place constant pool entries and fix up branches until there | 
|  | 197 | // is no change. | 
|  | 198 | bool MadeChange = false; | 
|  | 199 | while (true) { | 
|  | 200 | bool Change = false; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 201 | for (unsigned i = 0, e = CPUsers.size(); i != e; ++i) | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 202 | Change |= HandleConstantPoolUser(Fn, CPUsers[i]); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 203 | for (unsigned i = 0, e = ImmBranches.size(); i != e; ++i) | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 204 | Change |= FixUpImmediateBr(Fn, ImmBranches[i]); | 
|  | 205 | if (!Change) | 
|  | 206 | break; | 
|  | 207 | MadeChange = true; | 
|  | 208 | } | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 209 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 210 | // If LR has been forced spilled and no far jumps (i.e. BL) has been issued. | 
|  | 211 | // Undo the spill / restore of LR if possible. | 
|  | 212 | if (!HasFarJump && AFI->isLRForceSpilled() && AFI->isThumbFunction()) | 
|  | 213 | MadeChange |= UndoLRSpillRestore(); | 
|  | 214 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 215 | BBSizes.clear(); | 
|  | 216 | WaterList.clear(); | 
|  | 217 | CPUsers.clear(); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 218 | CPEntries.clear(); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 219 | ImmBranches.clear(); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 220 | PushPopMIs.clear(); | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 221 |  | 
|  | 222 | return MadeChange; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 223 | } | 
|  | 224 |  | 
|  | 225 | /// DoInitialPlacement - Perform the initial placement of the constant pool | 
|  | 226 | /// entries.  To start with, we put them all at the end of the function. | 
|  | 227 | void ARMConstantIslands::DoInitialPlacement(MachineFunction &Fn, | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 228 | std::vector<MachineInstr*> &CPEMIs){ | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 229 | // Create the basic block to hold the CPE's. | 
|  | 230 | MachineBasicBlock *BB = new MachineBasicBlock(); | 
|  | 231 | Fn.getBasicBlockList().push_back(BB); | 
|  | 232 |  | 
|  | 233 | // Add all of the constants from the constant pool to the end block, use an | 
|  | 234 | // identity mapping of CPI's to CPE's. | 
|  | 235 | const std::vector<MachineConstantPoolEntry> &CPs = | 
|  | 236 | Fn.getConstantPool()->getConstants(); | 
|  | 237 |  | 
|  | 238 | const TargetData &TD = *Fn.getTarget().getTargetData(); | 
|  | 239 | for (unsigned i = 0, e = CPs.size(); i != e; ++i) { | 
|  | 240 | unsigned Size = TD.getTypeSize(CPs[i].getType()); | 
|  | 241 | // Verify that all constant pool entries are a multiple of 4 bytes.  If not, | 
|  | 242 | // we would have to pad them out or something so that instructions stay | 
|  | 243 | // aligned. | 
|  | 244 | assert((Size & 3) == 0 && "CP Entry not multiple of 4 bytes!"); | 
|  | 245 | MachineInstr *CPEMI = | 
|  | 246 | BuildMI(BB, TII->get(ARM::CONSTPOOL_ENTRY)) | 
|  | 247 | .addImm(i).addConstantPoolIndex(i).addImm(Size); | 
|  | 248 | CPEMIs.push_back(CPEMI); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 249 |  | 
|  | 250 | // Add a new CPEntry, but no corresponding CPUser yet. | 
|  | 251 | std::vector<CPEntry> CPEs; | 
|  | 252 | CPEs.push_back(CPEntry(CPEMI, i)); | 
|  | 253 | CPEntries.push_back(CPEs); | 
|  | 254 | NumCPEs++; | 
|  | 255 | DOUT << "Moved CPI#" << i << " to end of function as #" << i << "\n"; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 256 | } | 
|  | 257 | } | 
|  | 258 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 259 | /// BBHasFallthrough - Return true if the specified basic block can fallthrough | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 260 | /// into the block immediately after it. | 
|  | 261 | static bool BBHasFallthrough(MachineBasicBlock *MBB) { | 
|  | 262 | // Get the next machine basic block in the function. | 
|  | 263 | MachineFunction::iterator MBBI = MBB; | 
|  | 264 | if (next(MBBI) == MBB->getParent()->end())  // Can't fall off end of function. | 
|  | 265 | return false; | 
|  | 266 |  | 
|  | 267 | MachineBasicBlock *NextBB = next(MBBI); | 
|  | 268 | for (MachineBasicBlock::succ_iterator I = MBB->succ_begin(), | 
|  | 269 | E = MBB->succ_end(); I != E; ++I) | 
|  | 270 | if (*I == NextBB) | 
|  | 271 | return true; | 
|  | 272 |  | 
|  | 273 | return false; | 
|  | 274 | } | 
|  | 275 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 276 | /// findConstPoolEntry - Given the constpool index and CONSTPOOL_ENTRY MI, | 
|  | 277 | /// look up the corresponding CPEntry. | 
|  | 278 | ARMConstantIslands::CPEntry | 
|  | 279 | *ARMConstantIslands::findConstPoolEntry(unsigned CPI, | 
|  | 280 | const MachineInstr *CPEMI) { | 
|  | 281 | std::vector<CPEntry> &CPEs = CPEntries[CPI]; | 
|  | 282 | // Number of entries per constpool index should be small, just do a | 
|  | 283 | // linear search. | 
|  | 284 | for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { | 
|  | 285 | if (CPEs[i].CPEMI == CPEMI) | 
|  | 286 | return &CPEs[i]; | 
|  | 287 | } | 
|  | 288 | return NULL; | 
|  | 289 | } | 
|  | 290 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 291 | /// InitialFunctionScan - Do the initial scan of the function, building up | 
|  | 292 | /// information about the sizes of each block, the location of all the water, | 
|  | 293 | /// and finding all of the constant pool users. | 
|  | 294 | void ARMConstantIslands::InitialFunctionScan(MachineFunction &Fn, | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 295 | const std::vector<MachineInstr*> &CPEMIs) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 296 | for (MachineFunction::iterator MBBI = Fn.begin(), E = Fn.end(); | 
|  | 297 | MBBI != E; ++MBBI) { | 
|  | 298 | MachineBasicBlock &MBB = *MBBI; | 
|  | 299 |  | 
|  | 300 | // If this block doesn't fall through into the next MBB, then this is | 
|  | 301 | // 'water' that a constant pool island could be placed. | 
|  | 302 | if (!BBHasFallthrough(&MBB)) | 
|  | 303 | WaterList.push_back(&MBB); | 
|  | 304 |  | 
|  | 305 | unsigned MBBSize = 0; | 
|  | 306 | for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); | 
|  | 307 | I != E; ++I) { | 
|  | 308 | // Add instruction size to MBBSize. | 
| Evan Cheng | 29836c3 | 2007-01-29 23:45:17 +0000 | [diff] [blame] | 309 | MBBSize += ARM::GetInstSize(I); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 310 |  | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 311 | int Opc = I->getOpcode(); | 
|  | 312 | if (TII->isBranch(Opc)) { | 
|  | 313 | bool isCond = false; | 
|  | 314 | unsigned Bits = 0; | 
|  | 315 | unsigned Scale = 1; | 
|  | 316 | int UOpc = Opc; | 
|  | 317 | switch (Opc) { | 
| Evan Cheng | 743fa03 | 2007-01-25 19:43:52 +0000 | [diff] [blame] | 318 | default: | 
|  | 319 | continue;  // Ignore JT branches | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 320 | case ARM::Bcc: | 
|  | 321 | isCond = true; | 
|  | 322 | UOpc = ARM::B; | 
|  | 323 | // Fallthrough | 
|  | 324 | case ARM::B: | 
|  | 325 | Bits = 24; | 
|  | 326 | Scale = 4; | 
|  | 327 | break; | 
|  | 328 | case ARM::tBcc: | 
|  | 329 | isCond = true; | 
|  | 330 | UOpc = ARM::tB; | 
|  | 331 | Bits = 8; | 
|  | 332 | Scale = 2; | 
|  | 333 | break; | 
|  | 334 | case ARM::tB: | 
|  | 335 | Bits = 11; | 
|  | 336 | Scale = 2; | 
|  | 337 | break; | 
|  | 338 | } | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 339 |  | 
|  | 340 | // Record this immediate branch. | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 341 | unsigned MaxOffs = ((1 << (Bits-1))-1) * Scale; | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 342 | ImmBranches.push_back(ImmBranch(I, MaxOffs, isCond, UOpc)); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 343 | } | 
|  | 344 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 345 | if (Opc == ARM::tPUSH || Opc == ARM::tPOP_RET) | 
|  | 346 | PushPopMIs.push_back(I); | 
|  | 347 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 348 | // Scan the instructions for constant pool operands. | 
|  | 349 | for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op) | 
|  | 350 | if (I->getOperand(op).isConstantPoolIndex()) { | 
|  | 351 | // We found one.  The addressing mode tells us the max displacement | 
|  | 352 | // from the PC that this instruction permits. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 353 |  | 
|  | 354 | // Basic size info comes from the TSFlags field. | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 355 | unsigned Bits = 0; | 
|  | 356 | unsigned Scale = 1; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 357 | unsigned TSFlags = I->getInstrDescriptor()->TSFlags; | 
|  | 358 | switch (TSFlags & ARMII::AddrModeMask) { | 
|  | 359 | default: | 
|  | 360 | // Constant pool entries can reach anything. | 
|  | 361 | if (I->getOpcode() == ARM::CONSTPOOL_ENTRY) | 
|  | 362 | continue; | 
|  | 363 | assert(0 && "Unknown addressing mode for CP reference!"); | 
|  | 364 | case ARMII::AddrMode1: // AM1: 8 bits << 2 | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 365 | Bits = 8; | 
|  | 366 | Scale = 4;  // Taking the address of a CP entry. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 367 | break; | 
|  | 368 | case ARMII::AddrMode2: | 
| Evan Cheng | 556f33c | 2007-02-01 20:44:52 +0000 | [diff] [blame] | 369 | Bits = 12;  // +-offset_12 | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 370 | break; | 
|  | 371 | case ARMII::AddrMode3: | 
| Evan Cheng | 556f33c | 2007-02-01 20:44:52 +0000 | [diff] [blame] | 372 | Bits = 8;   // +-offset_8 | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 373 | break; | 
|  | 374 | // addrmode4 has no immediate offset. | 
|  | 375 | case ARMII::AddrMode5: | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 376 | Bits = 8; | 
|  | 377 | Scale = 4;  // +-(offset_8*4) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 378 | break; | 
|  | 379 | case ARMII::AddrModeT1: | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 380 | Bits = 5;  // +offset_5 | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 381 | break; | 
|  | 382 | case ARMII::AddrModeT2: | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 383 | Bits = 5; | 
|  | 384 | Scale = 2;  // +(offset_5*2) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 385 | break; | 
|  | 386 | case ARMII::AddrModeT4: | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 387 | Bits = 5; | 
|  | 388 | Scale = 4;  // +(offset_5*4) | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 389 | break; | 
| Evan Cheng | 012f2d9 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 390 | case ARMII::AddrModeTs: | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 391 | Bits = 8; | 
|  | 392 | Scale = 4;  // +(offset_8*4) | 
| Evan Cheng | 012f2d9 | 2007-01-24 08:53:17 +0000 | [diff] [blame] | 393 | break; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 394 | } | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 395 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 396 | // Remember that this is a user of a CP entry. | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 397 | unsigned CPI = I->getOperand(op).getConstantPoolIndex(); | 
|  | 398 | MachineInstr *CPEMI = CPEMIs[CPI]; | 
| Evan Cheng | 556f33c | 2007-02-01 20:44:52 +0000 | [diff] [blame] | 399 | unsigned MaxOffs = ((1 << Bits)-1) * Scale; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 400 | CPUsers.push_back(CPUser(I, CPEMI, MaxOffs)); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 401 |  | 
|  | 402 | // Increment corresponding CPEntry reference count. | 
|  | 403 | CPEntry *CPE = findConstPoolEntry(CPI, CPEMI); | 
|  | 404 | assert(CPE && "Cannot find a corresponding CPEntry!"); | 
|  | 405 | CPE->RefCount++; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 406 |  | 
|  | 407 | // Instructions can only use one CP entry, don't bother scanning the | 
|  | 408 | // rest of the operands. | 
|  | 409 | break; | 
|  | 410 | } | 
|  | 411 | } | 
| Evan Cheng | 2021abe | 2007-02-01 01:09:47 +0000 | [diff] [blame] | 412 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 413 | // In thumb mode, if this block is a constpool island, pessimistically | 
|  | 414 | // assume it needs to be padded by two byte so it's aligned on 4 byte | 
|  | 415 | // boundary. | 
| Evan Cheng | 2021abe | 2007-02-01 01:09:47 +0000 | [diff] [blame] | 416 | if (AFI->isThumbFunction() && | 
| Evan Cheng | 05cc424 | 2007-02-02 19:09:19 +0000 | [diff] [blame] | 417 | !MBB.empty() && | 
| Evan Cheng | 2021abe | 2007-02-01 01:09:47 +0000 | [diff] [blame] | 418 | MBB.begin()->getOpcode() == ARM::CONSTPOOL_ENTRY) | 
|  | 419 | MBBSize += 2; | 
|  | 420 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 421 | BBSizes.push_back(MBBSize); | 
|  | 422 | } | 
|  | 423 | } | 
|  | 424 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 425 | /// GetOffsetOf - Return the current offset of the specified machine instruction | 
|  | 426 | /// from the start of the function.  This offset changes as stuff is moved | 
|  | 427 | /// around inside the function. | 
|  | 428 | unsigned ARMConstantIslands::GetOffsetOf(MachineInstr *MI) const { | 
|  | 429 | MachineBasicBlock *MBB = MI->getParent(); | 
|  | 430 |  | 
|  | 431 | // The offset is composed of two things: the sum of the sizes of all MBB's | 
|  | 432 | // before this instruction's block, and the offset from the start of the block | 
|  | 433 | // it is in. | 
|  | 434 | unsigned Offset = 0; | 
|  | 435 |  | 
|  | 436 | // Sum block sizes before MBB. | 
|  | 437 | for (unsigned BB = 0, e = MBB->getNumber(); BB != e; ++BB) | 
|  | 438 | Offset += BBSizes[BB]; | 
|  | 439 |  | 
|  | 440 | // Sum instructions before MI in MBB. | 
|  | 441 | for (MachineBasicBlock::iterator I = MBB->begin(); ; ++I) { | 
|  | 442 | assert(I != MBB->end() && "Didn't find MI in its own basic block?"); | 
|  | 443 | if (&*I == MI) return Offset; | 
| Evan Cheng | 29836c3 | 2007-01-29 23:45:17 +0000 | [diff] [blame] | 444 | Offset += ARM::GetInstSize(I); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 445 | } | 
|  | 446 | } | 
|  | 447 |  | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 448 | /// GetOffsetOf - Return the current offset of the specified machine BB | 
|  | 449 | /// from the start of the function.  This offset changes as stuff is moved | 
|  | 450 | /// around inside the function. | 
|  | 451 | unsigned ARMConstantIslands::GetOffsetOf(MachineBasicBlock *MBB) const { | 
|  | 452 | // Sum block sizes before MBB. | 
|  | 453 | unsigned Offset = 0; | 
|  | 454 | for (unsigned BB = 0, e = MBB->getNumber(); BB != e; ++BB) | 
|  | 455 | Offset += BBSizes[BB]; | 
|  | 456 |  | 
|  | 457 | return Offset; | 
|  | 458 | } | 
|  | 459 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 460 | /// CompareMBBNumbers - Little predicate function to sort the WaterList by MBB | 
|  | 461 | /// ID. | 
|  | 462 | static bool CompareMBBNumbers(const MachineBasicBlock *LHS, | 
|  | 463 | const MachineBasicBlock *RHS) { | 
|  | 464 | return LHS->getNumber() < RHS->getNumber(); | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | /// UpdateForInsertedWaterBlock - When a block is newly inserted into the | 
|  | 468 | /// machine function, it upsets all of the block numbers.  Renumber the blocks | 
|  | 469 | /// and update the arrays that parallel this numbering. | 
|  | 470 | void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) { | 
|  | 471 | // Renumber the MBB's to keep them consequtive. | 
|  | 472 | NewBB->getParent()->RenumberBlocks(NewBB); | 
|  | 473 |  | 
|  | 474 | // Insert a size into BBSizes to align it properly with the (newly | 
|  | 475 | // renumbered) block numbers. | 
|  | 476 | BBSizes.insert(BBSizes.begin()+NewBB->getNumber(), 0); | 
|  | 477 |  | 
|  | 478 | // Next, update WaterList.  Specifically, we need to add NewMBB as having | 
|  | 479 | // available water after it. | 
| Evan Cheng | e03cff6 | 2007-02-09 23:59:14 +0000 | [diff] [blame] | 480 | std::vector<MachineBasicBlock*>::iterator IP = | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 481 | std::lower_bound(WaterList.begin(), WaterList.end(), NewBB, | 
|  | 482 | CompareMBBNumbers); | 
|  | 483 | WaterList.insert(IP, NewBB); | 
|  | 484 | } | 
|  | 485 |  | 
|  | 486 |  | 
|  | 487 | /// Split the basic block containing MI into two blocks, which are joined by | 
|  | 488 | /// an unconditional branch.  Update datastructures and renumber blocks to | 
| Evan Cheng | 0c61584 | 2007-01-31 02:22:22 +0000 | [diff] [blame] | 489 | /// account for this change and returns the newly created block. | 
|  | 490 | MachineBasicBlock *ARMConstantIslands::SplitBlockBeforeInstr(MachineInstr *MI) { | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 491 | MachineBasicBlock *OrigBB = MI->getParent(); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 492 | bool isThumb = AFI->isThumbFunction(); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 493 |  | 
|  | 494 | // Create a new MBB for the code after the OrigBB. | 
|  | 495 | MachineBasicBlock *NewBB = new MachineBasicBlock(OrigBB->getBasicBlock()); | 
|  | 496 | MachineFunction::iterator MBBI = OrigBB; ++MBBI; | 
|  | 497 | OrigBB->getParent()->getBasicBlockList().insert(MBBI, NewBB); | 
|  | 498 |  | 
|  | 499 | // Splice the instructions starting with MI over to NewBB. | 
|  | 500 | NewBB->splice(NewBB->end(), OrigBB, MI, OrigBB->end()); | 
|  | 501 |  | 
|  | 502 | // Add an unconditional branch from OrigBB to NewBB. | 
| Evan Cheng | a9b8b8d | 2007-01-31 18:29:27 +0000 | [diff] [blame] | 503 | // Note the new unconditional branch is not being recorded. | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 504 | BuildMI(OrigBB, TII->get(isThumb ? ARM::tB : ARM::B)).addMBB(NewBB); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 505 | NumSplit++; | 
|  | 506 |  | 
|  | 507 | // Update the CFG.  All succs of OrigBB are now succs of NewBB. | 
|  | 508 | while (!OrigBB->succ_empty()) { | 
|  | 509 | MachineBasicBlock *Succ = *OrigBB->succ_begin(); | 
|  | 510 | OrigBB->removeSuccessor(Succ); | 
|  | 511 | NewBB->addSuccessor(Succ); | 
|  | 512 |  | 
|  | 513 | // This pass should be run after register allocation, so there should be no | 
|  | 514 | // PHI nodes to update. | 
|  | 515 | assert((Succ->empty() || Succ->begin()->getOpcode() != TargetInstrInfo::PHI) | 
|  | 516 | && "PHI nodes should be eliminated by now!"); | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | // OrigBB branches to NewBB. | 
|  | 520 | OrigBB->addSuccessor(NewBB); | 
|  | 521 |  | 
|  | 522 | // Update internal data structures to account for the newly inserted MBB. | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 523 | // This is almost the same as UpdateForInsertedWaterBlock, except that | 
|  | 524 | // the Water goes after OrigBB, not NewBB. | 
|  | 525 | NewBB->getParent()->RenumberBlocks(NewBB); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 526 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 527 | // Insert a size into BBSizes to align it properly with the (newly | 
|  | 528 | // renumbered) block numbers. | 
|  | 529 | BBSizes.insert(BBSizes.begin()+NewBB->getNumber(), 0); | 
|  | 530 |  | 
|  | 531 | // Next, update WaterList.  Specifically, we need to add OrigMBB as having | 
|  | 532 | // available water after it (but not if it's already there, which happens | 
|  | 533 | // when splitting before a conditional branch that is followed by an | 
|  | 534 | // unconditional branch - in that case we want to insert NewBB). | 
|  | 535 | std::vector<MachineBasicBlock*>::iterator IP = | 
|  | 536 | std::lower_bound(WaterList.begin(), WaterList.end(), OrigBB, | 
|  | 537 | CompareMBBNumbers); | 
|  | 538 | MachineBasicBlock* WaterBB = *IP; | 
|  | 539 | if (WaterBB == OrigBB) | 
|  | 540 | WaterList.insert(next(IP), NewBB); | 
|  | 541 | else | 
|  | 542 | WaterList.insert(IP, OrigBB); | 
|  | 543 |  | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 544 | // Figure out how large the first NewMBB is. | 
|  | 545 | unsigned NewBBSize = 0; | 
|  | 546 | for (MachineBasicBlock::iterator I = NewBB->begin(), E = NewBB->end(); | 
|  | 547 | I != E; ++I) | 
| Evan Cheng | 29836c3 | 2007-01-29 23:45:17 +0000 | [diff] [blame] | 548 | NewBBSize += ARM::GetInstSize(I); | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 549 |  | 
|  | 550 | // Set the size of NewBB in BBSizes. | 
|  | 551 | BBSizes[NewBB->getNumber()] = NewBBSize; | 
|  | 552 |  | 
|  | 553 | // We removed instructions from UserMBB, subtract that off from its size. | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 554 | // Add 2 or 4 to the block to count the unconditional branch we added to it. | 
|  | 555 | BBSizes[OrigBB->getNumber()] -= NewBBSize - (isThumb ? 2 : 4); | 
| Evan Cheng | 0c61584 | 2007-01-31 02:22:22 +0000 | [diff] [blame] | 556 |  | 
|  | 557 | return NewBB; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 558 | } | 
|  | 559 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 560 | /// WaterIsInRange - Returns true if a CPE placed after the specified | 
|  | 561 | /// Water (a basic block) will be in range for the specific MI. | 
|  | 562 |  | 
|  | 563 | bool ARMConstantIslands::WaterIsInRange(unsigned UserOffset, | 
|  | 564 | std::vector<MachineBasicBlock*>::iterator IP, | 
|  | 565 | unsigned MaxDisp) | 
|  | 566 | { | 
|  | 567 | MachineBasicBlock *Water = *IP; | 
|  | 568 | unsigned Index = IP - WaterList.begin(); | 
|  | 569 | unsigned CPEOffset = WaterListOffsets[Index]  + | 
|  | 570 | BBSizes[Water->getNumber()]; | 
|  | 571 | // If the Water is a constpool island, it has already been aligned. | 
|  | 572 | // If not, align it. | 
|  | 573 | if (AFI->isThumbFunction() && | 
|  | 574 | (Water->empty() || | 
|  | 575 | Water->begin()->getOpcode() != ARM::CONSTPOOL_ENTRY)) | 
|  | 576 | CPEOffset += 2; | 
|  | 577 |  | 
|  | 578 | if (UserOffset <= CPEOffset) { | 
|  | 579 | // User before the CPE. | 
|  | 580 | if (CPEOffset-UserOffset <= MaxDisp) | 
|  | 581 | return true; | 
|  | 582 | } else if (!AFI->isThumbFunction()) { | 
|  | 583 | // Thumb LDR cannot encode negative offset. | 
|  | 584 | if (UserOffset-CPEOffset <= MaxDisp) | 
|  | 585 | return true; | 
|  | 586 | } | 
|  | 587 | return false; | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | /// CPEIsInRange - Returns true if the distance between specific MI and | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 591 | /// specific ConstPool entry instruction can fit in MI's displacement field. | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 592 | bool ARMConstantIslands::CPEIsInRange(MachineInstr *MI, unsigned UserOffset, | 
|  | 593 | MachineInstr *CPEMI, | 
|  | 594 | unsigned MaxDisp, bool DoDump) { | 
|  | 595 | // In thumb mode, pessimistically assumes the .align 2 before the first CPE | 
| Evan Cheng | 2021abe | 2007-02-01 01:09:47 +0000 | [diff] [blame] | 596 | // in the island adds two byte padding. | 
|  | 597 | unsigned AlignAdj   = AFI->isThumbFunction() ? 2 : 0; | 
|  | 598 | unsigned CPEOffset  = GetOffsetOf(CPEMI) + AlignAdj; | 
|  | 599 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 600 | if (DoDump) { | 
|  | 601 | DOUT << "User of CPE#" << CPEMI->getOperand(0).getImm() | 
|  | 602 | << " max delta=" << MaxDisp | 
|  | 603 | << " insn address=" << UserOffset | 
|  | 604 | << " CPE address=" << CPEOffset | 
|  | 605 | << " offset=" << int(CPEOffset-UserOffset) << "\t" << *MI; | 
|  | 606 | } | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 607 |  | 
| Evan Cheng | a2e3558 | 2007-01-31 23:35:18 +0000 | [diff] [blame] | 608 | if (UserOffset <= CPEOffset) { | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 609 | // User before the CPE. | 
|  | 610 | if (CPEOffset-UserOffset <= MaxDisp) | 
|  | 611 | return true; | 
|  | 612 | } else if (!AFI->isThumbFunction()) { | 
|  | 613 | // Thumb LDR cannot encode negative offset. | 
|  | 614 | if (UserOffset-CPEOffset <= MaxDisp) | 
|  | 615 | return true; | 
|  | 616 | } | 
|  | 617 | return false; | 
|  | 618 | } | 
|  | 619 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 620 | /// BBIsJumpedOver - Return true of the specified basic block's only predecessor | 
|  | 621 | /// unconditionally branches to its only successor. | 
|  | 622 | static bool BBIsJumpedOver(MachineBasicBlock *MBB) { | 
|  | 623 | if (MBB->pred_size() != 1 || MBB->succ_size() != 1) | 
|  | 624 | return false; | 
|  | 625 |  | 
|  | 626 | MachineBasicBlock *Succ = *MBB->succ_begin(); | 
|  | 627 | MachineBasicBlock *Pred = *MBB->pred_begin(); | 
|  | 628 | MachineInstr *PredMI = &Pred->back(); | 
|  | 629 | if (PredMI->getOpcode() == ARM::B || PredMI->getOpcode() == ARM::tB) | 
|  | 630 | return PredMI->getOperand(0).getMBB() == Succ; | 
|  | 631 | return false; | 
|  | 632 | } | 
|  | 633 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 634 | /// DecrementOldEntry - find the constant pool entry with index CPI | 
|  | 635 | /// and instruction CPEMI, and decrement its refcount.  If the refcount | 
|  | 636 | /// becomes 0 remove the entry and instruction.  Returns true if we removed | 
|  | 637 | /// the entry, false if we didn't. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 638 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 639 | bool ARMConstantIslands::DecrementOldEntry(unsigned CPI, MachineInstr *CPEMI, | 
|  | 640 | unsigned Size) { | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 641 | // Find the old entry. Eliminate it if it is no longer used. | 
|  | 642 | CPEntry *OldCPE = findConstPoolEntry(CPI, CPEMI); | 
|  | 643 | assert(OldCPE && "Unexpected!"); | 
|  | 644 | if (--OldCPE->RefCount == 0) { | 
|  | 645 | MachineBasicBlock *OldCPEBB = OldCPE->CPEMI->getParent(); | 
|  | 646 | if (OldCPEBB->empty()) { | 
|  | 647 | // In thumb mode, the size of island is padded by two to compensate for | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 648 | // the alignment requirement.  Thus it will now be 2 when the block is | 
|  | 649 | // empty, so fix this. | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 650 | BBSizes[OldCPEBB->getNumber()] = 0; | 
|  | 651 | // An island has only one predecessor BB and one successor BB. Check if | 
|  | 652 | // this BB's predecessor jumps directly to this BB's successor. This | 
|  | 653 | // shouldn't happen currently. | 
|  | 654 | assert(!BBIsJumpedOver(OldCPEBB) && "How did this happen?"); | 
|  | 655 | // FIXME: remove the empty blocks after all the work is done? | 
|  | 656 | } else | 
|  | 657 | BBSizes[OldCPEBB->getNumber()] -= Size; | 
|  | 658 | OldCPE->CPEMI->eraseFromParent(); | 
|  | 659 | OldCPE->CPEMI = NULL; | 
|  | 660 | NumCPEs--; | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 661 | return true; | 
|  | 662 | } | 
|  | 663 | return false; | 
|  | 664 | } | 
|  | 665 |  | 
|  | 666 | /// ComputeWaterListOffsets - just what you think. | 
|  | 667 | /// This vector is built to avoid re-adding BBSizes for each WaterBB under test | 
|  | 668 | /// (which would cause the algorithm to be n^2). | 
|  | 669 | void ARMConstantIslands::ComputeWaterListOffsets(MachineFunction &Fn) { | 
|  | 670 | unsigned WaterListIndex = 0; | 
|  | 671 | unsigned Offset = 0; | 
|  | 672 | unsigned BB = 0; | 
|  | 673 | WaterListOffsets.clear(); | 
|  | 674 | for (MachineFunction::iterator MBBI = Fn.begin(), E = Fn.end(); | 
|  | 675 | MBBI != E;  ++BB, ++MBBI) { | 
|  | 676 | MachineBasicBlock *MBB = MBBI; | 
|  | 677 | if (MBB == WaterList[WaterListIndex]) { | 
|  | 678 | WaterListOffsets.push_back(Offset); | 
|  | 679 | WaterListIndex++; | 
|  | 680 | } | 
|  | 681 | Offset += BBSizes[BB]; | 
|  | 682 | } | 
|  | 683 | } | 
|  | 684 |  | 
|  | 685 | /// LookForCPEntryInRange - see if the currently referenced CPE is in range; | 
|  | 686 | /// if not, see if an in-range clone of the CPE is in range, and if so, | 
|  | 687 | /// change the data structures so the user references the clone.  Returns: | 
|  | 688 | /// 0 = no existing entry found | 
|  | 689 | /// 1 = entry found, and there were no code insertions or deletions | 
|  | 690 | /// 2 = entry found, and there were code insertions or deletions | 
|  | 691 | int ARMConstantIslands::LookForExistingCPEntry(CPUser& U, unsigned UserOffset) | 
|  | 692 | { | 
|  | 693 | MachineInstr *UserMI = U.MI; | 
|  | 694 | MachineInstr *CPEMI  = U.CPEMI; | 
|  | 695 |  | 
|  | 696 | // Check to see if the CPE is already in-range. | 
|  | 697 | if (CPEIsInRange(UserMI, UserOffset, CPEMI, U.MaxDisp, true)) { | 
|  | 698 | DOUT << "In range\n"; | 
|  | 699 | return 1; | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 700 | } | 
|  | 701 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 702 | // No.  Look for previously created clones of the CPE that are in range. | 
|  | 703 | unsigned CPI = CPEMI->getOperand(1).getConstantPoolIndex(); | 
|  | 704 | std::vector<CPEntry> &CPEs = CPEntries[CPI]; | 
|  | 705 | for (unsigned i = 0, e = CPEs.size(); i != e; ++i) { | 
|  | 706 | // We already tried this one | 
|  | 707 | if (CPEs[i].CPEMI == CPEMI) | 
|  | 708 | continue; | 
|  | 709 | // Removing CPEs can leave empty entries, skip | 
|  | 710 | if (CPEs[i].CPEMI == NULL) | 
|  | 711 | continue; | 
|  | 712 | if (CPEIsInRange(UserMI, UserOffset, CPEs[i].CPEMI, U.MaxDisp, false)) { | 
|  | 713 | DOUT << "Replacing CPE#" << CPI << " with CPE#" << CPEs[i].CPI << "\n"; | 
|  | 714 | // Point the CPUser node to the replacement | 
|  | 715 | U.CPEMI = CPEs[i].CPEMI; | 
|  | 716 | // Change the CPI in the instruction operand to refer to the clone. | 
|  | 717 | for (unsigned j = 0, e = UserMI->getNumOperands(); j != e; ++j) | 
|  | 718 | if (UserMI->getOperand(j).isConstantPoolIndex()) { | 
|  | 719 | UserMI->getOperand(j).setConstantPoolIndex(CPEs[i].CPI); | 
|  | 720 | break; | 
|  | 721 | } | 
|  | 722 | // Adjust the refcount of the clone... | 
|  | 723 | CPEs[i].RefCount++; | 
|  | 724 | // ...and the original.  If we didn't remove the old entry, none of the | 
|  | 725 | // addresses changed, so we don't need another pass. | 
|  | 726 | unsigned Size = CPEMI->getOperand(2).getImm(); | 
|  | 727 | return DecrementOldEntry(CPI, CPEMI, Size) ? 2 : 1; | 
|  | 728 | } | 
|  | 729 | } | 
|  | 730 | return 0; | 
|  | 731 | } | 
|  | 732 |  | 
|  | 733 | /// HandleConstantPoolUser - Analyze the specified user, checking to see if it | 
|  | 734 | /// is out-of-range.  If so, pick it up the constant pool value and move it some | 
|  | 735 | /// place in-range.  Return true if we changed any addresses (thus must run | 
|  | 736 | /// another pass of branch lengthening), false otherwise. | 
|  | 737 | bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &Fn, CPUser &U){ | 
|  | 738 | MachineInstr *UserMI = U.MI; | 
|  | 739 | MachineInstr *CPEMI  = U.CPEMI; | 
|  | 740 | unsigned CPI = CPEMI->getOperand(1).getConstantPoolIndex(); | 
|  | 741 | unsigned Size = CPEMI->getOperand(2).getImm(); | 
|  | 742 | bool isThumb = AFI->isThumbFunction(); | 
|  | 743 | MachineBasicBlock *NewMBB; | 
|  | 744 | // Compute this only once, it's expensive | 
|  | 745 | unsigned UserOffset = GetOffsetOf(UserMI) + (isThumb ? 4 : 8); | 
|  | 746 |  | 
|  | 747 | // See if the current entry is within range, or there is a clone of it | 
|  | 748 | // in range. | 
|  | 749 | int result = LookForExistingCPEntry(U, UserOffset); | 
|  | 750 | if (result==1) return false; | 
|  | 751 | else if (result==2) return true; | 
|  | 752 |  | 
|  | 753 | // No existing clone of this CPE is within range. | 
|  | 754 | // We will be generating a new clone.  Get a UID for it. | 
|  | 755 | unsigned ID  = NextUID++; | 
|  | 756 |  | 
|  | 757 | // Look for water where we can place this CPE.  We look for the farthest one | 
|  | 758 | // away that will work.  Forward references only for now (although later | 
|  | 759 | // we might find some that are backwards). | 
|  | 760 | bool WaterFound = false; | 
|  | 761 | if (!WaterList.empty()) { | 
|  | 762 | // Compute offsets for the blocks in the current WaterList. | 
|  | 763 | // It is a big compile-time speed win to do this only once | 
|  | 764 | // rather than for each WaterList entry. | 
|  | 765 | ComputeWaterListOffsets(Fn); | 
|  | 766 | assert(WaterList.size() == WaterListOffsets.size()); | 
|  | 767 | for (std::vector<MachineBasicBlock*>::iterator IP = prior(WaterList.end()), | 
|  | 768 | B = WaterList.begin();; --IP) { | 
|  | 769 | MachineBasicBlock* WaterBB = *IP; | 
|  | 770 | if (WaterIsInRange(UserOffset, IP, U.MaxDisp)) { | 
|  | 771 | WaterFound = true; | 
|  | 772 | DOUT << "found water in range\n"; | 
|  | 773 | // CPE goes before following block (NewMBB). | 
|  | 774 | NewMBB = next(MachineFunction::iterator(WaterBB)); | 
|  | 775 | // Remove the original WaterList entry; we want subsequent | 
|  | 776 | // insertions in this vicinity to go after the one we're | 
|  | 777 | // about to insert.  This considerably reduces the number | 
|  | 778 | // of times we have to move the same CPE more than once. | 
|  | 779 | WaterList.erase(IP); | 
|  | 780 | break; | 
|  | 781 | } | 
|  | 782 | if (IP == B) | 
|  | 783 | break; | 
|  | 784 | } | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | if (!WaterFound) { | 
|  | 788 | // No water found. | 
|  | 789 | // Solution of last resort: split the user's MBB right after the user | 
|  | 790 | // and insert a clone of the CPE into the newly created water. | 
|  | 791 |  | 
|  | 792 | DOUT << "No water found\n"; | 
|  | 793 | MachineBasicBlock *UserMBB = UserMI->getParent(); | 
|  | 794 |  | 
|  | 795 | // TODO: Search for the best place to split the code.  In practice, using | 
|  | 796 | // loop nesting information to insert these guys outside of loops would be | 
|  | 797 | // sufficient. | 
|  | 798 | if (&UserMBB->back() == UserMI) { | 
|  | 799 | assert(BBHasFallthrough(UserMBB) && "Expected a fallthrough BB!"); | 
|  | 800 | NewMBB = next(MachineFunction::iterator(UserMBB)); | 
|  | 801 | // Add an unconditional branch from UserMBB to fallthrough block. | 
|  | 802 | // Note the new unconditional branch is not being recorded. | 
|  | 803 | BuildMI(UserMBB, TII->get(isThumb ? ARM::tB : ARM::B)).addMBB(NewMBB); | 
|  | 804 | BBSizes[UserMBB->getNumber()] += isThumb ? 2 : 4; | 
|  | 805 | } else { | 
|  | 806 | MachineInstr *NextMI = next(MachineBasicBlock::iterator(UserMI)); | 
|  | 807 | NewMBB = SplitBlockBeforeInstr(NextMI); | 
|  | 808 | } | 
|  | 809 | } | 
|  | 810 |  | 
|  | 811 | // Okay, we know we can put an island before NewMBB now, do it! | 
|  | 812 | MachineBasicBlock *NewIsland = new MachineBasicBlock(); | 
|  | 813 | Fn.getBasicBlockList().insert(NewMBB, NewIsland); | 
|  | 814 |  | 
|  | 815 | // Update internal data structures to account for the newly inserted MBB. | 
|  | 816 | UpdateForInsertedWaterBlock(NewIsland); | 
|  | 817 |  | 
|  | 818 | // Decrement the old entry, and remove it if refcount becomes 0. | 
|  | 819 | DecrementOldEntry(CPI, CPEMI, Size); | 
|  | 820 |  | 
|  | 821 | // Now that we have an island to add the CPE to, clone the original CPE and | 
|  | 822 | // add it to the island. | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 823 | U.CPEMI = BuildMI(NewIsland, TII->get(ARM::CONSTPOOL_ENTRY)) | 
|  | 824 | .addImm(ID).addConstantPoolIndex(CPI).addImm(Size); | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 825 | CPEntries[CPI].push_back(CPEntry(U.CPEMI, ID, 1)); | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 826 | NumCPEs++; | 
|  | 827 |  | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 828 | // Compensate for .align 2 in thumb mode. | 
|  | 829 | if (isThumb) Size += 2; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 830 | // Increase the size of the island block to account for the new entry. | 
|  | 831 | BBSizes[NewIsland->getNumber()] += Size; | 
|  | 832 |  | 
|  | 833 | // Finally, change the CPI in the instruction operand to be ID. | 
|  | 834 | for (unsigned i = 0, e = UserMI->getNumOperands(); i != e; ++i) | 
|  | 835 | if (UserMI->getOperand(i).isConstantPoolIndex()) { | 
|  | 836 | UserMI->getOperand(i).setConstantPoolIndex(ID); | 
|  | 837 | break; | 
|  | 838 | } | 
|  | 839 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 840 | DOUT << "  Moved CPE to #" << ID << " CPI=" << CPI << "\t" << *UserMI; | 
| Evan Cheng | a8e2989 | 2007-01-19 07:51:42 +0000 | [diff] [blame] | 841 |  | 
|  | 842 | return true; | 
|  | 843 | } | 
|  | 844 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 845 | /// BBIsInRange - Returns true if the distance between specific MI and | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 846 | /// specific BB can fit in MI's displacement field. | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 847 | bool ARMConstantIslands::BBIsInRange(MachineInstr *MI,MachineBasicBlock *DestBB, | 
|  | 848 | unsigned MaxDisp) { | 
|  | 849 | unsigned PCAdj      = AFI->isThumbFunction() ? 4 : 8; | 
|  | 850 | unsigned BrOffset   = GetOffsetOf(MI) + PCAdj; | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 851 | unsigned DestOffset = GetOffsetOf(DestBB); | 
|  | 852 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 853 | DOUT << "Branch of destination BB#" << DestBB->getNumber() | 
|  | 854 | << " from BB#" << MI->getParent()->getNumber() | 
|  | 855 | << " max delta=" << MaxDisp | 
|  | 856 | << " at offset " << int(DestOffset-BrOffset) << "\t" << *MI; | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 857 |  | 
| Evan Cheng | a2e3558 | 2007-01-31 23:35:18 +0000 | [diff] [blame] | 858 | if (BrOffset <= DestOffset) { | 
| Evan Cheng | b43216e | 2007-02-01 10:16:15 +0000 | [diff] [blame] | 859 | if (DestOffset - BrOffset <= MaxDisp) | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 860 | return true; | 
|  | 861 | } else { | 
|  | 862 | if (BrOffset - DestOffset <= MaxDisp) | 
|  | 863 | return true; | 
|  | 864 | } | 
|  | 865 | return false; | 
|  | 866 | } | 
|  | 867 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 868 | /// FixUpImmediateBr - Fix up an immediate branch whose destination is too far | 
|  | 869 | /// away to fit in its displacement field. | 
|  | 870 | bool ARMConstantIslands::FixUpImmediateBr(MachineFunction &Fn, ImmBranch &Br) { | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 871 | MachineInstr *MI = Br.MI; | 
|  | 872 | MachineBasicBlock *DestBB = MI->getOperand(0).getMachineBasicBlock(); | 
|  | 873 |  | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 874 | // Check to see if the DestBB is already in-range. | 
|  | 875 | if (BBIsInRange(MI, DestBB, Br.MaxDisp)) | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 876 | return false; | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 877 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 878 | if (!Br.isCond) | 
|  | 879 | return FixUpUnconditionalBr(Fn, Br); | 
|  | 880 | return FixUpConditionalBr(Fn, Br); | 
|  | 881 | } | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 882 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 883 | /// FixUpUnconditionalBr - Fix up an unconditional branch whose destination is | 
|  | 884 | /// too far away to fit in its displacement field. If the LR register has been | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 885 | /// spilled in the epilogue, then we can use BL to implement a far jump. | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 886 | /// Otherwise, add an intermediate branch instruction to to a branch. | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 887 | bool | 
|  | 888 | ARMConstantIslands::FixUpUnconditionalBr(MachineFunction &Fn, ImmBranch &Br) { | 
|  | 889 | MachineInstr *MI = Br.MI; | 
|  | 890 | MachineBasicBlock *MBB = MI->getParent(); | 
|  | 891 | assert(AFI->isThumbFunction() && "Expected a Thumb function!"); | 
|  | 892 |  | 
|  | 893 | // Use BL to implement far jump. | 
|  | 894 | Br.MaxDisp = (1 << 21) * 2; | 
|  | 895 | MI->setInstrDescriptor(TII->get(ARM::tBfar)); | 
|  | 896 | BBSizes[MBB->getNumber()] += 2; | 
|  | 897 | HasFarJump = true; | 
|  | 898 | NumUBrFixed++; | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 899 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 900 | DOUT << "  Changed B to long jump " << *MI; | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 901 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 902 | return true; | 
|  | 903 | } | 
|  | 904 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 905 | /// getUnconditionalBrDisp - Returns the maximum displacement that can fit in | 
|  | 906 | /// the specific unconditional branch instruction. | 
| Evan Cheng | a9b8b8d | 2007-01-31 18:29:27 +0000 | [diff] [blame] | 907 | static inline unsigned getUnconditionalBrDisp(int Opc) { | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 908 | return (Opc == ARM::tB) ? (1<<10)*2 : (1<<23)*4; | 
|  | 909 | } | 
|  | 910 |  | 
| Dale Johannesen | 88e37ae | 2007-02-23 05:02:36 +0000 | [diff] [blame^] | 911 | /// FixUpConditionalBr - Fix up a conditional branch whose destination is too | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 912 | /// far away to fit in its displacement field. It is converted to an inverse | 
|  | 913 | /// conditional branch + an unconditional branch to the destination. | 
|  | 914 | bool | 
|  | 915 | ARMConstantIslands::FixUpConditionalBr(MachineFunction &Fn, ImmBranch &Br) { | 
|  | 916 | MachineInstr *MI = Br.MI; | 
|  | 917 | MachineBasicBlock *DestBB = MI->getOperand(0).getMachineBasicBlock(); | 
|  | 918 |  | 
|  | 919 | // Add a unconditional branch to the destination and invert the branch | 
|  | 920 | // condition to jump over it: | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 921 | // blt L1 | 
|  | 922 | // => | 
|  | 923 | // bge L2 | 
|  | 924 | // b   L1 | 
|  | 925 | // L2: | 
|  | 926 | ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(1).getImmedValue(); | 
|  | 927 | CC = ARMCC::getOppositeCondition(CC); | 
|  | 928 |  | 
|  | 929 | // If the branch is at the end of its MBB and that has a fall-through block, | 
|  | 930 | // direct the updated conditional branch to the fall-through block. Otherwise, | 
|  | 931 | // split the MBB before the next instruction. | 
|  | 932 | MachineBasicBlock *MBB = MI->getParent(); | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 933 | MachineInstr *BMI = &MBB->back(); | 
|  | 934 | bool NeedSplit = (BMI != MI) || !BBHasFallthrough(MBB); | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 935 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 936 | NumCBrFixed++; | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 937 | if (BMI != MI) { | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 938 | if (next(MachineBasicBlock::iterator(MI)) == MBB->back() && | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 939 | BMI->getOpcode() == Br.UncondBr) { | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 940 | // Last MI in the BB is a unconditional branch. Can we simply invert the | 
|  | 941 | // condition and swap destinations: | 
|  | 942 | // beq L1 | 
|  | 943 | // b   L2 | 
|  | 944 | // => | 
|  | 945 | // bne L2 | 
|  | 946 | // b   L1 | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 947 | MachineBasicBlock *NewDest = BMI->getOperand(0).getMachineBasicBlock(); | 
| Evan Cheng | c0dbec7 | 2007-01-31 19:57:44 +0000 | [diff] [blame] | 948 | if (BBIsInRange(MI, NewDest, Br.MaxDisp)) { | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 949 | DOUT << "  Invert Bcc condition and swap its destination with " << *BMI; | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 950 | BMI->getOperand(0).setMachineBasicBlock(DestBB); | 
| Evan Cheng | 43aeab6 | 2007-01-26 20:38:26 +0000 | [diff] [blame] | 951 | MI->getOperand(0).setMachineBasicBlock(NewDest); | 
|  | 952 | MI->getOperand(1).setImm(CC); | 
|  | 953 | return true; | 
|  | 954 | } | 
|  | 955 | } | 
|  | 956 | } | 
|  | 957 |  | 
|  | 958 | if (NeedSplit) { | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 959 | SplitBlockBeforeInstr(MI); | 
| Evan Cheng | dd353b8 | 2007-01-26 02:02:39 +0000 | [diff] [blame] | 960 | // No need for the branch to the next block. We're adding a unconditional | 
|  | 961 | // branch to the destination. | 
|  | 962 | MBB->back().eraseFromParent(); | 
|  | 963 | } | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 964 | MachineBasicBlock *NextBB = next(MachineFunction::iterator(MBB)); | 
| Evan Cheng | bd5d3db | 2007-02-03 02:08:34 +0000 | [diff] [blame] | 965 |  | 
| Evan Cheng | c99ef08 | 2007-02-09 20:54:44 +0000 | [diff] [blame] | 966 | DOUT << "  Insert B to BB#" << DestBB->getNumber() | 
|  | 967 | << " also invert condition and change dest. to BB#" | 
|  | 968 | << NextBB->getNumber() << "\n"; | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 969 |  | 
|  | 970 | // Insert a unconditional branch and replace the conditional branch. | 
|  | 971 | // Also update the ImmBranch as well as adding a new entry for the new branch. | 
| Evan Cheng | dd353b8 | 2007-01-26 02:02:39 +0000 | [diff] [blame] | 972 | BuildMI(MBB, TII->get(MI->getOpcode())).addMBB(NextBB).addImm(CC); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 973 | Br.MI = &MBB->back(); | 
|  | 974 | BuildMI(MBB, TII->get(Br.UncondBr)).addMBB(DestBB); | 
| Evan Cheng | a9b8b8d | 2007-01-31 18:29:27 +0000 | [diff] [blame] | 975 | unsigned MaxDisp = getUnconditionalBrDisp(Br.UncondBr); | 
| Evan Cheng | a0bf794 | 2007-01-25 23:31:04 +0000 | [diff] [blame] | 976 | ImmBranches.push_back(ImmBranch(&MBB->back(), MaxDisp, false, Br.UncondBr)); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 977 | MI->eraseFromParent(); | 
|  | 978 |  | 
|  | 979 | // Increase the size of MBB to account for the new unconditional branch. | 
| Evan Cheng | 29836c3 | 2007-01-29 23:45:17 +0000 | [diff] [blame] | 980 | BBSizes[MBB->getNumber()] += ARM::GetInstSize(&MBB->back()); | 
| Evan Cheng | af5cbcb | 2007-01-25 03:12:46 +0000 | [diff] [blame] | 981 | return true; | 
|  | 982 | } | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 983 |  | 
| Evan Cheng | d1b2c1e | 2007-01-30 01:18:38 +0000 | [diff] [blame] | 984 | /// UndoLRSpillRestore - Remove Thumb push / pop instructions that only spills | 
|  | 985 | /// LR / restores LR to pc. | 
|  | 986 | bool ARMConstantIslands::UndoLRSpillRestore() { | 
|  | 987 | bool MadeChange = false; | 
|  | 988 | for (unsigned i = 0, e = PushPopMIs.size(); i != e; ++i) { | 
|  | 989 | MachineInstr *MI = PushPopMIs[i]; | 
|  | 990 | if (MI->getNumOperands() == 1) { | 
|  | 991 | if (MI->getOpcode() == ARM::tPOP_RET && | 
|  | 992 | MI->getOperand(0).getReg() == ARM::PC) | 
|  | 993 | BuildMI(MI->getParent(), TII->get(ARM::tBX_RET)); | 
|  | 994 | MI->eraseFromParent(); | 
|  | 995 | MadeChange = true; | 
|  | 996 | } | 
|  | 997 | } | 
|  | 998 | return MadeChange; | 
|  | 999 | } |