Path: blob/main/contrib/llvm-project/llvm/lib/Target/Lanai/LanaiDelaySlotFiller.cpp
35271 views
//===-- LanaiDelaySlotFiller.cpp - Lanai delay slot filler ----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Simple pass to fill delay slots with useful instructions.9//10//===----------------------------------------------------------------------===//1112#include "Lanai.h"13#include "LanaiTargetMachine.h"14#include "llvm/ADT/SmallSet.h"15#include "llvm/ADT/Statistic.h"16#include "llvm/CodeGen/MachineFunctionPass.h"17#include "llvm/CodeGen/MachineInstrBuilder.h"18#include "llvm/CodeGen/TargetInstrInfo.h"19#include "llvm/Support/CommandLine.h"2021using namespace llvm;2223#define DEBUG_TYPE "delay-slot-filler"2425STATISTIC(FilledSlots, "Number of delay slots filled");2627static cl::opt<bool>28NopDelaySlotFiller("lanai-nop-delay-filler", cl::init(false),29cl::desc("Fill Lanai delay slots with NOPs."),30cl::Hidden);3132namespace {33struct Filler : public MachineFunctionPass {34// Target machine description which we query for reg. names, data35// layout, etc.36const TargetInstrInfo *TII;37const TargetRegisterInfo *TRI;38MachineBasicBlock::instr_iterator LastFiller;3940static char ID;41explicit Filler() : MachineFunctionPass(ID) {}4243StringRef getPassName() const override { return "Lanai Delay Slot Filler"; }4445bool runOnMachineBasicBlock(MachineBasicBlock &MBB);4647bool runOnMachineFunction(MachineFunction &MF) override {48const LanaiSubtarget &Subtarget = MF.getSubtarget<LanaiSubtarget>();49TII = Subtarget.getInstrInfo();50TRI = Subtarget.getRegisterInfo();5152bool Changed = false;53for (MachineBasicBlock &MBB : MF)54Changed |= runOnMachineBasicBlock(MBB);55return Changed;56}5758MachineFunctionProperties getRequiredProperties() const override {59return MachineFunctionProperties().set(60MachineFunctionProperties::Property::NoVRegs);61}6263void insertDefsUses(MachineBasicBlock::instr_iterator MI,64SmallSet<unsigned, 32> &RegDefs,65SmallSet<unsigned, 32> &RegUses);6667bool isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg);6869bool delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,70bool &SawStore, SmallSet<unsigned, 32> &RegDefs,71SmallSet<unsigned, 32> &RegUses);7273bool findDelayInstr(MachineBasicBlock &MBB,74MachineBasicBlock::instr_iterator Slot,75MachineBasicBlock::instr_iterator &Filler);76};77char Filler::ID = 0;78} // end of anonymous namespace7980// createLanaiDelaySlotFillerPass - Returns a pass that fills in delay81// slots in Lanai MachineFunctions82FunctionPass *83llvm::createLanaiDelaySlotFillerPass(const LanaiTargetMachine & /*tm*/) {84return new Filler();85}8687// runOnMachineBasicBlock - Fill in delay slots for the given basic block.88// There is one or two delay slot per delayed instruction.89bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {90bool Changed = false;91LastFiller = MBB.instr_end();9293for (MachineBasicBlock::instr_iterator I = MBB.instr_begin();94I != MBB.instr_end(); ++I) {95if (I->getDesc().hasDelaySlot()) {96MachineBasicBlock::instr_iterator InstrWithSlot = I;97MachineBasicBlock::instr_iterator J = I;9899// Treat RET specially as it is only instruction with 2 delay slots100// generated while all others generated have 1 delay slot.101if (I->getOpcode() == Lanai::RET) {102// RET is generated as part of epilogue generation and hence we know103// what the two instructions preceding it are and that it is safe to104// insert RET above them.105MachineBasicBlock::reverse_instr_iterator RI = ++I.getReverse();106assert(RI->getOpcode() == Lanai::LDW_RI && RI->getOperand(0).isReg() &&107RI->getOperand(0).getReg() == Lanai::FP &&108RI->getOperand(1).isReg() &&109RI->getOperand(1).getReg() == Lanai::FP &&110RI->getOperand(2).isImm() && RI->getOperand(2).getImm() == -8);111++RI;112assert(RI->getOpcode() == Lanai::ADD_I_LO &&113RI->getOperand(0).isReg() &&114RI->getOperand(0).getReg() == Lanai::SP &&115RI->getOperand(1).isReg() &&116RI->getOperand(1).getReg() == Lanai::FP);117MachineBasicBlock::instr_iterator FI = RI.getReverse();118MBB.splice(std::next(I), &MBB, FI, I);119FilledSlots += 2;120} else {121if (!NopDelaySlotFiller && findDelayInstr(MBB, I, J)) {122MBB.splice(std::next(I), &MBB, J);123} else {124BuildMI(MBB, std::next(I), DebugLoc(), TII->get(Lanai::NOP));125}126++FilledSlots;127}128129Changed = true;130// Record the filler instruction that filled the delay slot.131// The instruction after it will be visited in the next iteration.132LastFiller = ++I;133134// Bundle the delay slot filler to InstrWithSlot so that the machine135// verifier doesn't expect this instruction to be a terminator.136MIBundleBuilder(MBB, InstrWithSlot, std::next(LastFiller));137}138}139return Changed;140}141142bool Filler::findDelayInstr(MachineBasicBlock &MBB,143MachineBasicBlock::instr_iterator Slot,144MachineBasicBlock::instr_iterator &Filler) {145SmallSet<unsigned, 32> RegDefs;146SmallSet<unsigned, 32> RegUses;147148insertDefsUses(Slot, RegDefs, RegUses);149150bool SawLoad = false;151bool SawStore = false;152153for (MachineBasicBlock::reverse_instr_iterator I = ++Slot.getReverse();154I != MBB.instr_rend(); ++I) {155// skip debug value156if (I->isDebugInstr())157continue;158159// Convert to forward iterator.160MachineBasicBlock::instr_iterator FI = I.getReverse();161162if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() ||163FI == LastFiller || I->isPseudo())164break;165166if (delayHasHazard(FI, SawLoad, SawStore, RegDefs, RegUses)) {167insertDefsUses(FI, RegDefs, RegUses);168continue;169}170Filler = FI;171return true;172}173return false;174}175176bool Filler::delayHasHazard(MachineBasicBlock::instr_iterator MI, bool &SawLoad,177bool &SawStore, SmallSet<unsigned, 32> &RegDefs,178SmallSet<unsigned, 32> &RegUses) {179if (MI->isImplicitDef() || MI->isKill())180return true;181182// Loads or stores cannot be moved past a store to the delay slot183// and stores cannot be moved past a load.184if (MI->mayLoad()) {185if (SawStore)186return true;187SawLoad = true;188}189190if (MI->mayStore()) {191if (SawStore)192return true;193SawStore = true;194if (SawLoad)195return true;196}197198assert((!MI->isCall() && !MI->isReturn()) &&199"Cannot put calls or returns in delay slot.");200201for (const MachineOperand &MO : MI->operands()) {202unsigned Reg;203204if (!MO.isReg() || !(Reg = MO.getReg()))205continue; // skip206207if (MO.isDef()) {208// check whether Reg is defined or used before delay slot.209if (isRegInSet(RegDefs, Reg) || isRegInSet(RegUses, Reg))210return true;211}212if (MO.isUse()) {213// check whether Reg is defined before delay slot.214if (isRegInSet(RegDefs, Reg))215return true;216}217}218return false;219}220221// Insert Defs and Uses of MI into the sets RegDefs and RegUses.222void Filler::insertDefsUses(MachineBasicBlock::instr_iterator MI,223SmallSet<unsigned, 32> &RegDefs,224SmallSet<unsigned, 32> &RegUses) {225// If MI is a call or return, just examine the explicit non-variadic operands.226const MCInstrDesc &MCID = MI->getDesc();227unsigned E = MI->isCall() || MI->isReturn() ? MCID.getNumOperands()228: MI->getNumOperands();229for (unsigned I = 0; I != E; ++I) {230const MachineOperand &MO = MI->getOperand(I);231unsigned Reg;232233if (!MO.isReg() || !(Reg = MO.getReg()))234continue;235236if (MO.isDef())237RegDefs.insert(Reg);238else if (MO.isUse())239RegUses.insert(Reg);240}241242// Call & return instructions defines SP implicitly. Implicit defines are not243// included in the RegDefs set of calls but instructions modifying SP cannot244// be inserted in the delay slot of a call/return as these instructions are245// expanded to multiple instructions with SP modified before the branch that246// has the delay slot.247if (MI->isCall() || MI->isReturn())248RegDefs.insert(Lanai::SP);249}250251// Returns true if the Reg or its alias is in the RegSet.252bool Filler::isRegInSet(SmallSet<unsigned, 32> &RegSet, unsigned Reg) {253// Check Reg and all aliased Registers.254for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)255if (RegSet.count(*AI))256return true;257return false;258}259260261