263 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- LanaiDelaySlotFiller.cpp - Lanai 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 fills 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 (MachineFunction::iterator FI = MF.begin(), FE = MF.end(); FI != FE;
 | |
|          ++FI)
 | |
|       Changed |= runOnMachineBasicBlock(*FI);
 | |
|     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 (unsigned I = 0, E = MI->getNumOperands(); I != E; ++I) {
 | |
|     const MachineOperand &MO = MI->getOperand(I);
 | |
|     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.
 | |
|   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;
 | |
| }
 |