xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/DelaySlotFiller.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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 {
40*480093f4SDimitry Andric     const SparcSubtarget *Subtarget = nullptr;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric     static char ID;
430b57cec5SDimitry Andric     Filler() : MachineFunctionPass(ID) {}
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric     StringRef getPassName() const override { return "SPARC Delay Slot Filler"; }
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
480b57cec5SDimitry 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 
560b57cec5SDimitry Andric       for (MachineFunction::iterator FI = F.begin(), FE = F.end();
570b57cec5SDimitry Andric            FI != FE; ++FI)
580b57cec5SDimitry Andric         Changed |= runOnMachineBasicBlock(*FI);
590b57cec5SDimitry Andric       return Changed;
600b57cec5SDimitry Andric     }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
630b57cec5SDimitry Andric       return MachineFunctionProperties().set(
640b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
650b57cec5SDimitry Andric     }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric     void insertCallDefsUses(MachineBasicBlock::iterator MI,
680b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegDefs,
690b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegUses);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric     void insertDefsUses(MachineBasicBlock::iterator MI,
720b57cec5SDimitry Andric                         SmallSet<unsigned, 32>& RegDefs,
730b57cec5SDimitry Andric                         SmallSet<unsigned, 32>& RegUses);
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     bool IsRegInSet(SmallSet<unsigned, 32>& RegSet,
760b57cec5SDimitry Andric                     unsigned Reg);
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     bool delayHasHazard(MachineBasicBlock::iterator candidate,
790b57cec5SDimitry Andric                         bool &sawLoad, bool &sawStore,
800b57cec5SDimitry Andric                         SmallSet<unsigned, 32> &RegDefs,
810b57cec5SDimitry Andric                         SmallSet<unsigned, 32> &RegUses);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric     MachineBasicBlock::iterator
840b57cec5SDimitry Andric     findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric     bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric     bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
890b57cec5SDimitry Andric                                        MachineBasicBlock::iterator MBBI);
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   };
920b57cec5SDimitry Andric   char Filler::ID = 0;
930b57cec5SDimitry Andric } // end of anonymous namespace
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric /// createSparcDelaySlotFillerPass - Returns a pass that fills in delay
960b57cec5SDimitry Andric /// slots in Sparc MachineFunctions
970b57cec5SDimitry Andric ///
980b57cec5SDimitry Andric FunctionPass *llvm::createSparcDelaySlotFillerPass() {
990b57cec5SDimitry Andric   return new Filler;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric /// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
1040b57cec5SDimitry Andric /// We assume there is only one delay slot per delayed instruction.
1050b57cec5SDimitry Andric ///
1060b57cec5SDimitry Andric bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
1070b57cec5SDimitry Andric   bool Changed = false;
1080b57cec5SDimitry Andric   Subtarget = &MBB.getParent()->getSubtarget<SparcSubtarget>();
1090b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget->getInstrInfo();
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
1120b57cec5SDimitry Andric     MachineBasicBlock::iterator MI = I;
1130b57cec5SDimitry Andric     ++I;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric     // If MI is restore, try combining it with previous inst.
1160b57cec5SDimitry Andric     if (!DisableDelaySlotFiller &&
1170b57cec5SDimitry Andric         (MI->getOpcode() == SP::RESTORErr
1180b57cec5SDimitry Andric          || MI->getOpcode() == SP::RESTOREri)) {
1190b57cec5SDimitry Andric       Changed |= tryCombineRestoreWithPrevInst(MBB, MI);
1200b57cec5SDimitry Andric       continue;
1210b57cec5SDimitry Andric     }
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     // TODO: If we ever want to support v7, this needs to be extended
1240b57cec5SDimitry Andric     // to cover all floating point operations.
1250b57cec5SDimitry Andric     if (!Subtarget->isV9() &&
1260b57cec5SDimitry Andric         (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD
1270b57cec5SDimitry Andric          || MI->getOpcode() == SP::FCMPQ)) {
1280b57cec5SDimitry Andric       BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
1290b57cec5SDimitry Andric       Changed = true;
1300b57cec5SDimitry Andric       continue;
1310b57cec5SDimitry Andric     }
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric     // If MI has no delay slot, skip.
1340b57cec5SDimitry Andric     if (!MI->hasDelaySlot())
1350b57cec5SDimitry Andric       continue;
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric     MachineBasicBlock::iterator D = MBB.end();
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     if (!DisableDelaySlotFiller)
1400b57cec5SDimitry Andric       D = findDelayInstr(MBB, MI);
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     ++FilledSlots;
1430b57cec5SDimitry Andric     Changed = true;
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric     if (D == MBB.end())
1460b57cec5SDimitry Andric       BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
1470b57cec5SDimitry Andric     else
1480b57cec5SDimitry Andric       MBB.splice(I, &MBB, D);
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric     unsigned structSize = 0;
1510b57cec5SDimitry Andric     if (needsUnimp(MI, structSize)) {
1520b57cec5SDimitry Andric       MachineBasicBlock::iterator J = MI;
1530b57cec5SDimitry Andric       ++J; // skip the delay filler.
1540b57cec5SDimitry Andric       assert (J != MBB.end() && "MI needs a delay instruction.");
1550b57cec5SDimitry Andric       BuildMI(MBB, ++J, MI->getDebugLoc(),
1560b57cec5SDimitry Andric               TII->get(SP::UNIMP)).addImm(structSize);
1570b57cec5SDimitry Andric       // Bundle the delay filler and unimp with the instruction.
1580b57cec5SDimitry Andric       MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J);
1590b57cec5SDimitry Andric     } else {
1600b57cec5SDimitry Andric       MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I);
1610b57cec5SDimitry Andric     }
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric   return Changed;
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric MachineBasicBlock::iterator
1670b57cec5SDimitry Andric Filler::findDelayInstr(MachineBasicBlock &MBB,
1680b57cec5SDimitry Andric                        MachineBasicBlock::iterator slot)
1690b57cec5SDimitry Andric {
1700b57cec5SDimitry Andric   SmallSet<unsigned, 32> RegDefs;
1710b57cec5SDimitry Andric   SmallSet<unsigned, 32> RegUses;
1720b57cec5SDimitry Andric   bool sawLoad = false;
1730b57cec5SDimitry Andric   bool sawStore = false;
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   if (slot == MBB.begin())
1760b57cec5SDimitry Andric     return MBB.end();
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL)
1790b57cec5SDimitry Andric     return MBB.end();
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric   if (slot->getOpcode() == SP::RETL) {
1820b57cec5SDimitry Andric     MachineBasicBlock::iterator J = slot;
1830b57cec5SDimitry Andric     --J;
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric     if (J->getOpcode() == SP::RESTORErr
1860b57cec5SDimitry Andric         || J->getOpcode() == SP::RESTOREri) {
1870b57cec5SDimitry Andric       // change retl to ret.
1880b57cec5SDimitry Andric       slot->setDesc(Subtarget->getInstrInfo()->get(SP::RET));
1890b57cec5SDimitry Andric       return J;
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   // Call's delay filler can def some of call's uses.
1940b57cec5SDimitry Andric   if (slot->isCall())
1950b57cec5SDimitry Andric     insertCallDefsUses(slot, RegDefs, RegUses);
1960b57cec5SDimitry Andric   else
1970b57cec5SDimitry Andric     insertDefsUses(slot, RegDefs, RegUses);
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   bool done = false;
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   MachineBasicBlock::iterator I = slot;
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   while (!done) {
2040b57cec5SDimitry Andric     done = (I == MBB.begin());
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     if (!done)
2070b57cec5SDimitry Andric       --I;
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     // skip debug instruction
2100b57cec5SDimitry Andric     if (I->isDebugInstr())
2110b57cec5SDimitry Andric       continue;
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric     if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() ||
2140b57cec5SDimitry Andric         I->hasDelaySlot() || I->isBundledWithSucc())
2150b57cec5SDimitry Andric       break;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
2180b57cec5SDimitry Andric       insertDefsUses(I, RegDefs, RegUses);
2190b57cec5SDimitry Andric       continue;
2200b57cec5SDimitry Andric     }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric     return I;
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric   return MBB.end();
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate,
2280b57cec5SDimitry Andric                             bool &sawLoad,
2290b57cec5SDimitry Andric                             bool &sawStore,
2300b57cec5SDimitry Andric                             SmallSet<unsigned, 32> &RegDefs,
2310b57cec5SDimitry Andric                             SmallSet<unsigned, 32> &RegUses)
2320b57cec5SDimitry Andric {
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   if (candidate->isImplicitDef() || candidate->isKill())
2350b57cec5SDimitry Andric     return true;
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   if (candidate->mayLoad()) {
2380b57cec5SDimitry Andric     sawLoad = true;
2390b57cec5SDimitry Andric     if (sawStore)
2400b57cec5SDimitry Andric       return true;
2410b57cec5SDimitry Andric   }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric   if (candidate->mayStore()) {
2440b57cec5SDimitry Andric     if (sawStore)
2450b57cec5SDimitry Andric       return true;
2460b57cec5SDimitry Andric     sawStore = true;
2470b57cec5SDimitry Andric     if (sawLoad)
2480b57cec5SDimitry Andric       return true;
2490b57cec5SDimitry Andric   }
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) {
2520b57cec5SDimitry Andric     const MachineOperand &MO = candidate->getOperand(i);
2530b57cec5SDimitry Andric     if (!MO.isReg())
2540b57cec5SDimitry Andric       continue; // skip
2550b57cec5SDimitry Andric 
2568bcb0991SDimitry Andric     Register Reg = MO.getReg();
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric     if (MO.isDef()) {
2590b57cec5SDimitry Andric       // check whether Reg is defined or used before delay slot.
2600b57cec5SDimitry Andric       if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg))
2610b57cec5SDimitry Andric         return true;
2620b57cec5SDimitry Andric     }
2630b57cec5SDimitry Andric     if (MO.isUse()) {
2640b57cec5SDimitry Andric       // check whether Reg is defined before delay slot.
2650b57cec5SDimitry Andric       if (IsRegInSet(RegDefs, Reg))
2660b57cec5SDimitry Andric         return true;
2670b57cec5SDimitry Andric     }
2680b57cec5SDimitry Andric   }
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   unsigned Opcode = candidate->getOpcode();
2710b57cec5SDimitry Andric   // LD and LDD may have NOPs inserted afterwards in the case of some LEON
2720b57cec5SDimitry Andric   // processors, so we can't use the delay slot if this feature is switched-on.
2730b57cec5SDimitry Andric   if (Subtarget->insertNOPLoad()
2740b57cec5SDimitry Andric       &&
2750b57cec5SDimitry Andric       Opcode >=  SP::LDDArr && Opcode <= SP::LDrr)
2760b57cec5SDimitry Andric     return true;
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric   // Same as above for FDIV and FSQRT on some LEON processors.
2790b57cec5SDimitry Andric   if (Subtarget->fixAllFDIVSQRT()
2800b57cec5SDimitry Andric       &&
2810b57cec5SDimitry Andric       Opcode >=  SP::FDIVD && Opcode <= SP::FSQRTD)
2820b57cec5SDimitry Andric     return true;
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   return false;
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
2900b57cec5SDimitry Andric                                 SmallSet<unsigned, 32>& RegDefs,
2910b57cec5SDimitry Andric                                 SmallSet<unsigned, 32>& RegUses)
2920b57cec5SDimitry Andric {
2930b57cec5SDimitry Andric   // Call defines o7, which is visible to the instruction in delay slot.
2940b57cec5SDimitry Andric   RegDefs.insert(SP::O7);
2950b57cec5SDimitry Andric 
2960b57cec5SDimitry Andric   switch(MI->getOpcode()) {
2970b57cec5SDimitry Andric   default: llvm_unreachable("Unknown opcode.");
2980b57cec5SDimitry Andric   case SP::CALL: break;
2990b57cec5SDimitry Andric   case SP::CALLrr:
3000b57cec5SDimitry Andric   case SP::CALLri:
3010b57cec5SDimitry Andric     assert(MI->getNumOperands() >= 2);
3020b57cec5SDimitry Andric     const MachineOperand &Reg = MI->getOperand(0);
3030b57cec5SDimitry Andric     assert(Reg.isReg() && "CALL first operand is not a register.");
3040b57cec5SDimitry Andric     assert(Reg.isUse() && "CALL first operand is not a use.");
3050b57cec5SDimitry Andric     RegUses.insert(Reg.getReg());
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric     const MachineOperand &Operand1 = MI->getOperand(1);
3080b57cec5SDimitry Andric     if (Operand1.isImm() || Operand1.isGlobal())
3090b57cec5SDimitry Andric         break;
3100b57cec5SDimitry Andric     assert(Operand1.isReg() && "CALLrr second operand is not a register.");
3110b57cec5SDimitry Andric     assert(Operand1.isUse() && "CALLrr second operand is not a use.");
3120b57cec5SDimitry Andric     RegUses.insert(Operand1.getReg());
3130b57cec5SDimitry Andric     break;
3140b57cec5SDimitry Andric   }
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric // Insert Defs and Uses of MI into the sets RegDefs and RegUses.
3180b57cec5SDimitry Andric void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
3190b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegDefs,
3200b57cec5SDimitry Andric                             SmallSet<unsigned, 32>& RegUses)
3210b57cec5SDimitry Andric {
3220b57cec5SDimitry Andric   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
3230b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(i);
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.
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 
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;
3650b57cec5SDimitry Andric   }
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   const MachineOperand &MO = I->getOperand(structSizeOpNum);
3680b57cec5SDimitry Andric   if (!MO.isImm())
3690b57cec5SDimitry Andric     return false;
3700b57cec5SDimitry Andric   StructSize = MO.getImm();
3710b57cec5SDimitry Andric   return true;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
3750b57cec5SDimitry Andric                               MachineBasicBlock::iterator AddMI,
3760b57cec5SDimitry Andric                               const TargetInstrInfo *TII)
3770b57cec5SDimitry Andric {
3780b57cec5SDimitry Andric   // Before:  add  <op0>, <op1>, %i[0-7]
3790b57cec5SDimitry Andric   //          restore %g0, %g0, %i[0-7]
3800b57cec5SDimitry Andric   //
3810b57cec5SDimitry Andric   // After :  restore <op0>, <op1>, %o[0-7]
3820b57cec5SDimitry Andric 
3838bcb0991SDimitry Andric   Register reg = AddMI->getOperand(0).getReg();
3840b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
3850b57cec5SDimitry Andric     return false;
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   // Erase RESTORE.
3880b57cec5SDimitry Andric   RestoreMI->eraseFromParent();
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   // Change ADD to RESTORE.
3910b57cec5SDimitry Andric   AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr)
3920b57cec5SDimitry Andric                           ? SP::RESTORErr
3930b57cec5SDimitry Andric                           : SP::RESTOREri));
3940b57cec5SDimitry Andric 
3950b57cec5SDimitry Andric   // Map the destination register.
3960b57cec5SDimitry Andric   AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric   return true;
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
4020b57cec5SDimitry Andric                              MachineBasicBlock::iterator OrMI,
4030b57cec5SDimitry Andric                              const TargetInstrInfo *TII)
4040b57cec5SDimitry Andric {
4050b57cec5SDimitry Andric   // Before:  or  <op0>, <op1>, %i[0-7]
4060b57cec5SDimitry Andric   //          restore %g0, %g0, %i[0-7]
4070b57cec5SDimitry Andric   //    and <op0> or <op1> is zero,
4080b57cec5SDimitry Andric   //
4090b57cec5SDimitry Andric   // After :  restore <op0>, <op1>, %o[0-7]
4100b57cec5SDimitry Andric 
4118bcb0991SDimitry Andric   Register reg = OrMI->getOperand(0).getReg();
4120b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
4130b57cec5SDimitry Andric     return false;
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   // check whether it is a copy.
4160b57cec5SDimitry Andric   if (OrMI->getOpcode() == SP::ORrr
4170b57cec5SDimitry Andric       && OrMI->getOperand(1).getReg() != SP::G0
4180b57cec5SDimitry Andric       && OrMI->getOperand(2).getReg() != SP::G0)
4190b57cec5SDimitry Andric     return false;
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   if (OrMI->getOpcode() == SP::ORri
4220b57cec5SDimitry Andric       && OrMI->getOperand(1).getReg() != SP::G0
4230b57cec5SDimitry Andric       && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
4240b57cec5SDimitry Andric     return false;
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric   // Erase RESTORE.
4270b57cec5SDimitry Andric   RestoreMI->eraseFromParent();
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   // Change OR to RESTORE.
4300b57cec5SDimitry Andric   OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr)
4310b57cec5SDimitry Andric                          ? SP::RESTORErr
4320b57cec5SDimitry Andric                          : SP::RESTOREri));
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric   // Map the destination register.
4350b57cec5SDimitry Andric   OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   return true;
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,
4410b57cec5SDimitry Andric                                  MachineBasicBlock::iterator SetHiMI,
4420b57cec5SDimitry Andric                                  const TargetInstrInfo *TII)
4430b57cec5SDimitry Andric {
4440b57cec5SDimitry Andric   // Before:  sethi imm3, %i[0-7]
4450b57cec5SDimitry Andric   //          restore %g0, %g0, %g0
4460b57cec5SDimitry Andric   //
4470b57cec5SDimitry Andric   // After :  restore %g0, (imm3<<10), %o[0-7]
4480b57cec5SDimitry Andric 
4498bcb0991SDimitry Andric   Register reg = SetHiMI->getOperand(0).getReg();
4500b57cec5SDimitry Andric   if (reg < SP::I0 || reg > SP::I7)
4510b57cec5SDimitry Andric     return false;
4520b57cec5SDimitry Andric 
4530b57cec5SDimitry Andric   if (!SetHiMI->getOperand(1).isImm())
4540b57cec5SDimitry Andric     return false;
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   int64_t imm = SetHiMI->getOperand(1).getImm();
4570b57cec5SDimitry Andric 
4580b57cec5SDimitry Andric   // Is it a 3 bit immediate?
4590b57cec5SDimitry Andric   if (!isInt<3>(imm))
4600b57cec5SDimitry Andric     return false;
4610b57cec5SDimitry Andric 
4620b57cec5SDimitry Andric   // Make it a 13 bit immediate.
4630b57cec5SDimitry Andric   imm = (imm << 10) & 0x1FFF;
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric   assert(RestoreMI->getOpcode() == SP::RESTORErr);
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric   RestoreMI->setDesc(TII->get(SP::RESTOREri));
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
4700b57cec5SDimitry Andric   RestoreMI->getOperand(1).setReg(SP::G0);
4710b57cec5SDimitry Andric   RestoreMI->getOperand(2).ChangeToImmediate(imm);
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric   // Erase the original SETHI.
4750b57cec5SDimitry Andric   SetHiMI->eraseFromParent();
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric   return true;
4780b57cec5SDimitry Andric }
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
4810b57cec5SDimitry Andric                                         MachineBasicBlock::iterator MBBI)
4820b57cec5SDimitry Andric {
4830b57cec5SDimitry Andric   // No previous instruction.
4840b57cec5SDimitry Andric   if (MBBI == MBB.begin())
4850b57cec5SDimitry Andric     return false;
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   // assert that MBBI is a "restore %g0, %g0, %g0".
4880b57cec5SDimitry Andric   assert(MBBI->getOpcode() == SP::RESTORErr
4890b57cec5SDimitry Andric          && MBBI->getOperand(0).getReg() == SP::G0
4900b57cec5SDimitry Andric          && MBBI->getOperand(1).getReg() == SP::G0
4910b57cec5SDimitry Andric          && MBBI->getOperand(2).getReg() == SP::G0);
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric   MachineBasicBlock::iterator PrevInst = std::prev(MBBI);
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric   // It cannot be combined with a bundled instruction.
4960b57cec5SDimitry Andric   if (PrevInst->isBundledWithSucc())
4970b57cec5SDimitry Andric     return false;
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   const TargetInstrInfo *TII = Subtarget->getInstrInfo();
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   switch (PrevInst->getOpcode()) {
5020b57cec5SDimitry Andric   default: break;
5030b57cec5SDimitry Andric   case SP::ADDrr:
5040b57cec5SDimitry Andric   case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
5050b57cec5SDimitry Andric   case SP::ORrr:
5060b57cec5SDimitry Andric   case SP::ORri:  return combineRestoreOR(MBBI, PrevInst, TII); break;
5070b57cec5SDimitry Andric   case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
5080b57cec5SDimitry Andric   }
5090b57cec5SDimitry Andric   // It cannot combine with the previous instruction.
5100b57cec5SDimitry Andric   return false;
5110b57cec5SDimitry Andric }
512