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