#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPC.h"
#include "PPCInstrBuilder.h"
#include "PPCInstrInfo.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
#define DEBUG_TYPE "ppc-mi-peepholes"
STATISTIC(RemoveTOCSave, "Number of TOC saves removed");
STATISTIC(MultiTOCSaves,
"Number of functions with multiple TOC saves that must be kept");
STATISTIC(NumTOCSavesInPrologue, "Number of TOC saves placed in the prologue");
STATISTIC(NumEliminatedSExt, "Number of eliminated sign-extensions");
STATISTIC(NumEliminatedZExt, "Number of eliminated zero-extensions");
STATISTIC(NumOptADDLIs, "Number of optimized ADD instruction fed by LI");
STATISTIC(NumConvertedToImmediateForm,
"Number of instructions converted to their immediate form");
STATISTIC(NumFunctionsEnteredInMIPeephole,
"Number of functions entered in PPC MI Peepholes");
STATISTIC(NumFixedPointIterations,
"Number of fixed-point iterations converting reg-reg instructions "
"to reg-imm ones");
STATISTIC(NumRotatesCollapsed,
"Number of pairs of rotate left, clear left/right collapsed");
STATISTIC(NumEXTSWAndSLDICombined,
"Number of pairs of EXTSW and SLDI combined as EXTSWSLI");
STATISTIC(NumLoadImmZeroFoldedAndRemoved,
"Number of LI(8) reg, 0 that are folded to r0 and removed");
static cl::opt<bool>
FixedPointRegToImm("ppc-reg-to-imm-fixed-point", cl::Hidden, cl::init(true),
cl::desc("Iterate to a fixed point when attempting to "
"convert reg-reg instructions to reg-imm"));
static cl::opt<bool>
ConvertRegReg("ppc-convert-rr-to-ri", cl::Hidden, cl::init(true),
cl::desc("Convert eligible reg+reg instructions to reg+imm"));
static cl::opt<bool>
EnableSExtElimination("ppc-eliminate-signext",
cl::desc("enable elimination of sign-extensions"),
cl::init(false), cl::Hidden);
static cl::opt<bool>
EnableZExtElimination("ppc-eliminate-zeroext",
cl::desc("enable elimination of zero-extensions"),
cl::init(false), cl::Hidden);
static cl::opt<bool>
EnableTrapOptimization("ppc-opt-conditional-trap",
cl::desc("enable optimization of conditional traps"),
cl::init(false), cl::Hidden);
namespace {
struct PPCMIPeephole : public MachineFunctionPass {
static char ID;
const PPCInstrInfo *TII;
MachineFunction *MF;
MachineRegisterInfo *MRI;
PPCMIPeephole() : MachineFunctionPass(ID) {
initializePPCMIPeepholePass(*PassRegistry::getPassRegistry());
}
private:
MachineDominatorTree *MDT;
MachinePostDominatorTree *MPDT;
MachineBlockFrequencyInfo *MBFI;
uint64_t EntryFreq;
void initialize(MachineFunction &MFParm);
bool simplifyCode();
bool eliminateRedundantCompare();
bool eliminateRedundantTOCSaves(std::map<MachineInstr *, bool> &TOCSaves);
bool combineSEXTAndSHL(MachineInstr &MI, MachineInstr *&ToErase);
bool emitRLDICWhenLoweringJumpTables(MachineInstr &MI);
void UpdateTOCSaves(std::map<MachineInstr *, bool> &TOCSaves,
MachineInstr *MI);
public:
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<MachineDominatorTree>();
AU.addRequired<MachinePostDominatorTree>();
AU.addRequired<MachineBlockFrequencyInfo>();
AU.addPreserved<MachineDominatorTree>();
AU.addPreserved<MachinePostDominatorTree>();
AU.addPreserved<MachineBlockFrequencyInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
bool runOnMachineFunction(MachineFunction &MF) override {
initialize(MF);
assert((MF.getRegInfo().use_empty(PPC::X2) ||
!MF.getSubtarget<PPCSubtarget>().isUsingPCRelativeCalls()) &&
"TOC pointer used in a function using PC-Relative addressing!");
if (skipFunction(MF.getFunction()))
return false;
return simplifyCode();
}
};
void PPCMIPeephole::initialize(MachineFunction &MFParm) {
MF = &MFParm;
MRI = &MF->getRegInfo();
MDT = &getAnalysis<MachineDominatorTree>();
MPDT = &getAnalysis<MachinePostDominatorTree>();
MBFI = &getAnalysis<MachineBlockFrequencyInfo>();
EntryFreq = MBFI->getEntryFreq();
TII = MF->getSubtarget<PPCSubtarget>().getInstrInfo();
LLVM_DEBUG(dbgs() << "*** PowerPC MI peephole pass ***\n\n");
LLVM_DEBUG(MF->dump());
}
static MachineInstr *getVRegDefOrNull(MachineOperand *Op,
MachineRegisterInfo *MRI) {
assert(Op && "Invalid Operand!");
if (!Op->isReg())
return nullptr;
Register Reg = Op->getReg();
if (!Register::isVirtualRegister(Reg))
return nullptr;
return MRI->getVRegDef(Reg);
}
static unsigned
getKnownLeadingZeroCount(MachineInstr *MI, const PPCInstrInfo *TII) {
unsigned Opcode = MI->getOpcode();
if (Opcode == PPC::RLDICL || Opcode == PPC::RLDICL_rec ||
Opcode == PPC::RLDCL || Opcode == PPC::RLDCL_rec)
return MI->getOperand(3).getImm();
if ((Opcode == PPC::RLDIC || Opcode == PPC::RLDIC_rec) &&
MI->getOperand(3).getImm() <= 63 - MI->getOperand(2).getImm())
return MI->getOperand(3).getImm();
if ((Opcode == PPC::RLWINM || Opcode == PPC::RLWINM_rec ||
Opcode == PPC::RLWNM || Opcode == PPC::RLWNM_rec ||
Opcode == PPC::RLWINM8 || Opcode == PPC::RLWNM8) &&
MI->getOperand(3).getImm() <= MI->getOperand(4).getImm())
return 32 + MI->getOperand(3).getImm();
if (Opcode == PPC::ANDI_rec) {
uint16_t Imm = MI->getOperand(2).getImm();
return 48 + countLeadingZeros(Imm);
}
if (Opcode == PPC::CNTLZW || Opcode == PPC::CNTLZW_rec ||
Opcode == PPC::CNTTZW || Opcode == PPC::CNTTZW_rec ||
Opcode == PPC::CNTLZW8 || Opcode == PPC::CNTTZW8)
return 58;
if (Opcode == PPC::CNTLZD || Opcode == PPC::CNTLZD_rec ||
Opcode == PPC::CNTTZD || Opcode == PPC::CNTTZD_rec)
return 57;
if (Opcode == PPC::LHZ || Opcode == PPC::LHZX ||
Opcode == PPC::LHZ8 || Opcode == PPC::LHZX8 ||
Opcode == PPC::LHZU || Opcode == PPC::LHZUX ||
Opcode == PPC::LHZU8 || Opcode == PPC::LHZUX8)
return 48;
if (Opcode == PPC::LBZ || Opcode == PPC::LBZX ||
Opcode == PPC::LBZ8 || Opcode == PPC::LBZX8 ||
Opcode == PPC::LBZU || Opcode == PPC::LBZUX ||
Opcode == PPC::LBZU8 || Opcode == PPC::LBZUX8)
return 56;
if (TII->isZeroExtended(*MI))
return 32;
return 0;
}
void PPCMIPeephole::UpdateTOCSaves(
std::map<MachineInstr *, bool> &TOCSaves, MachineInstr *MI) {
assert(TII->isTOCSaveMI(*MI) && "Expecting a TOC save instruction here");
if (MF->getSubtarget<PPCSubtarget>().isELFv2ABI()) {
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
MachineBasicBlock *Entry = &MF->front();
uint64_t CurrBlockFreq = MBFI->getBlockFreq(MI->getParent()).getFrequency();
if (CurrBlockFreq > EntryFreq || MPDT->dominates(MI->getParent(), Entry))
FI->setMustSaveTOC(true);
if (FI->mustSaveTOC()) {
for (auto &TOCSave : TOCSaves)
TOCSave.second = false;
TOCSaves[MI] = false;
return;
}
}
bool Keep = true;
for (auto &I : TOCSaves) {
MachineInstr *CurrInst = I.first;
if (I.second && MDT->dominates(MI, CurrInst))
I.second = false;
if (MDT->dominates(CurrInst, MI)) {
Keep = false;
break;
}
}
TOCSaves[MI] = Keep;
}
static bool collectUnprimedAccPHIs(MachineRegisterInfo *MRI,
MachineInstr *RootPHI,
SmallVectorImpl<MachineInstr *> &PHIs) {
PHIs.push_back(RootPHI);
unsigned VisitedIndex = 0;
while (VisitedIndex < PHIs.size()) {
MachineInstr *VisitedPHI = PHIs[VisitedIndex];
for (unsigned PHIOp = 1, NumOps = VisitedPHI->getNumOperands();
PHIOp != NumOps; PHIOp += 2) {
Register RegOp = VisitedPHI->getOperand(PHIOp).getReg();
if (!Register::isVirtualRegister(RegOp))
return false;
MachineInstr *Instr = MRI->getVRegDef(RegOp);
unsigned Opcode = Instr->getOpcode();
if (Opcode == PPC::COPY) {
Register Reg = Instr->getOperand(1).getReg();
if (!Register::isVirtualRegister(Reg) ||
MRI->getRegClass(Reg) != &PPC::ACCRCRegClass)
return false;
} else if (Opcode != PPC::IMPLICIT_DEF && Opcode != PPC::PHI)
return false;
if (Opcode != PPC::PHI)
continue;
if (llvm::is_contained(PHIs, Instr))
return false;
PHIs.push_back(Instr);
}
VisitedIndex++;
}
return true;
}
static void convertUnprimedAccPHIs(const PPCInstrInfo *TII,
MachineRegisterInfo *MRI,
SmallVectorImpl<MachineInstr *> &PHIs,
Register Dst) {
DenseMap<MachineInstr *, MachineInstr *> ChangedPHIMap;
for (MachineInstr *PHI : llvm::reverse(PHIs)) {
SmallVector<std::pair<MachineOperand, MachineOperand>, 4> PHIOps;
for (unsigned PHIOp = 1, NumOps = PHI->getNumOperands(); PHIOp != NumOps;
PHIOp += 2) {
Register RegOp = PHI->getOperand(PHIOp).getReg();
MachineInstr *PHIInput = MRI->getVRegDef(RegOp);
unsigned Opcode = PHIInput->getOpcode();
assert((Opcode == PPC::COPY || Opcode == PPC::IMPLICIT_DEF ||
Opcode == PPC::PHI) &&
"Unexpected instruction");
if (Opcode == PPC::COPY) {
assert(MRI->getRegClass(PHIInput->getOperand(1).getReg()) ==
&PPC::ACCRCRegClass &&
"Unexpected register class");
PHIOps.push_back({PHIInput->getOperand(1), PHI->getOperand(PHIOp + 1)});
} else if (Opcode == PPC::IMPLICIT_DEF) {
Register AccReg = MRI->createVirtualRegister(&PPC::ACCRCRegClass);
BuildMI(*PHIInput->getParent(), PHIInput, PHIInput->getDebugLoc(),
TII->get(PPC::IMPLICIT_DEF), AccReg);
PHIOps.push_back({MachineOperand::CreateReg(AccReg, false),
PHI->getOperand(PHIOp + 1)});
} else if (Opcode == PPC::PHI) {
assert(ChangedPHIMap.count(PHIInput) == 1 &&
"This PHI node should have already been changed.");
MachineInstr *PrimedAccPHI = ChangedPHIMap.lookup(PHIInput);
PHIOps.push_back({MachineOperand::CreateReg(
PrimedAccPHI->getOperand(0).getReg(), false),
PHI->getOperand(PHIOp + 1)});
}
}
Register AccReg = Dst;
if (PHI != PHIs[0])
AccReg = MRI->createVirtualRegister(&PPC::ACCRCRegClass);
MachineInstrBuilder NewPHI = BuildMI(
*PHI->getParent(), PHI, PHI->getDebugLoc(), TII->get(PPC::PHI), AccReg);
for (auto RegMBB : PHIOps)
NewPHI.add(RegMBB.first).add(RegMBB.second);
ChangedPHIMap[PHI] = NewPHI.getInstr();
}
}
bool PPCMIPeephole::simplifyCode() {
bool Simplified = false;
bool TrapOpt = false;
MachineInstr* ToErase = nullptr;
std::map<MachineInstr *, bool> TOCSaves;
const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
NumFunctionsEnteredInMIPeephole++;
if (ConvertRegReg) {
bool SomethingChanged = false;
do {
NumFixedPointIterations++;
SomethingChanged = false;
for (MachineBasicBlock &MBB : *MF) {
for (MachineInstr &MI : MBB) {
if (MI.isDebugInstr())
continue;
if (TII->convertToImmediateForm(MI)) {
LLVM_DEBUG(dbgs() << "Converted instruction to imm form: ");
LLVM_DEBUG(MI.dump());
NumConvertedToImmediateForm++;
SomethingChanged = true;
Simplified = true;
continue;
}
}
}
} while (SomethingChanged && FixedPointRegToImm);
}
for (MachineBasicBlock &MBB : *MF) {
for (MachineInstr &MI : MBB) {
if (ToErase) {
ToErase->eraseFromParent();
ToErase = nullptr;
}
if (EnableTrapOptimization && TrapOpt) {
ToErase = &MI;
continue;
}
if (MI.isDebugInstr())
continue;
switch (MI.getOpcode()) {
default:
break;
case PPC::COPY: {
Register Src = MI.getOperand(1).getReg();
Register Dst = MI.getOperand(0).getReg();
if (!Register::isVirtualRegister(Src) ||
!Register::isVirtualRegister(Dst))
break;
if (MRI->getRegClass(Src) != &PPC::UACCRCRegClass ||
MRI->getRegClass(Dst) != &PPC::ACCRCRegClass)
break;
MachineInstr *RootPHI = MRI->getVRegDef(Src);
if (RootPHI->getOpcode() != PPC::PHI)
break;
SmallVector<MachineInstr *, 4> PHIs;
if (!collectUnprimedAccPHIs(MRI, RootPHI, PHIs))
break;
convertUnprimedAccPHIs(TII, MRI, PHIs, Dst);
ToErase = &MI;
break;
}
case PPC::LI:
case PPC::LI8: {
if (!MI.getOperand(1).isImm() || MI.getOperand(1).getImm() != 0)
break;
Register MIDestReg = MI.getOperand(0).getReg();
for (MachineInstr& UseMI : MRI->use_instructions(MIDestReg))
Simplified |= TII->onlyFoldImmediate(UseMI, MI, MIDestReg);
if (MRI->use_nodbg_empty(MIDestReg)) {
++NumLoadImmZeroFoldedAndRemoved;
ToErase = &MI;
}
break;
}
case PPC::STW:
case PPC::STD: {
MachineFrameInfo &MFI = MF->getFrameInfo();
if (MFI.hasVarSizedObjects() ||
(!MF->getSubtarget<PPCSubtarget>().isELFv2ABI() &&
!MF->getSubtarget<PPCSubtarget>().isAIXABI()))
break;
if (TII->isTOCSaveMI(MI))
UpdateTOCSaves(TOCSaves, &MI);
break;
}
case PPC::XXPERMDI: {
int Immed = MI.getOperand(3).getImm();
if (Immed == 1)
break;
Register TrueReg1 =
TRI->lookThruCopyLike(MI.getOperand(1).getReg(), MRI);
Register TrueReg2 =
TRI->lookThruCopyLike(MI.getOperand(2).getReg(), MRI);
if (!(TrueReg1 == TrueReg2 && Register::isVirtualRegister(TrueReg1)))
break;
MachineInstr *DefMI = MRI->getVRegDef(TrueReg1);
if (!DefMI)
break;
unsigned DefOpc = DefMI->getOpcode();
auto isConversionOfLoadAndSplat = [=]() -> bool {
if (DefOpc != PPC::XVCVDPSXDS && DefOpc != PPC::XVCVDPUXDS)
return false;
Register FeedReg1 =
TRI->lookThruCopyLike(DefMI->getOperand(1).getReg(), MRI);
if (Register::isVirtualRegister(FeedReg1)) {
MachineInstr *LoadMI = MRI->getVRegDef(FeedReg1);
if (LoadMI && LoadMI->getOpcode() == PPC::LXVDSX)
return true;
}
return false;
};
if ((Immed == 0 || Immed == 3) &&
(DefOpc == PPC::LXVDSX || isConversionOfLoadAndSplat())) {
LLVM_DEBUG(dbgs() << "Optimizing load-and-splat/splat "
"to load-and-splat/copy: ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(MI.getOperand(1));
ToErase = &MI;
Simplified = true;
}
if (DefOpc == PPC::XXPERMDI) {
Register DefReg1 = DefMI->getOperand(1).getReg();
Register DefReg2 = DefMI->getOperand(2).getReg();
unsigned DefImmed = DefMI->getOperand(3).getImm();
if (DefReg1 != DefReg2) {
Register FeedReg1 = TRI->lookThruCopyLike(DefReg1, MRI);
Register FeedReg2 = TRI->lookThruCopyLike(DefReg2, MRI);
if (!(FeedReg1 == FeedReg2 &&
Register::isVirtualRegister(FeedReg1)))
break;
}
if (DefImmed == 0 || DefImmed == 3) {
LLVM_DEBUG(dbgs() << "Optimizing splat/swap or splat/splat "
"to splat/copy: ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(MI.getOperand(1));
ToErase = &MI;
Simplified = true;
}
else if ((Immed == 0 || Immed == 3) && DefImmed == 2) {
LLVM_DEBUG(dbgs() << "Optimizing swap/splat => splat: ");
LLVM_DEBUG(MI.dump());
MI.getOperand(1).setReg(DefReg1);
MI.getOperand(2).setReg(DefReg2);
MI.getOperand(3).setImm(3 - Immed);
Simplified = true;
}
else if (Immed == 2 && DefImmed == 2) {
LLVM_DEBUG(dbgs() << "Optimizing swap/swap => copy: ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(DefMI->getOperand(1));
ToErase = &MI;
Simplified = true;
}
} else if ((Immed == 0 || Immed == 3 || Immed == 2) &&
DefOpc == PPC::XXPERMDIs &&
(DefMI->getOperand(2).getImm() == 0 ||
DefMI->getOperand(2).getImm() == 3)) {
ToErase = &MI;
Simplified = true;
if (Immed == 2) {
LLVM_DEBUG(dbgs() << "Optimizing swap(splat) => copy(splat): ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(MI.getOperand(1));
break;
}
DefMI->getOperand(0).setReg(MI.getOperand(0).getReg());
LLVM_DEBUG(dbgs() << "Removing redundant splat: ");
LLVM_DEBUG(MI.dump());
}
break;
}
case PPC::VSPLTB:
case PPC::VSPLTH:
case PPC::XXSPLTW: {
unsigned MyOpcode = MI.getOpcode();
unsigned OpNo = MyOpcode == PPC::XXSPLTW ? 1 : 2;
Register TrueReg =
TRI->lookThruCopyLike(MI.getOperand(OpNo).getReg(), MRI);
if (!Register::isVirtualRegister(TrueReg))
break;
MachineInstr *DefMI = MRI->getVRegDef(TrueReg);
if (!DefMI)
break;
unsigned DefOpcode = DefMI->getOpcode();
auto isConvertOfSplat = [=]() -> bool {
if (DefOpcode != PPC::XVCVSPSXWS && DefOpcode != PPC::XVCVSPUXWS)
return false;
Register ConvReg = DefMI->getOperand(1).getReg();
if (!Register::isVirtualRegister(ConvReg))
return false;
MachineInstr *Splt = MRI->getVRegDef(ConvReg);
return Splt && (Splt->getOpcode() == PPC::LXVWSX ||
Splt->getOpcode() == PPC::XXSPLTW);
};
bool AlreadySplat = (MyOpcode == DefOpcode) ||
(MyOpcode == PPC::VSPLTB && DefOpcode == PPC::VSPLTBs) ||
(MyOpcode == PPC::VSPLTH && DefOpcode == PPC::VSPLTHs) ||
(MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::XXSPLTWs) ||
(MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::LXVWSX) ||
(MyOpcode == PPC::XXSPLTW && DefOpcode == PPC::MTVSRWS)||
(MyOpcode == PPC::XXSPLTW && isConvertOfSplat());
if (AlreadySplat) {
LLVM_DEBUG(dbgs() << "Changing redundant splat to a copy: ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(MI.getOperand(OpNo));
ToErase = &MI;
Simplified = true;
}
if (DefOpcode == PPC::XXSLDWI) {
Register ShiftRes = DefMI->getOperand(0).getReg();
Register ShiftOp1 = DefMI->getOperand(1).getReg();
Register ShiftOp2 = DefMI->getOperand(2).getReg();
unsigned ShiftImm = DefMI->getOperand(3).getImm();
unsigned SplatImm =
MI.getOperand(MyOpcode == PPC::XXSPLTW ? 2 : 1).getImm();
if (ShiftOp1 == ShiftOp2) {
unsigned NewElem = (SplatImm + ShiftImm) & 0x3;
if (MRI->hasOneNonDBGUse(ShiftRes)) {
LLVM_DEBUG(dbgs() << "Removing redundant shift: ");
LLVM_DEBUG(DefMI->dump());
ToErase = DefMI;
}
Simplified = true;
LLVM_DEBUG(dbgs() << "Changing splat immediate from " << SplatImm
<< " to " << NewElem << " in instruction: ");
LLVM_DEBUG(MI.dump());
MI.getOperand(1).setReg(ShiftOp1);
MI.getOperand(2).setImm(NewElem);
}
}
break;
}
case PPC::XVCVDPSP: {
Register TrueReg =
TRI->lookThruCopyLike(MI.getOperand(1).getReg(), MRI);
if (!Register::isVirtualRegister(TrueReg))
break;
MachineInstr *DefMI = MRI->getVRegDef(TrueReg);
if (DefMI && DefMI->getOpcode() == PPC::XXPERMDI) {
Register DefsReg1 =
TRI->lookThruCopyLike(DefMI->getOperand(1).getReg(), MRI);
Register DefsReg2 =
TRI->lookThruCopyLike(DefMI->getOperand(2).getReg(), MRI);
if (!Register::isVirtualRegister(DefsReg1) ||
!Register::isVirtualRegister(DefsReg2))
break;
MachineInstr *P1 = MRI->getVRegDef(DefsReg1);
MachineInstr *P2 = MRI->getVRegDef(DefsReg2);
if (!P1 || !P2)
break;
auto removeFRSPIfPossible = [&](MachineInstr *RoundInstr) {
unsigned Opc = RoundInstr->getOpcode();
if ((Opc == PPC::FRSP || Opc == PPC::XSRSP) &&
MRI->hasOneNonDBGUse(RoundInstr->getOperand(0).getReg())) {
Simplified = true;
Register ConvReg1 = RoundInstr->getOperand(1).getReg();
Register FRSPDefines = RoundInstr->getOperand(0).getReg();
MachineInstr &Use = *(MRI->use_instr_nodbg_begin(FRSPDefines));
for (int i = 0, e = Use.getNumOperands(); i < e; ++i)
if (Use.getOperand(i).isReg() &&
Use.getOperand(i).getReg() == FRSPDefines)
Use.getOperand(i).setReg(ConvReg1);
LLVM_DEBUG(dbgs() << "Removing redundant FRSP/XSRSP:\n");
LLVM_DEBUG(RoundInstr->dump());
LLVM_DEBUG(dbgs() << "As it feeds instruction:\n");
LLVM_DEBUG(MI.dump());
LLVM_DEBUG(dbgs() << "Through instruction:\n");
LLVM_DEBUG(DefMI->dump());
RoundInstr->eraseFromParent();
}
};
if (P1 != P2) {
removeFRSPIfPossible(P1);
removeFRSPIfPossible(P2);
break;
}
removeFRSPIfPossible(P1);
}
break;
}
case PPC::EXTSH:
case PPC::EXTSH8:
case PPC::EXTSH8_32_64: {
if (!EnableSExtElimination) break;
Register NarrowReg = MI.getOperand(1).getReg();
if (!Register::isVirtualRegister(NarrowReg))
break;
MachineInstr *SrcMI = MRI->getVRegDef(NarrowReg);
if (SrcMI->getOpcode() == PPC::LHZ ||
SrcMI->getOpcode() == PPC::LHZX) {
if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
break;
auto is64Bit = [] (unsigned Opcode) {
return Opcode == PPC::EXTSH8;
};
auto isXForm = [] (unsigned Opcode) {
return Opcode == PPC::LHZX;
};
auto getSextLoadOp = [] (bool is64Bit, bool isXForm) {
if (is64Bit)
if (isXForm) return PPC::LHAX8;
else return PPC::LHA8;
else
if (isXForm) return PPC::LHAX;
else return PPC::LHA;
};
unsigned Opc = getSextLoadOp(is64Bit(MI.getOpcode()),
isXForm(SrcMI->getOpcode()));
LLVM_DEBUG(dbgs() << "Zero-extending load\n");
LLVM_DEBUG(SrcMI->dump());
LLVM_DEBUG(dbgs() << "and sign-extension\n");
LLVM_DEBUG(MI.dump());
LLVM_DEBUG(dbgs() << "are merged into sign-extending load\n");
SrcMI->setDesc(TII->get(Opc));
SrcMI->getOperand(0).setReg(MI.getOperand(0).getReg());
ToErase = &MI;
Simplified = true;
NumEliminatedSExt++;
}
break;
}
case PPC::EXTSW:
case PPC::EXTSW_32:
case PPC::EXTSW_32_64: {
if (!EnableSExtElimination) break;
Register NarrowReg = MI.getOperand(1).getReg();
if (!Register::isVirtualRegister(NarrowReg))
break;
MachineInstr *SrcMI = MRI->getVRegDef(NarrowReg);
if (SrcMI->getOpcode() == PPC::LWZ ||
SrcMI->getOpcode() == PPC::LWZX) {
if (!MRI->hasOneNonDBGUse(SrcMI->getOperand(0).getReg()))
break;
auto is64Bit = [] (unsigned Opcode) {
return Opcode == PPC::EXTSW || Opcode == PPC::EXTSW_32_64;
};
auto isXForm = [] (unsigned Opcode) {
return Opcode == PPC::LWZX;
};
auto getSextLoadOp = [] (bool is64Bit, bool isXForm) {
if (is64Bit)
if (isXForm) return PPC::LWAX;
else return PPC::LWA;
else
if (isXForm) return PPC::LWAX_32;
else return PPC::LWA_32;
};
unsigned Opc = getSextLoadOp(is64Bit(MI.getOpcode()),
isXForm(SrcMI->getOpcode()));
LLVM_DEBUG(dbgs() << "Zero-extending load\n");
LLVM_DEBUG(SrcMI->dump());
LLVM_DEBUG(dbgs() << "and sign-extension\n");
LLVM_DEBUG(MI.dump());
LLVM_DEBUG(dbgs() << "are merged into sign-extending load\n");
SrcMI->setDesc(TII->get(Opc));
SrcMI->getOperand(0).setReg(MI.getOperand(0).getReg());
ToErase = &MI;
Simplified = true;
NumEliminatedSExt++;
} else if (MI.getOpcode() == PPC::EXTSW_32_64 &&
TII->isSignExtended(*SrcMI)) {
LLVM_DEBUG(dbgs() << "Removing redundant sign-extension\n");
Register TmpReg =
MF->getRegInfo().createVirtualRegister(&PPC::G8RCRegClass);
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::IMPLICIT_DEF),
TmpReg);
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::INSERT_SUBREG),
MI.getOperand(0).getReg())
.addReg(TmpReg)
.addReg(NarrowReg)
.addImm(PPC::sub_32);
ToErase = &MI;
Simplified = true;
NumEliminatedSExt++;
}
break;
}
case PPC::RLDICL: {
if (!EnableZExtElimination) break;
if (MI.getOperand(2).getImm() != 0)
break;
Register SrcReg = MI.getOperand(1).getReg();
if (!Register::isVirtualRegister(SrcReg))
break;
MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
if (!(SrcMI && SrcMI->getOpcode() == PPC::INSERT_SUBREG &&
SrcMI->getOperand(0).isReg() && SrcMI->getOperand(1).isReg()))
break;
MachineInstr *ImpDefMI, *SubRegMI;
ImpDefMI = MRI->getVRegDef(SrcMI->getOperand(1).getReg());
SubRegMI = MRI->getVRegDef(SrcMI->getOperand(2).getReg());
if (ImpDefMI->getOpcode() != PPC::IMPLICIT_DEF) break;
SrcMI = SubRegMI;
if (SubRegMI->getOpcode() == PPC::COPY) {
Register CopyReg = SubRegMI->getOperand(1).getReg();
if (Register::isVirtualRegister(CopyReg))
SrcMI = MRI->getVRegDef(CopyReg);
}
unsigned KnownZeroCount = getKnownLeadingZeroCount(SrcMI, TII);
if (MI.getOperand(3).getImm() <= KnownZeroCount) {
LLVM_DEBUG(dbgs() << "Removing redundant zero-extension\n");
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.addReg(SrcReg);
ToErase = &MI;
Simplified = true;
NumEliminatedZExt++;
}
break;
}
case PPC::ADD4:
case PPC::ADD8: {
auto isSingleUsePHI = [&](MachineOperand *PhiOp) {
assert(PhiOp && "Invalid Operand!");
MachineInstr *DefPhiMI = getVRegDefOrNull(PhiOp, MRI);
return DefPhiMI && (DefPhiMI->getOpcode() == PPC::PHI) &&
MRI->hasOneNonDBGUse(DefPhiMI->getOperand(0).getReg());
};
auto dominatesAllSingleUseLIs = [&](MachineOperand *DominatorOp,
MachineOperand *PhiOp) {
assert(PhiOp && "Invalid Operand!");
assert(DominatorOp && "Invalid Operand!");
MachineInstr *DefPhiMI = getVRegDefOrNull(PhiOp, MRI);
MachineInstr *DefDomMI = getVRegDefOrNull(DominatorOp, MRI);
for (unsigned i = 1; i < DefPhiMI->getNumOperands(); i += 2) {
MachineInstr *LiMI =
getVRegDefOrNull(&DefPhiMI->getOperand(i), MRI);
if (!LiMI ||
(LiMI->getOpcode() != PPC::LI && LiMI->getOpcode() != PPC::LI8)
|| !MRI->hasOneNonDBGUse(LiMI->getOperand(0).getReg()) ||
!MDT->dominates(DefDomMI, LiMI))
return false;
}
return true;
};
MachineOperand Op1 = MI.getOperand(1);
MachineOperand Op2 = MI.getOperand(2);
if (isSingleUsePHI(&Op2) && dominatesAllSingleUseLIs(&Op1, &Op2))
std::swap(Op1, Op2);
else if (!isSingleUsePHI(&Op1) || !dominatesAllSingleUseLIs(&Op2, &Op1))
break;
Register DominatorReg = Op2.getReg();
const TargetRegisterClass *TRC = MI.getOpcode() == PPC::ADD8
? &PPC::G8RC_and_G8RC_NOX0RegClass
: &PPC::GPRC_and_GPRC_NOR0RegClass;
MRI->setRegClass(DominatorReg, TRC);
MachineInstr *DefPhiMI = getVRegDefOrNull(&Op1, MRI);
for (unsigned i = 1; i < DefPhiMI->getNumOperands(); i += 2) {
MachineInstr *LiMI = getVRegDefOrNull(&DefPhiMI->getOperand(i), MRI);
LLVM_DEBUG(dbgs() << "Optimizing LI to ADDI: ");
LLVM_DEBUG(LiMI->dump());
if (LiMI->getOpcode() == PPC::ADDI || LiMI->getOpcode() == PPC::ADDI8)
continue;
assert((LiMI->getOpcode() == PPC::LI ||
LiMI->getOpcode() == PPC::LI8) &&
"Invalid Opcode!");
auto LiImm = LiMI->getOperand(1).getImm(); LiMI->removeOperand(1); LiMI->setDesc(TII->get(LiMI->getOpcode() == PPC::LI ? PPC::ADDI
: PPC::ADDI8));
MachineInstrBuilder(*LiMI->getParent()->getParent(), *LiMI)
.addReg(DominatorReg)
.addImm(LiImm); LLVM_DEBUG(LiMI->dump());
}
LLVM_DEBUG(dbgs() << "Optimizing ADD to COPY: ");
LLVM_DEBUG(MI.dump());
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::COPY),
MI.getOperand(0).getReg())
.add(Op1);
ToErase = &MI;
Simplified = true;
NumOptADDLIs++;
break;
}
case PPC::RLDICR: {
Simplified |= emitRLDICWhenLoweringJumpTables(MI) ||
combineSEXTAndSHL(MI, ToErase);
break;
}
case PPC::RLWINM:
case PPC::RLWINM_rec:
case PPC::RLWINM8:
case PPC::RLWINM8_rec: {
Simplified = TII->combineRLWINM(MI, &ToErase);
if (Simplified)
++NumRotatesCollapsed;
break;
}
case PPC::TDI:
case PPC::TWI:
case PPC::TD:
case PPC::TW: {
if (!EnableTrapOptimization) break;
MachineInstr *LiMI1 = getVRegDefOrNull(&MI.getOperand(1), MRI);
MachineInstr *LiMI2 = getVRegDefOrNull(&MI.getOperand(2), MRI);
bool IsOperand2Immediate = MI.getOperand(2).isImm();
if (!(LiMI1 && (LiMI1->getOpcode() == PPC::LI ||
LiMI1->getOpcode() == PPC::LI8)))
break;
if (!IsOperand2Immediate &&
!(LiMI2 && (LiMI2->getOpcode() == PPC::LI ||
LiMI2->getOpcode() == PPC::LI8)))
break;
auto ImmOperand0 = MI.getOperand(0).getImm();
auto ImmOperand1 = LiMI1->getOperand(1).getImm();
auto ImmOperand2 = IsOperand2Immediate ? MI.getOperand(2).getImm()
: LiMI2->getOperand(1).getImm();
if ((ImmOperand0 == 31) ||
((ImmOperand0 & 0x10) &&
((int64_t)ImmOperand1 < (int64_t)ImmOperand2)) ||
((ImmOperand0 & 0x8) &&
((int64_t)ImmOperand1 > (int64_t)ImmOperand2)) ||
((ImmOperand0 & 0x2) &&
((uint64_t)ImmOperand1 < (uint64_t)ImmOperand2)) ||
((ImmOperand0 & 0x1) &&
((uint64_t)ImmOperand1 > (uint64_t)ImmOperand2)) ||
((ImmOperand0 & 0x4) && (ImmOperand1 == ImmOperand2))) {
BuildMI(MBB, &MI, MI.getDebugLoc(), TII->get(PPC::TRAP));
TrapOpt = true;
}
ToErase = &MI;
Simplified = true;
break;
}
}
}
if (ToErase) {
ToErase->eraseFromParent();
ToErase = nullptr;
}
if (EnableTrapOptimization)
TrapOpt = false;
}
Simplified |= eliminateRedundantTOCSaves(TOCSaves);
PPCFunctionInfo *FI = MF->getInfo<PPCFunctionInfo>();
if (FI->mustSaveTOC())
NumTOCSavesInPrologue++;
Simplified |= eliminateRedundantCompare();
return Simplified;
}
static bool isEqOrNe(MachineInstr *BI) {
PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm();
unsigned PredCond = PPC::getPredicateCondition(Pred);
return (PredCond == PPC::PRED_EQ || PredCond == PPC::PRED_NE);
}
static bool isSupportedCmpOp(unsigned opCode) {
return (opCode == PPC::CMPLD || opCode == PPC::CMPD ||
opCode == PPC::CMPLW || opCode == PPC::CMPW ||
opCode == PPC::CMPLDI || opCode == PPC::CMPDI ||
opCode == PPC::CMPLWI || opCode == PPC::CMPWI);
}
static bool is64bitCmpOp(unsigned opCode) {
return (opCode == PPC::CMPLD || opCode == PPC::CMPD ||
opCode == PPC::CMPLDI || opCode == PPC::CMPDI);
}
static bool isSignedCmpOp(unsigned opCode) {
return (opCode == PPC::CMPD || opCode == PPC::CMPW ||
opCode == PPC::CMPDI || opCode == PPC::CMPWI);
}
static unsigned getSignedCmpOpCode(unsigned opCode) {
if (opCode == PPC::CMPLD) return PPC::CMPD;
if (opCode == PPC::CMPLW) return PPC::CMPW;
if (opCode == PPC::CMPLDI) return PPC::CMPDI;
if (opCode == PPC::CMPLWI) return PPC::CMPWI;
return opCode;
}
static unsigned getPredicateToDecImm(MachineInstr *BI, MachineInstr *CMPI) {
uint64_t Imm = CMPI->getOperand(2).getImm();
bool SignedCmp = isSignedCmpOp(CMPI->getOpcode());
if ((!SignedCmp && Imm == 0) || (SignedCmp && Imm == 0x8000))
return 0;
PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm();
unsigned PredCond = PPC::getPredicateCondition(Pred);
unsigned PredHint = PPC::getPredicateHint(Pred);
if (PredCond == PPC::PRED_GE)
return PPC::getPredicate(PPC::PRED_GT, PredHint);
if (PredCond == PPC::PRED_LT)
return PPC::getPredicate(PPC::PRED_LE, PredHint);
return 0;
}
static unsigned getPredicateToIncImm(MachineInstr *BI, MachineInstr *CMPI) {
uint64_t Imm = CMPI->getOperand(2).getImm();
bool SignedCmp = isSignedCmpOp(CMPI->getOpcode());
if ((!SignedCmp && Imm == 0xFFFF) || (SignedCmp && Imm == 0x7FFF))
return 0;
PPC::Predicate Pred = (PPC::Predicate)BI->getOperand(0).getImm();
unsigned PredCond = PPC::getPredicateCondition(Pred);
unsigned PredHint = PPC::getPredicateHint(Pred);
if (PredCond == PPC::PRED_GT)
return PPC::getPredicate(PPC::PRED_GE, PredHint);
if (PredCond == PPC::PRED_LE)
return PPC::getPredicate(PPC::PRED_LT, PredHint);
return 0;
}
static unsigned getIncomingRegForBlock(MachineInstr *Phi,
MachineBasicBlock *MBB) {
for (unsigned I = 2, E = Phi->getNumOperands() + 1; I != E; I += 2) {
MachineOperand &MO = Phi->getOperand(I);
if (MO.getMBB() == MBB)
return Phi->getOperand(I-1).getReg();
}
llvm_unreachable("invalid src basic block for this Phi node\n");
return 0;
}
static unsigned getSrcVReg(unsigned Reg, MachineBasicBlock *BB1,
MachineBasicBlock *BB2, MachineRegisterInfo *MRI) {
unsigned SrcReg = Reg;
while (true) {
unsigned NextReg = SrcReg;
MachineInstr *Inst = MRI->getVRegDef(SrcReg);
if (BB1 && Inst->getOpcode() == PPC::PHI && Inst->getParent() == BB2) {
NextReg = getIncomingRegForBlock(Inst, BB1);
BB1 = nullptr;
}
else if (Inst->isFullCopy())
NextReg = Inst->getOperand(1).getReg();
if (NextReg == SrcReg || !Register::isVirtualRegister(NextReg))
break;
SrcReg = NextReg;
}
return SrcReg;
}
static bool eligibleForCompareElimination(MachineBasicBlock &MBB,
MachineBasicBlock *&PredMBB,
MachineBasicBlock *&MBBtoMoveCmp,
MachineRegisterInfo *MRI) {
auto isEligibleBB = [&](MachineBasicBlock &BB) {
auto BII = BB.getFirstInstrTerminator();
if (BB.succ_size() == 2 &&
BII != BB.instr_end() &&
(*BII).getOpcode() == PPC::BCC &&
(*BII).getOperand(1).isReg()) {
Register CndReg = (*BII).getOperand(1).getReg();
if (!Register::isVirtualRegister(CndReg) || !MRI->hasOneNonDBGUse(CndReg))
return false;
MachineInstr *CMPI = MRI->getVRegDef(CndReg);
if (CMPI->getParent() != &BB)
return false;
for (MachineOperand &MO : CMPI->operands())
if (MO.isReg() && !Register::isVirtualRegister(MO.getReg()))
return false;
return true;
}
return false;
};
auto isEligibleForMoveCmp = [](MachineBasicBlock &BB) {
return BB.succ_size() == 1;
};
if (!isEligibleBB(MBB))
return false;
unsigned NumPredBBs = MBB.pred_size();
if (NumPredBBs == 1) {
MachineBasicBlock *TmpMBB = *MBB.pred_begin();
if (isEligibleBB(*TmpMBB)) {
PredMBB = TmpMBB;
MBBtoMoveCmp = nullptr;
return true;
}
}
else if (NumPredBBs == 2) {
MachineBasicBlock::pred_iterator PI = MBB.pred_begin();
MachineBasicBlock *Pred1MBB = *PI;
MachineBasicBlock *Pred2MBB = *(PI+1);
if (isEligibleBB(*Pred1MBB) && isEligibleForMoveCmp(*Pred2MBB)) {
}
else if (isEligibleBB(*Pred2MBB) && isEligibleForMoveCmp(*Pred1MBB)) {
std::swap(Pred1MBB, Pred2MBB);
}
else return false;
MachineInstr *BI = &*MBB.getFirstInstrTerminator();
MachineInstr *CMPI = MRI->getVRegDef(BI->getOperand(1).getReg());
for (int I = 1; I <= 2; I++)
if (CMPI->getOperand(I).isReg()) {
MachineInstr *Inst = MRI->getVRegDef(CMPI->getOperand(I).getReg());
if (Inst->getParent() == &MBB && Inst->getOpcode() != PPC::PHI)
return false;
}
PredMBB = Pred1MBB;
MBBtoMoveCmp = Pred2MBB;
return true;
}
return false;
}
bool PPCMIPeephole::eliminateRedundantTOCSaves(
std::map<MachineInstr *, bool> &TOCSaves) {
bool Simplified = false;
int NumKept = 0;
for (auto TOCSave : TOCSaves) {
if (!TOCSave.second) {
TOCSave.first->eraseFromParent();
RemoveTOCSave++;
Simplified = true;
} else {
NumKept++;
}
}
if (NumKept > 1)
MultiTOCSaves++;
return Simplified;
}
bool PPCMIPeephole::eliminateRedundantCompare() {
bool Simplified = false;
for (MachineBasicBlock &MBB2 : *MF) {
MachineBasicBlock *MBB1 = nullptr, *MBBtoMoveCmp = nullptr;
if (!eligibleForCompareElimination(MBB2, MBB1, MBBtoMoveCmp, MRI))
continue;
MachineInstr *BI1 = &*MBB1->getFirstInstrTerminator();
MachineInstr *CMPI1 = MRI->getVRegDef(BI1->getOperand(1).getReg());
MachineInstr *BI2 = &*MBB2.getFirstInstrTerminator();
MachineInstr *CMPI2 = MRI->getVRegDef(BI2->getOperand(1).getReg());
bool IsPartiallyRedundant = (MBBtoMoveCmp != nullptr);
if (!isSupportedCmpOp(CMPI1->getOpcode()) ||
!isSupportedCmpOp(CMPI2->getOpcode()) ||
is64bitCmpOp(CMPI1->getOpcode()) != is64bitCmpOp(CMPI2->getOpcode()))
continue;
unsigned NewOpCode = 0;
unsigned NewPredicate1 = 0, NewPredicate2 = 0;
int16_t Imm1 = 0, NewImm1 = 0, Imm2 = 0, NewImm2 = 0;
bool SwapOperands = false;
if (CMPI1->getOpcode() != CMPI2->getOpcode()) {
auto CmpAgainstImmWithSignBit = [](MachineInstr *I) {
if (!I->getOperand(2).isImm())
return false;
int16_t Imm = (int16_t)I->getOperand(2).getImm();
return Imm < 0;
};
if (isEqOrNe(BI2) && !CmpAgainstImmWithSignBit(CMPI2) &&
CMPI1->getOpcode() == getSignedCmpOpCode(CMPI2->getOpcode()))
NewOpCode = CMPI1->getOpcode();
else if (isEqOrNe(BI1) && !CmpAgainstImmWithSignBit(CMPI1) &&
getSignedCmpOpCode(CMPI1->getOpcode()) == CMPI2->getOpcode())
NewOpCode = CMPI2->getOpcode();
else continue;
}
if (CMPI1->getOperand(2).isReg() && CMPI2->getOperand(2).isReg()) {
unsigned Cmp1Operand1 = getSrcVReg(CMPI1->getOperand(1).getReg(),
nullptr, nullptr, MRI);
unsigned Cmp1Operand2 = getSrcVReg(CMPI1->getOperand(2).getReg(),
nullptr, nullptr, MRI);
unsigned Cmp2Operand1 = getSrcVReg(CMPI2->getOperand(1).getReg(),
MBB1, &MBB2, MRI);
unsigned Cmp2Operand2 = getSrcVReg(CMPI2->getOperand(2).getReg(),
MBB1, &MBB2, MRI);
if (Cmp1Operand1 == Cmp2Operand1 && Cmp1Operand2 == Cmp2Operand2) {
}
else if (Cmp1Operand1 == Cmp2Operand2 && Cmp1Operand2 == Cmp2Operand1) {
PPC::Predicate Pred = (PPC::Predicate)BI2->getOperand(0).getImm();
NewPredicate2 = (unsigned)PPC::getSwappedPredicate(Pred);
SwapOperands = true;
}
else continue;
}
else if (CMPI1->getOperand(2).isImm() && CMPI2->getOperand(2).isImm()) {
unsigned Cmp1Operand1 = getSrcVReg(CMPI1->getOperand(1).getReg(),
nullptr, nullptr, MRI);
unsigned Cmp2Operand1 = getSrcVReg(CMPI2->getOperand(1).getReg(),
MBB1, &MBB2, MRI);
if (Cmp1Operand1 != Cmp2Operand1)
continue;
NewImm1 = Imm1 = (int16_t)CMPI1->getOperand(2).getImm();
NewImm2 = Imm2 = (int16_t)CMPI2->getOperand(2).getImm();
if (Imm1 != Imm2 && (!isEqOrNe(BI2) || !isEqOrNe(BI1))) {
int Diff = Imm1 - Imm2;
if (Diff < -2 || Diff > 2)
continue;
unsigned PredToInc1 = getPredicateToIncImm(BI1, CMPI1);
unsigned PredToDec1 = getPredicateToDecImm(BI1, CMPI1);
unsigned PredToInc2 = getPredicateToIncImm(BI2, CMPI2);
unsigned PredToDec2 = getPredicateToDecImm(BI2, CMPI2);
if (Diff == 2) {
if (PredToInc2 && PredToDec1) {
NewPredicate2 = PredToInc2;
NewPredicate1 = PredToDec1;
NewImm2++;
NewImm1--;
}
}
else if (Diff == 1) {
if (PredToInc2) {
NewImm2++;
NewPredicate2 = PredToInc2;
}
else if (PredToDec1) {
NewImm1--;
NewPredicate1 = PredToDec1;
}
}
else if (Diff == -1) {
if (PredToDec2) {
NewImm2--;
NewPredicate2 = PredToDec2;
}
else if (PredToInc1) {
NewImm1++;
NewPredicate1 = PredToInc1;
}
}
else if (Diff == -2) {
if (PredToDec2 && PredToInc1) {
NewPredicate2 = PredToDec2;
NewPredicate1 = PredToInc1;
NewImm2--;
NewImm1++;
}
}
}
if (NewImm2 != NewImm1)
continue;
}
LLVM_DEBUG(dbgs() << "Optimize two pairs of compare and branch:\n");
LLVM_DEBUG(CMPI1->dump());
LLVM_DEBUG(BI1->dump());
LLVM_DEBUG(CMPI2->dump());
LLVM_DEBUG(BI2->dump());
if (NewOpCode != 0 && NewOpCode != CMPI1->getOpcode()) {
CMPI1->setDesc(TII->get(NewOpCode));
}
if (NewPredicate1) {
BI1->getOperand(0).setImm(NewPredicate1);
}
if (NewPredicate2) {
BI2->getOperand(0).setImm(NewPredicate2);
}
if (NewImm1 != Imm1) {
CMPI1->getOperand(2).setImm(NewImm1);
}
if (IsPartiallyRedundant) {
if (SwapOperands) {
Register Op1 = CMPI2->getOperand(1).getReg();
Register Op2 = CMPI2->getOperand(2).getReg();
CMPI2->getOperand(1).setReg(Op2);
CMPI2->getOperand(2).setReg(Op1);
}
if (NewImm2 != Imm2)
CMPI2->getOperand(2).setImm(NewImm2);
for (int I = 1; I <= 2; I++) {
if (CMPI2->getOperand(I).isReg()) {
MachineInstr *Inst = MRI->getVRegDef(CMPI2->getOperand(I).getReg());
if (Inst->getParent() != &MBB2)
continue;
assert(Inst->getOpcode() == PPC::PHI &&
"We cannot support if an operand comes from this BB.");
unsigned SrcReg = getIncomingRegForBlock(Inst, MBBtoMoveCmp);
CMPI2->getOperand(I).setReg(SrcReg);
}
}
auto I = MachineBasicBlock::iterator(MBBtoMoveCmp->getFirstTerminator());
MBBtoMoveCmp->splice(I, &MBB2, MachineBasicBlock::iterator(CMPI2));
DebugLoc DL = CMPI2->getDebugLoc();
Register NewVReg = MRI->createVirtualRegister(&PPC::CRRCRegClass);
BuildMI(MBB2, MBB2.begin(), DL,
TII->get(PPC::PHI), NewVReg)
.addReg(BI1->getOperand(1).getReg()).addMBB(MBB1)
.addReg(BI2->getOperand(1).getReg()).addMBB(MBBtoMoveCmp);
BI2->getOperand(1).setReg(NewVReg);
}
else {
BI2->getOperand(1).setReg(BI1->getOperand(1).getReg());
CMPI2->eraseFromParent();
}
BI2->getOperand(1).setIsKill(true);
BI1->getOperand(1).setIsKill(false);
LLVM_DEBUG(dbgs() << "into a compare and two branches:\n");
LLVM_DEBUG(CMPI1->dump());
LLVM_DEBUG(BI1->dump());
LLVM_DEBUG(BI2->dump());
if (IsPartiallyRedundant) {
LLVM_DEBUG(dbgs() << "The following compare is moved into "
<< printMBBReference(*MBBtoMoveCmp)
<< " to handle partial redundancy.\n");
LLVM_DEBUG(CMPI2->dump());
}
Simplified = true;
}
return Simplified;
}
bool PPCMIPeephole::emitRLDICWhenLoweringJumpTables(MachineInstr &MI) {
if (MI.getOpcode() != PPC::RLDICR)
return false;
Register SrcReg = MI.getOperand(1).getReg();
if (!Register::isVirtualRegister(SrcReg))
return false;
MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
if (SrcMI->getOpcode() != PPC::RLDICL)
return false;
MachineOperand MOpSHSrc = SrcMI->getOperand(2);
MachineOperand MOpMBSrc = SrcMI->getOperand(3);
MachineOperand MOpSHMI = MI.getOperand(2);
MachineOperand MOpMEMI = MI.getOperand(3);
if (!(MOpSHSrc.isImm() && MOpMBSrc.isImm() && MOpSHMI.isImm() &&
MOpMEMI.isImm()))
return false;
uint64_t SHSrc = MOpSHSrc.getImm();
uint64_t MBSrc = MOpMBSrc.getImm();
uint64_t SHMI = MOpSHMI.getImm();
uint64_t MEMI = MOpMEMI.getImm();
uint64_t NewSH = SHSrc + SHMI;
uint64_t NewMB = MBSrc - SHMI;
if (NewMB > 63 || NewSH > 63)
return false;
if ((63 - NewSH) != MEMI)
return false;
LLVM_DEBUG(dbgs() << "Converting pair: ");
LLVM_DEBUG(SrcMI->dump());
LLVM_DEBUG(MI.dump());
MI.setDesc(TII->get(PPC::RLDIC));
MI.getOperand(1).setReg(SrcMI->getOperand(1).getReg());
MI.getOperand(2).setImm(NewSH);
MI.getOperand(3).setImm(NewMB);
MI.getOperand(1).setIsKill(SrcMI->getOperand(1).isKill());
SrcMI->getOperand(1).setIsKill(false);
LLVM_DEBUG(dbgs() << "To: ");
LLVM_DEBUG(MI.dump());
NumRotatesCollapsed++;
if (MRI->use_nodbg_empty(SrcReg)) {
assert(!SrcMI->hasImplicitDef() &&
"Not expecting an implicit def with this instr.");
SrcMI->eraseFromParent();
}
return true;
}
bool PPCMIPeephole::combineSEXTAndSHL(MachineInstr &MI,
MachineInstr *&ToErase) {
if (MI.getOpcode() != PPC::RLDICR)
return false;
if (!MF->getSubtarget<PPCSubtarget>().isISA3_0())
return false;
assert(MI.getNumOperands() == 4 && "RLDICR should have 4 operands");
MachineOperand MOpSHMI = MI.getOperand(2);
MachineOperand MOpMEMI = MI.getOperand(3);
if (!(MOpSHMI.isImm() && MOpMEMI.isImm()))
return false;
uint64_t SHMI = MOpSHMI.getImm();
uint64_t MEMI = MOpMEMI.getImm();
if (SHMI + MEMI != 63)
return false;
Register SrcReg = MI.getOperand(1).getReg();
if (!Register::isVirtualRegister(SrcReg))
return false;
MachineInstr *SrcMI = MRI->getVRegDef(SrcReg);
if (SrcMI->getOpcode() != PPC::EXTSW &&
SrcMI->getOpcode() != PPC::EXTSW_32_64)
return false;
if (!MRI->hasOneNonDBGUse(SrcReg))
return false;
assert(SrcMI->getNumOperands() == 2 && "EXTSW should have 2 operands");
assert(SrcMI->getOperand(1).isReg() &&
"EXTSW's second operand should be a register");
if (!Register::isVirtualRegister(SrcMI->getOperand(1).getReg()))
return false;
LLVM_DEBUG(dbgs() << "Combining pair: ");
LLVM_DEBUG(SrcMI->dump());
LLVM_DEBUG(MI.dump());
MachineInstr *NewInstr =
BuildMI(*MI.getParent(), &MI, MI.getDebugLoc(),
SrcMI->getOpcode() == PPC::EXTSW ? TII->get(PPC::EXTSWSLI)
: TII->get(PPC::EXTSWSLI_32_64),
MI.getOperand(0).getReg())
.add(SrcMI->getOperand(1))
.add(MOpSHMI);
(void)NewInstr;
LLVM_DEBUG(dbgs() << "TO: ");
LLVM_DEBUG(NewInstr->dump());
++NumEXTSWAndSLDICombined;
ToErase = &MI;
SrcMI->eraseFromParent();
return true;
}
}
INITIALIZE_PASS_BEGIN(PPCMIPeephole, DEBUG_TYPE,
"PowerPC MI Peephole Optimization", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfo)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(MachinePostDominatorTree)
INITIALIZE_PASS_END(PPCMIPeephole, DEBUG_TYPE,
"PowerPC MI Peephole Optimization", false, false)
char PPCMIPeephole::ID = 0;
FunctionPass*
llvm::createPPCMIPeepholePass() { return new PPCMIPeephole(); }