| Jim Grosbach | 4e9f379 | 2009-11-07 22:00:39 +0000 | [diff] [blame] | 1 | //===-- Thumb2ITBlockPass.cpp - Insert Thumb IT blocks ----------*- C++ -*-===// | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
|  | 10 | #define DEBUG_TYPE "thumb2-it" | 
|  | 11 | #include "ARM.h" | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 12 | #include "ARMMachineFunctionInfo.h" | 
| Evan Cheng | 017288a | 2009-07-11 07:26:20 +0000 | [diff] [blame] | 13 | #include "Thumb2InstrInfo.h" | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 14 | #include "llvm/CodeGen/MachineInstr.h" | 
|  | 15 | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | 16 | #include "llvm/CodeGen/MachineFunctionPass.h" | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/SmallSet.h" | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/Statistic.h" | 
|  | 19 | using namespace llvm; | 
|  | 20 |  | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 21 | STATISTIC(NumITs,        "Number of IT blocks inserted"); | 
|  | 22 | STATISTIC(NumMovedInsts, "Number of predicated instructions moved"); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 23 |  | 
|  | 24 | namespace { | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 25 | class Thumb2ITBlockPass : public MachineFunctionPass { | 
|  | 26 | bool PreRegAlloc; | 
|  | 27 |  | 
|  | 28 | public: | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 29 | static char ID; | 
| Owen Anderson | a7aed18 | 2010-08-06 18:33:48 +0000 | [diff] [blame] | 30 | Thumb2ITBlockPass() : MachineFunctionPass(ID) {} | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 31 |  | 
| Evan Cheng | 017288a | 2009-07-11 07:26:20 +0000 | [diff] [blame] | 32 | const Thumb2InstrInfo *TII; | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 33 | const TargetRegisterInfo *TRI; | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 34 | ARMFunctionInfo *AFI; | 
|  | 35 |  | 
|  | 36 | virtual bool runOnMachineFunction(MachineFunction &Fn); | 
|  | 37 |  | 
|  | 38 | virtual const char *getPassName() const { | 
|  | 39 | return "Thumb IT blocks insertion pass"; | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | private: | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 43 | bool MoveCopyOutOfITBlock(MachineInstr *MI, | 
|  | 44 | ARMCC::CondCodes CC, ARMCC::CondCodes OCC, | 
|  | 45 | SmallSet<unsigned, 4> &Defs, | 
|  | 46 | SmallSet<unsigned, 4> &Uses); | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 47 | bool InsertITInstructions(MachineBasicBlock &MBB); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 48 | }; | 
|  | 49 | char Thumb2ITBlockPass::ID = 0; | 
|  | 50 | } | 
|  | 51 |  | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 52 | /// TrackDefUses - Tracking what registers are being defined and used by | 
|  | 53 | /// instructions in the IT block. This also tracks "dependencies", i.e. uses | 
|  | 54 | /// in the IT block that are defined before the IT instruction. | 
|  | 55 | static void TrackDefUses(MachineInstr *MI, | 
|  | 56 | SmallSet<unsigned, 4> &Defs, | 
|  | 57 | SmallSet<unsigned, 4> &Uses, | 
|  | 58 | const TargetRegisterInfo *TRI) { | 
|  | 59 | SmallVector<unsigned, 4> LocalDefs; | 
|  | 60 | SmallVector<unsigned, 4> LocalUses; | 
|  | 61 |  | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 62 | for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { | 
|  | 63 | MachineOperand &MO = MI->getOperand(i); | 
|  | 64 | if (!MO.isReg()) | 
|  | 65 | continue; | 
|  | 66 | unsigned Reg = MO.getReg(); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 67 | if (!Reg || Reg == ARM::ITSTATE || Reg == ARM::SP) | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 68 | continue; | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 69 | if (MO.isUse()) | 
|  | 70 | LocalUses.push_back(Reg); | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 71 | else | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 72 | LocalDefs.push_back(Reg); | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 73 | } | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 74 |  | 
|  | 75 | for (unsigned i = 0, e = LocalUses.size(); i != e; ++i) { | 
|  | 76 | unsigned Reg = LocalUses[i]; | 
|  | 77 | Uses.insert(Reg); | 
|  | 78 | for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | 
|  | 79 | *Subreg; ++Subreg) | 
|  | 80 | Uses.insert(*Subreg); | 
|  | 81 | } | 
|  | 82 |  | 
|  | 83 | for (unsigned i = 0, e = LocalDefs.size(); i != e; ++i) { | 
|  | 84 | unsigned Reg = LocalDefs[i]; | 
|  | 85 | Defs.insert(Reg); | 
|  | 86 | for (const unsigned *Subreg = TRI->getSubRegisters(Reg); | 
|  | 87 | *Subreg; ++Subreg) | 
|  | 88 | Defs.insert(*Subreg); | 
|  | 89 | if (Reg == ARM::CPSR) | 
|  | 90 | continue; | 
|  | 91 | } | 
|  | 92 | } | 
|  | 93 |  | 
| Jakob Stoklund Olesen | 54bcf50 | 2010-07-16 22:35:32 +0000 | [diff] [blame] | 94 | static bool isCopy(MachineInstr *MI) { | 
|  | 95 | switch (MI->getOpcode()) { | 
|  | 96 | default: | 
|  | 97 | return false; | 
|  | 98 | case ARM::MOVr: | 
|  | 99 | case ARM::MOVr_TC: | 
|  | 100 | case ARM::tMOVr: | 
| Jakob Stoklund Olesen | 54bcf50 | 2010-07-16 22:35:32 +0000 | [diff] [blame] | 101 | case ARM::t2MOVr: | 
|  | 102 | return true; | 
|  | 103 | } | 
|  | 104 | } | 
|  | 105 |  | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 106 | bool | 
|  | 107 | Thumb2ITBlockPass::MoveCopyOutOfITBlock(MachineInstr *MI, | 
|  | 108 | ARMCC::CondCodes CC, ARMCC::CondCodes OCC, | 
|  | 109 | SmallSet<unsigned, 4> &Defs, | 
|  | 110 | SmallSet<unsigned, 4> &Uses) { | 
| Jakob Stoklund Olesen | 54bcf50 | 2010-07-16 22:35:32 +0000 | [diff] [blame] | 111 | if (!isCopy(MI)) | 
|  | 112 | return false; | 
|  | 113 | // llvm models select's as two-address instructions. That means a copy | 
|  | 114 | // is inserted before a t2MOVccr, etc. If the copy is scheduled in | 
|  | 115 | // between selects we would end up creating multiple IT blocks. | 
|  | 116 | assert(MI->getOperand(0).getSubReg() == 0 && | 
|  | 117 | MI->getOperand(1).getSubReg() == 0 && | 
|  | 118 | "Sub-register indices still around?"); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 119 |  | 
| Jakob Stoklund Olesen | 54bcf50 | 2010-07-16 22:35:32 +0000 | [diff] [blame] | 120 | unsigned DstReg = MI->getOperand(0).getReg(); | 
|  | 121 | unsigned SrcReg = MI->getOperand(1).getReg(); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 122 |  | 
| Jakob Stoklund Olesen | 54bcf50 | 2010-07-16 22:35:32 +0000 | [diff] [blame] | 123 | // First check if it's safe to move it. | 
|  | 124 | if (Uses.count(DstReg) || Defs.count(SrcReg)) | 
|  | 125 | return false; | 
|  | 126 |  | 
|  | 127 | // Then peek at the next instruction to see if it's predicated on CC or OCC. | 
|  | 128 | // If not, then there is nothing to be gained by moving the copy. | 
|  | 129 | MachineBasicBlock::iterator I = MI; ++I; | 
|  | 130 | MachineBasicBlock::iterator E = MI->getParent()->end(); | 
|  | 131 | while (I != E && I->isDebugValue()) | 
|  | 132 | ++I; | 
|  | 133 | if (I != E) { | 
|  | 134 | unsigned NPredReg = 0; | 
|  | 135 | ARMCC::CondCodes NCC = llvm::getITInstrPredicate(I, NPredReg); | 
|  | 136 | if (NCC == CC || NCC == OCC) | 
|  | 137 | return true; | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 138 | } | 
|  | 139 | return false; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 140 | } | 
|  | 141 |  | 
|  | 142 | bool Thumb2ITBlockPass::InsertITInstructions(MachineBasicBlock &MBB) { | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 143 | bool Modified = false; | 
|  | 144 |  | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 145 | SmallSet<unsigned, 4> Defs; | 
|  | 146 | SmallSet<unsigned, 4> Uses; | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 147 | MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); | 
|  | 148 | while (MBBI != E) { | 
|  | 149 | MachineInstr *MI = &*MBBI; | 
| Evan Cheng | 83e0d48 | 2009-09-28 09:14:39 +0000 | [diff] [blame] | 150 | DebugLoc dl = MI->getDebugLoc(); | 
|  | 151 | unsigned PredReg = 0; | 
| Evan Cheng | 37bb617 | 2010-06-22 01:18:16 +0000 | [diff] [blame] | 152 | ARMCC::CondCodes CC = llvm::getITInstrPredicate(MI, PredReg); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 153 | if (CC == ARMCC::AL) { | 
|  | 154 | ++MBBI; | 
|  | 155 | continue; | 
|  | 156 | } | 
|  | 157 |  | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 158 | Defs.clear(); | 
|  | 159 | Uses.clear(); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 160 | TrackDefUses(MI, Defs, Uses, TRI); | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 161 |  | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 162 | // Insert an IT instruction. | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 163 | MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII->get(ARM::t2IT)) | 
|  | 164 | .addImm(CC); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 165 |  | 
|  | 166 | // Add implicit use of ITSTATE to IT block instructions. | 
|  | 167 | MI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, | 
|  | 168 | true/*isImp*/, false/*isKill*/)); | 
|  | 169 |  | 
|  | 170 | MachineInstr *LastITMI = MI; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 171 | MachineBasicBlock::iterator InsertPos = MIB; | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 172 | ++MBBI; | 
|  | 173 |  | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 174 | // Form IT block. | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 175 | ARMCC::CondCodes OCC = ARMCC::getOppositeCondition(CC); | 
| Evan Cheng | 6ddd7bc | 2009-08-15 07:59:10 +0000 | [diff] [blame] | 176 | unsigned Mask = 0, Pos = 3; | 
| Sandeep Patel | 3f23601 | 2009-10-15 22:25:32 +0000 | [diff] [blame] | 177 | // Branches, including tricky ones like LDM_RET, need to end an IT | 
|  | 178 | // block so check the instruction we just put in the block. | 
| Jim Grosbach | 723d242 | 2010-06-07 21:48:47 +0000 | [diff] [blame] | 179 | for (; MBBI != E && Pos && | 
|  | 180 | (!MI->getDesc().isBranch() && !MI->getDesc().isReturn()) ; ++MBBI) { | 
|  | 181 | if (MBBI->isDebugValue()) | 
|  | 182 | continue; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 183 |  | 
| Evan Cheng | 4854ef0 | 2009-09-28 20:47:15 +0000 | [diff] [blame] | 184 | MachineInstr *NMI = &*MBBI; | 
| Sandeep Patel | 3f23601 | 2009-10-15 22:25:32 +0000 | [diff] [blame] | 185 | MI = NMI; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 186 |  | 
| Evan Cheng | 4854ef0 | 2009-09-28 20:47:15 +0000 | [diff] [blame] | 187 | unsigned NPredReg = 0; | 
| Evan Cheng | 37bb617 | 2010-06-22 01:18:16 +0000 | [diff] [blame] | 188 | ARMCC::CondCodes NCC = llvm::getITInstrPredicate(NMI, NPredReg); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 189 | if (NCC == CC || NCC == OCC) { | 
| Johnny Chen | 0910b5a | 2010-03-17 23:14:23 +0000 | [diff] [blame] | 190 | Mask |= (NCC & 1) << Pos; | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 191 | // Add implicit use of ITSTATE. | 
|  | 192 | NMI->addOperand(MachineOperand::CreateReg(ARM::ITSTATE, false/*ifDef*/, | 
| Jim Grosbach | 7ea5fc0 | 2010-06-28 04:27:01 +0000 | [diff] [blame] | 193 | true/*isImp*/, false/*isKill*/)); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 194 | LastITMI = NMI; | 
|  | 195 | } else { | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 196 | if (NCC == ARMCC::AL && | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 197 | MoveCopyOutOfITBlock(NMI, CC, OCC, Defs, Uses)) { | 
|  | 198 | --MBBI; | 
|  | 199 | MBB.remove(NMI); | 
|  | 200 | MBB.insert(InsertPos, NMI); | 
|  | 201 | ++NumMovedInsts; | 
|  | 202 | continue; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 203 | } | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 204 | break; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 205 | } | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 206 | TrackDefUses(NMI, Defs, Uses, TRI); | 
| Evan Cheng | 6ddd7bc | 2009-08-15 07:59:10 +0000 | [diff] [blame] | 207 | --Pos; | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 208 | } | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 209 |  | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 210 | // Finalize IT mask. | 
| Evan Cheng | 6ddd7bc | 2009-08-15 07:59:10 +0000 | [diff] [blame] | 211 | Mask |= (1 << Pos); | 
| Johnny Chen | 0910b5a | 2010-03-17 23:14:23 +0000 | [diff] [blame] | 212 | // Tag along (firstcond[0] << 4) with the mask. | 
|  | 213 | Mask |= (CC & 1) << 4; | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 214 | MIB.addImm(Mask); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 215 |  | 
|  | 216 | // Last instruction in IT block kills ITSTATE. | 
|  | 217 | LastITMI->findRegisterUseOperand(ARM::ITSTATE)->setIsKill(); | 
|  | 218 |  | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 219 | Modified = true; | 
|  | 220 | ++NumITs; | 
|  | 221 | } | 
|  | 222 |  | 
|  | 223 | return Modified; | 
|  | 224 | } | 
|  | 225 |  | 
|  | 226 | bool Thumb2ITBlockPass::runOnMachineFunction(MachineFunction &Fn) { | 
|  | 227 | const TargetMachine &TM = Fn.getTarget(); | 
|  | 228 | AFI = Fn.getInfo<ARMFunctionInfo>(); | 
| Evan Cheng | 017288a | 2009-07-11 07:26:20 +0000 | [diff] [blame] | 229 | TII = static_cast<const Thumb2InstrInfo*>(TM.getInstrInfo()); | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 230 | TRI = TM.getRegisterInfo(); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 231 |  | 
|  | 232 | if (!AFI->isThumbFunction()) | 
|  | 233 | return false; | 
|  | 234 |  | 
|  | 235 | bool Modified = false; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 236 | for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; ) { | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 237 | MachineBasicBlock &MBB = *MFI; | 
| Evan Cheng | 47cd593 | 2010-06-09 01:46:50 +0000 | [diff] [blame] | 238 | ++MFI; | 
| Evan Cheng | c3525dc | 2010-07-02 21:07:09 +0000 | [diff] [blame] | 239 | Modified |= InsertITInstructions(MBB); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 240 | } | 
|  | 241 |  | 
| Evan Cheng | c3525dc | 2010-07-02 21:07:09 +0000 | [diff] [blame] | 242 | if (Modified) | 
| Evan Cheng | 2d51c7c | 2010-06-18 23:09:54 +0000 | [diff] [blame] | 243 | AFI->setHasITBlocks(true); | 
|  | 244 |  | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 245 | return Modified; | 
|  | 246 | } | 
|  | 247 |  | 
| Evan Cheng | 4dc201e | 2009-08-08 02:54:37 +0000 | [diff] [blame] | 248 | /// createThumb2ITBlockPass - Returns an instance of the Thumb2 IT blocks | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 249 | /// insertion pass. | 
| Evan Cheng | c3525dc | 2010-07-02 21:07:09 +0000 | [diff] [blame] | 250 | FunctionPass *llvm::createThumb2ITBlockPass() { | 
|  | 251 | return new Thumb2ITBlockPass(); | 
| Evan Cheng | 0f9cce7 | 2009-07-10 01:54:42 +0000 | [diff] [blame] | 252 | } |