26#include "llvm/Config/llvm-config.h"
32#define DEBUG_TYPE "ppc-reduce-cr-ops"
35 "Number of single-use binary CR logical ops contained in a block");
37 "Number of binary CR logical ops that can be used to split blocks");
38STATISTIC(TotalCRLogicals,
"Number of CR logical ops.");
40 "Number of nullary CR logical ops (CRSET/CRUNSET).");
41STATISTIC(TotalUnaryCRLogicals,
"Number of unary CR logical ops.");
42STATISTIC(TotalBinaryCRLogicals,
"Number of CR logical ops.");
44 "Number of blocks split on CR binary logical ops.");
46 "Number of blocks not split due to operands being identical.");
48 "Number of blocks not split due to operands being chained copies.");
50 "Number of blocks not split due to the wrong opcode.");
63 for (
unsigned i = 2, e =
MI.getNumOperands() + 1; i != e; i += 2) {
65 if (MO.
getMBB() == OrigMBB) {
67 if (
MI.getOperand(i - 1).isReg()) {
69 if (
DefMI->getParent() == NewMBB ||
90 "NewMBB must be a successor of OrigMBB");
96 for (
unsigned i = 2, e =
MI.getNumOperands() + 1; i != e; i += 2) {
98 if (MO.
getMBB() == OrigMBB) {
108struct BlockSplitInfo {
109 MachineInstr *OrigBranch;
110 MachineInstr *SplitBefore;
111 MachineInstr *SplitCond;
113 unsigned SplitCondSubreg;
114 bool InvertNewBranch;
115 bool InvertOrigBranch;
116 bool BranchToFallThrough;
117 const MachineBranchProbabilityInfo *MBPI;
118 MachineInstr *MIToDelete;
119 MachineInstr *NewCond;
120 bool allInstrsInSameMBB() {
121 if (!OrigBranch || !SplitBefore || !SplitCond)
126 if (MIToDelete && MIToDelete->getParent() !=
MBB)
128 if (NewCond && NewCond->getParent() !=
MBB)
145 assert(BSI.allInstrsInSameMBB() &&
146 "All instructions must be in the same block.");
151 assert(
MRI->isSSA() &&
"Can only do this while the function is in SSA form.");
154 dbgs() <<
"Don't know how to handle blocks that don't have exactly"
155 <<
" two successors.\n");
160 unsigned OrigBROpcode = BSI.OrigBranch->
getOpcode();
161 unsigned InvertedOpcode =
162 OrigBROpcode == PPC::BC
164 : OrigBROpcode == PPC::BCn
166 : OrigBROpcode == PPC::BCLR ? PPC::BCLRn : PPC::BCLR;
167 unsigned NewBROpcode = BSI.InvertNewBranch ? InvertedOpcode : OrigBROpcode;
173 BSI.BranchToFallThrough ? OrigFallThrough : OrigTarget;
189 if (BSI.BranchToFallThrough) {
191 ProbFallThrough = ProbToNewTarget.
getCompl();
192 ProbOrigFallThrough = ProbToNewTarget / ProbToNewTarget.
getCompl();
193 ProbOrigTarget = ProbOrigFallThrough.
getCompl();
196 ProbFallThrough = ProbToNewTarget.
getCompl();
197 ProbOrigTarget = ProbToNewTarget / ProbToNewTarget.
getCompl();
198 ProbOrigFallThrough = ProbOrigTarget.
getCompl();
225 TII->get(NewBROpcode))
237 assert(FirstTerminator->getOperand(0).isReg() &&
238 "Can't update condition of unconditional branch.");
240 FirstTerminator->getOperand(0).setSubReg(BSI.OrigSubreg);
242 if (BSI.InvertOrigBranch)
243 FirstTerminator->setDesc(
TII->get(InvertedOpcode));
263 return MI.getNumOperands() == 3;
267 return MI.getNumOperands() == 1;
277 bool &InvertNewBranch,
bool &InvertOrigBranch,
278 bool &TargetIsFallThrough) {
283 if (BROp == PPC::BC || BROp == PPC::BCLR) {
289 InvertNewBranch =
false;
290 InvertOrigBranch =
false;
291 TargetIsFallThrough =
false;
294 InvertNewBranch =
true;
295 InvertOrigBranch =
false;
296 TargetIsFallThrough =
true;
299 InvertNewBranch =
true;
300 InvertOrigBranch =
true;
301 TargetIsFallThrough =
false;
304 InvertNewBranch =
false;
305 InvertOrigBranch =
true;
306 TargetIsFallThrough =
true;
309 InvertNewBranch = UsingDef1;
310 InvertOrigBranch = !UsingDef1;
311 TargetIsFallThrough =
false;
314 InvertNewBranch = !UsingDef1;
315 InvertOrigBranch = !UsingDef1;
316 TargetIsFallThrough =
true;
319 }
else if (BROp == PPC::BCn || BROp == PPC::BCLRn) {
325 InvertNewBranch =
true;
326 InvertOrigBranch =
false;
327 TargetIsFallThrough =
true;
330 InvertNewBranch =
false;
331 InvertOrigBranch =
false;
332 TargetIsFallThrough =
false;
335 InvertNewBranch =
false;
336 InvertOrigBranch =
true;
337 TargetIsFallThrough =
true;
340 InvertNewBranch =
true;
341 InvertOrigBranch =
true;
342 TargetIsFallThrough =
false;
345 InvertNewBranch = !UsingDef1;
346 InvertOrigBranch = !UsingDef1;
347 TargetIsFallThrough =
true;
350 InvertNewBranch = UsingDef1;
351 InvertOrigBranch = !UsingDef1;
352 TargetIsFallThrough =
false;
364 struct CRLogicalOpInfo {
367 std::pair<MachineInstr*, MachineInstr*> CopyDefs;
368 std::pair<MachineInstr*, MachineInstr*> TrueDefs;
369 unsigned IsBinary : 1;
370 unsigned IsNullary : 1;
371 unsigned ContainedInBlock : 1;
372 unsigned FeedsISEL : 1;
373 unsigned FeedsBR : 1;
374 unsigned FeedsLogical : 1;
375 unsigned SingleUse : 1;
376 unsigned DefsSingleUse : 1;
379 CRLogicalOpInfo() : MI(nullptr), IsBinary(0), IsNullary(0),
380 ContainedInBlock(0), FeedsISEL(0), FeedsBR(0),
381 FeedsLogical(0), SingleUse(0), DefsSingleUse(1),
382 SubregDef1(0), SubregDef2(0) { }
387 const PPCInstrInfo *TII =
nullptr;
388 MachineFunction *MF =
nullptr;
389 MachineRegisterInfo *MRI =
nullptr;
390 const MachineBranchProbabilityInfo *MBPI =
nullptr;
395 void collectCRLogicals();
396 bool handleCROp(
unsigned Idx);
397 bool splitBlockOnBinaryCROp(CRLogicalOpInfo &CRI);
398 static bool isCRLogical(MachineInstr &
MI) {
399 unsigned Opc =
MI.getOpcode();
400 return Opc == PPC::CRAND ||
Opc == PPC::CRNAND ||
Opc == PPC::CROR ||
401 Opc == PPC::CRXOR ||
Opc == PPC::CRNOR ||
Opc == PPC::CRNOT ||
402 Opc == PPC::CREQV ||
Opc == PPC::CRANDC ||
Opc == PPC::CRORC ||
403 Opc == PPC::CRSET ||
Opc == PPC::CRUNSET ||
Opc == PPC::CR6SET ||
404 Opc == PPC::CR6UNSET;
406 bool simplifyCode() {
410 for (
unsigned i = 0; i < AllCRLogicalOps.size(); i++)
416 PPCReduceCRLogicals() : MachineFunctionPass(ID) {}
418 MachineInstr *lookThroughCRCopy(
unsigned Reg,
unsigned &Subreg,
419 MachineInstr *&CpDef);
420 bool runOnMachineFunction(MachineFunction &MF)
override {
421 if (skipFunction(MF.getFunction()))
425 const PPCSubtarget &STI = MF.getSubtarget<PPCSubtarget>();
426 if (!STI.useCRBits())
431 return simplifyCode();
433 CRLogicalOpInfo createCRLogicalOpInfo(MachineInstr &
MI);
434 void getAnalysisUsage(AnalysisUsage &AU)
const override {
435 AU.
addRequired<MachineBranchProbabilityInfoWrapperPass>();
442#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
444 dbgs() <<
"CRLogicalOpMI: ";
446 dbgs() <<
"IsBinary: " << IsBinary <<
", FeedsISEL: " << FeedsISEL;
447 dbgs() <<
", FeedsBR: " << FeedsBR <<
", FeedsLogical: ";
448 dbgs() << FeedsLogical <<
", SingleUse: " << SingleUse;
449 dbgs() <<
", DefsSingleUse: " << DefsSingleUse;
450 dbgs() <<
", SubregDef1: " << SubregDef1 <<
", SubregDef2: ";
451 dbgs() << SubregDef2 <<
", ContainedInBlock: " << ContainedInBlock;
453 dbgs() <<
"\nDefs:\n";
454 TrueDefs.first->dump();
457 TrueDefs.second->dump();
459 if (CopyDefs.first) {
460 dbgs() <<
"CopyDef1: ";
461 CopyDefs.first->dump();
463 if (CopyDefs.second) {
464 dbgs() <<
"CopyDef2: ";
465 CopyDefs.second->dump();
470PPCReduceCRLogicals::CRLogicalOpInfo
471PPCReduceCRLogicals::createCRLogicalOpInfo(MachineInstr &MIParam) {
477 Ret.TrueDefs = std::make_pair(
nullptr,
nullptr);
478 Ret.CopyDefs = std::make_pair(
nullptr,
nullptr);
481 Ret.SubregDef1, Ret.CopyDefs.first);
483 assert(Def1 &&
"Must be able to find a definition of operand 1.");
487 MRI->hasOneNonDBGUse(Ret.CopyDefs.first->getOperand(0).getReg());
492 Ret.CopyDefs.second);
494 assert(Def2 &&
"Must be able to find a definition of operand 2.");
498 MRI->hasOneNonDBGUse(Ret.CopyDefs.second->getOperand(0).getReg());
499 Ret.TrueDefs = std::make_pair(Def1, Def2);
501 Ret.TrueDefs = std::make_pair(Def1,
nullptr);
502 Ret.CopyDefs.second =
nullptr;
506 Ret.ContainedInBlock = 1;
508 for (MachineInstr &
UseMI :
511 if (
Opc == PPC::ISEL ||
Opc == PPC::ISEL8)
513 if (
Opc == PPC::BC ||
Opc == PPC::BCn ||
Opc == PPC::BCLR ||
516 Ret.FeedsLogical = isCRLogical(
UseMI);
518 Ret.ContainedInBlock = 0;
523 if (!Ret.IsNullary) {
524 Ret.ContainedInBlock &=
525 (MIParam.
getParent() == Ret.TrueDefs.first->getParent());
527 Ret.ContainedInBlock &=
528 (MIParam.
getParent() == Ret.TrueDefs.second->getParent());
531 if (Ret.IsBinary && Ret.ContainedInBlock && Ret.SingleUse) {
532 NumContainedSingleUseBinOps++;
533 if (Ret.FeedsBR && Ret.DefsSingleUse)
545MachineInstr *PPCReduceCRLogicals::lookThroughCRCopy(
unsigned Reg,
547 MachineInstr *&CpDef) {
548 if (!Register::isVirtualRegister(
Reg))
560 if ((--Me)->modifiesRegister(CopySrc,
TRI))
564 return MRI->getVRegDef(CopySrc);
567void PPCReduceCRLogicals::initialize(MachineFunction &MFParam) {
571 MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
573 AllCRLogicalOps.
clear();
581bool PPCReduceCRLogicals::handleCROp(
unsigned Idx) {
585 CRLogicalOpInfo CRI = AllCRLogicalOps[Idx];
586 if (CRI.IsBinary && CRI.ContainedInBlock && CRI.SingleUse && CRI.FeedsBR &&
588 Changed = splitBlockOnBinaryCROp(CRI);
590 NumBlocksSplitOnBinaryCROp++;
612bool PPCReduceCRLogicals::splitBlockOnBinaryCROp(CRLogicalOpInfo &CRI) {
613 if (CRI.CopyDefs.first == CRI.CopyDefs.second) {
614 LLVM_DEBUG(
dbgs() <<
"Unable to split as the two operands are the same\n");
615 NumNotSplitIdenticalOperands++;
618 if (CRI.TrueDefs.first->isCopy() || CRI.TrueDefs.second->isCopy() ||
619 CRI.TrueDefs.first->isPHI() || CRI.TrueDefs.second->isPHI()) {
621 dbgs() <<
"Unable to split because one of the operands is a PHI or "
622 "chain of copies.\n");
623 NumNotSplitChainCopies++;
627 if (CRI.MI->getOpcode() != PPC::CROR &&
628 CRI.MI->getOpcode() != PPC::CRAND &&
629 CRI.MI->getOpcode() != PPC::CRNOR &&
630 CRI.MI->getOpcode() != PPC::CRNAND &&
631 CRI.MI->getOpcode() != PPC::CRORC &&
632 CRI.MI->getOpcode() != PPC::CRANDC) {
634 NumNotSplitWrongOpcode++;
637 LLVM_DEBUG(
dbgs() <<
"Splitting the following CR op:\n"; CRI.dump());
641 bool UsingDef1 =
false;
642 MachineInstr *SplitBefore = &*Def2It;
643 for (
auto E = CRI.MI->getParent()->end(); Def2It !=
E; ++Def2It) {
644 if (Def1It == Def2It) {
645 SplitBefore = &*Def1It;
657 MRI->use_nodbg_begin(CRI.MI->getOperand(0).getReg())->getParent();
666 UsingDef1 ? CRI.TrueDefs.first : CRI.TrueDefs.second;
668 UsingDef1 ? CRI.CopyDefs.first : CRI.CopyDefs.second;
675 if (FirstInstrToMove != SecondInstrToMove)
679 unsigned Opc = CRI.MI->getOpcode();
680 bool InvertOrigBranch, InvertNewBranch, TargetIsFallThrough;
682 InvertNewBranch, InvertOrigBranch,
683 TargetIsFallThrough);
684 MachineInstr *NewCond = CRI.CopyDefs.first;
685 MachineInstr *SplitCond = CRI.CopyDefs.second;
688 std::swap(CRI.SubregDef1, CRI.SubregDef2);
690 LLVM_DEBUG(
dbgs() <<
"We will " << (InvertNewBranch ?
"invert" :
"copy"));
691 LLVM_DEBUG(
dbgs() <<
" the original branch and the target is the "
692 << (TargetIsFallThrough ?
"fallthrough block\n"
693 :
"orig. target block\n"));
696 Branch, SplitBefore, SplitCond, CRI.SubregDef1,
697 CRI.SubregDef2, InvertNewBranch, InvertOrigBranch, TargetIsFallThrough,
698 MBPI, CRI.MI, NewCond};
703 bool Input1CRlogical =
704 CRI.TrueDefs.first && isCRLogical(*CRI.TrueDefs.first);
705 bool Input2CRlogical =
706 CRI.TrueDefs.second && isCRLogical(*CRI.TrueDefs.second);
708 AllCRLogicalOps.
push_back(createCRLogicalOpInfo(*CRI.TrueDefs.first));
710 AllCRLogicalOps.
push_back(createCRLogicalOpInfo(*CRI.TrueDefs.second));
715void PPCReduceCRLogicals::collectCRLogicals() {
716 for (MachineBasicBlock &
MBB : *MF) {
717 for (MachineInstr &
MI :
MBB) {
718 if (isCRLogical(
MI)) {
719 AllCRLogicalOps.
push_back(createCRLogicalOpInfo(
MI));
721 if (AllCRLogicalOps.
back().IsNullary)
722 TotalNullaryCRLogicals++;
723 else if (AllCRLogicalOps.
back().IsBinary)
724 TotalBinaryCRLogicals++;
726 TotalUnaryCRLogicals++;
733 "PowerPC Reduce CR logical Operation",
false,
false)
738char PPCReduceCRLogicals::
ID = 0;
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineInstrBuilder MachineInstrBuilder & DefMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
static bool isBinary(MachineInstr &MI)
static bool isNullary(MachineInstr &MI)
static bool splitMBB(BlockSplitInfo &BSI)
Splits a MachineBasicBlock to branch before SplitBefore.
static void computeBranchTargetAndInversion(unsigned CROp, unsigned BROp, bool UsingDef1, bool &InvertNewBranch, bool &InvertOrigBranch, bool &TargetIsFallThrough)
Given a CR logical operation CROp, branch opcode BROp as well as a flag to indicate if the first oper...
static void addIncomingValuesToPHIs(MachineBasicBlock *Successor, MachineBasicBlock *OrigMBB, MachineBasicBlock *NewMBB, MachineRegisterInfo *MRI)
Given a basic block Successor that potentially contains PHIs, this function will look for PHIs that h...
static void updatePHIs(MachineBasicBlock *Successor, MachineBasicBlock *OrigMBB, MachineBasicBlock *NewMBB, MachineRegisterInfo *MRI)
Given a basic block Successor that potentially contains PHIs, this function will look for any incomin...
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
AnalysisUsage & addRequired()
LLVM Basic Block Representation.
static BranchProbability getUnknown()
BranchProbability getCompl() const
FunctionPass class - This class is used to implement most global optimizations.
const HexagonRegisterInfo & getRegisterInfo() const
LLVM_ABI void transferSuccessors(MachineBasicBlock *FromMBB)
Transfers all the successors from MBB to this machine basic block (i.e., copies all the successors Fr...
void setCallFrameSize(unsigned N)
Set the call frame size on entry to this basic block.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void setSuccProbability(succ_iterator I, BranchProbability Prob)
Set successor probability of a given iterator.
succ_iterator succ_begin()
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
unsigned succ_size() const
LLVM_ABI void dump() const
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
succ_reverse_iterator succ_rbegin()
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< succ_iterator > successors()
LLVM_ABI bool isSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a successor of this block.
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
BranchProbability getEdgeProbability(const MachineBasicBlock *Src, const MachineBasicBlock *Dst) const
Analysis pass which computes a MachineDominatorTree.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
BasicBlockListType::iterator iterator
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
unsigned getSubReg() const
MachineBasicBlock * getMBB() const
void setMBB(MachineBasicBlock *MBB)
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
void push_back(const T &Elt)
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FunctionPass * createPPCReduceCRLogicalsPass()
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.