summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
committerpatrick <patrick@openbsd.org>2020-08-03 15:06:44 +0000
commitb64793999546ed8adebaeebd9d8345d18db8927d (patch)
tree4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
parentAdd support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff)
downloadwireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz
wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp')
-rw-r--r--gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp934
1 files changed, 0 insertions, 934 deletions
diff --git a/gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp b/gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
deleted file mode 100644
index 61e77fbeea6..00000000000
--- a/gnu/llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
+++ /dev/null
@@ -1,934 +0,0 @@
-//===- MipsDelaySlotFiller.cpp - Mips Delay Slot Filler -------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Simple pass to fill delay slots with useful instructions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "MCTargetDesc/MipsMCNaCl.h"
-#include "Mips.h"
-#include "MipsInstrInfo.h"
-#include "MipsRegisterInfo.h"
-#include "MipsSubtarget.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/PointerUnion.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Analysis/AliasAnalysis.h"
-#include "llvm/Analysis/ValueTracking.h"
-#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineFunctionPass.h"
-#include "llvm/CodeGen/MachineInstr.h"
-#include "llvm/CodeGen/MachineInstrBuilder.h"
-#include "llvm/CodeGen/MachineOperand.h"
-#include "llvm/CodeGen/MachineRegisterInfo.h"
-#include "llvm/CodeGen/PseudoSourceValue.h"
-#include "llvm/CodeGen/TargetRegisterInfo.h"
-#include "llvm/CodeGen/TargetSubtargetInfo.h"
-#include "llvm/MC/MCInstrDesc.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Target/TargetMachine.h"
-#include <algorithm>
-#include <cassert>
-#include <iterator>
-#include <memory>
-#include <utility>
-
-using namespace llvm;
-
-#define DEBUG_TYPE "mips-delay-slot-filler"
-
-STATISTIC(FilledSlots, "Number of delay slots filled");
-STATISTIC(UsefulSlots, "Number of delay slots filled with instructions that"
- " are not NOP.");
-
-static cl::opt<bool> DisableDelaySlotFiller(
- "disable-mips-delay-filler",
- cl::init(false),
- cl::desc("Fill all delay slots with NOPs."),
- cl::Hidden);
-
-static cl::opt<bool> DisableForwardSearch(
- "disable-mips-df-forward-search",
- cl::init(true),
- cl::desc("Disallow MIPS delay filler to search forward."),
- cl::Hidden);
-
-static cl::opt<bool> DisableSuccBBSearch(
- "disable-mips-df-succbb-search",
- cl::init(true),
- cl::desc("Disallow MIPS delay filler to search successor basic blocks."),
- cl::Hidden);
-
-static cl::opt<bool> DisableBackwardSearch(
- "disable-mips-df-backward-search",
- cl::init(false),
- cl::desc("Disallow MIPS delay filler to search backward."),
- cl::Hidden);
-
-enum CompactBranchPolicy {
- CB_Never, ///< The policy 'never' may in some circumstances or for some
- ///< ISAs not be absolutely adhered to.
- CB_Optimal, ///< Optimal is the default and will produce compact branches
- ///< when delay slots cannot be filled.
- CB_Always ///< 'always' may in some circumstances may not be
- ///< absolutely adhered to there may not be a corresponding
- ///< compact form of a branch.
-};
-
-static cl::opt<CompactBranchPolicy> MipsCompactBranchPolicy(
- "mips-compact-branches",cl::Optional,
- cl::init(CB_Optimal),
- cl::desc("MIPS Specific: Compact branch policy."),
- cl::values(
- clEnumValN(CB_Never, "never", "Do not use compact branches if possible."),
- clEnumValN(CB_Optimal, "optimal", "Use compact branches where appropiate (default)."),
- clEnumValN(CB_Always, "always", "Always use compact branches if possible.")
- )
-);
-
-namespace {
-
- using Iter = MachineBasicBlock::iterator;
- using ReverseIter = MachineBasicBlock::reverse_iterator;
- using BB2BrMap = SmallDenseMap<MachineBasicBlock *, MachineInstr *, 2>;
-
- class RegDefsUses {
- public:
- RegDefsUses(const TargetRegisterInfo &TRI);
-
- void init(const MachineInstr &MI);
-
- /// This function sets all caller-saved registers in Defs.
- void setCallerSaved(const MachineInstr &MI);
-
- /// This function sets all unallocatable registers in Defs.
- void setUnallocatableRegs(const MachineFunction &MF);
-
- /// Set bits in Uses corresponding to MBB's live-out registers except for
- /// the registers that are live-in to SuccBB.
- void addLiveOut(const MachineBasicBlock &MBB,
- const MachineBasicBlock &SuccBB);
-
- bool update(const MachineInstr &MI, unsigned Begin, unsigned End);
-
- private:
- bool checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses, unsigned Reg,
- bool IsDef) const;
-
- /// Returns true if Reg or its alias is in RegSet.
- bool isRegInSet(const BitVector &RegSet, unsigned Reg) const;
-
- const TargetRegisterInfo &TRI;
- BitVector Defs, Uses;
- };
-
- /// Base class for inspecting loads and stores.
- class InspectMemInstr {
- public:
- InspectMemInstr(bool ForbidMemInstr_) : ForbidMemInstr(ForbidMemInstr_) {}
- virtual ~InspectMemInstr() = default;
-
- /// Return true if MI cannot be moved to delay slot.
- bool hasHazard(const MachineInstr &MI);
-
- protected:
- /// Flags indicating whether loads or stores have been seen.
- bool OrigSeenLoad = false;
- bool OrigSeenStore = false;
- bool SeenLoad = false;
- bool SeenStore = false;
-
- /// Memory instructions are not allowed to move to delay slot if this flag
- /// is true.
- bool ForbidMemInstr;
-
- private:
- virtual bool hasHazard_(const MachineInstr &MI) = 0;
- };
-
- /// This subclass rejects any memory instructions.
- class NoMemInstr : public InspectMemInstr {
- public:
- NoMemInstr() : InspectMemInstr(true) {}
-
- private:
- bool hasHazard_(const MachineInstr &MI) override { return true; }
- };
-
- /// This subclass accepts loads from stacks and constant loads.
- class LoadFromStackOrConst : public InspectMemInstr {
- public:
- LoadFromStackOrConst() : InspectMemInstr(false) {}
-
- private:
- bool hasHazard_(const MachineInstr &MI) override;
- };
-
- /// This subclass uses memory dependence information to determine whether a
- /// memory instruction can be moved to a delay slot.
- class MemDefsUses : public InspectMemInstr {
- public:
- MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI);
-
- private:
- using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
-
- bool hasHazard_(const MachineInstr &MI) override;
-
- /// Update Defs and Uses. Return true if there exist dependences that
- /// disqualify the delay slot candidate between V and values in Uses and
- /// Defs.
- bool updateDefsUses(ValueType V, bool MayStore);
-
- /// Get the list of underlying objects of MI's memory operand.
- bool getUnderlyingObjects(const MachineInstr &MI,
- SmallVectorImpl<ValueType> &Objects) const;
-
- const MachineFrameInfo *MFI;
- SmallPtrSet<ValueType, 4> Uses, Defs;
- const DataLayout &DL;
-
- /// Flags indicating whether loads or stores with no underlying objects have
- /// been seen.
- bool SeenNoObjLoad = false;
- bool SeenNoObjStore = false;
- };
-
- class MipsDelaySlotFiller : public MachineFunctionPass {
- public:
- MipsDelaySlotFiller() : MachineFunctionPass(ID) {
- initializeMipsDelaySlotFillerPass(*PassRegistry::getPassRegistry());
- }
-
- StringRef getPassName() const override { return "Mips Delay Slot Filler"; }
-
- bool runOnMachineFunction(MachineFunction &F) override {
- TM = &F.getTarget();
- bool Changed = false;
- for (MachineFunction::iterator FI = F.begin(), FE = F.end();
- FI != FE; ++FI)
- Changed |= runOnMachineBasicBlock(*FI);
-
- // This pass invalidates liveness information when it reorders
- // instructions to fill delay slot. Without this, -verify-machineinstrs
- // will fail.
- if (Changed)
- F.getRegInfo().invalidateLiveness();
-
- return Changed;
- }
-
- MachineFunctionProperties getRequiredProperties() const override {
- return MachineFunctionProperties().set(
- MachineFunctionProperties::Property::NoVRegs);
- }
-
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<MachineBranchProbabilityInfo>();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
-
- static char ID;
-
- private:
- bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
-
- Iter replaceWithCompactBranch(MachineBasicBlock &MBB, Iter Branch,
- const DebugLoc &DL);
-
- /// This function checks if it is valid to move Candidate to the delay slot
- /// and returns true if it isn't. It also updates memory and register
- /// dependence information.
- bool delayHasHazard(const MachineInstr &Candidate, RegDefsUses &RegDU,
- InspectMemInstr &IM) const;
-
- /// This function searches range [Begin, End) for an instruction that can be
- /// moved to the delay slot. Returns true on success.
- template<typename IterTy>
- bool searchRange(MachineBasicBlock &MBB, IterTy Begin, IterTy End,
- RegDefsUses &RegDU, InspectMemInstr &IM, Iter Slot,
- IterTy &Filler) const;
-
- /// This function searches in the backward direction for an instruction that
- /// can be moved to the delay slot. Returns true on success.
- bool searchBackward(MachineBasicBlock &MBB, MachineInstr &Slot) const;
-
- /// This function searches MBB in the forward direction for an instruction
- /// that can be moved to the delay slot. Returns true on success.
- bool searchForward(MachineBasicBlock &MBB, Iter Slot) const;
-
- /// This function searches one of MBB's successor blocks for an instruction
- /// that can be moved to the delay slot and inserts clones of the
- /// instruction into the successor's predecessor blocks.
- bool searchSuccBBs(MachineBasicBlock &MBB, Iter Slot) const;
-
- /// Pick a successor block of MBB. Return NULL if MBB doesn't have a
- /// successor block that is not a landing pad.
- MachineBasicBlock *selectSuccBB(MachineBasicBlock &B) const;
-
- /// This function analyzes MBB and returns an instruction with an unoccupied
- /// slot that branches to Dst.
- std::pair<MipsInstrInfo::BranchType, MachineInstr *>
- getBranch(MachineBasicBlock &MBB, const MachineBasicBlock &Dst) const;
-
- /// Examine Pred and see if it is possible to insert an instruction into
- /// one of its branches delay slot or its end.
- bool examinePred(MachineBasicBlock &Pred, const MachineBasicBlock &Succ,
- RegDefsUses &RegDU, bool &HasMultipleSuccs,
- BB2BrMap &BrMap) const;
-
- bool terminateSearch(const MachineInstr &Candidate) const;
-
- const TargetMachine *TM = nullptr;
- };
-
-} // end anonymous namespace
-
-char MipsDelaySlotFiller::ID = 0;
-
-static bool hasUnoccupiedSlot(const MachineInstr *MI) {
- return MI->hasDelaySlot() && !MI->isBundledWithSucc();
-}
-
-INITIALIZE_PASS(MipsDelaySlotFiller, DEBUG_TYPE,
- "Fill delay slot for MIPS", false, false)
-
-/// This function inserts clones of Filler into predecessor blocks.
-static void insertDelayFiller(Iter Filler, const BB2BrMap &BrMap) {
- MachineFunction *MF = Filler->getParent()->getParent();
-
- for (BB2BrMap::const_iterator I = BrMap.begin(); I != BrMap.end(); ++I) {
- if (I->second) {
- MIBundleBuilder(I->second).append(MF->CloneMachineInstr(&*Filler));
- ++UsefulSlots;
- } else {
- I->first->insert(I->first->end(), MF->CloneMachineInstr(&*Filler));
- }
- }
-}
-
-/// This function adds registers Filler defines to MBB's live-in register list.
-static void addLiveInRegs(Iter Filler, MachineBasicBlock &MBB) {
- for (unsigned I = 0, E = Filler->getNumOperands(); I != E; ++I) {
- const MachineOperand &MO = Filler->getOperand(I);
- unsigned R;
-
- if (!MO.isReg() || !MO.isDef() || !(R = MO.getReg()))
- continue;
-
-#ifndef NDEBUG
- const MachineFunction &MF = *MBB.getParent();
- assert(MF.getSubtarget().getRegisterInfo()->getAllocatableSet(MF).test(R) &&
- "Shouldn't move an instruction with unallocatable registers across "
- "basic block boundaries.");
-#endif
-
- if (!MBB.isLiveIn(R))
- MBB.addLiveIn(R);
- }
-}
-
-RegDefsUses::RegDefsUses(const TargetRegisterInfo &TRI)
- : TRI(TRI), Defs(TRI.getNumRegs(), false), Uses(TRI.getNumRegs(), false) {}
-
-void RegDefsUses::init(const MachineInstr &MI) {
- // Add all register operands which are explicit and non-variadic.
- update(MI, 0, MI.getDesc().getNumOperands());
-
- // If MI is a call, add RA to Defs to prevent users of RA from going into
- // delay slot.
- if (MI.isCall())
- Defs.set(Mips::RA);
-
- // Add all implicit register operands of branch instructions except
- // register AT.
- if (MI.isBranch()) {
- update(MI, MI.getDesc().getNumOperands(), MI.getNumOperands());
- Defs.reset(Mips::AT);
- }
-}
-
-void RegDefsUses::setCallerSaved(const MachineInstr &MI) {
- assert(MI.isCall());
-
- // Add RA/RA_64 to Defs to prevent users of RA/RA_64 from going into
- // the delay slot. The reason is that RA/RA_64 must not be changed
- // in the delay slot so that the callee can return to the caller.
- if (MI.definesRegister(Mips::RA) || MI.definesRegister(Mips::RA_64)) {
- Defs.set(Mips::RA);
- Defs.set(Mips::RA_64);
- }
-
- // If MI is a call, add all caller-saved registers to Defs.
- BitVector CallerSavedRegs(TRI.getNumRegs(), true);
-
- CallerSavedRegs.reset(Mips::ZERO);
- CallerSavedRegs.reset(Mips::ZERO_64);
-
- for (const MCPhysReg *R = TRI.getCalleeSavedRegs(MI.getParent()->getParent());
- *R; ++R)
- for (MCRegAliasIterator AI(*R, &TRI, true); AI.isValid(); ++AI)
- CallerSavedRegs.reset(*AI);
-
- Defs |= CallerSavedRegs;
-}
-
-void RegDefsUses::setUnallocatableRegs(const MachineFunction &MF) {
- BitVector AllocSet = TRI.getAllocatableSet(MF);
-
- for (unsigned R : AllocSet.set_bits())
- for (MCRegAliasIterator AI(R, &TRI, false); AI.isValid(); ++AI)
- AllocSet.set(*AI);
-
- AllocSet.set(Mips::ZERO);
- AllocSet.set(Mips::ZERO_64);
-
- Defs |= AllocSet.flip();
-}
-
-void RegDefsUses::addLiveOut(const MachineBasicBlock &MBB,
- const MachineBasicBlock &SuccBB) {
- for (MachineBasicBlock::const_succ_iterator SI = MBB.succ_begin(),
- SE = MBB.succ_end(); SI != SE; ++SI)
- if (*SI != &SuccBB)
- for (const auto &LI : (*SI)->liveins())
- Uses.set(LI.PhysReg);
-}
-
-bool RegDefsUses::update(const MachineInstr &MI, unsigned Begin, unsigned End) {
- BitVector NewDefs(TRI.getNumRegs()), NewUses(TRI.getNumRegs());
- bool HasHazard = false;
-
- for (unsigned I = Begin; I != End; ++I) {
- const MachineOperand &MO = MI.getOperand(I);
-
- if (MO.isReg() && MO.getReg())
- HasHazard |= checkRegDefsUses(NewDefs, NewUses, MO.getReg(), MO.isDef());
- }
-
- Defs |= NewDefs;
- Uses |= NewUses;
-
- return HasHazard;
-}
-
-bool RegDefsUses::checkRegDefsUses(BitVector &NewDefs, BitVector &NewUses,
- unsigned Reg, bool IsDef) const {
- if (IsDef) {
- NewDefs.set(Reg);
- // check whether Reg has already been defined or used.
- return (isRegInSet(Defs, Reg) || isRegInSet(Uses, Reg));
- }
-
- NewUses.set(Reg);
- // check whether Reg has already been defined.
- return isRegInSet(Defs, Reg);
-}
-
-bool RegDefsUses::isRegInSet(const BitVector &RegSet, unsigned Reg) const {
- // Check Reg and all aliased Registers.
- for (MCRegAliasIterator AI(Reg, &TRI, true); AI.isValid(); ++AI)
- if (RegSet.test(*AI))
- return true;
- return false;
-}
-
-bool InspectMemInstr::hasHazard(const MachineInstr &MI) {
- if (!MI.mayStore() && !MI.mayLoad())
- return false;
-
- if (ForbidMemInstr)
- return true;
-
- OrigSeenLoad = SeenLoad;
- OrigSeenStore = SeenStore;
- SeenLoad |= MI.mayLoad();
- SeenStore |= MI.mayStore();
-
- // If MI is an ordered or volatile memory reference, disallow moving
- // subsequent loads and stores to delay slot.
- if (MI.hasOrderedMemoryRef() && (OrigSeenLoad || OrigSeenStore)) {
- ForbidMemInstr = true;
- return true;
- }
-
- return hasHazard_(MI);
-}
-
-bool LoadFromStackOrConst::hasHazard_(const MachineInstr &MI) {
- if (MI.mayStore())
- return true;
-
- if (!MI.hasOneMemOperand() || !(*MI.memoperands_begin())->getPseudoValue())
- return true;
-
- if (const PseudoSourceValue *PSV =
- (*MI.memoperands_begin())->getPseudoValue()) {
- if (isa<FixedStackPseudoSourceValue>(PSV))
- return false;
- return !PSV->isConstant(nullptr) && !PSV->isStack();
- }
-
- return true;
-}
-
-MemDefsUses::MemDefsUses(const DataLayout &DL, const MachineFrameInfo *MFI_)
- : InspectMemInstr(false), MFI(MFI_), DL(DL) {}
-
-bool MemDefsUses::hasHazard_(const MachineInstr &MI) {
- bool HasHazard = false;
- SmallVector<ValueType, 4> Objs;
-
- // Check underlying object list.
- if (getUnderlyingObjects(MI, Objs)) {
- for (SmallVectorImpl<ValueType>::const_iterator I = Objs.begin();
- I != Objs.end(); ++I)
- HasHazard |= updateDefsUses(*I, MI.mayStore());
-
- return HasHazard;
- }
-
- // No underlying objects found.
- HasHazard = MI.mayStore() && (OrigSeenLoad || OrigSeenStore);
- HasHazard |= MI.mayLoad() || OrigSeenStore;
-
- SeenNoObjLoad |= MI.mayLoad();
- SeenNoObjStore |= MI.mayStore();
-
- return HasHazard;
-}
-
-bool MemDefsUses::updateDefsUses(ValueType V, bool MayStore) {
- if (MayStore)
- return !Defs.insert(V).second || Uses.count(V) || SeenNoObjStore ||
- SeenNoObjLoad;
-
- Uses.insert(V);
- return Defs.count(V) || SeenNoObjStore;
-}
-
-bool MemDefsUses::
-getUnderlyingObjects(const MachineInstr &MI,
- SmallVectorImpl<ValueType> &Objects) const {
- if (!MI.hasOneMemOperand() ||
- (!(*MI.memoperands_begin())->getValue() &&
- !(*MI.memoperands_begin())->getPseudoValue()))
- return false;
-
- if (const PseudoSourceValue *PSV =
- (*MI.memoperands_begin())->getPseudoValue()) {
- if (!PSV->isAliased(MFI))
- return false;
- Objects.push_back(PSV);
- return true;
- }
-
- const Value *V = (*MI.memoperands_begin())->getValue();
-
- SmallVector<Value *, 4> Objs;
- GetUnderlyingObjects(const_cast<Value *>(V), Objs, DL);
-
- for (SmallVectorImpl<Value *>::iterator I = Objs.begin(), E = Objs.end();
- I != E; ++I) {
- if (!isIdentifiedObject(V))
- return false;
-
- Objects.push_back(*I);
- }
-
- return true;
-}
-
-// Replace Branch with the compact branch instruction.
-Iter MipsDelaySlotFiller::replaceWithCompactBranch(MachineBasicBlock &MBB,
- Iter Branch,
- const DebugLoc &DL) {
- const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
- const MipsInstrInfo *TII = STI.getInstrInfo();
-
- unsigned NewOpcode = TII->getEquivalentCompactForm(Branch);
- Branch = TII->genInstrWithNewOpc(NewOpcode, Branch);
-
- std::next(Branch)->eraseFromParent();
- return Branch;
-}
-
-// For given opcode returns opcode of corresponding instruction with short
-// delay slot.
-// For the pseudo TAILCALL*_MM instructions return the short delay slot
-// form. Unfortunately, TAILCALL<->b16 is denied as b16 has a limited range
-// that is too short to make use of for tail calls.
-static int getEquivalentCallShort(int Opcode) {
- switch (Opcode) {
- case Mips::BGEZAL:
- return Mips::BGEZALS_MM;
- case Mips::BLTZAL:
- return Mips::BLTZALS_MM;
- case Mips::JAL:
- case Mips::JAL_MM:
- return Mips::JALS_MM;
- case Mips::JALR:
- return Mips::JALRS_MM;
- case Mips::JALR16_MM:
- return Mips::JALRS16_MM;
- case Mips::TAILCALL_MM:
- llvm_unreachable("Attempting to shorten the TAILCALL_MM pseudo!");
- case Mips::TAILCALLREG:
- return Mips::JR16_MM;
- default:
- llvm_unreachable("Unexpected call instruction for microMIPS.");
- }
-}
-
-/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
-/// We assume there is only one delay slot per delayed instruction.
-bool MipsDelaySlotFiller::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
- bool Changed = false;
- const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
- bool InMicroMipsMode = STI.inMicroMipsMode();
- const MipsInstrInfo *TII = STI.getInstrInfo();
-
- for (Iter I = MBB.begin(); I != MBB.end(); ++I) {
- if (!hasUnoccupiedSlot(&*I))
- continue;
-
- // Delay slot filling is disabled at -O0, or in microMIPS32R6.
- if (!DisableDelaySlotFiller && (TM->getOptLevel() != CodeGenOpt::None) &&
- !(InMicroMipsMode && STI.hasMips32r6())) {
-
- bool Filled = false;
-
- if (MipsCompactBranchPolicy.getValue() != CB_Always ||
- !TII->getEquivalentCompactForm(I)) {
- if (searchBackward(MBB, *I)) {
- Filled = true;
- } else if (I->isTerminator()) {
- if (searchSuccBBs(MBB, I)) {
- Filled = true;
- }
- } else if (searchForward(MBB, I)) {
- Filled = true;
- }
- }
-
- if (Filled) {
- // Get instruction with delay slot.
- MachineBasicBlock::instr_iterator DSI = I.getInstrIterator();
-
- if (InMicroMipsMode && TII->getInstSizeInBytes(*std::next(DSI)) == 2 &&
- DSI->isCall()) {
- // If instruction in delay slot is 16b change opcode to
- // corresponding instruction with short delay slot.
-
- // TODO: Implement an instruction mapping table of 16bit opcodes to
- // 32bit opcodes so that an instruction can be expanded. This would
- // save 16 bits as a TAILCALL_MM pseudo requires a fullsized nop.
- // TODO: Permit b16 when branching backwards to the same function
- // if it is in range.
- DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode())));
- }
- ++FilledSlots;
- Changed = true;
- continue;
- }
- }
-
- // For microMIPS if instruction is BEQ or BNE with one ZERO register, then
- // instead of adding NOP replace this instruction with the corresponding
- // compact branch instruction, i.e. BEQZC or BNEZC. Additionally
- // PseudoReturn and PseudoIndirectBranch are expanded to JR_MM, so they can
- // be replaced with JRC16_MM.
-
- // For MIPSR6 attempt to produce the corresponding compact (no delay slot)
- // form of the CTI. For indirect jumps this will not require inserting a
- // NOP and for branches will hopefully avoid requiring a NOP.
- if ((InMicroMipsMode ||
- (STI.hasMips32r6() && MipsCompactBranchPolicy != CB_Never)) &&
- TII->getEquivalentCompactForm(I)) {
- I = replaceWithCompactBranch(MBB, I, I->getDebugLoc());
- Changed = true;
- continue;
- }
-
- // Bundle the NOP to the instruction with the delay slot.
- BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP));
- MIBundleBuilder(MBB, I, std::next(I, 2));
- ++FilledSlots;
- Changed = true;
- }
-
- return Changed;
-}
-
-template <typename IterTy>
-bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
- IterTy End, RegDefsUses &RegDU,
- InspectMemInstr &IM, Iter Slot,
- IterTy &Filler) const {
- for (IterTy I = Begin; I != End;) {
- IterTy CurrI = I;
- ++I;
-
- // skip debug value
- if (CurrI->isDebugInstr())
- continue;
-
- if (terminateSearch(*CurrI))
- break;
-
- assert((!CurrI->isCall() && !CurrI->isReturn() && !CurrI->isBranch()) &&
- "Cannot put calls, returns or branches in delay slot.");
-
- if (CurrI->isKill()) {
- CurrI->eraseFromParent();
- continue;
- }
-
- if (delayHasHazard(*CurrI, RegDU, IM))
- continue;
-
- const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>();
- if (STI.isTargetNaCl()) {
- // In NaCl, instructions that must be masked are forbidden in delay slots.
- // We only check for loads, stores and SP changes. Calls, returns and
- // branches are not checked because non-NaCl targets never put them in
- // delay slots.
- unsigned AddrIdx;
- if ((isBasePlusOffsetMemoryAccess(CurrI->getOpcode(), &AddrIdx) &&
- baseRegNeedsLoadStoreMask(CurrI->getOperand(AddrIdx).getReg())) ||
- CurrI->modifiesRegister(Mips::SP, STI.getRegisterInfo()))
- continue;
- }
-
- bool InMicroMipsMode = STI.inMicroMipsMode();
- const MipsInstrInfo *TII = STI.getInstrInfo();
- unsigned Opcode = (*Slot).getOpcode();
- // This is complicated by the tail call optimization. For non-PIC code
- // there is only a 32bit sized unconditional branch which can be assumed
- // to be able to reach the target. b16 only has a range of +/- 1 KB.
- // It's entirely possible that the target function is reachable with b16
- // but we don't have enough information to make that decision.
- if (InMicroMipsMode && TII->getInstSizeInBytes(*CurrI) == 2 &&
- (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
- Opcode == Mips::PseudoIndirectBranch_MM ||
- Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
- continue;
- // Instructions LWP/SWP and MOVEP should not be in a delay slot as that
- // results in unpredictable behaviour
- if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM ||
- Opcode == Mips::MOVEP_MM))
- continue;
-
- Filler = CurrI;
- return true;
- }
-
- return false;
-}
-
-bool MipsDelaySlotFiller::searchBackward(MachineBasicBlock &MBB,
- MachineInstr &Slot) const {
- if (DisableBackwardSearch)
- return false;
-
- auto *Fn = MBB.getParent();
- RegDefsUses RegDU(*Fn->getSubtarget().getRegisterInfo());
- MemDefsUses MemDU(Fn->getDataLayout(), &Fn->getFrameInfo());
- ReverseIter Filler;
-
- RegDU.init(Slot);
-
- MachineBasicBlock::iterator SlotI = Slot;
- if (!searchRange(MBB, ++SlotI.getReverse(), MBB.rend(), RegDU, MemDU, Slot,
- Filler))
- return false;
-
- MBB.splice(std::next(SlotI), &MBB, Filler.getReverse());
- MIBundleBuilder(MBB, SlotI, std::next(SlotI, 2));
- ++UsefulSlots;
- return true;
-}
-
-bool MipsDelaySlotFiller::searchForward(MachineBasicBlock &MBB,
- Iter Slot) const {
- // Can handle only calls.
- if (DisableForwardSearch || !Slot->isCall())
- return false;
-
- RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo());
- NoMemInstr NM;
- Iter Filler;
-
- RegDU.setCallerSaved(*Slot);
-
- if (!searchRange(MBB, std::next(Slot), MBB.end(), RegDU, NM, Slot, Filler))
- return false;
-
- MBB.splice(std::next(Slot), &MBB, Filler);
- MIBundleBuilder(MBB, Slot, std::next(Slot, 2));
- ++UsefulSlots;
- return true;
-}
-
-bool MipsDelaySlotFiller::searchSuccBBs(MachineBasicBlock &MBB,
- Iter Slot) const {
- if (DisableSuccBBSearch)
- return false;
-
- MachineBasicBlock *SuccBB = selectSuccBB(MBB);
-
- if (!SuccBB)
- return false;
-
- RegDefsUses RegDU(*MBB.getParent()->getSubtarget().getRegisterInfo());
- bool HasMultipleSuccs = false;
- BB2BrMap BrMap;
- std::unique_ptr<InspectMemInstr> IM;
- Iter Filler;
- auto *Fn = MBB.getParent();
-
- // Iterate over SuccBB's predecessor list.
- for (MachineBasicBlock::pred_iterator PI = SuccBB->pred_begin(),
- PE = SuccBB->pred_end(); PI != PE; ++PI)
- if (!examinePred(**PI, *SuccBB, RegDU, HasMultipleSuccs, BrMap))
- return false;
-
- // Do not allow moving instructions which have unallocatable register operands
- // across basic block boundaries.
- RegDU.setUnallocatableRegs(*Fn);
-
- // Only allow moving loads from stack or constants if any of the SuccBB's
- // predecessors have multiple successors.
- if (HasMultipleSuccs) {
- IM.reset(new LoadFromStackOrConst());
- } else {
- const MachineFrameInfo &MFI = Fn->getFrameInfo();
- IM.reset(new MemDefsUses(Fn->getDataLayout(), &MFI));
- }
-
- if (!searchRange(MBB, SuccBB->begin(), SuccBB->end(), RegDU, *IM, Slot,
- Filler))
- return false;
-
- insertDelayFiller(Filler, BrMap);
- addLiveInRegs(Filler, *SuccBB);
- Filler->eraseFromParent();
-
- return true;
-}
-
-MachineBasicBlock *
-MipsDelaySlotFiller::selectSuccBB(MachineBasicBlock &B) const {
- if (B.succ_empty())
- return nullptr;
-
- // Select the successor with the larget edge weight.
- auto &Prob = getAnalysis<MachineBranchProbabilityInfo>();
- MachineBasicBlock *S = *std::max_element(
- B.succ_begin(), B.succ_end(),
- [&](const MachineBasicBlock *Dst0, const MachineBasicBlock *Dst1) {
- return Prob.getEdgeProbability(&B, Dst0) <
- Prob.getEdgeProbability(&B, Dst1);
- });
- return S->isEHPad() ? nullptr : S;
-}
-
-std::pair<MipsInstrInfo::BranchType, MachineInstr *>
-MipsDelaySlotFiller::getBranch(MachineBasicBlock &MBB,
- const MachineBasicBlock &Dst) const {
- const MipsInstrInfo *TII =
- MBB.getParent()->getSubtarget<MipsSubtarget>().getInstrInfo();
- MachineBasicBlock *TrueBB = nullptr, *FalseBB = nullptr;
- SmallVector<MachineInstr*, 2> BranchInstrs;
- SmallVector<MachineOperand, 2> Cond;
-
- MipsInstrInfo::BranchType R =
- TII->analyzeBranch(MBB, TrueBB, FalseBB, Cond, false, BranchInstrs);
-
- if ((R == MipsInstrInfo::BT_None) || (R == MipsInstrInfo::BT_NoBranch))
- return std::make_pair(R, nullptr);
-
- if (R != MipsInstrInfo::BT_CondUncond) {
- if (!hasUnoccupiedSlot(BranchInstrs[0]))
- return std::make_pair(MipsInstrInfo::BT_None, nullptr);
-
- assert(((R != MipsInstrInfo::BT_Uncond) || (TrueBB == &Dst)));
-
- return std::make_pair(R, BranchInstrs[0]);
- }
-
- assert((TrueBB == &Dst) || (FalseBB == &Dst));
-
- // Examine the conditional branch. See if its slot is occupied.
- if (hasUnoccupiedSlot(BranchInstrs[0]))
- return std::make_pair(MipsInstrInfo::BT_Cond, BranchInstrs[0]);
-
- // If that fails, try the unconditional branch.
- if (hasUnoccupiedSlot(BranchInstrs[1]) && (FalseBB == &Dst))
- return std::make_pair(MipsInstrInfo::BT_Uncond, BranchInstrs[1]);
-
- return std::make_pair(MipsInstrInfo::BT_None, nullptr);
-}
-
-bool MipsDelaySlotFiller::examinePred(MachineBasicBlock &Pred,
- const MachineBasicBlock &Succ,
- RegDefsUses &RegDU,
- bool &HasMultipleSuccs,
- BB2BrMap &BrMap) const {
- std::pair<MipsInstrInfo::BranchType, MachineInstr *> P =
- getBranch(Pred, Succ);
-
- // Return if either getBranch wasn't able to analyze the branches or there
- // were no branches with unoccupied slots.
- if (P.first == MipsInstrInfo::BT_None)
- return false;
-
- if ((P.first != MipsInstrInfo::BT_Uncond) &&
- (P.first != MipsInstrInfo::BT_NoBranch)) {
- HasMultipleSuccs = true;
- RegDU.addLiveOut(Pred, Succ);
- }
-
- BrMap[&Pred] = P.second;
- return true;
-}
-
-bool MipsDelaySlotFiller::delayHasHazard(const MachineInstr &Candidate,
- RegDefsUses &RegDU,
- InspectMemInstr &IM) const {
- assert(!Candidate.isKill() &&
- "KILL instructions should have been eliminated at this point.");
-
- bool HasHazard = Candidate.isImplicitDef();
-
- HasHazard |= IM.hasHazard(Candidate);
- HasHazard |= RegDU.update(Candidate, 0, Candidate.getNumOperands());
-
- return HasHazard;
-}
-
-bool MipsDelaySlotFiller::terminateSearch(const MachineInstr &Candidate) const {
- return (Candidate.isTerminator() || Candidate.isCall() ||
- Candidate.isPosition() || Candidate.isInlineAsm() ||
- Candidate.hasUnmodeledSideEffects());
-}
-
-/// createMipsDelaySlotFillerPass - Returns a pass that fills in delay
-/// slots in Mips MachineFunctions
-FunctionPass *llvm::createMipsDelaySlotFillerPass() { return new MipsDelaySlotFiller(); }