xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Sparc/DelaySlotFiller.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===-- DelaySlotFiller.cpp - SPARC 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 //
90b57cec5SDimitry Andric // This is a simple local pass that attempts to fill delay slots with useful
100b57cec5SDimitry Andric // instructions. If no instructions can be moved into the delay slot, then a
110b57cec5SDimitry Andric // NOP is placed.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "Sparc.h"
150b57cec5SDimitry Andric #include "SparcSubtarget.h"
160b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
170b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
230b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
240b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #define DEBUG_TYPE "delay-slot-filler"
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric STATISTIC(FilledSlots, "Number of delay slots filled");
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric static cl::opt<bool> DisableDelaySlotFiller(
330b57cec5SDimitry Andric   "disable-sparc-delay-filler",
340b57cec5SDimitry Andric   cl::init(false),
350b57cec5SDimitry Andric   cl::desc("Disable the Sparc delay slot filler."),
360b57cec5SDimitry Andric   cl::Hidden);
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace {
390b57cec5SDimitry Andric   struct Filler : public MachineFunctionPass {
40480093f4SDimitry Andric     const SparcSubtarget *Subtarget = nullptr;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric     static char ID;
Filler__anonbd2fc6ef0111::Filler430b57cec5SDimitry Andric     Filler() : MachineFunctionPass(ID) {}
440b57cec5SDimitry Andric 
getPassName__anonbd2fc6ef0111::Filler450b57cec5SDimitry Andric     StringRef getPassName() const override { return "SPARC Delay Slot Filler"; }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
runOnMachineFunction__anonbd2fc6ef0111::Filler480b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &F) override {
490b57cec5SDimitry Andric       bool Changed = false;
500b57cec5SDimitry Andric       Subtarget = &F.getSubtarget<SparcSubtarget>();
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric       // This pass invalidates liveness information when it reorders
530b57cec5SDimitry Andric       // instructions to fill delay slot.
540b57cec5SDimitry Andric       F.getRegInfo().invalidateLiveness();
550b57cec5SDimitry Andric 
564824e7fdSDimitry Andric       for (MachineBasicBlock &MBB : F)
574824e7fdSDimitry Andric         Changed |= runOnMachineBasicBlock(MBB);
580b57cec5SDimitry Andric       return Changed;
590b57cec5SDimitry Andric     }
600b57cec5SDimitry Andric 
getRequiredProperties__anonbd2fc6ef0111::Filler610b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
620b57cec5SDimitry Andric       return MachineFunctionProperties().set(
630b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
640b57cec5SDimitry Andric     }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric     void insertCallDefsUses(MachineBasicBlock::iterator MI,
670b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegDefs,
680b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegUses);
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric     void insertDefsUses(MachineBasicBlock::iterator MI,
710b57cec5SDimitry Andric                         SmallSet<unsigned, 32>& RegDefs,
720b57cec5SDimitry Andric                         SmallSet<unsigned, 32>& RegUses);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric     bool IsRegInSet(SmallSet<unsigned, 32>& RegSet,
750b57cec5SDimitry Andric                     unsigned Reg);
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric     bool delayHasHazard(MachineBasicBlock::iterator candidate,
780b57cec5SDimitry Andric                         bool &sawLoad, bool &sawStore,
790b57cec5SDimitry Andric                         SmallSet<unsigned, 32> &RegDefs,
800b57cec5SDimitry Andric                         SmallSet<unsigned, 32> &RegUses);
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric     MachineBasicBlock::iterator
830b57cec5SDimitry Andric     findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot);
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize);
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric     bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
880b57cec5SDimitry Andric                                        MachineBasicBlock::iterator MBBI);
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   };
910b57cec5SDimitry Andric   char Filler::ID = 0;
920b57cec5SDimitry Andric } // end of anonymous namespace
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric /// createSparcDelaySlotFillerPass - Returns a pass that fills in delay
950b57cec5SDimitry Andric /// slots in Sparc MachineFunctions
960b57cec5SDimitry Andric ///
createSparcDelaySlotFillerPass()970b57cec5SDimitry Andric FunctionPass *llvm::createSparcDelaySlotFillerPass() {
980b57cec5SDimitry Andric   return new Filler;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric /// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
1030b57cec5SDimitry Andric /// We assume there is only one delay slot per delayed instruction.
1040b57cec5SDimitry Andric ///
runOnMachineBasicBlock(MachineBasicBlock & MBB)1050b57cec5SDimitry Andric bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
1060b57cec5SDimitry Andric   bool Changed = false;
1070b57cec5SDimitry Andric   Subtarget = &MBB.getParent()->getSubtarget<SparcSubtarget>();
1080b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget->getInstrInfo();
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
1110b57cec5SDimitry Andric     MachineBasicBlock::iterator MI = I;
1120b57cec5SDimitry Andric     ++I;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric     // If MI is restore, try combining it with previous inst.
1150b57cec5SDimitry Andric     if (!DisableDelaySlotFiller &&
1160b57cec5SDimitry Andric         (MI->getOpcode() == SP::RESTORErr
1170b57cec5SDimitry Andric          || MI->getOpcode() == SP::RESTOREri)) {
1180b57cec5SDimitry Andric       Changed |= tryCombineRestoreWithPrevInst(MBB, MI);
1190b57cec5SDimitry Andric       continue;
1200b57cec5SDimitry Andric     }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     // TODO: If we ever want to support v7, this needs to be extended
1230b57cec5SDimitry Andric     // to cover all floating point operations.
1240b57cec5SDimitry Andric     if (!Subtarget->isV9() &&
1250b57cec5SDimitry Andric         (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD
1260b57cec5SDimitry Andric          || MI->getOpcode() == SP::FCMPQ)) {
1270b57cec5SDimitry Andric       BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
1280b57cec5SDimitry Andric       Changed = true;
1290b57cec5SDimitry Andric       continue;
1300b57cec5SDimitry Andric     }
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric     // If MI has no delay slot, skip.
1330b57cec5SDimitry Andric     if (!MI->hasDelaySlot())
1340b57cec5SDimitry Andric       continue;
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric     MachineBasicBlock::iterator D = MBB.end();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric     if (!DisableDelaySlotFiller)
1390b57cec5SDimitry Andric       D = findDelayInstr(MBB, MI);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric     ++FilledSlots;
1420b57cec5SDimitry Andric     Changed = true;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric     if (D == MBB.end())
1450b57cec5SDimitry Andric       BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
1460b57cec5SDimitry Andric     else
1470b57cec5SDimitry Andric       MBB.splice(I, &MBB, D);
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric     unsigned structSize = 0;
1500b57cec5SDimitry Andric     if (needsUnimp(MI, structSize)) {
1510b57cec5SDimitry Andric       MachineBasicBlock::iterator J = MI;
1520b57cec5SDimitry Andric       ++J; // skip the delay filler.
1530b57cec5SDimitry Andric       assert (J != MBB.end() && "MI needs a delay instruction.");
1540b57cec5SDimitry Andric       BuildMI(MBB, ++J, MI->getDebugLoc(),
1550b57cec5SDimitry Andric               TII->get(SP::UNIMP)).addImm(structSize);
1560b57cec5SDimitry Andric       // Bundle the delay filler and unimp with the instruction.
1570b57cec5SDimitry Andric       MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J);
1580b57cec5SDimitry Andric     } else {
1590b57cec5SDimitry Andric       MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I);
1600b57cec5SDimitry Andric     }
1610b57cec5SDimitry Andric   }
1620b57cec5SDimitry Andric   return Changed;
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric MachineBasicBlock::iterator
findDelayInstr(MachineBasicBlock & MBB,MachineBasicBlock::iterator slot)1660b57cec5SDimitry Andric Filler::findDelayInstr(MachineBasicBlock &MBB,
1670b57cec5SDimitry Andric                        MachineBasicBlock::iterator slot)
1680b57cec5SDimitry Andric {
1690b57cec5SDimitry Andric   SmallSet<unsigned, 32> RegDefs;
1700b57cec5SDimitry Andric   SmallSet<unsigned, 32> RegUses;
1710b57cec5SDimitry Andric   bool sawLoad = false;
1720b57cec5SDimitry Andric   bool sawStore = false;
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   if (slot == MBB.begin())
1750b57cec5SDimitry Andric     return MBB.end();
1760b57cec5SDimitry Andric 
17781ad6265SDimitry Andric   unsigned Opc = slot->getOpcode();
17881ad6265SDimitry Andric 
17981ad6265SDimitry Andric   if (Opc == SP::RET || Opc == SP::TLS_CALL)
1800b57cec5SDimitry Andric     return MBB.end();
1810b57cec5SDimitry Andric 
18281ad6265SDimitry Andric   if (Opc == SP::RETL || Opc == SP::TAIL_CALL || Opc == SP::TAIL_CALLri) {
1830b57cec5SDimitry Andric     MachineBasicBlock::iterator J = slot;
1840b57cec5SDimitry Andric     --J;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric     if (J->getOpcode() == SP::RESTORErr
1870b57cec5SDimitry Andric         || J->getOpcode() == SP::RESTOREri) {
1880b57cec5SDimitry Andric       // change retl to ret.
18981ad6265SDimitry Andric       if (Opc == SP::RETL)
1900b57cec5SDimitry Andric         slot->setDesc(Subtarget->getInstrInfo()->get(SP::RET));
1910b57cec5SDimitry Andric       return J;
1920b57cec5SDimitry Andric     }
1930b57cec5SDimitry Andric   }
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   // Call's delay filler can def some of call's uses.
1960b57cec5SDimitry Andric   if (slot->isCall())
1970b57cec5SDimitry Andric     insertCallDefsUses(slot, RegDefs, RegUses);
1980b57cec5SDimitry Andric   else
1990b57cec5SDimitry Andric     insertDefsUses(slot, RegDefs, RegUses);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   bool done = false;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   MachineBasicBlock::iterator I = slot;
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric   while (!done) {
2060b57cec5SDimitry Andric     done = (I == MBB.begin());
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric     if (!done)
2090b57cec5SDimitry Andric       --I;
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric     // skip debug instruction
2120b57cec5SDimitry Andric     if (I->isDebugInstr())
2130b57cec5SDimitry Andric       continue;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() ||
2160b57cec5SDimitry Andric         I->hasDelaySlot() || I->isBundledWithSucc())
2170b57cec5SDimitry Andric       break;
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric     if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
2200b57cec5SDimitry Andric       insertDefsUses(I, RegDefs, RegUses);
2210b57cec5SDimitry Andric       continue;
2220b57cec5SDimitry Andric     }
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     return I;
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   return MBB.end();
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
delayHasHazard(MachineBasicBlock::iterator candidate,bool & sawLoad,bool & sawStore,SmallSet<unsigned,32> & RegDefs,SmallSet<unsigned,32> & RegUses)2290b57cec5SDimitry Andric bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate,
2300b57cec5SDimitry Andric                             bool &sawLoad,
2310b57cec5SDimitry Andric                             bool &sawStore,
2320b57cec5SDimitry Andric                             SmallSet<unsigned, 32> &RegDefs,
2330b57cec5SDimitry Andric                             SmallSet<unsigned, 32> &RegUses)
2340b57cec5SDimitry Andric {
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   if (candidate->isImplicitDef() || candidate->isKill())
2370b57cec5SDimitry Andric     return true;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   if (candidate->mayLoad()) {
2400b57cec5SDimitry Andric     sawLoad = true;
2410b57cec5SDimitry Andric     if (sawStore)
2420b57cec5SDimitry Andric       return true;
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   if (candidate->mayStore()) {
2460b57cec5SDimitry Andric     if (sawStore)
2470b57cec5SDimitry Andric       return true;
2480b57cec5SDimitry Andric     sawStore = true;
2490b57cec5SDimitry Andric     if (sawLoad)
2500b57cec5SDimitry Andric       return true;
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
253*06c3fb27SDimitry Andric   for (const MachineOperand &MO : candidate->operands()) {
2540b57cec5SDimitry Andric     if (!MO.isReg())
2550b57cec5SDimitry Andric       continue; // skip
2560b57cec5SDimitry Andric 
2578bcb0991SDimitry Andric     Register Reg = MO.getReg();
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric     if (MO.isDef()) {
2600b57cec5SDimitry Andric       // check whether Reg is defined or used before delay slot.
2610b57cec5SDimitry Andric       if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg))
2620b57cec5SDimitry Andric         return true;
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric     if (MO.isUse()) {
2650b57cec5SDimitry Andric       // check whether Reg is defined before delay slot.
2660b57cec5SDimitry Andric       if (IsRegInSet(RegDefs, Reg))
2670b57cec5SDimitry Andric         return true;
2680b57cec5SDimitry Andric     }
2690b57cec5SDimitry Andric   }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric   unsigned Opcode = candidate->getOpcode();
2720b57cec5SDimitry Andric   // LD and LDD may have NOPs inserted afterwards in the case of some LEON
2730b57cec5SDimitry Andric   // processors, so we can't use the delay slot if this feature is switched-on.
2740b57cec5SDimitry Andric   if (Subtarget->insertNOPLoad()
2750b57cec5SDimitry Andric       &&
2760b57cec5SDimitry Andric       Opcode >=  SP::LDDArr && Opcode <= SP::LDrr)
2770b57cec5SDimitry Andric     return true;
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric   // Same as above for FDIV and FSQRT on some LEON processors.
2800b57cec5SDimitry Andric   if (Subtarget->fixAllFDIVSQRT()
2810b57cec5SDimitry Andric       &&
2820b57cec5SDimitry Andric       Opcode >=  SP::FDIVD && Opcode <= SP::FSQRTD)
2830b57cec5SDimitry Andric     return true;
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   return false;
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric 
insertCallDefsUses(MachineBasicBlock::iterator MI,SmallSet<unsigned,32> & RegDefs,SmallSet<unsigned,32> & RegUses)2900b57cec5SDimitry Andric void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
2910b57cec5SDimitry Andric                                 SmallSet<unsigned, 32>& RegDefs,
2920b57cec5SDimitry Andric                                 SmallSet<unsigned, 32>& RegUses)
2930b57cec5SDimitry Andric {
2940b57cec5SDimitry Andric   // Call defines o7, which is visible to the instruction in delay slot.
2950b57cec5SDimitry Andric   RegDefs.insert(SP::O7);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   switch(MI->getOpcode()) {
2980b57cec5SDimitry Andric   default: llvm_unreachable("Unknown opcode.");
2990b57cec5SDimitry Andric   case SP::CALL: break;
3000b57cec5SDimitry Andric   case SP::CALLrr:
3010b57cec5SDimitry Andric   case SP::CALLri:
3020b57cec5SDimitry Andric     assert(MI->getNumOperands() >= 2);
3030b57cec5SDimitry Andric     const MachineOperand &Reg = MI->getOperand(0);
3040b57cec5SDimitry Andric     assert(Reg.isReg() && "CALL first operand is not a register.");
3050b57cec5SDimitry Andric     assert(Reg.isUse() && "CALL first operand is not a use.");
3060b57cec5SDimitry Andric     RegUses.insert(Reg.getReg());
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     const MachineOperand &Operand1 = MI->getOperand(1);
3090b57cec5SDimitry Andric     if (Operand1.isImm() || Operand1.isGlobal())
3100b57cec5SDimitry Andric         break;
3110b57cec5SDimitry Andric     assert(Operand1.isReg() && "CALLrr second operand is not a register.");
3120b57cec5SDimitry Andric     assert(Operand1.isUse() && "CALLrr second operand is not a use.");
3130b57cec5SDimitry Andric     RegUses.insert(Operand1.getReg());
3140b57cec5SDimitry Andric     break;
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric // Insert Defs and Uses of MI into the sets RegDefs and RegUses.
insertDefsUses(MachineBasicBlock::iterator MI,SmallSet<unsigned,32> & RegDefs,SmallSet<unsigned,32> & RegUses)3190b57cec5SDimitry Andric void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
3200b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegDefs,
3210b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegUses)
3220b57cec5SDimitry Andric {
3234824e7fdSDimitry Andric   for (const MachineOperand &MO : MI->operands()) {
3240b57cec5SDimitry Andric     if (!MO.isReg())
3250b57cec5SDimitry Andric       continue;
3260b57cec5SDimitry Andric 
3278bcb0991SDimitry Andric     Register Reg = MO.getReg();
3280b57cec5SDimitry Andric     if (Reg == 0)
3290b57cec5SDimitry Andric       continue;
3300b57cec5SDimitry Andric     if (MO.isDef())
3310b57cec5SDimitry Andric       RegDefs.insert(Reg);
3320b57cec5SDimitry Andric     if (MO.isUse()) {
3330b57cec5SDimitry Andric       // Implicit register uses of retl are return values and
3340b57cec5SDimitry Andric       // retl does not use them.
3350b57cec5SDimitry Andric       if (MO.isImplicit() && MI->getOpcode() == SP::RETL)
3360b57cec5SDimitry Andric         continue;
3370b57cec5SDimitry Andric       RegUses.insert(Reg);
3380b57cec5SDimitry Andric     }
3390b57cec5SDimitry Andric   }
3400b57cec5SDimitry Andric }
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric // returns true if the Reg or its alias is in the RegSet.
IsRegInSet(SmallSet<unsigned,32> & RegSet,unsigned Reg)3430b57cec5SDimitry Andric bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg)
3440b57cec5SDimitry Andric {
3450b57cec5SDimitry Andric   // Check Reg and all aliased Registers.
3460b57cec5SDimitry Andric   for (MCRegAliasIterator AI(Reg, Subtarget->getRegisterInfo(), true);
3470b57cec5SDimitry Andric        AI.isValid(); ++AI)
3480b57cec5SDimitry Andric     if (RegSet.count(*AI))
3490b57cec5SDimitry Andric       return true;
3500b57cec5SDimitry Andric   return false;
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
needsUnimp(MachineBasicBlock::iterator I,unsigned & StructSize)3530b57cec5SDimitry Andric bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
3540b57cec5SDimitry Andric {
3550b57cec5SDimitry Andric   if (!I->isCall())
3560b57cec5SDimitry Andric     return false;
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric   unsigned structSizeOpNum = 0;
3590b57cec5SDimitry Andric   switch (I->getOpcode()) {
3600b57cec5SDimitry Andric   default: llvm_unreachable("Unknown call opcode.");
3610b57cec5SDimitry Andric   case SP::CALL: structSizeOpNum = 1; break;
3620b57cec5SDimitry Andric   case SP::CALLrr:
3630b57cec5SDimitry Andric   case SP::CALLri: structSizeOpNum = 2; break;
3640b57cec5SDimitry Andric   case SP::TLS_CALL: return false;
36581ad6265SDimitry Andric   case SP::TAIL_CALLri:
36681ad6265SDimitry Andric   case SP::TAIL_CALL: return false;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   const MachineOperand &MO = I->getOperand(structSizeOpNum);
3700b57cec5SDimitry Andric   if (!MO.isImm())
3710b57cec5SDimitry Andric     return false;
3720b57cec5SDimitry Andric   StructSize = MO.getImm();
3730b57cec5SDimitry Andric   return true;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric 
combineRestoreADD(MachineBasicBlock::iterator RestoreMI,MachineBasicBlock::iterator AddMI,const TargetInstrInfo * TII)3760b57cec5SDimitry Andric static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
3770b57cec5SDimitry Andric                               MachineBasicBlock::iterator AddMI,
3780b57cec5SDimitry Andric                               const TargetInstrInfo *TII)
3790b57cec5SDimitry Andric {
3800b57cec5SDimitry Andric   // Before:  add  <op0>, <op1>, %i[0-7]
3810b57cec5SDimitry Andric   //          restore %g0, %g0, %i[0-7]
3820b57cec5SDimitry Andric   //
3830b57cec5SDimitry Andric   // After :  restore <op0>, <op1>, %o[0-7]
3840b57cec5SDimitry Andric 
3858bcb0991SDimitry Andric   Register reg = AddMI->getOperand(0).getReg();
3860b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
3870b57cec5SDimitry Andric     return false;
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   // Erase RESTORE.
3900b57cec5SDimitry Andric   RestoreMI->eraseFromParent();
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric   // Change ADD to RESTORE.
3930b57cec5SDimitry Andric   AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr)
3940b57cec5SDimitry Andric                           ? SP::RESTORErr
3950b57cec5SDimitry Andric                           : SP::RESTOREri));
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric   // Map the destination register.
3980b57cec5SDimitry Andric   AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
3990b57cec5SDimitry Andric 
4000b57cec5SDimitry Andric   return true;
4010b57cec5SDimitry Andric }
4020b57cec5SDimitry Andric 
combineRestoreOR(MachineBasicBlock::iterator RestoreMI,MachineBasicBlock::iterator OrMI,const TargetInstrInfo * TII)4030b57cec5SDimitry Andric static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
4040b57cec5SDimitry Andric                              MachineBasicBlock::iterator OrMI,
4050b57cec5SDimitry Andric                              const TargetInstrInfo *TII)
4060b57cec5SDimitry Andric {
4070b57cec5SDimitry Andric   // Before:  or  <op0>, <op1>, %i[0-7]
4080b57cec5SDimitry Andric   //          restore %g0, %g0, %i[0-7]
4090b57cec5SDimitry Andric   //    and <op0> or <op1> is zero,
4100b57cec5SDimitry Andric   //
4110b57cec5SDimitry Andric   // After :  restore <op0>, <op1>, %o[0-7]
4120b57cec5SDimitry Andric 
4138bcb0991SDimitry Andric   Register reg = OrMI->getOperand(0).getReg();
4140b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
4150b57cec5SDimitry Andric     return false;
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric   // check whether it is a copy.
4180b57cec5SDimitry Andric   if (OrMI->getOpcode() == SP::ORrr
4190b57cec5SDimitry Andric       && OrMI->getOperand(1).getReg() != SP::G0
4200b57cec5SDimitry Andric       && OrMI->getOperand(2).getReg() != SP::G0)
4210b57cec5SDimitry Andric     return false;
4220b57cec5SDimitry Andric 
4230b57cec5SDimitry Andric   if (OrMI->getOpcode() == SP::ORri
4240b57cec5SDimitry Andric       && OrMI->getOperand(1).getReg() != SP::G0
4250b57cec5SDimitry Andric       && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
4260b57cec5SDimitry Andric     return false;
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   // Erase RESTORE.
4290b57cec5SDimitry Andric   RestoreMI->eraseFromParent();
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   // Change OR to RESTORE.
4320b57cec5SDimitry Andric   OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr)
4330b57cec5SDimitry Andric                          ? SP::RESTORErr
4340b57cec5SDimitry Andric                          : SP::RESTOREri));
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric   // Map the destination register.
4370b57cec5SDimitry Andric   OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
4380b57cec5SDimitry Andric 
4390b57cec5SDimitry Andric   return true;
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric 
combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,MachineBasicBlock::iterator SetHiMI,const TargetInstrInfo * TII)4420b57cec5SDimitry Andric static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,
4430b57cec5SDimitry Andric                                  MachineBasicBlock::iterator SetHiMI,
4440b57cec5SDimitry Andric                                  const TargetInstrInfo *TII)
4450b57cec5SDimitry Andric {
4460b57cec5SDimitry Andric   // Before:  sethi imm3, %i[0-7]
4470b57cec5SDimitry Andric   //          restore %g0, %g0, %g0
4480b57cec5SDimitry Andric   //
4490b57cec5SDimitry Andric   // After :  restore %g0, (imm3<<10), %o[0-7]
4500b57cec5SDimitry Andric 
4518bcb0991SDimitry Andric   Register reg = SetHiMI->getOperand(0).getReg();
4520b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
4530b57cec5SDimitry Andric     return false;
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric   if (!SetHiMI->getOperand(1).isImm())
4560b57cec5SDimitry Andric     return false;
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   int64_t imm = SetHiMI->getOperand(1).getImm();
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // Is it a 3 bit immediate?
4610b57cec5SDimitry Andric   if (!isInt<3>(imm))
4620b57cec5SDimitry Andric     return false;
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   // Make it a 13 bit immediate.
4650b57cec5SDimitry Andric   imm = (imm << 10) & 0x1FFF;
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   assert(RestoreMI->getOpcode() == SP::RESTORErr);
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   RestoreMI->setDesc(TII->get(SP::RESTOREri));
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric   RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
4720b57cec5SDimitry Andric   RestoreMI->getOperand(1).setReg(SP::G0);
4730b57cec5SDimitry Andric   RestoreMI->getOperand(2).ChangeToImmediate(imm);
4740b57cec5SDimitry Andric 
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   // Erase the original SETHI.
4770b57cec5SDimitry Andric   SetHiMI->eraseFromParent();
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric   return true;
4800b57cec5SDimitry Andric }
4810b57cec5SDimitry Andric 
tryCombineRestoreWithPrevInst(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI)4820b57cec5SDimitry Andric bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
4830b57cec5SDimitry Andric                                         MachineBasicBlock::iterator MBBI)
4840b57cec5SDimitry Andric {
4850b57cec5SDimitry Andric   // No previous instruction.
4860b57cec5SDimitry Andric   if (MBBI == MBB.begin())
4870b57cec5SDimitry Andric     return false;
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric   // assert that MBBI is a "restore %g0, %g0, %g0".
4900b57cec5SDimitry Andric   assert(MBBI->getOpcode() == SP::RESTORErr
4910b57cec5SDimitry Andric          && MBBI->getOperand(0).getReg() == SP::G0
4920b57cec5SDimitry Andric          && MBBI->getOperand(1).getReg() == SP::G0
4930b57cec5SDimitry Andric          && MBBI->getOperand(2).getReg() == SP::G0);
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric   MachineBasicBlock::iterator PrevInst = std::prev(MBBI);
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   // It cannot be combined with a bundled instruction.
4980b57cec5SDimitry Andric   if (PrevInst->isBundledWithSucc())
4990b57cec5SDimitry Andric     return false;
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget->getInstrInfo();
5020b57cec5SDimitry Andric 
5030b57cec5SDimitry Andric   switch (PrevInst->getOpcode()) {
5040b57cec5SDimitry Andric   default: break;
5050b57cec5SDimitry Andric   case SP::ADDrr:
5060b57cec5SDimitry Andric   case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
5070b57cec5SDimitry Andric   case SP::ORrr:
5080b57cec5SDimitry Andric   case SP::ORri:  return combineRestoreOR(MBBI, PrevInst, TII); break;
5090b57cec5SDimitry Andric   case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
5100b57cec5SDimitry Andric   }
5110b57cec5SDimitry Andric   // It cannot combine with the previous instruction.
5120b57cec5SDimitry Andric   return false;
5130b57cec5SDimitry Andric }
514