|  | //===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // Simple pass to fill delay slots with useful instructions. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Lanai.h" | 
|  | #include "LanaiTargetMachine.h" | 
|  | #include "llvm/ADT/SmallSet.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/CodeGen/MachineFunctionPass.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/TargetInstrInfo.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "delay-slot-filler" | 
|  |  | 
|  | STATISTIC(FilledSlots, "Number of delay slots filled"); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false), | 
|  | cl::desc("Fill Lanai delay slots with NOPs."), | 
|  | cl::Hidden); | 
|  |  | 
|  | namespace { | 
|  | struct Filler : public MachineFunctionPass { | 
|  | // Target machine description which we query for reg. names, data | 
|  | // layout, etc. | 
|  | const TargetInstrInfo *TII; | 
|  | const TargetRegisterInfo *TRI; | 
|  | MachineBasicBlock::instr_iterator LastFiller; | 
|  |  | 
|  | static char ID; | 
|  | explicit Filler() : MachineFunctionPass(ID) {} | 
|  |  | 
|  | StringRef getPassName() const override { return "Lanai Delay Slot Filler"; } | 
|  |  | 
|  | bool runOnMachineBasicBlock(MachineBasicBlock &MBB); | 
|  |  | 
|  | bool runOnMachineFunction(MachineFunction &MF) override { | 
|  | const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>(); | 
|  | TII = Subtarget.getInstrInfo(); | 
|  | TRI = Subtarget.getRegisterInfo(); | 
|  |  | 
|  | bool Changed = false; | 
|  | for (MachineBasicBlock &MBB : MF) | 
|  | Changed |= runOnMachineBasicBlock(MBB); | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | MachineFunctionProperties getRequiredProperties() const override { | 
|  | return MachineFunctionProperties().set( | 
|  | MachineFunctionProperties::Property::NoVRegs); | 
|  | } | 
|  |  | 
|  | void insertDefsUses(MachineBasicBlock::instr_iterator MI, | 
|  | SmallSet<unsigned, 32> &RegDefs, | 
|  | SmallSet<unsigned, 32> &RegUses); | 
|  |  | 
|  | bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg); | 
|  |  | 
|  | bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad, | 
|  | bool &SawStore, SmallSet<unsigned, 32> &RegDefs, | 
|  | SmallSet<unsigned, 32> &RegUses); | 
|  |  | 
|  | bool findDelayInstr(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::instr_iterator Slot, | 
|  | MachineBasicBlock::instr_iterator &Filler); | 
|  | }; | 
|  | char Filler::ID = 0; | 
|  | } // end of anonymous namespace | 
|  |  | 
|  | // createLanaiDelaySlotFillerPass - Returns a pass that fills in delay | 
|  | // slots in Lanai MachineFunctions | 
|  | FunctionPass * | 
|  | llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine & /*tm*/) { | 
|  | return new Filler(); | 
|  | } | 
|  |  | 
|  | // runOnMachineBasicBlock - Fill in delay slots for the given basic block. | 
|  | // There is one or two delay slot per delayed instruction. | 
|  | bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { | 
|  | bool Changed = false; | 
|  | LastFiller = MBB.instr_end(); | 
|  |  | 
|  | for (MachineBasicBlock::instr_iterator I = MBB.instr_begin(); | 
|  | I != MBB.instr_end(); ++I) { | 
|  | if (I->getDesc().hasDelaySlot()) { | 
|  | MachineBasicBlock::instr_iterator InstrWithSlot = I; | 
|  | MachineBasicBlock::instr_iterator J = I; | 
|  |  | 
|  | // Treat RET specially as it is only instruction with 2 delay slots | 
|  | // generated while all others generated have 1 delay slot. | 
|  | if (I->getOpcode() == Lanai::RET) { | 
|  | // RET is generated as part of epilogue generation and hence we know | 
|  | // what the two instructions preceding it are and that it is safe to | 
|  | // insert RET above them. | 
|  | MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse(); | 
|  | assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() && | 
|  | RI->getOperand(0).getReg() == Lanai::FP && | 
|  | RI->getOperand(1).isReg() && | 
|  | RI->getOperand(1).getReg() == Lanai::FP && | 
|  | RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8); | 
|  | ++RI; | 
|  | assert(RI->getOpcode() == Lanai::ADD_I_LO && | 
|  | RI->getOperand(0).isReg() && | 
|  | RI->getOperand(0).getReg() == Lanai::SP && | 
|  | RI->getOperand(1).isReg() && | 
|  | RI->getOperand(1).getReg() == Lanai::FP); | 
|  | MachineBasicBlock::instr_iterator FI = RI.getReverse(); | 
|  | MBB.splice(std::next(I), &MBB, FI, I); | 
|  | FilledSlots += 2; | 
|  | } else { | 
|  | if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) { | 
|  | MBB.splice(std::next(I), &MBB, J); | 
|  | } else { | 
|  | BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP)); | 
|  | } | 
|  | ++FilledSlots; | 
|  | } | 
|  |  | 
|  | Changed = true; | 
|  | // Record the filler instruction that filled the delay slot. | 
|  | // The instruction after it will be visited in the next iteration. | 
|  | LastFiller = ++I; | 
|  |  | 
|  | // Bundle the delay slot filler to InstrWithSlot so that the machine | 
|  | // verifier doesn't expect this instruction to be a terminator. | 
|  | MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller)); | 
|  | } | 
|  | } | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | bool Filler::findDelayInstr(MachineBasicBlock &MBB, | 
|  | MachineBasicBlock::instr_iterator Slot, | 
|  | MachineBasicBlock::instr_iterator &Filler) { | 
|  | SmallSet<unsigned, 32> RegDefs; | 
|  | SmallSet<unsigned, 32> RegUses; | 
|  |  | 
|  | insertDefsUses(Slot, RegDefs, RegUses); | 
|  |  | 
|  | bool SawLoad = false; | 
|  | bool SawStore = false; | 
|  |  | 
|  | for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse(); | 
|  | I != MBB.instr_rend(); ++I) { | 
|  | // skip debug value | 
|  | if (I->isDebugInstr()) | 
|  | continue; | 
|  |  | 
|  | // Convert to forward iterator. | 
|  | MachineBasicBlock::instr_iterator FI = I.getReverse(); | 
|  |  | 
|  | if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() || | 
|  | FI == LastFiller || I->isPseudo()) | 
|  | break; | 
|  |  | 
|  | if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) { | 
|  | insertDefsUses(FI, RegDefs, RegUses); | 
|  | continue; | 
|  | } | 
|  | Filler = FI; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad, | 
|  | bool &SawStore, SmallSet<unsigned, 32> &RegDefs, | 
|  | SmallSet<unsigned, 32> &RegUses) { | 
|  | if (MI->isImplicitDef() || MI->isKill()) | 
|  | return true; | 
|  |  | 
|  | // Loads or stores cannot be moved past a store to the delay slot | 
|  | // and stores cannot be moved past a load. | 
|  | if (MI->mayLoad()) { | 
|  | if (SawStore) | 
|  | return true; | 
|  | SawLoad = true; | 
|  | } | 
|  |  | 
|  | if (MI->mayStore()) { | 
|  | if (SawStore) | 
|  | return true; | 
|  | SawStore = true; | 
|  | if (SawLoad) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | assert((!MI->isCall() && !MI->isReturn()) && | 
|  | "Cannot put calls or returns in delay slot."); | 
|  |  | 
|  | for (const MachineOperand &MO : MI->operands()) { | 
|  | unsigned Reg; | 
|  |  | 
|  | if (!MO.isReg() || !(Reg = MO.getReg())) | 
|  | continue; // skip | 
|  |  | 
|  | if (MO.isDef()) { | 
|  | // 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. | 
|  | if (isRegInSet(RegDefs, Reg)) | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Insert Defs and Uses of MI into the sets RegDefs and RegUses. | 
|  | void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI, | 
|  | SmallSet<unsigned, 32> &RegDefs, | 
|  | SmallSet<unsigned, 32> &RegUses) { | 
|  | // If MI is a call or return, just examine the explicit non-variadic operands. | 
|  | const MCInstrDesc &MCID = MI->getDesc(); | 
|  | unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands() | 
|  | : MI->getNumOperands(); | 
|  | for (unsigned I = 0; I != E; ++I) { | 
|  | const MachineOperand &MO = MI->getOperand(I); | 
|  | unsigned Reg; | 
|  |  | 
|  | if (!MO.isReg() || !(Reg = MO.getReg())) | 
|  | continue; | 
|  |  | 
|  | if (MO.isDef()) | 
|  | RegDefs.insert(Reg); | 
|  | else if (MO.isUse()) | 
|  | RegUses.insert(Reg); | 
|  | } | 
|  |  | 
|  | // Call & return instructions defines SP implicitly. Implicit defines are not | 
|  | // included in the RegDefs set of calls but instructions modifying SP cannot | 
|  | // be inserted in the delay slot of a call/return as these instructions are | 
|  | // expanded to multiple instructions with SP modified before the branch that | 
|  | // has the delay slot. | 
|  | if (MI->isCall() || MI->isReturn()) | 
|  | RegDefs.insert(Lanai::SP); | 
|  | } | 
|  |  | 
|  | // Returns true if the Reg or its alias is in the RegSet. | 
|  | bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) { | 
|  | // Check Reg and all aliased Registers. | 
|  | for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI) | 
|  | if (RegSet.count(*AI)) | 
|  | return true; | 
|  | return false; | 
|  | } |