X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FSparc%2FDelaySlotFiller.cpp;h=28369fd5c342f064f3a44744af7fadcd0e4a9c36;hb=aa5b9c0f6f3a99f955fe0ded13d61d7eb4e1a0b5;hp=b0d669b860f1ed3fccc21252b7c5ca4fdaf5cc6e;hpb=71e39dac0ce9676dd3d0a92164167e18499d40fa;p=oota-llvm.git diff --git a/lib/Target/Sparc/DelaySlotFiller.cpp b/lib/Target/Sparc/DelaySlotFiller.cpp index b0d669b860f..28369fd5c34 100644 --- a/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/lib/Target/Sparc/DelaySlotFiller.cpp @@ -12,19 +12,22 @@ // NOP is placed. //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "delay-slot-filler" #include "Sparc.h" +#include "SparcSubtarget.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/Statistic.h" using namespace llvm; +#define DEBUG_TYPE "delay-slot-filler" + STATISTIC(FilledSlots, "Number of delay slots filled"); static cl::opt DisableDelaySlotFiller( @@ -39,30 +42,35 @@ namespace { /// layout, etc. /// TargetMachine &TM; - const TargetInstrInfo *TII; + const SparcSubtarget *Subtarget; static char ID; - Filler(TargetMachine &tm) - : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } + Filler(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), + Subtarget(&TM.getSubtarget()) { + } - virtual const char *getPassName() const { + const char *getPassName() const override { return "SPARC Delay Slot Filler"; } bool runOnMachineBasicBlock(MachineBasicBlock &MBB); - bool runOnMachineFunction(MachineFunction &F) { + bool runOnMachineFunction(MachineFunction &F) override { bool Changed = false; + + // This pass invalidates liveness information when it reorders + // instructions to fill delay slot. + F.getRegInfo().invalidateLiveness(); + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI) Changed |= runOnMachineBasicBlock(*FI); return Changed; } - bool isDelayFiller(MachineBasicBlock &MBB, - MachineBasicBlock::iterator candidate); - - void insertCallUses(MachineBasicBlock::iterator MI, - SmallSet& RegUses); + void insertCallDefsUses(MachineBasicBlock::iterator MI, + SmallSet& RegDefs, + SmallSet& RegUses); void insertDefsUses(MachineBasicBlock::iterator MI, SmallSet& RegDefs, @@ -79,6 +87,10 @@ namespace { MachineBasicBlock::iterator findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot); + bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize); + + bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); }; char Filler::ID = 0; @@ -91,28 +103,65 @@ FunctionPass *llvm::createSparcDelaySlotFillerPass(TargetMachine &tm) { return new Filler(tm); } + /// runOnMachineBasicBlock - Fill in delay slots for the given basic block. /// We assume there is only one delay slot per delayed instruction. /// bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; - for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ++I) - if (I->getDesc().hasDelaySlot()) { - MachineBasicBlock::iterator D = MBB.end(); - MachineBasicBlock::iterator J = I; + const TargetInstrInfo *TII = TM.getSubtargetImpl()->getInstrInfo(); + + for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { + MachineBasicBlock::iterator MI = I; + ++I; - if (!DisableDelaySlotFiller) - D = findDelayInstr(MBB, I); + // If MI is restore, try combining it with previous inst. + if (!DisableDelaySlotFiller && + (MI->getOpcode() == SP::RESTORErr + || MI->getOpcode() == SP::RESTOREri)) { + Changed |= tryCombineRestoreWithPrevInst(MBB, MI); + continue; + } - ++FilledSlots; + if (!Subtarget->isV9() && + (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD + || MI->getOpcode() == SP::FCMPQ)) { + BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); Changed = true; + continue; + } + + // If MI has no delay slot, skip. + if (!MI->hasDelaySlot()) + continue; - if (D == MBB.end()) - BuildMI(MBB, ++J, I->getDebugLoc(), TII->get(SP::NOP)); - else - MBB.splice(++J, &MBB, D); + MachineBasicBlock::iterator D = MBB.end(); + + if (!DisableDelaySlotFiller) + D = findDelayInstr(MBB, MI); + + ++FilledSlots; + Changed = true; + + if (D == MBB.end()) + BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP)); + else + MBB.splice(I, &MBB, D); + + unsigned structSize = 0; + if (needsUnimp(MI, structSize)) { + MachineBasicBlock::iterator J = MI; + ++J; // skip the delay filler. + assert (J != MBB.end() && "MI needs a delay instruction."); + BuildMI(MBB, ++J, MI->getDebugLoc(), + TII->get(SP::UNIMP)).addImm(structSize); + // Bundle the delay filler and unimp with the instruction. + MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J); + } else { + MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I); } + } return Changed; } @@ -125,28 +174,34 @@ Filler::findDelayInstr(MachineBasicBlock &MBB, bool sawLoad = false; bool sawStore = false; - MachineBasicBlock::iterator I = slot; + if (slot == MBB.begin()) + return MBB.end(); - if (slot->getOpcode() == SP::RET) + if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL) return MBB.end(); if (slot->getOpcode() == SP::RETL) { - --I; - if (I->getOpcode() != SP::RESTORErr) - return MBB.end(); - //change retl to ret - slot->setDesc(TII->get(SP::RET)); - return I; + MachineBasicBlock::iterator J = slot; + --J; + + if (J->getOpcode() == SP::RESTORErr + || J->getOpcode() == SP::RESTOREri) { + // change retl to ret. + slot->setDesc(TM.getSubtargetImpl()->getInstrInfo()->get(SP::RET)); + return J; + } } - //Call's delay filler can def some of call's uses. - if (slot->getDesc().isCall()) - insertCallUses(slot, RegUses); + // Call's delay filler can def some of call's uses. + if (slot->isCall()) + insertCallDefsUses(slot, RegDefs, RegUses); else insertDefsUses(slot, RegDefs, RegUses); bool done = false; + MachineBasicBlock::iterator I = slot; + while (!done) { done = (I == MBB.begin()); @@ -157,12 +212,8 @@ Filler::findDelayInstr(MachineBasicBlock &MBB, if (I->isDebugValue()) continue; - - if (I->hasUnmodeledSideEffects() - || I->isInlineAsm() - || I->isLabel() - || I->getDesc().hasDelaySlot() - || isDelayFiller(MBB, I)) + if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() || + I->hasDelaySlot() || I->isBundledWithSucc()) break; if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { @@ -182,13 +233,16 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, SmallSet &RegUses) { - if (candidate->getDesc().mayLoad()) { + if (candidate->isImplicitDef() || candidate->isKill()) + return true; + + if (candidate->mayLoad()) { sawLoad = true; if (sawStore) return true; } - if (candidate->getDesc().mayStore()) { + if (candidate->mayStore()) { if (sawStore) return true; sawStore = true; @@ -204,12 +258,12 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, unsigned Reg = MO.getReg(); if (MO.isDef()) { - //check whether Reg is defined or used before delay slot. + // check whether Reg is defined or used before delay slot. if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg)) return true; } if (MO.isUse()) { - //check whether Reg is defined before delay slot. + // check whether Reg is defined before delay slot. if (IsRegInSet(RegDefs, Reg)) return true; } @@ -218,32 +272,35 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, } -void Filler::insertCallUses(MachineBasicBlock::iterator MI, - SmallSet& RegUses) +void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI, + SmallSet& RegDefs, + SmallSet& RegUses) { + // Call defines o7, which is visible to the instruction in delay slot. + RegDefs.insert(SP::O7); switch(MI->getOpcode()) { default: llvm_unreachable("Unknown opcode."); case SP::CALL: break; - case SP::JMPLrr: - case SP::JMPLri: + case SP::CALLrr: + case SP::CALLri: assert(MI->getNumOperands() >= 2); const MachineOperand &Reg = MI->getOperand(0); - assert(Reg.isReg() && "JMPL first operand is not a register."); - assert(Reg.isUse() && "JMPL first operand is not a use."); + assert(Reg.isReg() && "CALL first operand is not a register."); + assert(Reg.isUse() && "CALL first operand is not a use."); RegUses.insert(Reg.getReg()); const MachineOperand &RegOrImm = MI->getOperand(1); if (RegOrImm.isImm()) break; - assert(RegOrImm.isReg() && "JMPLrr second operand is not a register."); - assert(RegOrImm.isUse() && "JMPLrr second operand is not a use."); + assert(RegOrImm.isReg() && "CALLrr second operand is not a register."); + assert(RegOrImm.isUse() && "CALLrr second operand is not a use."); RegUses.insert(RegOrImm.getReg()); break; } } -//Insert Defs and Uses of MI into the sets RegDefs and RegUses. +// Insert Defs and Uses of MI into the sets RegDefs and RegUses. void Filler::insertDefsUses(MachineBasicBlock::iterator MI, SmallSet& RegDefs, SmallSet& RegUses) @@ -258,32 +315,184 @@ void Filler::insertDefsUses(MachineBasicBlock::iterator MI, continue; if (MO.isDef()) RegDefs.insert(Reg); - if (MO.isUse()) + if (MO.isUse()) { + // Implicit register uses of retl are return values and + // retl does not use them. + if (MO.isImplicit() && MI->getOpcode() == SP::RETL) + continue; RegUses.insert(Reg); - + } } } -//returns true if the Reg or its alias is in the RegSet. +// returns true if the Reg or its alias is in the RegSet. bool Filler::IsRegInSet(SmallSet& RegSet, unsigned Reg) { - if (RegSet.count(Reg)) - return true; - // check Aliased Registers - for (const unsigned *Alias = TM.getRegisterInfo()->getAliasSet(Reg); - *Alias; ++ Alias) - if (RegSet.count(*Alias)) + // Check Reg and all aliased Registers. + for (MCRegAliasIterator AI(Reg, TM.getSubtargetImpl()->getRegisterInfo(), + true); + AI.isValid(); ++AI) + if (RegSet.count(*AI)) return true; - return false; } -// return true if the candidate is a delay filler. -bool Filler::isDelayFiller(MachineBasicBlock &MBB, - MachineBasicBlock::iterator candidate) +bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) +{ + if (!I->isCall()) + return false; + + unsigned structSizeOpNum = 0; + switch (I->getOpcode()) { + default: llvm_unreachable("Unknown call opcode."); + case SP::CALL: structSizeOpNum = 1; break; + case SP::CALLrr: + case SP::CALLri: structSizeOpNum = 2; break; + case SP::TLS_CALL: return false; + } + + const MachineOperand &MO = I->getOperand(structSizeOpNum); + if (!MO.isImm()) + return false; + StructSize = MO.getImm(); + return true; +} + +static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI, + MachineBasicBlock::iterator AddMI, + const TargetInstrInfo *TII) +{ + // Before: add , , %i[0-7] + // restore %g0, %g0, %i[0-7] + // + // After : restore , , %o[0-7] + + unsigned reg = AddMI->getOperand(0).getReg(); + if (reg < SP::I0 || reg > SP::I7) + return false; + + // Erase RESTORE. + RestoreMI->eraseFromParent(); + + // Change ADD to RESTORE. + AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr) + ? SP::RESTORErr + : SP::RESTOREri)); + + // Map the destination register. + AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); + + return true; +} + +static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI, + MachineBasicBlock::iterator OrMI, + const TargetInstrInfo *TII) +{ + // Before: or , , %i[0-7] + // restore %g0, %g0, %i[0-7] + // and or is zero, + // + // After : restore , , %o[0-7] + + unsigned reg = OrMI->getOperand(0).getReg(); + if (reg < SP::I0 || reg > SP::I7) + return false; + + // check whether it is a copy. + if (OrMI->getOpcode() == SP::ORrr + && OrMI->getOperand(1).getReg() != SP::G0 + && OrMI->getOperand(2).getReg() != SP::G0) + return false; + + if (OrMI->getOpcode() == SP::ORri + && OrMI->getOperand(1).getReg() != SP::G0 + && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0)) + return false; + + // Erase RESTORE. + RestoreMI->eraseFromParent(); + + // Change OR to RESTORE. + OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr) + ? SP::RESTORErr + : SP::RESTOREri)); + + // Map the destination register. + OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); + + return true; +} + +static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI, + MachineBasicBlock::iterator SetHiMI, + const TargetInstrInfo *TII) { - if (candidate == MBB.begin()) + // Before: sethi imm3, %i[0-7] + // restore %g0, %g0, %g0 + // + // After : restore %g0, (imm3<<10), %o[0-7] + + unsigned reg = SetHiMI->getOperand(0).getReg(); + if (reg < SP::I0 || reg > SP::I7) return false; - const TargetInstrDesc &prevdesc = (--candidate)->getDesc(); - return prevdesc.hasDelaySlot(); + + if (!SetHiMI->getOperand(1).isImm()) + return false; + + int64_t imm = SetHiMI->getOperand(1).getImm(); + + // Is it a 3 bit immediate? + if (!isInt<3>(imm)) + return false; + + // Make it a 13 bit immediate. + imm = (imm << 10) & 0x1FFF; + + assert(RestoreMI->getOpcode() == SP::RESTORErr); + + RestoreMI->setDesc(TII->get(SP::RESTOREri)); + + RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); + RestoreMI->getOperand(1).setReg(SP::G0); + RestoreMI->getOperand(2).ChangeToImmediate(imm); + + + // Erase the original SETHI. + SetHiMI->eraseFromParent(); + + return true; +} + +bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) +{ + // No previous instruction. + if (MBBI == MBB.begin()) + return false; + + // assert that MBBI is a "restore %g0, %g0, %g0". + assert(MBBI->getOpcode() == SP::RESTORErr + && MBBI->getOperand(0).getReg() == SP::G0 + && MBBI->getOperand(1).getReg() == SP::G0 + && MBBI->getOperand(2).getReg() == SP::G0); + + MachineBasicBlock::iterator PrevInst = std::prev(MBBI); + + // It cannot be combined with a bundled instruction. + if (PrevInst->isBundledWithSucc()) + return false; + + const TargetInstrInfo *TII = TM.getSubtargetImpl()->getInstrInfo(); + + switch (PrevInst->getOpcode()) { + default: break; + case SP::ADDrr: + case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break; + case SP::ORrr: + case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break; + case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break; + } + // It cannot combine with the previous instruction. + return false; }