1*0b57cec5SDimitry Andric //===-- DelaySlotFiller.cpp - SPARC delay slot filler ---------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This is a simple local pass that attempts to fill delay slots with useful 10*0b57cec5SDimitry Andric // instructions. If no instructions can be moved into the delay slot, then a 11*0b57cec5SDimitry Andric // NOP is placed. 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "Sparc.h" 15*0b57cec5SDimitry Andric #include "SparcSubtarget.h" 16*0b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 17*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 18*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 21*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 23*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 24*0b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric using namespace llvm; 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric #define DEBUG_TYPE "delay-slot-filler" 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric STATISTIC(FilledSlots, "Number of delay slots filled"); 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric static cl::opt<bool> DisableDelaySlotFiller( 33*0b57cec5SDimitry Andric "disable-sparc-delay-filler", 34*0b57cec5SDimitry Andric cl::init(false), 35*0b57cec5SDimitry Andric cl::desc("Disable the Sparc delay slot filler."), 36*0b57cec5SDimitry Andric cl::Hidden); 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric namespace { 39*0b57cec5SDimitry Andric struct Filler : public MachineFunctionPass { 40*0b57cec5SDimitry Andric const SparcSubtarget *Subtarget; 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric static char ID; 43*0b57cec5SDimitry Andric Filler() : MachineFunctionPass(ID) {} 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric StringRef getPassName() const override { return "SPARC Delay Slot Filler"; } 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric bool runOnMachineBasicBlock(MachineBasicBlock &MBB); 48*0b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &F) override { 49*0b57cec5SDimitry Andric bool Changed = false; 50*0b57cec5SDimitry Andric Subtarget = &F.getSubtarget<SparcSubtarget>(); 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric // This pass invalidates liveness information when it reorders 53*0b57cec5SDimitry Andric // instructions to fill delay slot. 54*0b57cec5SDimitry Andric F.getRegInfo().invalidateLiveness(); 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric for (MachineFunction::iterator FI = F.begin(), FE = F.end(); 57*0b57cec5SDimitry Andric FI != FE; ++FI) 58*0b57cec5SDimitry Andric Changed |= runOnMachineBasicBlock(*FI); 59*0b57cec5SDimitry Andric return Changed; 60*0b57cec5SDimitry Andric } 61*0b57cec5SDimitry Andric 62*0b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 63*0b57cec5SDimitry Andric return MachineFunctionProperties().set( 64*0b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric void insertCallDefsUses(MachineBasicBlock::iterator MI, 68*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegDefs, 69*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegUses); 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric void insertDefsUses(MachineBasicBlock::iterator MI, 72*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegDefs, 73*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegUses); 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric bool IsRegInSet(SmallSet<unsigned, 32>& RegSet, 76*0b57cec5SDimitry Andric unsigned Reg); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric bool delayHasHazard(MachineBasicBlock::iterator candidate, 79*0b57cec5SDimitry Andric bool &sawLoad, bool &sawStore, 80*0b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegDefs, 81*0b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses); 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric MachineBasicBlock::iterator 84*0b57cec5SDimitry Andric findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot); 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize); 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, 89*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI); 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric }; 92*0b57cec5SDimitry Andric char Filler::ID = 0; 93*0b57cec5SDimitry Andric } // end of anonymous namespace 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric /// createSparcDelaySlotFillerPass - Returns a pass that fills in delay 96*0b57cec5SDimitry Andric /// slots in Sparc MachineFunctions 97*0b57cec5SDimitry Andric /// 98*0b57cec5SDimitry Andric FunctionPass *llvm::createSparcDelaySlotFillerPass() { 99*0b57cec5SDimitry Andric return new Filler; 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric /// runOnMachineBasicBlock - Fill in delay slots for the given basic block. 104*0b57cec5SDimitry Andric /// We assume there is only one delay slot per delayed instruction. 105*0b57cec5SDimitry Andric /// 106*0b57cec5SDimitry Andric bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { 107*0b57cec5SDimitry Andric bool Changed = false; 108*0b57cec5SDimitry Andric Subtarget = &MBB.getParent()->getSubtarget<SparcSubtarget>(); 109*0b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget->getInstrInfo(); 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { 112*0b57cec5SDimitry Andric MachineBasicBlock::iterator MI = I; 113*0b57cec5SDimitry Andric ++I; 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric // If MI is restore, try combining it with previous inst. 116*0b57cec5SDimitry Andric if (!DisableDelaySlotFiller && 117*0b57cec5SDimitry Andric (MI->getOpcode() == SP::RESTORErr 118*0b57cec5SDimitry Andric || MI->getOpcode() == SP::RESTOREri)) { 119*0b57cec5SDimitry Andric Changed |= tryCombineRestoreWithPrevInst(MBB, MI); 120*0b57cec5SDimitry Andric continue; 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric // TODO: If we ever want to support v7, this needs to be extended 124*0b57cec5SDimitry Andric // to cover all floating point operations. 125*0b57cec5SDimitry Andric if (!Subtarget->isV9() && 126*0b57cec5SDimitry Andric (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD 127*0b57cec5SDimitry Andric || MI->getOpcode() == SP::FCMPQ)) { 128*0b57cec5SDimitry Andric BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); 129*0b57cec5SDimitry Andric Changed = true; 130*0b57cec5SDimitry Andric continue; 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric // If MI has no delay slot, skip. 134*0b57cec5SDimitry Andric if (!MI->hasDelaySlot()) 135*0b57cec5SDimitry Andric continue; 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric MachineBasicBlock::iterator D = MBB.end(); 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric if (!DisableDelaySlotFiller) 140*0b57cec5SDimitry Andric D = findDelayInstr(MBB, MI); 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric ++FilledSlots; 143*0b57cec5SDimitry Andric Changed = true; 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric if (D == MBB.end()) 146*0b57cec5SDimitry Andric BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); 147*0b57cec5SDimitry Andric else 148*0b57cec5SDimitry Andric MBB.splice(I, &MBB, D); 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric unsigned structSize = 0; 151*0b57cec5SDimitry Andric if (needsUnimp(MI, structSize)) { 152*0b57cec5SDimitry Andric MachineBasicBlock::iterator J = MI; 153*0b57cec5SDimitry Andric ++J; // skip the delay filler. 154*0b57cec5SDimitry Andric assert (J != MBB.end() && "MI needs a delay instruction."); 155*0b57cec5SDimitry Andric BuildMI(MBB, ++J, MI->getDebugLoc(), 156*0b57cec5SDimitry Andric TII->get(SP::UNIMP)).addImm(structSize); 157*0b57cec5SDimitry Andric // Bundle the delay filler and unimp with the instruction. 158*0b57cec5SDimitry Andric MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J); 159*0b57cec5SDimitry Andric } else { 160*0b57cec5SDimitry Andric MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I); 161*0b57cec5SDimitry Andric } 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric return Changed; 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric MachineBasicBlock::iterator 167*0b57cec5SDimitry Andric Filler::findDelayInstr(MachineBasicBlock &MBB, 168*0b57cec5SDimitry Andric MachineBasicBlock::iterator slot) 169*0b57cec5SDimitry Andric { 170*0b57cec5SDimitry Andric SmallSet<unsigned, 32> RegDefs; 171*0b57cec5SDimitry Andric SmallSet<unsigned, 32> RegUses; 172*0b57cec5SDimitry Andric bool sawLoad = false; 173*0b57cec5SDimitry Andric bool sawStore = false; 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric if (slot == MBB.begin()) 176*0b57cec5SDimitry Andric return MBB.end(); 177*0b57cec5SDimitry Andric 178*0b57cec5SDimitry Andric if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL) 179*0b57cec5SDimitry Andric return MBB.end(); 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric if (slot->getOpcode() == SP::RETL) { 182*0b57cec5SDimitry Andric MachineBasicBlock::iterator J = slot; 183*0b57cec5SDimitry Andric --J; 184*0b57cec5SDimitry Andric 185*0b57cec5SDimitry Andric if (J->getOpcode() == SP::RESTORErr 186*0b57cec5SDimitry Andric || J->getOpcode() == SP::RESTOREri) { 187*0b57cec5SDimitry Andric // change retl to ret. 188*0b57cec5SDimitry Andric slot->setDesc(Subtarget->getInstrInfo()->get(SP::RET)); 189*0b57cec5SDimitry Andric return J; 190*0b57cec5SDimitry Andric } 191*0b57cec5SDimitry Andric } 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric // Call's delay filler can def some of call's uses. 194*0b57cec5SDimitry Andric if (slot->isCall()) 195*0b57cec5SDimitry Andric insertCallDefsUses(slot, RegDefs, RegUses); 196*0b57cec5SDimitry Andric else 197*0b57cec5SDimitry Andric insertDefsUses(slot, RegDefs, RegUses); 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric bool done = false; 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = slot; 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric while (!done) { 204*0b57cec5SDimitry Andric done = (I == MBB.begin()); 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric if (!done) 207*0b57cec5SDimitry Andric --I; 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric // skip debug instruction 210*0b57cec5SDimitry Andric if (I->isDebugInstr()) 211*0b57cec5SDimitry Andric continue; 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() || 214*0b57cec5SDimitry Andric I->hasDelaySlot() || I->isBundledWithSucc()) 215*0b57cec5SDimitry Andric break; 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { 218*0b57cec5SDimitry Andric insertDefsUses(I, RegDefs, RegUses); 219*0b57cec5SDimitry Andric continue; 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric 222*0b57cec5SDimitry Andric return I; 223*0b57cec5SDimitry Andric } 224*0b57cec5SDimitry Andric return MBB.end(); 225*0b57cec5SDimitry Andric } 226*0b57cec5SDimitry Andric 227*0b57cec5SDimitry Andric bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, 228*0b57cec5SDimitry Andric bool &sawLoad, 229*0b57cec5SDimitry Andric bool &sawStore, 230*0b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegDefs, 231*0b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses) 232*0b57cec5SDimitry Andric { 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric if (candidate->isImplicitDef() || candidate->isKill()) 235*0b57cec5SDimitry Andric return true; 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric if (candidate->mayLoad()) { 238*0b57cec5SDimitry Andric sawLoad = true; 239*0b57cec5SDimitry Andric if (sawStore) 240*0b57cec5SDimitry Andric return true; 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric 243*0b57cec5SDimitry Andric if (candidate->mayStore()) { 244*0b57cec5SDimitry Andric if (sawStore) 245*0b57cec5SDimitry Andric return true; 246*0b57cec5SDimitry Andric sawStore = true; 247*0b57cec5SDimitry Andric if (sawLoad) 248*0b57cec5SDimitry Andric return true; 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) { 252*0b57cec5SDimitry Andric const MachineOperand &MO = candidate->getOperand(i); 253*0b57cec5SDimitry Andric if (!MO.isReg()) 254*0b57cec5SDimitry Andric continue; // skip 255*0b57cec5SDimitry Andric 256*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 257*0b57cec5SDimitry Andric 258*0b57cec5SDimitry Andric if (MO.isDef()) { 259*0b57cec5SDimitry Andric // check whether Reg is defined or used before delay slot. 260*0b57cec5SDimitry Andric if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg)) 261*0b57cec5SDimitry Andric return true; 262*0b57cec5SDimitry Andric } 263*0b57cec5SDimitry Andric if (MO.isUse()) { 264*0b57cec5SDimitry Andric // check whether Reg is defined before delay slot. 265*0b57cec5SDimitry Andric if (IsRegInSet(RegDefs, Reg)) 266*0b57cec5SDimitry Andric return true; 267*0b57cec5SDimitry Andric } 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric unsigned Opcode = candidate->getOpcode(); 271*0b57cec5SDimitry Andric // LD and LDD may have NOPs inserted afterwards in the case of some LEON 272*0b57cec5SDimitry Andric // processors, so we can't use the delay slot if this feature is switched-on. 273*0b57cec5SDimitry Andric if (Subtarget->insertNOPLoad() 274*0b57cec5SDimitry Andric && 275*0b57cec5SDimitry Andric Opcode >= SP::LDDArr && Opcode <= SP::LDrr) 276*0b57cec5SDimitry Andric return true; 277*0b57cec5SDimitry Andric 278*0b57cec5SDimitry Andric // Same as above for FDIV and FSQRT on some LEON processors. 279*0b57cec5SDimitry Andric if (Subtarget->fixAllFDIVSQRT() 280*0b57cec5SDimitry Andric && 281*0b57cec5SDimitry Andric Opcode >= SP::FDIVD && Opcode <= SP::FSQRTD) 282*0b57cec5SDimitry Andric return true; 283*0b57cec5SDimitry Andric 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric return false; 286*0b57cec5SDimitry Andric } 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI, 290*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegDefs, 291*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegUses) 292*0b57cec5SDimitry Andric { 293*0b57cec5SDimitry Andric // Call defines o7, which is visible to the instruction in delay slot. 294*0b57cec5SDimitry Andric RegDefs.insert(SP::O7); 295*0b57cec5SDimitry Andric 296*0b57cec5SDimitry Andric switch(MI->getOpcode()) { 297*0b57cec5SDimitry Andric default: llvm_unreachable("Unknown opcode."); 298*0b57cec5SDimitry Andric case SP::CALL: break; 299*0b57cec5SDimitry Andric case SP::CALLrr: 300*0b57cec5SDimitry Andric case SP::CALLri: 301*0b57cec5SDimitry Andric assert(MI->getNumOperands() >= 2); 302*0b57cec5SDimitry Andric const MachineOperand &Reg = MI->getOperand(0); 303*0b57cec5SDimitry Andric assert(Reg.isReg() && "CALL first operand is not a register."); 304*0b57cec5SDimitry Andric assert(Reg.isUse() && "CALL first operand is not a use."); 305*0b57cec5SDimitry Andric RegUses.insert(Reg.getReg()); 306*0b57cec5SDimitry Andric 307*0b57cec5SDimitry Andric const MachineOperand &Operand1 = MI->getOperand(1); 308*0b57cec5SDimitry Andric if (Operand1.isImm() || Operand1.isGlobal()) 309*0b57cec5SDimitry Andric break; 310*0b57cec5SDimitry Andric assert(Operand1.isReg() && "CALLrr second operand is not a register."); 311*0b57cec5SDimitry Andric assert(Operand1.isUse() && "CALLrr second operand is not a use."); 312*0b57cec5SDimitry Andric RegUses.insert(Operand1.getReg()); 313*0b57cec5SDimitry Andric break; 314*0b57cec5SDimitry Andric } 315*0b57cec5SDimitry Andric } 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric // Insert Defs and Uses of MI into the sets RegDefs and RegUses. 318*0b57cec5SDimitry Andric void Filler::insertDefsUses(MachineBasicBlock::iterator MI, 319*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegDefs, 320*0b57cec5SDimitry Andric SmallSet<unsigned, 32>& RegUses) 321*0b57cec5SDimitry Andric { 322*0b57cec5SDimitry Andric for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { 323*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(i); 324*0b57cec5SDimitry Andric if (!MO.isReg()) 325*0b57cec5SDimitry Andric continue; 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 328*0b57cec5SDimitry Andric if (Reg == 0) 329*0b57cec5SDimitry Andric continue; 330*0b57cec5SDimitry Andric if (MO.isDef()) 331*0b57cec5SDimitry Andric RegDefs.insert(Reg); 332*0b57cec5SDimitry Andric if (MO.isUse()) { 333*0b57cec5SDimitry Andric // Implicit register uses of retl are return values and 334*0b57cec5SDimitry Andric // retl does not use them. 335*0b57cec5SDimitry Andric if (MO.isImplicit() && MI->getOpcode() == SP::RETL) 336*0b57cec5SDimitry Andric continue; 337*0b57cec5SDimitry Andric RegUses.insert(Reg); 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric } 340*0b57cec5SDimitry Andric } 341*0b57cec5SDimitry Andric 342*0b57cec5SDimitry Andric // returns true if the Reg or its alias is in the RegSet. 343*0b57cec5SDimitry Andric bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg) 344*0b57cec5SDimitry Andric { 345*0b57cec5SDimitry Andric // Check Reg and all aliased Registers. 346*0b57cec5SDimitry Andric for (MCRegAliasIterator AI(Reg, Subtarget->getRegisterInfo(), true); 347*0b57cec5SDimitry Andric AI.isValid(); ++AI) 348*0b57cec5SDimitry Andric if (RegSet.count(*AI)) 349*0b57cec5SDimitry Andric return true; 350*0b57cec5SDimitry Andric return false; 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric 353*0b57cec5SDimitry Andric bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) 354*0b57cec5SDimitry Andric { 355*0b57cec5SDimitry Andric if (!I->isCall()) 356*0b57cec5SDimitry Andric return false; 357*0b57cec5SDimitry Andric 358*0b57cec5SDimitry Andric unsigned structSizeOpNum = 0; 359*0b57cec5SDimitry Andric switch (I->getOpcode()) { 360*0b57cec5SDimitry Andric default: llvm_unreachable("Unknown call opcode."); 361*0b57cec5SDimitry Andric case SP::CALL: structSizeOpNum = 1; break; 362*0b57cec5SDimitry Andric case SP::CALLrr: 363*0b57cec5SDimitry Andric case SP::CALLri: structSizeOpNum = 2; break; 364*0b57cec5SDimitry Andric case SP::TLS_CALL: return false; 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric const MachineOperand &MO = I->getOperand(structSizeOpNum); 368*0b57cec5SDimitry Andric if (!MO.isImm()) 369*0b57cec5SDimitry Andric return false; 370*0b57cec5SDimitry Andric StructSize = MO.getImm(); 371*0b57cec5SDimitry Andric return true; 372*0b57cec5SDimitry Andric } 373*0b57cec5SDimitry Andric 374*0b57cec5SDimitry Andric static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI, 375*0b57cec5SDimitry Andric MachineBasicBlock::iterator AddMI, 376*0b57cec5SDimitry Andric const TargetInstrInfo *TII) 377*0b57cec5SDimitry Andric { 378*0b57cec5SDimitry Andric // Before: add <op0>, <op1>, %i[0-7] 379*0b57cec5SDimitry Andric // restore %g0, %g0, %i[0-7] 380*0b57cec5SDimitry Andric // 381*0b57cec5SDimitry Andric // After : restore <op0>, <op1>, %o[0-7] 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric unsigned reg = AddMI->getOperand(0).getReg(); 384*0b57cec5SDimitry Andric if (reg < SP::I0 || reg > SP::I7) 385*0b57cec5SDimitry Andric return false; 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric // Erase RESTORE. 388*0b57cec5SDimitry Andric RestoreMI->eraseFromParent(); 389*0b57cec5SDimitry Andric 390*0b57cec5SDimitry Andric // Change ADD to RESTORE. 391*0b57cec5SDimitry Andric AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr) 392*0b57cec5SDimitry Andric ? SP::RESTORErr 393*0b57cec5SDimitry Andric : SP::RESTOREri)); 394*0b57cec5SDimitry Andric 395*0b57cec5SDimitry Andric // Map the destination register. 396*0b57cec5SDimitry Andric AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); 397*0b57cec5SDimitry Andric 398*0b57cec5SDimitry Andric return true; 399*0b57cec5SDimitry Andric } 400*0b57cec5SDimitry Andric 401*0b57cec5SDimitry Andric static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI, 402*0b57cec5SDimitry Andric MachineBasicBlock::iterator OrMI, 403*0b57cec5SDimitry Andric const TargetInstrInfo *TII) 404*0b57cec5SDimitry Andric { 405*0b57cec5SDimitry Andric // Before: or <op0>, <op1>, %i[0-7] 406*0b57cec5SDimitry Andric // restore %g0, %g0, %i[0-7] 407*0b57cec5SDimitry Andric // and <op0> or <op1> is zero, 408*0b57cec5SDimitry Andric // 409*0b57cec5SDimitry Andric // After : restore <op0>, <op1>, %o[0-7] 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric unsigned reg = OrMI->getOperand(0).getReg(); 412*0b57cec5SDimitry Andric if (reg < SP::I0 || reg > SP::I7) 413*0b57cec5SDimitry Andric return false; 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric // check whether it is a copy. 416*0b57cec5SDimitry Andric if (OrMI->getOpcode() == SP::ORrr 417*0b57cec5SDimitry Andric && OrMI->getOperand(1).getReg() != SP::G0 418*0b57cec5SDimitry Andric && OrMI->getOperand(2).getReg() != SP::G0) 419*0b57cec5SDimitry Andric return false; 420*0b57cec5SDimitry Andric 421*0b57cec5SDimitry Andric if (OrMI->getOpcode() == SP::ORri 422*0b57cec5SDimitry Andric && OrMI->getOperand(1).getReg() != SP::G0 423*0b57cec5SDimitry Andric && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0)) 424*0b57cec5SDimitry Andric return false; 425*0b57cec5SDimitry Andric 426*0b57cec5SDimitry Andric // Erase RESTORE. 427*0b57cec5SDimitry Andric RestoreMI->eraseFromParent(); 428*0b57cec5SDimitry Andric 429*0b57cec5SDimitry Andric // Change OR to RESTORE. 430*0b57cec5SDimitry Andric OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr) 431*0b57cec5SDimitry Andric ? SP::RESTORErr 432*0b57cec5SDimitry Andric : SP::RESTOREri)); 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric // Map the destination register. 435*0b57cec5SDimitry Andric OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric return true; 438*0b57cec5SDimitry Andric } 439*0b57cec5SDimitry Andric 440*0b57cec5SDimitry Andric static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI, 441*0b57cec5SDimitry Andric MachineBasicBlock::iterator SetHiMI, 442*0b57cec5SDimitry Andric const TargetInstrInfo *TII) 443*0b57cec5SDimitry Andric { 444*0b57cec5SDimitry Andric // Before: sethi imm3, %i[0-7] 445*0b57cec5SDimitry Andric // restore %g0, %g0, %g0 446*0b57cec5SDimitry Andric // 447*0b57cec5SDimitry Andric // After : restore %g0, (imm3<<10), %o[0-7] 448*0b57cec5SDimitry Andric 449*0b57cec5SDimitry Andric unsigned reg = SetHiMI->getOperand(0).getReg(); 450*0b57cec5SDimitry Andric if (reg < SP::I0 || reg > SP::I7) 451*0b57cec5SDimitry Andric return false; 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric if (!SetHiMI->getOperand(1).isImm()) 454*0b57cec5SDimitry Andric return false; 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric int64_t imm = SetHiMI->getOperand(1).getImm(); 457*0b57cec5SDimitry Andric 458*0b57cec5SDimitry Andric // Is it a 3 bit immediate? 459*0b57cec5SDimitry Andric if (!isInt<3>(imm)) 460*0b57cec5SDimitry Andric return false; 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric // Make it a 13 bit immediate. 463*0b57cec5SDimitry Andric imm = (imm << 10) & 0x1FFF; 464*0b57cec5SDimitry Andric 465*0b57cec5SDimitry Andric assert(RestoreMI->getOpcode() == SP::RESTORErr); 466*0b57cec5SDimitry Andric 467*0b57cec5SDimitry Andric RestoreMI->setDesc(TII->get(SP::RESTOREri)); 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); 470*0b57cec5SDimitry Andric RestoreMI->getOperand(1).setReg(SP::G0); 471*0b57cec5SDimitry Andric RestoreMI->getOperand(2).ChangeToImmediate(imm); 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric 474*0b57cec5SDimitry Andric // Erase the original SETHI. 475*0b57cec5SDimitry Andric SetHiMI->eraseFromParent(); 476*0b57cec5SDimitry Andric 477*0b57cec5SDimitry Andric return true; 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, 481*0b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI) 482*0b57cec5SDimitry Andric { 483*0b57cec5SDimitry Andric // No previous instruction. 484*0b57cec5SDimitry Andric if (MBBI == MBB.begin()) 485*0b57cec5SDimitry Andric return false; 486*0b57cec5SDimitry Andric 487*0b57cec5SDimitry Andric // assert that MBBI is a "restore %g0, %g0, %g0". 488*0b57cec5SDimitry Andric assert(MBBI->getOpcode() == SP::RESTORErr 489*0b57cec5SDimitry Andric && MBBI->getOperand(0).getReg() == SP::G0 490*0b57cec5SDimitry Andric && MBBI->getOperand(1).getReg() == SP::G0 491*0b57cec5SDimitry Andric && MBBI->getOperand(2).getReg() == SP::G0); 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric MachineBasicBlock::iterator PrevInst = std::prev(MBBI); 494*0b57cec5SDimitry Andric 495*0b57cec5SDimitry Andric // It cannot be combined with a bundled instruction. 496*0b57cec5SDimitry Andric if (PrevInst->isBundledWithSucc()) 497*0b57cec5SDimitry Andric return false; 498*0b57cec5SDimitry Andric 499*0b57cec5SDimitry Andric const TargetInstrInfo *TII = Subtarget->getInstrInfo(); 500*0b57cec5SDimitry Andric 501*0b57cec5SDimitry Andric switch (PrevInst->getOpcode()) { 502*0b57cec5SDimitry Andric default: break; 503*0b57cec5SDimitry Andric case SP::ADDrr: 504*0b57cec5SDimitry Andric case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break; 505*0b57cec5SDimitry Andric case SP::ORrr: 506*0b57cec5SDimitry Andric case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break; 507*0b57cec5SDimitry Andric case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break; 508*0b57cec5SDimitry Andric } 509*0b57cec5SDimitry Andric // It cannot combine with the previous instruction. 510*0b57cec5SDimitry Andric return false; 511*0b57cec5SDimitry Andric } 512