1//===-- SPUInstrInfo.cpp - Cell SPU Instruction Information ---------------===// 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// This file contains the Cell SPU implementation of the TargetInstrInfo class. 11// 12//===----------------------------------------------------------------------===// 13 14#include "SPUInstrInfo.h" 15#include "SPUInstrBuilder.h" 16#include "SPUTargetMachine.h" 17#include "SPUHazardRecognizers.h" 18#include "llvm/CodeGen/MachineInstrBuilder.h" 19#include "llvm/MC/MCContext.h" 20#include "llvm/Support/Debug.h" 21#include "llvm/Support/ErrorHandling.h" 22#include "llvm/Support/TargetRegistry.h" 23#include "llvm/Support/raw_ostream.h" 24 25#define GET_INSTRINFO_CTOR 26#include "SPUGenInstrInfo.inc" 27 28using namespace llvm; 29 30namespace { 31 //! Predicate for an unconditional branch instruction 32 inline bool isUncondBranch(const MachineInstr *I) { 33 unsigned opc = I->getOpcode(); 34 35 return (opc == SPU::BR 36 || opc == SPU::BRA 37 || opc == SPU::BI); 38 } 39 40 //! Predicate for a conditional branch instruction 41 inline bool isCondBranch(const MachineInstr *I) { 42 unsigned opc = I->getOpcode(); 43 44 return (opc == SPU::BRNZr32 45 || opc == SPU::BRNZv4i32 46 || opc == SPU::BRZr32 47 || opc == SPU::BRZv4i32 48 || opc == SPU::BRHNZr16 49 || opc == SPU::BRHNZv8i16 50 || opc == SPU::BRHZr16 51 || opc == SPU::BRHZv8i16); 52 } 53} 54 55SPUInstrInfo::SPUInstrInfo(SPUTargetMachine &tm) 56 : SPUGenInstrInfo(SPU::ADJCALLSTACKDOWN, SPU::ADJCALLSTACKUP), 57 TM(tm), 58 RI(*TM.getSubtargetImpl(), *this) 59{ /* NOP */ } 60 61/// CreateTargetHazardRecognizer - Return the hazard recognizer to use for 62/// this target when scheduling the DAG. 63ScheduleHazardRecognizer *SPUInstrInfo::CreateTargetHazardRecognizer( 64 const TargetMachine *TM, 65 const ScheduleDAG *DAG) const { 66 const TargetInstrInfo *TII = TM->getInstrInfo(); 67 assert(TII && "No InstrInfo?"); 68 return new SPUHazardRecognizer(*TII); 69} 70 71unsigned 72SPUInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, 73 int &FrameIndex) const { 74 switch (MI->getOpcode()) { 75 default: break; 76 case SPU::LQDv16i8: 77 case SPU::LQDv8i16: 78 case SPU::LQDv4i32: 79 case SPU::LQDv4f32: 80 case SPU::LQDv2f64: 81 case SPU::LQDr128: 82 case SPU::LQDr64: 83 case SPU::LQDr32: 84 case SPU::LQDr16: { 85 const MachineOperand MOp1 = MI->getOperand(1); 86 const MachineOperand MOp2 = MI->getOperand(2); 87 if (MOp1.isImm() && MOp2.isFI()) { 88 FrameIndex = MOp2.getIndex(); 89 return MI->getOperand(0).getReg(); 90 } 91 break; 92 } 93 } 94 return 0; 95} 96 97unsigned 98SPUInstrInfo::isStoreToStackSlot(const MachineInstr *MI, 99 int &FrameIndex) const { 100 switch (MI->getOpcode()) { 101 default: break; 102 case SPU::STQDv16i8: 103 case SPU::STQDv8i16: 104 case SPU::STQDv4i32: 105 case SPU::STQDv4f32: 106 case SPU::STQDv2f64: 107 case SPU::STQDr128: 108 case SPU::STQDr64: 109 case SPU::STQDr32: 110 case SPU::STQDr16: 111 case SPU::STQDr8: { 112 const MachineOperand MOp1 = MI->getOperand(1); 113 const MachineOperand MOp2 = MI->getOperand(2); 114 if (MOp1.isImm() && MOp2.isFI()) { 115 FrameIndex = MOp2.getIndex(); 116 return MI->getOperand(0).getReg(); 117 } 118 break; 119 } 120 } 121 return 0; 122} 123 124void SPUInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 125 MachineBasicBlock::iterator I, DebugLoc DL, 126 unsigned DestReg, unsigned SrcReg, 127 bool KillSrc) const 128{ 129 // We support cross register class moves for our aliases, such as R3 in any 130 // reg class to any other reg class containing R3. This is required because 131 // we instruction select bitconvert i64 -> f64 as a noop for example, so our 132 // types have no specific meaning. 133 134 BuildMI(MBB, I, DL, get(SPU::LRr128), DestReg) 135 .addReg(SrcReg, getKillRegState(KillSrc)); 136} 137 138void 139SPUInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, 140 MachineBasicBlock::iterator MI, 141 unsigned SrcReg, bool isKill, int FrameIdx, 142 const TargetRegisterClass *RC, 143 const TargetRegisterInfo *TRI) const { 144 unsigned opc; 145 bool isValidFrameIdx = (FrameIdx < SPUFrameLowering::maxFrameOffset()); 146 if (RC == &SPU::GPRCRegClass) 147 opc = isValidFrameIdx ? SPU::STQDr128 : SPU::STQXr128; 148 else if (RC == &SPU::R64CRegClass) 149 opc = isValidFrameIdx ? SPU::STQDr64 : SPU::STQXr64; 150 else if (RC == &SPU::R64FPRegClass) 151 opc = isValidFrameIdx ? SPU::STQDr64 : SPU::STQXr64; 152 else if (RC == &SPU::R32CRegClass) 153 opc = isValidFrameIdx ? SPU::STQDr32 : SPU::STQXr32; 154 else if (RC == &SPU::R32FPRegClass) 155 opc = isValidFrameIdx ? SPU::STQDr32 : SPU::STQXr32; 156 else if (RC == &SPU::R16CRegClass) 157 opc = isValidFrameIdx ? SPU::STQDr16 : SPU::STQXr16; 158 else if (RC == &SPU::R8CRegClass) 159 opc = isValidFrameIdx ? SPU::STQDr8 : SPU::STQXr8; 160 else if (RC == &SPU::VECREGRegClass) 161 opc = isValidFrameIdx ? SPU::STQDv16i8 : SPU::STQXv16i8; 162 else 163 llvm_unreachable("Unknown regclass!"); 164 165 DebugLoc DL; 166 if (MI != MBB.end()) DL = MI->getDebugLoc(); 167 addFrameReference(BuildMI(MBB, MI, DL, get(opc)) 168 .addReg(SrcReg, getKillRegState(isKill)), FrameIdx); 169} 170 171void 172SPUInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 173 MachineBasicBlock::iterator MI, 174 unsigned DestReg, int FrameIdx, 175 const TargetRegisterClass *RC, 176 const TargetRegisterInfo *TRI) const { 177 unsigned opc; 178 bool isValidFrameIdx = (FrameIdx < SPUFrameLowering::maxFrameOffset()); 179 if (RC == &SPU::GPRCRegClass) 180 opc = isValidFrameIdx ? SPU::LQDr128 : SPU::LQXr128; 181 else if (RC == &SPU::R64CRegClass) 182 opc = isValidFrameIdx ? SPU::LQDr64 : SPU::LQXr64; 183 else if (RC == &SPU::R64FPRegClass) 184 opc = isValidFrameIdx ? SPU::LQDr64 : SPU::LQXr64; 185 else if (RC == &SPU::R32CRegClass) 186 opc = isValidFrameIdx ? SPU::LQDr32 : SPU::LQXr32; 187 else if (RC == &SPU::R32FPRegClass) 188 opc = isValidFrameIdx ? SPU::LQDr32 : SPU::LQXr32; 189 else if (RC == &SPU::R16CRegClass) 190 opc = isValidFrameIdx ? SPU::LQDr16 : SPU::LQXr16; 191 else if (RC == &SPU::R8CRegClass) 192 opc = isValidFrameIdx ? SPU::LQDr8 : SPU::LQXr8; 193 else if (RC == &SPU::VECREGRegClass) 194 opc = isValidFrameIdx ? SPU::LQDv16i8 : SPU::LQXv16i8; 195 else 196 llvm_unreachable("Unknown regclass in loadRegFromStackSlot!"); 197 198 DebugLoc DL; 199 if (MI != MBB.end()) DL = MI->getDebugLoc(); 200 addFrameReference(BuildMI(MBB, MI, DL, get(opc), DestReg), FrameIdx); 201} 202 203//! Branch analysis 204/*! 205 \note This code was kiped from PPC. There may be more branch analysis for 206 CellSPU than what's currently done here. 207 */ 208bool 209SPUInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, 210 MachineBasicBlock *&FBB, 211 SmallVectorImpl<MachineOperand> &Cond, 212 bool AllowModify) const { 213 // If the block has no terminators, it just falls into the block after it. 214 MachineBasicBlock::iterator I = MBB.end(); 215 if (I == MBB.begin()) 216 return false; 217 --I; 218 while (I->isDebugValue()) { 219 if (I == MBB.begin()) 220 return false; 221 --I; 222 } 223 if (!isUnpredicatedTerminator(I)) 224 return false; 225 226 // Get the last instruction in the block. 227 MachineInstr *LastInst = I; 228 229 // If there is only one terminator instruction, process it. 230 if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { 231 if (isUncondBranch(LastInst)) { 232 // Check for jump tables 233 if (!LastInst->getOperand(0).isMBB()) 234 return true; 235 TBB = LastInst->getOperand(0).getMBB(); 236 return false; 237 } else if (isCondBranch(LastInst)) { 238 // Block ends with fall-through condbranch. 239 TBB = LastInst->getOperand(1).getMBB(); 240 DEBUG(errs() << "Pushing LastInst: "); 241 DEBUG(LastInst->dump()); 242 Cond.push_back(MachineOperand::CreateImm(LastInst->getOpcode())); 243 Cond.push_back(LastInst->getOperand(0)); 244 return false; 245 } 246 // Otherwise, don't know what this is. 247 return true; 248 } 249 250 // Get the instruction before it if it's a terminator. 251 MachineInstr *SecondLastInst = I; 252 253 // If there are three terminators, we don't know what sort of block this is. 254 if (SecondLastInst && I != MBB.begin() && 255 isUnpredicatedTerminator(--I)) 256 return true; 257 258 // If the block ends with a conditional and unconditional branch, handle it. 259 if (isCondBranch(SecondLastInst) && isUncondBranch(LastInst)) { 260 TBB = SecondLastInst->getOperand(1).getMBB(); 261 DEBUG(errs() << "Pushing SecondLastInst: "); 262 DEBUG(SecondLastInst->dump()); 263 Cond.push_back(MachineOperand::CreateImm(SecondLastInst->getOpcode())); 264 Cond.push_back(SecondLastInst->getOperand(0)); 265 FBB = LastInst->getOperand(0).getMBB(); 266 return false; 267 } 268 269 // If the block ends with two unconditional branches, handle it. The second 270 // one is not executed, so remove it. 271 if (isUncondBranch(SecondLastInst) && isUncondBranch(LastInst)) { 272 TBB = SecondLastInst->getOperand(0).getMBB(); 273 I = LastInst; 274 if (AllowModify) 275 I->eraseFromParent(); 276 return false; 277 } 278 279 // Otherwise, can't handle this. 280 return true; 281} 282 283// search MBB for branch hint labels and branch hit ops 284static void removeHBR( MachineBasicBlock &MBB) { 285 for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I){ 286 if (I->getOpcode() == SPU::HBRA || 287 I->getOpcode() == SPU::HBR_LABEL){ 288 I=MBB.erase(I); 289 if (I == MBB.end()) 290 break; 291 } 292 } 293} 294 295unsigned 296SPUInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { 297 MachineBasicBlock::iterator I = MBB.end(); 298 removeHBR(MBB); 299 if (I == MBB.begin()) 300 return 0; 301 --I; 302 while (I->isDebugValue()) { 303 if (I == MBB.begin()) 304 return 0; 305 --I; 306 } 307 if (!isCondBranch(I) && !isUncondBranch(I)) 308 return 0; 309 310 // Remove the first branch. 311 DEBUG(errs() << "Removing branch: "); 312 DEBUG(I->dump()); 313 I->eraseFromParent(); 314 I = MBB.end(); 315 if (I == MBB.begin()) 316 return 1; 317 318 --I; 319 if (!(isCondBranch(I) || isUncondBranch(I))) 320 return 1; 321 322 // Remove the second branch. 323 DEBUG(errs() << "Removing second branch: "); 324 DEBUG(I->dump()); 325 I->eraseFromParent(); 326 return 2; 327} 328 329/** Find the optimal position for a hint branch instruction in a basic block. 330 * This should take into account: 331 * -the branch hint delays 332 * -congestion of the memory bus 333 * -dual-issue scheduling (i.e. avoid insertion of nops) 334 * Current implementation is rather simplistic. 335 */ 336static MachineBasicBlock::iterator findHBRPosition(MachineBasicBlock &MBB) 337{ 338 MachineBasicBlock::iterator J = MBB.end(); 339 for( int i=0; i<8; i++) { 340 if( J == MBB.begin() ) return J; 341 J--; 342 } 343 return J; 344} 345 346unsigned 347SPUInstrInfo::InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, 348 MachineBasicBlock *FBB, 349 const SmallVectorImpl<MachineOperand> &Cond, 350 DebugLoc DL) const { 351 // Shouldn't be a fall through. 352 assert(TBB && "InsertBranch must not be told to insert a fallthrough"); 353 assert((Cond.size() == 2 || Cond.size() == 0) && 354 "SPU branch conditions have two components!"); 355 356 MachineInstrBuilder MIB; 357 //TODO: make a more accurate algorithm. 358 bool haveHBR = MBB.size()>8; 359 360 removeHBR(MBB); 361 MCSymbol *branchLabel = MBB.getParent()->getContext().CreateTempSymbol(); 362 // Add a label just before the branch 363 if (haveHBR) 364 MIB = BuildMI(&MBB, DL, get(SPU::HBR_LABEL)).addSym(branchLabel); 365 366 // One-way branch. 367 if (FBB == 0) { 368 if (Cond.empty()) { 369 // Unconditional branch 370 MIB = BuildMI(&MBB, DL, get(SPU::BR)); 371 MIB.addMBB(TBB); 372 373 DEBUG(errs() << "Inserted one-way uncond branch: "); 374 DEBUG((*MIB).dump()); 375 376 // basic blocks have just one branch so it is safe to add the hint a its 377 if (haveHBR) { 378 MIB = BuildMI( MBB, findHBRPosition(MBB), DL, get(SPU::HBRA)); 379 MIB.addSym(branchLabel); 380 MIB.addMBB(TBB); 381 } 382 } else { 383 // Conditional branch 384 MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 385 MIB.addReg(Cond[1].getReg()).addMBB(TBB); 386 387 if (haveHBR) { 388 MIB = BuildMI(MBB, findHBRPosition(MBB), DL, get(SPU::HBRA)); 389 MIB.addSym(branchLabel); 390 MIB.addMBB(TBB); 391 } 392 393 DEBUG(errs() << "Inserted one-way cond branch: "); 394 DEBUG((*MIB).dump()); 395 } 396 return 1; 397 } else { 398 MIB = BuildMI(&MBB, DL, get(Cond[0].getImm())); 399 MachineInstrBuilder MIB2 = BuildMI(&MBB, DL, get(SPU::BR)); 400 401 // Two-way Conditional Branch. 402 MIB.addReg(Cond[1].getReg()).addMBB(TBB); 403 MIB2.addMBB(FBB); 404 405 if (haveHBR) { 406 MIB = BuildMI( MBB, findHBRPosition(MBB), DL, get(SPU::HBRA)); 407 MIB.addSym(branchLabel); 408 MIB.addMBB(FBB); 409 } 410 411 DEBUG(errs() << "Inserted conditional branch: "); 412 DEBUG((*MIB).dump()); 413 DEBUG(errs() << "part 2: "); 414 DEBUG((*MIB2).dump()); 415 return 2; 416 } 417} 418 419//! Reverses a branch's condition, returning false on success. 420bool 421SPUInstrInfo::ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) 422 const { 423 // Pretty brainless way of inverting the condition, but it works, considering 424 // there are only two conditions... 425 static struct { 426 unsigned Opc; //! The incoming opcode 427 unsigned RevCondOpc; //! The reversed condition opcode 428 } revconds[] = { 429 { SPU::BRNZr32, SPU::BRZr32 }, 430 { SPU::BRNZv4i32, SPU::BRZv4i32 }, 431 { SPU::BRZr32, SPU::BRNZr32 }, 432 { SPU::BRZv4i32, SPU::BRNZv4i32 }, 433 { SPU::BRHNZr16, SPU::BRHZr16 }, 434 { SPU::BRHNZv8i16, SPU::BRHZv8i16 }, 435 { SPU::BRHZr16, SPU::BRHNZr16 }, 436 { SPU::BRHZv8i16, SPU::BRHNZv8i16 } 437 }; 438 439 unsigned Opc = unsigned(Cond[0].getImm()); 440 // Pretty dull mapping between the two conditions that SPU can generate: 441 for (int i = sizeof(revconds)/sizeof(revconds[0]) - 1; i >= 0; --i) { 442 if (revconds[i].Opc == Opc) { 443 Cond[0].setImm(revconds[i].RevCondOpc); 444 return false; 445 } 446 } 447 448 return true; 449} 450