10b57cec5SDimitry Andric //===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
98bcb0991SDimitry Andric // Simple pass to fill delay slots with useful instructions.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "Lanai.h"
140b57cec5SDimitry Andric #include "LanaiTargetMachine.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
160b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
200b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric #define DEBUG_TYPE "delay-slot-filler"
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric STATISTIC(FilledSlots, "Number of delay slots filled");
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric static cl::opt<bool>
290b57cec5SDimitry Andric NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false),
300b57cec5SDimitry Andric cl::desc("Fill Lanai delay slots with NOPs."),
310b57cec5SDimitry Andric cl::Hidden);
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric namespace {
340b57cec5SDimitry Andric struct Filler : public MachineFunctionPass {
350b57cec5SDimitry Andric // Target machine description which we query for reg. names, data
360b57cec5SDimitry Andric // layout, etc.
370b57cec5SDimitry Andric const TargetInstrInfo *TII;
380b57cec5SDimitry Andric const TargetRegisterInfo *TRI;
390b57cec5SDimitry Andric MachineBasicBlock::instr_iterator LastFiller;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric static char ID;
Filler__anone523896e0111::Filler420b57cec5SDimitry Andric explicit Filler() : MachineFunctionPass(ID) {}
430b57cec5SDimitry Andric
getPassName__anone523896e0111::Filler440b57cec5SDimitry Andric StringRef getPassName() const override { return "Lanai Delay Slot Filler"; }
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
470b57cec5SDimitry Andric
runOnMachineFunction__anone523896e0111::Filler480b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override {
490b57cec5SDimitry Andric const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();
500b57cec5SDimitry Andric TII = Subtarget.getInstrInfo();
510b57cec5SDimitry Andric TRI = Subtarget.getRegisterInfo();
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric bool Changed = false;
544824e7fdSDimitry Andric for (MachineBasicBlock &MBB : MF)
554824e7fdSDimitry Andric Changed |= runOnMachineBasicBlock(MBB);
560b57cec5SDimitry Andric return Changed;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric
getRequiredProperties__anone523896e0111::Filler590b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
600b57cec5SDimitry Andric return MachineFunctionProperties().set(
610b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric void insertDefsUses(MachineBasicBlock::instr_iterator MI,
650b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegDefs,
660b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses);
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
710b57cec5SDimitry Andric bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
720b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses);
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric bool findDelayInstr(MachineBasicBlock &MBB,
750b57cec5SDimitry Andric MachineBasicBlock::instr_iterator Slot,
760b57cec5SDimitry Andric MachineBasicBlock::instr_iterator &Filler);
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric char Filler::ID = 0;
790b57cec5SDimitry Andric } // end of anonymous namespace
800b57cec5SDimitry Andric
810b57cec5SDimitry Andric // createLanaiDelaySlotFillerPass - Returns a pass that fills in delay
820b57cec5SDimitry Andric // slots in Lanai MachineFunctions
830b57cec5SDimitry Andric FunctionPass *
createLanaiDelaySlotFillerPass(const LanaiTargetMachine &)840b57cec5SDimitry Andric llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine & /*tm*/) {
850b57cec5SDimitry Andric return new Filler();
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric // runOnMachineBasicBlock - Fill in delay slots for the given basic block.
890b57cec5SDimitry Andric // There is one or two delay slot per delayed instruction.
runOnMachineBasicBlock(MachineBasicBlock & MBB)900b57cec5SDimitry Andric bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
910b57cec5SDimitry Andric bool Changed = false;
920b57cec5SDimitry Andric LastFiller = MBB.instr_end();
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();
950b57cec5SDimitry Andric I != MBB.instr_end(); ++I) {
960b57cec5SDimitry Andric if (I->getDesc().hasDelaySlot()) {
970b57cec5SDimitry Andric MachineBasicBlock::instr_iterator InstrWithSlot = I;
980b57cec5SDimitry Andric MachineBasicBlock::instr_iterator J = I;
990b57cec5SDimitry Andric
1000b57cec5SDimitry Andric // Treat RET specially as it is only instruction with 2 delay slots
1010b57cec5SDimitry Andric // generated while all others generated have 1 delay slot.
1020b57cec5SDimitry Andric if (I->getOpcode() == Lanai::RET) {
1030b57cec5SDimitry Andric // RET is generated as part of epilogue generation and hence we know
1040b57cec5SDimitry Andric // what the two instructions preceding it are and that it is safe to
1050b57cec5SDimitry Andric // insert RET above them.
1060b57cec5SDimitry Andric MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();
1070b57cec5SDimitry Andric assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&
1080b57cec5SDimitry Andric RI->getOperand(0).getReg() == Lanai::FP &&
1090b57cec5SDimitry Andric RI->getOperand(1).isReg() &&
1100b57cec5SDimitry Andric RI->getOperand(1).getReg() == Lanai::FP &&
1110b57cec5SDimitry Andric RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);
1120b57cec5SDimitry Andric ++RI;
1130b57cec5SDimitry Andric assert(RI->getOpcode() == Lanai::ADD_I_LO &&
1140b57cec5SDimitry Andric RI->getOperand(0).isReg() &&
1150b57cec5SDimitry Andric RI->getOperand(0).getReg() == Lanai::SP &&
1160b57cec5SDimitry Andric RI->getOperand(1).isReg() &&
1170b57cec5SDimitry Andric RI->getOperand(1).getReg() == Lanai::FP);
1180b57cec5SDimitry Andric MachineBasicBlock::instr_iterator FI = RI.getReverse();
1190b57cec5SDimitry Andric MBB.splice(std::next(I), &MBB, FI, I);
1200b57cec5SDimitry Andric FilledSlots += 2;
1210b57cec5SDimitry Andric } else {
1220b57cec5SDimitry Andric if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {
1230b57cec5SDimitry Andric MBB.splice(std::next(I), &MBB, J);
1240b57cec5SDimitry Andric } else {
1250b57cec5SDimitry Andric BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP));
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric ++FilledSlots;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric Changed = true;
1310b57cec5SDimitry Andric // Record the filler instruction that filled the delay slot.
1320b57cec5SDimitry Andric // The instruction after it will be visited in the next iteration.
1330b57cec5SDimitry Andric LastFiller = ++I;
1340b57cec5SDimitry Andric
1350b57cec5SDimitry Andric // Bundle the delay slot filler to InstrWithSlot so that the machine
1360b57cec5SDimitry Andric // verifier doesn't expect this instruction to be a terminator.
1370b57cec5SDimitry Andric MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller));
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric return Changed;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric
findDelayInstr(MachineBasicBlock & MBB,MachineBasicBlock::instr_iterator Slot,MachineBasicBlock::instr_iterator & Filler)1430b57cec5SDimitry Andric bool Filler::findDelayInstr(MachineBasicBlock &MBB,
1440b57cec5SDimitry Andric MachineBasicBlock::instr_iterator Slot,
1450b57cec5SDimitry Andric MachineBasicBlock::instr_iterator &Filler) {
1460b57cec5SDimitry Andric SmallSet<unsigned, 32> RegDefs;
1470b57cec5SDimitry Andric SmallSet<unsigned, 32> RegUses;
1480b57cec5SDimitry Andric
1490b57cec5SDimitry Andric insertDefsUses(Slot, RegDefs, RegUses);
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric bool SawLoad = false;
1520b57cec5SDimitry Andric bool SawStore = false;
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();
1550b57cec5SDimitry Andric I != MBB.instr_rend(); ++I) {
1560b57cec5SDimitry Andric // skip debug value
1570b57cec5SDimitry Andric if (I->isDebugInstr())
1580b57cec5SDimitry Andric continue;
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andric // Convert to forward iterator.
1610b57cec5SDimitry Andric MachineBasicBlock::instr_iterator FI = I.getReverse();
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||
1640b57cec5SDimitry Andric FI == LastFiller || I->isPseudo())
1650b57cec5SDimitry Andric break;
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) {
1680b57cec5SDimitry Andric insertDefsUses(FI, RegDefs, RegUses);
1690b57cec5SDimitry Andric continue;
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric Filler = FI;
1720b57cec5SDimitry Andric return true;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric return false;
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric
delayHasHazard(MachineBasicBlock::instr_iterator MI,bool & SawLoad,bool & SawStore,SmallSet<unsigned,32> & RegDefs,SmallSet<unsigned,32> & RegUses)1770b57cec5SDimitry Andric bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,
1780b57cec5SDimitry Andric bool &SawStore, SmallSet<unsigned, 32> &RegDefs,
1790b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses) {
1800b57cec5SDimitry Andric if (MI->isImplicitDef() || MI->isKill())
1810b57cec5SDimitry Andric return true;
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric // Loads or stores cannot be moved past a store to the delay slot
1840b57cec5SDimitry Andric // and stores cannot be moved past a load.
1850b57cec5SDimitry Andric if (MI->mayLoad()) {
1860b57cec5SDimitry Andric if (SawStore)
1870b57cec5SDimitry Andric return true;
1880b57cec5SDimitry Andric SawLoad = true;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric if (MI->mayStore()) {
1920b57cec5SDimitry Andric if (SawStore)
1930b57cec5SDimitry Andric return true;
1940b57cec5SDimitry Andric SawStore = true;
1950b57cec5SDimitry Andric if (SawLoad)
1960b57cec5SDimitry Andric return true;
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric assert((!MI->isCall() && !MI->isReturn()) &&
2000b57cec5SDimitry Andric "Cannot put calls or returns in delay slot.");
2010b57cec5SDimitry Andric
2024824e7fdSDimitry Andric for (const MachineOperand &MO : MI->operands()) {
2030b57cec5SDimitry Andric unsigned Reg;
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric if (!MO.isReg() || !(Reg = MO.getReg()))
2060b57cec5SDimitry Andric continue; // skip
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric if (MO.isDef()) {
2090b57cec5SDimitry Andric // check whether Reg is defined or used before delay slot.
2100b57cec5SDimitry Andric if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg))
2110b57cec5SDimitry Andric return true;
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric if (MO.isUse()) {
2140b57cec5SDimitry Andric // check whether Reg is defined before delay slot.
2150b57cec5SDimitry Andric if (isRegInSet(RegDefs, Reg))
2160b57cec5SDimitry Andric return true;
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric }
2190b57cec5SDimitry Andric return false;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric // Insert Defs and Uses of MI into the sets RegDefs and RegUses.
insertDefsUses(MachineBasicBlock::instr_iterator MI,SmallSet<unsigned,32> & RegDefs,SmallSet<unsigned,32> & RegUses)2230b57cec5SDimitry Andric void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,
2240b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegDefs,
2250b57cec5SDimitry Andric SmallSet<unsigned, 32> &RegUses) {
2260b57cec5SDimitry Andric // If MI is a call or return, just examine the explicit non-variadic operands.
227*bdd1243dSDimitry Andric const MCInstrDesc &MCID = MI->getDesc();
2280b57cec5SDimitry Andric unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()
2290b57cec5SDimitry Andric : MI->getNumOperands();
2300b57cec5SDimitry Andric for (unsigned I = 0; I != E; ++I) {
2310b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(I);
2320b57cec5SDimitry Andric unsigned Reg;
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric if (!MO.isReg() || !(Reg = MO.getReg()))
2350b57cec5SDimitry Andric continue;
2360b57cec5SDimitry Andric
2370b57cec5SDimitry Andric if (MO.isDef())
2380b57cec5SDimitry Andric RegDefs.insert(Reg);
2390b57cec5SDimitry Andric else if (MO.isUse())
2400b57cec5SDimitry Andric RegUses.insert(Reg);
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric // Call & return instructions defines SP implicitly. Implicit defines are not
2440b57cec5SDimitry Andric // included in the RegDefs set of calls but instructions modifying SP cannot
2450b57cec5SDimitry Andric // be inserted in the delay slot of a call/return as these instructions are
2460b57cec5SDimitry Andric // expanded to multiple instructions with SP modified before the branch that
2470b57cec5SDimitry Andric // has the delay slot.
2480b57cec5SDimitry Andric if (MI->isCall() || MI->isReturn())
2490b57cec5SDimitry Andric RegDefs.insert(Lanai::SP);
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric // Returns true if the Reg or its alias is in the RegSet.
isRegInSet(SmallSet<unsigned,32> & RegSet,unsigned Reg)2530b57cec5SDimitry Andric bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {
2540b57cec5SDimitry Andric // Check Reg and all aliased Registers.
2550b57cec5SDimitry Andric for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
2560b57cec5SDimitry Andric if (RegSet.count(*AI))
2570b57cec5SDimitry Andric return true;
2580b57cec5SDimitry Andric return false;
2590b57cec5SDimitry Andric }
260