diff options
Diffstat (limited to 'contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp')
-rw-r--r-- | contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp b/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp new file mode 100644 index 000000000000..3d0d1cecd1f1 --- /dev/null +++ b/contrib/llvm/lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp @@ -0,0 +1,254 @@ +//===-- DelaySlotFiller.cpp - MBlaze delay slot filler --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A pass that attempts to fill instructions with delay slots. If no +// instructions can be moved into the delay slot then a NOP is placed there. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "delay-slot-filler" + +#include "MBlaze.h" +#include "MBlazeTargetMachine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +STATISTIC(FilledSlots, "Number of delay slots filled"); + +static cl::opt<bool> MBDisableDelaySlotFiller( + "disable-mblaze-delay-filler", + cl::init(false), + cl::desc("Disable the MBlaze delay slot filter."), + cl::Hidden); + +namespace { + struct Filler : public MachineFunctionPass { + + TargetMachine &TM; + const TargetInstrInfo *TII; + + static char ID; + Filler(TargetMachine &tm) + : MachineFunctionPass(ID), TM(tm), TII(tm.getInstrInfo()) { } + + virtual const char *getPassName() const { + return "MBlaze Delay Slot Filler"; + } + + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); + return Changed; + } + + }; + char Filler::ID = 0; +} // end of anonymous namespace + +static bool hasImmInstruction(MachineBasicBlock::iterator &candidate) { + // Any instruction with an immediate mode operand greater than + // 16-bits requires an implicit IMM instruction. + unsigned numOper = candidate->getNumOperands(); + for (unsigned op = 0; op < numOper; ++op) { + MachineOperand &mop = candidate->getOperand(op); + + // The operand requires more than 16-bits to represent. + if (mop.isImm() && (mop.getImm() < -0x8000 || mop.getImm() > 0x7fff)) + return true; + + // We must assume that unknown immediate values require more than + // 16-bits to represent. + if (mop.isGlobal() || mop.isSymbol() || mop.isJTI() || mop.isCPI()) + return true; + + // FIXME: we could probably check to see if the FP value happens + // to not need an IMM instruction. For now we just always + // assume that FP values do. + if (mop.isFPImm()) + return true; + } + + return false; +} + +static unsigned getLastRealOperand(MachineBasicBlock::iterator &instr) { + switch (instr->getOpcode()) { + default: return instr->getNumOperands(); + + // These instructions have a variable number of operands but the first two + // are the "real" operands that we care about during hazard detection. + case MBlaze::BRLID: + case MBlaze::BRALID: + case MBlaze::BRLD: + case MBlaze::BRALD: + return 2; + } +} + +static bool delayHasHazard(MachineBasicBlock::iterator &candidate, + MachineBasicBlock::iterator &slot) { + // Hazard check + MachineBasicBlock::iterator a = candidate; + MachineBasicBlock::iterator b = slot; + + // MBB layout:- + // candidate := a0 = operation(a1, a2) + // ...middle bit... + // slot := b0 = operation(b1, b2) + + // Possible hazards:-/ + // 1. a1 or a2 was written during the middle bit + // 2. a0 was read or written during the middle bit + // 3. a0 is one or more of {b0, b1, b2} + // 4. b0 is one or more of {a1, a2} + // 5. a accesses memory, and the middle bit + // contains a store operation. + bool a_is_memory = candidate->mayLoad() || candidate->mayStore(); + + // Determine the number of operands in the slot instruction and in the + // candidate instruction. + const unsigned aend = getLastRealOperand(a); + const unsigned bend = getLastRealOperand(b); + + // Check hazards type 1, 2 and 5 by scanning the middle bit + MachineBasicBlock::iterator m = a; + for (++m; m != b; ++m) { + for (unsigned aop = 0; aop<aend; ++aop) { + bool aop_is_reg = a->getOperand(aop).isReg(); + if (!aop_is_reg) continue; + + bool aop_is_def = a->getOperand(aop).isDef(); + unsigned aop_reg = a->getOperand(aop).getReg(); + + const unsigned mend = getLastRealOperand(m); + for (unsigned mop = 0; mop<mend; ++mop) { + bool mop_is_reg = m->getOperand(mop).isReg(); + if (!mop_is_reg) continue; + + bool mop_is_def = m->getOperand(mop).isDef(); + unsigned mop_reg = m->getOperand(mop).getReg(); + + if (aop_is_def && (mop_reg == aop_reg)) + return true; // Hazard type 2, because aop = a0 + else if (mop_is_def && (mop_reg == aop_reg)) + return true; // Hazard type 1, because aop in {a1, a2} + } + } + + // Check hazard type 5 + if (a_is_memory && m->mayStore()) + return true; + } + + // Check hazard type 3 & 4 + for (unsigned aop = 0; aop<aend; ++aop) { + if (a->getOperand(aop).isReg()) { + unsigned aop_reg = a->getOperand(aop).getReg(); + + for (unsigned bop = 0; bop<bend; ++bop) { + if (b->getOperand(bop).isReg() && !b->getOperand(bop).isImplicit()) { + unsigned bop_reg = b->getOperand(bop).getReg(); + if (aop_reg == bop_reg) + return true; + } + } + } + } + + return false; +} + +static bool isDelayFiller(MachineBasicBlock &MBB, + MachineBasicBlock::iterator candidate) { + if (candidate == MBB.begin()) + return false; + + --candidate; + return (candidate->hasDelaySlot()); +} + +static bool hasUnknownSideEffects(MachineBasicBlock::iterator &I) { + if (!I->hasUnmodeledSideEffects()) + return false; + + unsigned op = I->getOpcode(); + if (op == MBlaze::ADDK || op == MBlaze::ADDIK || + op == MBlaze::ADDC || op == MBlaze::ADDIC || + op == MBlaze::ADDKC || op == MBlaze::ADDIKC || + op == MBlaze::RSUBK || op == MBlaze::RSUBIK || + op == MBlaze::RSUBC || op == MBlaze::RSUBIC || + op == MBlaze::RSUBKC || op == MBlaze::RSUBIKC) + return false; + + return true; +} + +static MachineBasicBlock::iterator +findDelayInstr(MachineBasicBlock &MBB,MachineBasicBlock::iterator slot) { + MachineBasicBlock::iterator I = slot; + while (true) { + if (I == MBB.begin()) + break; + + --I; + if (I->hasDelaySlot() || I->isBranch() || isDelayFiller(MBB,I) || + I->isCall() || I->isReturn() || I->isBarrier() || + hasUnknownSideEffects(I)) + break; + + if (hasImmInstruction(I) || delayHasHazard(I,slot)) + continue; + + return I; + } + + return MBB.end(); +} + +/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. +/// Currently, we fill delay slots with NOPs. 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->hasDelaySlot()) { + MachineBasicBlock::iterator D = MBB.end(); + MachineBasicBlock::iterator J = I; + + if (!MBDisableDelaySlotFiller) + D = findDelayInstr(MBB,I); + + ++FilledSlots; + Changed = true; + + if (D == MBB.end()) + BuildMI(MBB, ++J, I->getDebugLoc(), TII->get(MBlaze::NOP)); + else + MBB.splice(++J, &MBB, D); + } + return Changed; +} + +/// createMBlazeDelaySlotFillerPass - Returns a pass that fills in delay +/// slots in MBlaze MachineFunctions +FunctionPass *llvm::createMBlazeDelaySlotFillerPass(MBlazeTargetMachine &tm) { + return new Filler(tm); +} + |