17330f729Sjoerg //===---- PPCReduceCRLogicals.cpp - Reduce CR Bit Logical operations ------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===---------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This pass aims to reduce the number of logical operations on bits in the CR
107330f729Sjoerg // register. These instructions have a fairly high latency and only a single
117330f729Sjoerg // pipeline at their disposal in modern PPC cores. Furthermore, they have a
127330f729Sjoerg // tendency to occur in fairly small blocks where there's little opportunity
137330f729Sjoerg // to hide the latency between the CR logical operation and its user.
147330f729Sjoerg //
157330f729Sjoerg //===---------------------------------------------------------------------===//
167330f729Sjoerg
177330f729Sjoerg #include "PPC.h"
187330f729Sjoerg #include "PPCInstrInfo.h"
197330f729Sjoerg #include "PPCTargetMachine.h"
207330f729Sjoerg #include "llvm/ADT/Statistic.h"
217330f729Sjoerg #include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
227330f729Sjoerg #include "llvm/CodeGen/MachineDominators.h"
237330f729Sjoerg #include "llvm/CodeGen/MachineFunctionPass.h"
247330f729Sjoerg #include "llvm/CodeGen/MachineInstrBuilder.h"
257330f729Sjoerg #include "llvm/CodeGen/MachineRegisterInfo.h"
267330f729Sjoerg #include "llvm/Config/llvm-config.h"
27*82d56013Sjoerg #include "llvm/InitializePasses.h"
287330f729Sjoerg #include "llvm/Support/Debug.h"
297330f729Sjoerg
307330f729Sjoerg using namespace llvm;
317330f729Sjoerg
327330f729Sjoerg #define DEBUG_TYPE "ppc-reduce-cr-ops"
337330f729Sjoerg
347330f729Sjoerg STATISTIC(NumContainedSingleUseBinOps,
357330f729Sjoerg "Number of single-use binary CR logical ops contained in a block");
367330f729Sjoerg STATISTIC(NumToSplitBlocks,
377330f729Sjoerg "Number of binary CR logical ops that can be used to split blocks");
387330f729Sjoerg STATISTIC(TotalCRLogicals, "Number of CR logical ops.");
397330f729Sjoerg STATISTIC(TotalNullaryCRLogicals,
407330f729Sjoerg "Number of nullary CR logical ops (CRSET/CRUNSET).");
417330f729Sjoerg STATISTIC(TotalUnaryCRLogicals, "Number of unary CR logical ops.");
427330f729Sjoerg STATISTIC(TotalBinaryCRLogicals, "Number of CR logical ops.");
437330f729Sjoerg STATISTIC(NumBlocksSplitOnBinaryCROp,
447330f729Sjoerg "Number of blocks split on CR binary logical ops.");
457330f729Sjoerg STATISTIC(NumNotSplitIdenticalOperands,
467330f729Sjoerg "Number of blocks not split due to operands being identical.");
477330f729Sjoerg STATISTIC(NumNotSplitChainCopies,
487330f729Sjoerg "Number of blocks not split due to operands being chained copies.");
497330f729Sjoerg STATISTIC(NumNotSplitWrongOpcode,
507330f729Sjoerg "Number of blocks not split due to the wrong opcode.");
517330f729Sjoerg
527330f729Sjoerg /// Given a basic block \p Successor that potentially contains PHIs, this
537330f729Sjoerg /// function will look for any incoming values in the PHIs that are supposed to
547330f729Sjoerg /// be coming from \p OrigMBB but whose definition is actually in \p NewMBB.
557330f729Sjoerg /// Any such PHIs will be updated to reflect reality.
updatePHIs(MachineBasicBlock * Successor,MachineBasicBlock * OrigMBB,MachineBasicBlock * NewMBB,MachineRegisterInfo * MRI)567330f729Sjoerg static void updatePHIs(MachineBasicBlock *Successor, MachineBasicBlock *OrigMBB,
577330f729Sjoerg MachineBasicBlock *NewMBB, MachineRegisterInfo *MRI) {
587330f729Sjoerg for (auto &MI : Successor->instrs()) {
597330f729Sjoerg if (!MI.isPHI())
607330f729Sjoerg continue;
617330f729Sjoerg // This is a really ugly-looking loop, but it was pillaged directly from
627330f729Sjoerg // MachineBasicBlock::transferSuccessorsAndUpdatePHIs().
637330f729Sjoerg for (unsigned i = 2, e = MI.getNumOperands() + 1; i != e; i += 2) {
647330f729Sjoerg MachineOperand &MO = MI.getOperand(i);
657330f729Sjoerg if (MO.getMBB() == OrigMBB) {
667330f729Sjoerg // Check if the instruction is actually defined in NewMBB.
677330f729Sjoerg if (MI.getOperand(i - 1).isReg()) {
687330f729Sjoerg MachineInstr *DefMI = MRI->getVRegDef(MI.getOperand(i - 1).getReg());
697330f729Sjoerg if (DefMI->getParent() == NewMBB ||
707330f729Sjoerg !OrigMBB->isSuccessor(Successor)) {
717330f729Sjoerg MO.setMBB(NewMBB);
727330f729Sjoerg break;
737330f729Sjoerg }
747330f729Sjoerg }
757330f729Sjoerg }
767330f729Sjoerg }
777330f729Sjoerg }
787330f729Sjoerg }
797330f729Sjoerg
807330f729Sjoerg /// Given a basic block \p Successor that potentially contains PHIs, this
817330f729Sjoerg /// function will look for PHIs that have an incoming value from \p OrigMBB
827330f729Sjoerg /// and will add the same incoming value from \p NewMBB.
837330f729Sjoerg /// NOTE: This should only be used if \p NewMBB is an immediate dominator of
847330f729Sjoerg /// \p OrigMBB.
addIncomingValuesToPHIs(MachineBasicBlock * Successor,MachineBasicBlock * OrigMBB,MachineBasicBlock * NewMBB,MachineRegisterInfo * MRI)857330f729Sjoerg static void addIncomingValuesToPHIs(MachineBasicBlock *Successor,
867330f729Sjoerg MachineBasicBlock *OrigMBB,
877330f729Sjoerg MachineBasicBlock *NewMBB,
887330f729Sjoerg MachineRegisterInfo *MRI) {
897330f729Sjoerg assert(OrigMBB->isSuccessor(NewMBB) &&
907330f729Sjoerg "NewMBB must be a successor of OrigMBB");
917330f729Sjoerg for (auto &MI : Successor->instrs()) {
927330f729Sjoerg if (!MI.isPHI())
937330f729Sjoerg continue;
947330f729Sjoerg // This is a really ugly-looking loop, but it was pillaged directly from
957330f729Sjoerg // MachineBasicBlock::transferSuccessorsAndUpdatePHIs().
967330f729Sjoerg for (unsigned i = 2, e = MI.getNumOperands() + 1; i != e; i += 2) {
977330f729Sjoerg MachineOperand &MO = MI.getOperand(i);
987330f729Sjoerg if (MO.getMBB() == OrigMBB) {
997330f729Sjoerg MachineInstrBuilder MIB(*MI.getParent()->getParent(), &MI);
1007330f729Sjoerg MIB.addReg(MI.getOperand(i - 1).getReg()).addMBB(NewMBB);
1017330f729Sjoerg break;
1027330f729Sjoerg }
1037330f729Sjoerg }
1047330f729Sjoerg }
1057330f729Sjoerg }
1067330f729Sjoerg
1077330f729Sjoerg struct BlockSplitInfo {
1087330f729Sjoerg MachineInstr *OrigBranch;
1097330f729Sjoerg MachineInstr *SplitBefore;
1107330f729Sjoerg MachineInstr *SplitCond;
1117330f729Sjoerg bool InvertNewBranch;
1127330f729Sjoerg bool InvertOrigBranch;
1137330f729Sjoerg bool BranchToFallThrough;
1147330f729Sjoerg const MachineBranchProbabilityInfo *MBPI;
1157330f729Sjoerg MachineInstr *MIToDelete;
1167330f729Sjoerg MachineInstr *NewCond;
allInstrsInSameMBBBlockSplitInfo1177330f729Sjoerg bool allInstrsInSameMBB() {
1187330f729Sjoerg if (!OrigBranch || !SplitBefore || !SplitCond)
1197330f729Sjoerg return false;
1207330f729Sjoerg MachineBasicBlock *MBB = OrigBranch->getParent();
1217330f729Sjoerg if (SplitBefore->getParent() != MBB || SplitCond->getParent() != MBB)
1227330f729Sjoerg return false;
1237330f729Sjoerg if (MIToDelete && MIToDelete->getParent() != MBB)
1247330f729Sjoerg return false;
1257330f729Sjoerg if (NewCond && NewCond->getParent() != MBB)
1267330f729Sjoerg return false;
1277330f729Sjoerg return true;
1287330f729Sjoerg }
1297330f729Sjoerg };
1307330f729Sjoerg
1317330f729Sjoerg /// Splits a MachineBasicBlock to branch before \p SplitBefore. The original
1327330f729Sjoerg /// branch is \p OrigBranch. The target of the new branch can either be the same
1337330f729Sjoerg /// as the target of the original branch or the fallthrough successor of the
1347330f729Sjoerg /// original block as determined by \p BranchToFallThrough. The branch
1357330f729Sjoerg /// conditions will be inverted according to \p InvertNewBranch and
1367330f729Sjoerg /// \p InvertOrigBranch. If an instruction that previously fed the branch is to
1377330f729Sjoerg /// be deleted, it is provided in \p MIToDelete and \p NewCond will be used as
1387330f729Sjoerg /// the branch condition. The branch probabilities will be set if the
1397330f729Sjoerg /// MachineBranchProbabilityInfo isn't null.
splitMBB(BlockSplitInfo & BSI)1407330f729Sjoerg static bool splitMBB(BlockSplitInfo &BSI) {
1417330f729Sjoerg assert(BSI.allInstrsInSameMBB() &&
1427330f729Sjoerg "All instructions must be in the same block.");
1437330f729Sjoerg
1447330f729Sjoerg MachineBasicBlock *ThisMBB = BSI.OrigBranch->getParent();
1457330f729Sjoerg MachineFunction *MF = ThisMBB->getParent();
1467330f729Sjoerg MachineRegisterInfo *MRI = &MF->getRegInfo();
1477330f729Sjoerg assert(MRI->isSSA() && "Can only do this while the function is in SSA form.");
1487330f729Sjoerg if (ThisMBB->succ_size() != 2) {
1497330f729Sjoerg LLVM_DEBUG(
1507330f729Sjoerg dbgs() << "Don't know how to handle blocks that don't have exactly"
1517330f729Sjoerg << " two successors.\n");
1527330f729Sjoerg return false;
1537330f729Sjoerg }
1547330f729Sjoerg
1557330f729Sjoerg const PPCInstrInfo *TII = MF->getSubtarget<PPCSubtarget>().getInstrInfo();
1567330f729Sjoerg unsigned OrigBROpcode = BSI.OrigBranch->getOpcode();
1577330f729Sjoerg unsigned InvertedOpcode =
1587330f729Sjoerg OrigBROpcode == PPC::BC
1597330f729Sjoerg ? PPC::BCn
1607330f729Sjoerg : OrigBROpcode == PPC::BCn
1617330f729Sjoerg ? PPC::BC
1627330f729Sjoerg : OrigBROpcode == PPC::BCLR ? PPC::BCLRn : PPC::BCLR;
1637330f729Sjoerg unsigned NewBROpcode = BSI.InvertNewBranch ? InvertedOpcode : OrigBROpcode;
1647330f729Sjoerg MachineBasicBlock *OrigTarget = BSI.OrigBranch->getOperand(1).getMBB();
1657330f729Sjoerg MachineBasicBlock *OrigFallThrough = OrigTarget == *ThisMBB->succ_begin()
1667330f729Sjoerg ? *ThisMBB->succ_rbegin()
1677330f729Sjoerg : *ThisMBB->succ_begin();
1687330f729Sjoerg MachineBasicBlock *NewBRTarget =
1697330f729Sjoerg BSI.BranchToFallThrough ? OrigFallThrough : OrigTarget;
1707330f729Sjoerg
1717330f729Sjoerg // It's impossible to know the precise branch probability after the split.
1727330f729Sjoerg // But it still needs to be reasonable, the whole probability to original
1737330f729Sjoerg // targets should not be changed.
1747330f729Sjoerg // After split NewBRTarget will get two incoming edges. Assume P0 is the
1757330f729Sjoerg // original branch probability to NewBRTarget, P1 and P2 are new branch
1767330f729Sjoerg // probabilies to NewBRTarget after split. If the two edge frequencies are
1777330f729Sjoerg // same, then
1787330f729Sjoerg // F * P1 = F * P0 / 2 ==> P1 = P0 / 2
1797330f729Sjoerg // F * (1 - P1) * P2 = F * P1 ==> P2 = P1 / (1 - P1)
1807330f729Sjoerg BranchProbability ProbToNewTarget, ProbFallThrough; // Prob for new Br.
1817330f729Sjoerg BranchProbability ProbOrigTarget, ProbOrigFallThrough; // Prob for orig Br.
1827330f729Sjoerg ProbToNewTarget = ProbFallThrough = BranchProbability::getUnknown();
1837330f729Sjoerg ProbOrigTarget = ProbOrigFallThrough = BranchProbability::getUnknown();
1847330f729Sjoerg if (BSI.MBPI) {
1857330f729Sjoerg if (BSI.BranchToFallThrough) {
1867330f729Sjoerg ProbToNewTarget = BSI.MBPI->getEdgeProbability(ThisMBB, OrigFallThrough) / 2;
1877330f729Sjoerg ProbFallThrough = ProbToNewTarget.getCompl();
1887330f729Sjoerg ProbOrigFallThrough = ProbToNewTarget / ProbToNewTarget.getCompl();
1897330f729Sjoerg ProbOrigTarget = ProbOrigFallThrough.getCompl();
1907330f729Sjoerg } else {
1917330f729Sjoerg ProbToNewTarget = BSI.MBPI->getEdgeProbability(ThisMBB, OrigTarget) / 2;
1927330f729Sjoerg ProbFallThrough = ProbToNewTarget.getCompl();
1937330f729Sjoerg ProbOrigTarget = ProbToNewTarget / ProbToNewTarget.getCompl();
1947330f729Sjoerg ProbOrigFallThrough = ProbOrigTarget.getCompl();
1957330f729Sjoerg }
1967330f729Sjoerg }
1977330f729Sjoerg
1987330f729Sjoerg // Create a new basic block.
1997330f729Sjoerg MachineBasicBlock::iterator InsertPoint = BSI.SplitBefore;
2007330f729Sjoerg const BasicBlock *LLVM_BB = ThisMBB->getBasicBlock();
2017330f729Sjoerg MachineFunction::iterator It = ThisMBB->getIterator();
2027330f729Sjoerg MachineBasicBlock *NewMBB = MF->CreateMachineBasicBlock(LLVM_BB);
2037330f729Sjoerg MF->insert(++It, NewMBB);
2047330f729Sjoerg
2057330f729Sjoerg // Move everything after SplitBefore into the new block.
2067330f729Sjoerg NewMBB->splice(NewMBB->end(), ThisMBB, InsertPoint, ThisMBB->end());
2077330f729Sjoerg NewMBB->transferSuccessors(ThisMBB);
2087330f729Sjoerg if (!ProbOrigTarget.isUnknown()) {
209*82d56013Sjoerg auto MBBI = find(NewMBB->successors(), OrigTarget);
2107330f729Sjoerg NewMBB->setSuccProbability(MBBI, ProbOrigTarget);
211*82d56013Sjoerg MBBI = find(NewMBB->successors(), OrigFallThrough);
2127330f729Sjoerg NewMBB->setSuccProbability(MBBI, ProbOrigFallThrough);
2137330f729Sjoerg }
2147330f729Sjoerg
2157330f729Sjoerg // Add the two successors to ThisMBB.
2167330f729Sjoerg ThisMBB->addSuccessor(NewBRTarget, ProbToNewTarget);
2177330f729Sjoerg ThisMBB->addSuccessor(NewMBB, ProbFallThrough);
2187330f729Sjoerg
2197330f729Sjoerg // Add the branches to ThisMBB.
2207330f729Sjoerg BuildMI(*ThisMBB, ThisMBB->end(), BSI.SplitBefore->getDebugLoc(),
2217330f729Sjoerg TII->get(NewBROpcode))
2227330f729Sjoerg .addReg(BSI.SplitCond->getOperand(0).getReg())
2237330f729Sjoerg .addMBB(NewBRTarget);
2247330f729Sjoerg BuildMI(*ThisMBB, ThisMBB->end(), BSI.SplitBefore->getDebugLoc(),
2257330f729Sjoerg TII->get(PPC::B))
2267330f729Sjoerg .addMBB(NewMBB);
2277330f729Sjoerg if (BSI.MIToDelete)
2287330f729Sjoerg BSI.MIToDelete->eraseFromParent();
2297330f729Sjoerg
2307330f729Sjoerg // Change the condition on the original branch and invert it if requested.
2317330f729Sjoerg auto FirstTerminator = NewMBB->getFirstTerminator();
2327330f729Sjoerg if (BSI.NewCond) {
2337330f729Sjoerg assert(FirstTerminator->getOperand(0).isReg() &&
2347330f729Sjoerg "Can't update condition of unconditional branch.");
2357330f729Sjoerg FirstTerminator->getOperand(0).setReg(BSI.NewCond->getOperand(0).getReg());
2367330f729Sjoerg }
2377330f729Sjoerg if (BSI.InvertOrigBranch)
2387330f729Sjoerg FirstTerminator->setDesc(TII->get(InvertedOpcode));
2397330f729Sjoerg
2407330f729Sjoerg // If any of the PHIs in the successors of NewMBB reference values that
2417330f729Sjoerg // now come from NewMBB, they need to be updated.
2427330f729Sjoerg for (auto *Succ : NewMBB->successors()) {
2437330f729Sjoerg updatePHIs(Succ, ThisMBB, NewMBB, MRI);
2447330f729Sjoerg }
2457330f729Sjoerg addIncomingValuesToPHIs(NewBRTarget, ThisMBB, NewMBB, MRI);
2467330f729Sjoerg
2477330f729Sjoerg LLVM_DEBUG(dbgs() << "After splitting, ThisMBB:\n"; ThisMBB->dump());
2487330f729Sjoerg LLVM_DEBUG(dbgs() << "NewMBB:\n"; NewMBB->dump());
2497330f729Sjoerg LLVM_DEBUG(dbgs() << "New branch-to block:\n"; NewBRTarget->dump());
2507330f729Sjoerg return true;
2517330f729Sjoerg }
2527330f729Sjoerg
isBinary(MachineInstr & MI)2537330f729Sjoerg static bool isBinary(MachineInstr &MI) {
2547330f729Sjoerg return MI.getNumOperands() == 3;
2557330f729Sjoerg }
2567330f729Sjoerg
isNullary(MachineInstr & MI)2577330f729Sjoerg static bool isNullary(MachineInstr &MI) {
2587330f729Sjoerg return MI.getNumOperands() == 1;
2597330f729Sjoerg }
2607330f729Sjoerg
2617330f729Sjoerg /// Given a CR logical operation \p CROp, branch opcode \p BROp as well as
2627330f729Sjoerg /// a flag to indicate if the first operand of \p CROp is used as the
2637330f729Sjoerg /// SplitBefore operand, determines whether either of the branches are to be
2647330f729Sjoerg /// inverted as well as whether the new target should be the original
2657330f729Sjoerg /// fall-through block.
2667330f729Sjoerg static void
computeBranchTargetAndInversion(unsigned CROp,unsigned BROp,bool UsingDef1,bool & InvertNewBranch,bool & InvertOrigBranch,bool & TargetIsFallThrough)2677330f729Sjoerg computeBranchTargetAndInversion(unsigned CROp, unsigned BROp, bool UsingDef1,
2687330f729Sjoerg bool &InvertNewBranch, bool &InvertOrigBranch,
2697330f729Sjoerg bool &TargetIsFallThrough) {
2707330f729Sjoerg // The conditions under which each of the output operands should be [un]set
2717330f729Sjoerg // can certainly be written much more concisely with just 3 if statements or
2727330f729Sjoerg // ternary expressions. However, this provides a much clearer overview to the
2737330f729Sjoerg // reader as to what is set for each <CROp, BROp, OpUsed> combination.
2747330f729Sjoerg if (BROp == PPC::BC || BROp == PPC::BCLR) {
2757330f729Sjoerg // Regular branches.
2767330f729Sjoerg switch (CROp) {
2777330f729Sjoerg default:
2787330f729Sjoerg llvm_unreachable("Don't know how to handle this CR logical.");
2797330f729Sjoerg case PPC::CROR:
2807330f729Sjoerg InvertNewBranch = false;
2817330f729Sjoerg InvertOrigBranch = false;
2827330f729Sjoerg TargetIsFallThrough = false;
2837330f729Sjoerg return;
2847330f729Sjoerg case PPC::CRAND:
2857330f729Sjoerg InvertNewBranch = true;
2867330f729Sjoerg InvertOrigBranch = false;
2877330f729Sjoerg TargetIsFallThrough = true;
2887330f729Sjoerg return;
2897330f729Sjoerg case PPC::CRNAND:
2907330f729Sjoerg InvertNewBranch = true;
2917330f729Sjoerg InvertOrigBranch = true;
2927330f729Sjoerg TargetIsFallThrough = false;
2937330f729Sjoerg return;
2947330f729Sjoerg case PPC::CRNOR:
2957330f729Sjoerg InvertNewBranch = false;
2967330f729Sjoerg InvertOrigBranch = true;
2977330f729Sjoerg TargetIsFallThrough = true;
2987330f729Sjoerg return;
2997330f729Sjoerg case PPC::CRORC:
3007330f729Sjoerg InvertNewBranch = UsingDef1;
3017330f729Sjoerg InvertOrigBranch = !UsingDef1;
3027330f729Sjoerg TargetIsFallThrough = false;
3037330f729Sjoerg return;
3047330f729Sjoerg case PPC::CRANDC:
3057330f729Sjoerg InvertNewBranch = !UsingDef1;
3067330f729Sjoerg InvertOrigBranch = !UsingDef1;
3077330f729Sjoerg TargetIsFallThrough = true;
3087330f729Sjoerg return;
3097330f729Sjoerg }
3107330f729Sjoerg } else if (BROp == PPC::BCn || BROp == PPC::BCLRn) {
3117330f729Sjoerg // Negated branches.
3127330f729Sjoerg switch (CROp) {
3137330f729Sjoerg default:
3147330f729Sjoerg llvm_unreachable("Don't know how to handle this CR logical.");
3157330f729Sjoerg case PPC::CROR:
3167330f729Sjoerg InvertNewBranch = true;
3177330f729Sjoerg InvertOrigBranch = false;
3187330f729Sjoerg TargetIsFallThrough = true;
3197330f729Sjoerg return;
3207330f729Sjoerg case PPC::CRAND:
3217330f729Sjoerg InvertNewBranch = false;
3227330f729Sjoerg InvertOrigBranch = false;
3237330f729Sjoerg TargetIsFallThrough = false;
3247330f729Sjoerg return;
3257330f729Sjoerg case PPC::CRNAND:
3267330f729Sjoerg InvertNewBranch = false;
3277330f729Sjoerg InvertOrigBranch = true;
3287330f729Sjoerg TargetIsFallThrough = true;
3297330f729Sjoerg return;
3307330f729Sjoerg case PPC::CRNOR:
3317330f729Sjoerg InvertNewBranch = true;
3327330f729Sjoerg InvertOrigBranch = true;
3337330f729Sjoerg TargetIsFallThrough = false;
3347330f729Sjoerg return;
3357330f729Sjoerg case PPC::CRORC:
3367330f729Sjoerg InvertNewBranch = !UsingDef1;
3377330f729Sjoerg InvertOrigBranch = !UsingDef1;
3387330f729Sjoerg TargetIsFallThrough = true;
3397330f729Sjoerg return;
3407330f729Sjoerg case PPC::CRANDC:
3417330f729Sjoerg InvertNewBranch = UsingDef1;
3427330f729Sjoerg InvertOrigBranch = !UsingDef1;
3437330f729Sjoerg TargetIsFallThrough = false;
3447330f729Sjoerg return;
3457330f729Sjoerg }
3467330f729Sjoerg } else
3477330f729Sjoerg llvm_unreachable("Don't know how to handle this branch.");
3487330f729Sjoerg }
3497330f729Sjoerg
3507330f729Sjoerg namespace {
3517330f729Sjoerg
3527330f729Sjoerg class PPCReduceCRLogicals : public MachineFunctionPass {
3537330f729Sjoerg
3547330f729Sjoerg public:
3557330f729Sjoerg static char ID;
3567330f729Sjoerg struct CRLogicalOpInfo {
3577330f729Sjoerg MachineInstr *MI;
3587330f729Sjoerg // FIXME: If chains of copies are to be handled, this should be a vector.
3597330f729Sjoerg std::pair<MachineInstr*, MachineInstr*> CopyDefs;
3607330f729Sjoerg std::pair<MachineInstr*, MachineInstr*> TrueDefs;
3617330f729Sjoerg unsigned IsBinary : 1;
3627330f729Sjoerg unsigned IsNullary : 1;
3637330f729Sjoerg unsigned ContainedInBlock : 1;
3647330f729Sjoerg unsigned FeedsISEL : 1;
3657330f729Sjoerg unsigned FeedsBR : 1;
3667330f729Sjoerg unsigned FeedsLogical : 1;
3677330f729Sjoerg unsigned SingleUse : 1;
3687330f729Sjoerg unsigned DefsSingleUse : 1;
3697330f729Sjoerg unsigned SubregDef1;
3707330f729Sjoerg unsigned SubregDef2;
CRLogicalOpInfo__anon4216a67e0111::PPCReduceCRLogicals::CRLogicalOpInfo3717330f729Sjoerg CRLogicalOpInfo() : MI(nullptr), IsBinary(0), IsNullary(0),
3727330f729Sjoerg ContainedInBlock(0), FeedsISEL(0), FeedsBR(0),
3737330f729Sjoerg FeedsLogical(0), SingleUse(0), DefsSingleUse(1),
3747330f729Sjoerg SubregDef1(0), SubregDef2(0) { }
3757330f729Sjoerg void dump();
3767330f729Sjoerg };
3777330f729Sjoerg
3787330f729Sjoerg private:
379*82d56013Sjoerg const PPCInstrInfo *TII = nullptr;
380*82d56013Sjoerg MachineFunction *MF = nullptr;
381*82d56013Sjoerg MachineRegisterInfo *MRI = nullptr;
382*82d56013Sjoerg const MachineBranchProbabilityInfo *MBPI = nullptr;
3837330f729Sjoerg
3847330f729Sjoerg // A vector to contain all the CR logical operations
3857330f729Sjoerg SmallVector<CRLogicalOpInfo, 16> AllCRLogicalOps;
3867330f729Sjoerg void initialize(MachineFunction &MFParm);
3877330f729Sjoerg void collectCRLogicals();
3887330f729Sjoerg bool handleCROp(unsigned Idx);
3897330f729Sjoerg bool splitBlockOnBinaryCROp(CRLogicalOpInfo &CRI);
isCRLogical(MachineInstr & MI)3907330f729Sjoerg static bool isCRLogical(MachineInstr &MI) {
3917330f729Sjoerg unsigned Opc = MI.getOpcode();
3927330f729Sjoerg return Opc == PPC::CRAND || Opc == PPC::CRNAND || Opc == PPC::CROR ||
3937330f729Sjoerg Opc == PPC::CRXOR || Opc == PPC::CRNOR || Opc == PPC::CREQV ||
3947330f729Sjoerg Opc == PPC::CRANDC || Opc == PPC::CRORC || Opc == PPC::CRSET ||
3957330f729Sjoerg Opc == PPC::CRUNSET || Opc == PPC::CR6SET || Opc == PPC::CR6UNSET;
3967330f729Sjoerg }
simplifyCode()3977330f729Sjoerg bool simplifyCode() {
3987330f729Sjoerg bool Changed = false;
3997330f729Sjoerg // Not using a range-based for loop here as the vector may grow while being
4007330f729Sjoerg // operated on.
4017330f729Sjoerg for (unsigned i = 0; i < AllCRLogicalOps.size(); i++)
4027330f729Sjoerg Changed |= handleCROp(i);
4037330f729Sjoerg return Changed;
4047330f729Sjoerg }
4057330f729Sjoerg
4067330f729Sjoerg public:
PPCReduceCRLogicals()4077330f729Sjoerg PPCReduceCRLogicals() : MachineFunctionPass(ID) {
4087330f729Sjoerg initializePPCReduceCRLogicalsPass(*PassRegistry::getPassRegistry());
4097330f729Sjoerg }
4107330f729Sjoerg
4117330f729Sjoerg MachineInstr *lookThroughCRCopy(unsigned Reg, unsigned &Subreg,
4127330f729Sjoerg MachineInstr *&CpDef);
runOnMachineFunction(MachineFunction & MF)4137330f729Sjoerg bool runOnMachineFunction(MachineFunction &MF) override {
4147330f729Sjoerg if (skipFunction(MF.getFunction()))
4157330f729Sjoerg return false;
4167330f729Sjoerg
4177330f729Sjoerg // If the subtarget doesn't use CR bits, there's nothing to do.
4187330f729Sjoerg const PPCSubtarget &STI = MF.getSubtarget<PPCSubtarget>();
4197330f729Sjoerg if (!STI.useCRBits())
4207330f729Sjoerg return false;
4217330f729Sjoerg
4227330f729Sjoerg initialize(MF);
4237330f729Sjoerg collectCRLogicals();
4247330f729Sjoerg return simplifyCode();
4257330f729Sjoerg }
4267330f729Sjoerg CRLogicalOpInfo createCRLogicalOpInfo(MachineInstr &MI);
getAnalysisUsage(AnalysisUsage & AU) const4277330f729Sjoerg void getAnalysisUsage(AnalysisUsage &AU) const override {
4287330f729Sjoerg AU.addRequired<MachineBranchProbabilityInfo>();
4297330f729Sjoerg AU.addRequired<MachineDominatorTree>();
4307330f729Sjoerg MachineFunctionPass::getAnalysisUsage(AU);
4317330f729Sjoerg }
4327330f729Sjoerg };
4337330f729Sjoerg
4347330f729Sjoerg #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump()4357330f729Sjoerg LLVM_DUMP_METHOD void PPCReduceCRLogicals::CRLogicalOpInfo::dump() {
4367330f729Sjoerg dbgs() << "CRLogicalOpMI: ";
4377330f729Sjoerg MI->dump();
4387330f729Sjoerg dbgs() << "IsBinary: " << IsBinary << ", FeedsISEL: " << FeedsISEL;
4397330f729Sjoerg dbgs() << ", FeedsBR: " << FeedsBR << ", FeedsLogical: ";
4407330f729Sjoerg dbgs() << FeedsLogical << ", SingleUse: " << SingleUse;
4417330f729Sjoerg dbgs() << ", DefsSingleUse: " << DefsSingleUse;
4427330f729Sjoerg dbgs() << ", SubregDef1: " << SubregDef1 << ", SubregDef2: ";
4437330f729Sjoerg dbgs() << SubregDef2 << ", ContainedInBlock: " << ContainedInBlock;
4447330f729Sjoerg if (!IsNullary) {
4457330f729Sjoerg dbgs() << "\nDefs:\n";
4467330f729Sjoerg TrueDefs.first->dump();
4477330f729Sjoerg }
4487330f729Sjoerg if (IsBinary)
4497330f729Sjoerg TrueDefs.second->dump();
4507330f729Sjoerg dbgs() << "\n";
4517330f729Sjoerg if (CopyDefs.first) {
4527330f729Sjoerg dbgs() << "CopyDef1: ";
4537330f729Sjoerg CopyDefs.first->dump();
4547330f729Sjoerg }
4557330f729Sjoerg if (CopyDefs.second) {
4567330f729Sjoerg dbgs() << "CopyDef2: ";
4577330f729Sjoerg CopyDefs.second->dump();
4587330f729Sjoerg }
4597330f729Sjoerg }
4607330f729Sjoerg #endif
4617330f729Sjoerg
4627330f729Sjoerg PPCReduceCRLogicals::CRLogicalOpInfo
createCRLogicalOpInfo(MachineInstr & MIParam)4637330f729Sjoerg PPCReduceCRLogicals::createCRLogicalOpInfo(MachineInstr &MIParam) {
4647330f729Sjoerg CRLogicalOpInfo Ret;
4657330f729Sjoerg Ret.MI = &MIParam;
4667330f729Sjoerg // Get the defs
4677330f729Sjoerg if (isNullary(MIParam)) {
4687330f729Sjoerg Ret.IsNullary = 1;
4697330f729Sjoerg Ret.TrueDefs = std::make_pair(nullptr, nullptr);
4707330f729Sjoerg Ret.CopyDefs = std::make_pair(nullptr, nullptr);
4717330f729Sjoerg } else {
4727330f729Sjoerg MachineInstr *Def1 = lookThroughCRCopy(MIParam.getOperand(1).getReg(),
4737330f729Sjoerg Ret.SubregDef1, Ret.CopyDefs.first);
474*82d56013Sjoerg assert(Def1 && "Must be able to find a definition of operand 1.");
4757330f729Sjoerg Ret.DefsSingleUse &=
4767330f729Sjoerg MRI->hasOneNonDBGUse(Def1->getOperand(0).getReg());
4777330f729Sjoerg Ret.DefsSingleUse &=
4787330f729Sjoerg MRI->hasOneNonDBGUse(Ret.CopyDefs.first->getOperand(0).getReg());
4797330f729Sjoerg if (isBinary(MIParam)) {
4807330f729Sjoerg Ret.IsBinary = 1;
4817330f729Sjoerg MachineInstr *Def2 = lookThroughCRCopy(MIParam.getOperand(2).getReg(),
4827330f729Sjoerg Ret.SubregDef2,
4837330f729Sjoerg Ret.CopyDefs.second);
484*82d56013Sjoerg assert(Def2 && "Must be able to find a definition of operand 2.");
4857330f729Sjoerg Ret.DefsSingleUse &=
4867330f729Sjoerg MRI->hasOneNonDBGUse(Def2->getOperand(0).getReg());
4877330f729Sjoerg Ret.DefsSingleUse &=
4887330f729Sjoerg MRI->hasOneNonDBGUse(Ret.CopyDefs.second->getOperand(0).getReg());
4897330f729Sjoerg Ret.TrueDefs = std::make_pair(Def1, Def2);
4907330f729Sjoerg } else {
4917330f729Sjoerg Ret.TrueDefs = std::make_pair(Def1, nullptr);
4927330f729Sjoerg Ret.CopyDefs.second = nullptr;
4937330f729Sjoerg }
4947330f729Sjoerg }
4957330f729Sjoerg
4967330f729Sjoerg Ret.ContainedInBlock = 1;
4977330f729Sjoerg // Get the uses
4987330f729Sjoerg for (MachineInstr &UseMI :
4997330f729Sjoerg MRI->use_nodbg_instructions(MIParam.getOperand(0).getReg())) {
5007330f729Sjoerg unsigned Opc = UseMI.getOpcode();
5017330f729Sjoerg if (Opc == PPC::ISEL || Opc == PPC::ISEL8)
5027330f729Sjoerg Ret.FeedsISEL = 1;
5037330f729Sjoerg if (Opc == PPC::BC || Opc == PPC::BCn || Opc == PPC::BCLR ||
5047330f729Sjoerg Opc == PPC::BCLRn)
5057330f729Sjoerg Ret.FeedsBR = 1;
5067330f729Sjoerg Ret.FeedsLogical = isCRLogical(UseMI);
5077330f729Sjoerg if (UseMI.getParent() != MIParam.getParent())
5087330f729Sjoerg Ret.ContainedInBlock = 0;
5097330f729Sjoerg }
5107330f729Sjoerg Ret.SingleUse = MRI->hasOneNonDBGUse(MIParam.getOperand(0).getReg()) ? 1 : 0;
5117330f729Sjoerg
5127330f729Sjoerg // We now know whether all the uses of the CR logical are in the same block.
5137330f729Sjoerg if (!Ret.IsNullary) {
5147330f729Sjoerg Ret.ContainedInBlock &=
5157330f729Sjoerg (MIParam.getParent() == Ret.TrueDefs.first->getParent());
5167330f729Sjoerg if (Ret.IsBinary)
5177330f729Sjoerg Ret.ContainedInBlock &=
5187330f729Sjoerg (MIParam.getParent() == Ret.TrueDefs.second->getParent());
5197330f729Sjoerg }
5207330f729Sjoerg LLVM_DEBUG(Ret.dump());
5217330f729Sjoerg if (Ret.IsBinary && Ret.ContainedInBlock && Ret.SingleUse) {
5227330f729Sjoerg NumContainedSingleUseBinOps++;
5237330f729Sjoerg if (Ret.FeedsBR && Ret.DefsSingleUse)
5247330f729Sjoerg NumToSplitBlocks++;
5257330f729Sjoerg }
5267330f729Sjoerg return Ret;
5277330f729Sjoerg }
5287330f729Sjoerg
5297330f729Sjoerg /// Looks through a COPY instruction to the actual definition of the CR-bit
5307330f729Sjoerg /// register and returns the instruction that defines it.
5317330f729Sjoerg /// FIXME: This currently handles what is by-far the most common case:
5327330f729Sjoerg /// an instruction that defines a CR field followed by a single copy of a bit
5337330f729Sjoerg /// from that field into a virtual register. If chains of copies need to be
5347330f729Sjoerg /// handled, this should have a loop until a non-copy instruction is found.
lookThroughCRCopy(unsigned Reg,unsigned & Subreg,MachineInstr * & CpDef)5357330f729Sjoerg MachineInstr *PPCReduceCRLogicals::lookThroughCRCopy(unsigned Reg,
5367330f729Sjoerg unsigned &Subreg,
5377330f729Sjoerg MachineInstr *&CpDef) {
5387330f729Sjoerg Subreg = -1;
5397330f729Sjoerg if (!Register::isVirtualRegister(Reg))
5407330f729Sjoerg return nullptr;
5417330f729Sjoerg MachineInstr *Copy = MRI->getVRegDef(Reg);
5427330f729Sjoerg CpDef = Copy;
5437330f729Sjoerg if (!Copy->isCopy())
5447330f729Sjoerg return Copy;
5457330f729Sjoerg Register CopySrc = Copy->getOperand(1).getReg();
5467330f729Sjoerg Subreg = Copy->getOperand(1).getSubReg();
5477330f729Sjoerg if (!Register::isVirtualRegister(CopySrc)) {
5487330f729Sjoerg const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
5497330f729Sjoerg // Set the Subreg
5507330f729Sjoerg if (CopySrc == PPC::CR0EQ || CopySrc == PPC::CR6EQ)
5517330f729Sjoerg Subreg = PPC::sub_eq;
5527330f729Sjoerg if (CopySrc == PPC::CR0LT || CopySrc == PPC::CR6LT)
5537330f729Sjoerg Subreg = PPC::sub_lt;
5547330f729Sjoerg if (CopySrc == PPC::CR0GT || CopySrc == PPC::CR6GT)
5557330f729Sjoerg Subreg = PPC::sub_gt;
5567330f729Sjoerg if (CopySrc == PPC::CR0UN || CopySrc == PPC::CR6UN)
5577330f729Sjoerg Subreg = PPC::sub_un;
5587330f729Sjoerg // Loop backwards and return the first MI that modifies the physical CR Reg.
5597330f729Sjoerg MachineBasicBlock::iterator Me = Copy, B = Copy->getParent()->begin();
5607330f729Sjoerg while (Me != B)
5617330f729Sjoerg if ((--Me)->modifiesRegister(CopySrc, TRI))
5627330f729Sjoerg return &*Me;
5637330f729Sjoerg return nullptr;
5647330f729Sjoerg }
5657330f729Sjoerg return MRI->getVRegDef(CopySrc);
5667330f729Sjoerg }
5677330f729Sjoerg
initialize(MachineFunction & MFParam)5687330f729Sjoerg void PPCReduceCRLogicals::initialize(MachineFunction &MFParam) {
5697330f729Sjoerg MF = &MFParam;
5707330f729Sjoerg MRI = &MF->getRegInfo();
5717330f729Sjoerg TII = MF->getSubtarget<PPCSubtarget>().getInstrInfo();
5727330f729Sjoerg MBPI = &getAnalysis<MachineBranchProbabilityInfo>();
5737330f729Sjoerg
5747330f729Sjoerg AllCRLogicalOps.clear();
5757330f729Sjoerg }
5767330f729Sjoerg
5777330f729Sjoerg /// Contains all the implemented transformations on CR logical operations.
5787330f729Sjoerg /// For example, a binary CR logical can be used to split a block on its inputs,
5797330f729Sjoerg /// a unary CR logical might be used to change the condition code on a
5807330f729Sjoerg /// comparison feeding it. A nullary CR logical might simply be removable
5817330f729Sjoerg /// if the user of the bit it [un]sets can be transformed.
handleCROp(unsigned Idx)5827330f729Sjoerg bool PPCReduceCRLogicals::handleCROp(unsigned Idx) {
5837330f729Sjoerg // We can definitely split a block on the inputs to a binary CR operation
5847330f729Sjoerg // whose defs and (single) use are within the same block.
5857330f729Sjoerg bool Changed = false;
5867330f729Sjoerg CRLogicalOpInfo CRI = AllCRLogicalOps[Idx];
5877330f729Sjoerg if (CRI.IsBinary && CRI.ContainedInBlock && CRI.SingleUse && CRI.FeedsBR &&
5887330f729Sjoerg CRI.DefsSingleUse) {
5897330f729Sjoerg Changed = splitBlockOnBinaryCROp(CRI);
5907330f729Sjoerg if (Changed)
5917330f729Sjoerg NumBlocksSplitOnBinaryCROp++;
5927330f729Sjoerg }
5937330f729Sjoerg return Changed;
5947330f729Sjoerg }
5957330f729Sjoerg
5967330f729Sjoerg /// Splits a block that contains a CR-logical operation that feeds a branch
5977330f729Sjoerg /// and whose operands are produced within the block.
5987330f729Sjoerg /// Example:
5997330f729Sjoerg /// %vr5<def> = CMPDI %vr2, 0; CRRC:%vr5 G8RC:%vr2
6007330f729Sjoerg /// %vr6<def> = COPY %vr5:sub_eq; CRBITRC:%vr6 CRRC:%vr5
6017330f729Sjoerg /// %vr7<def> = CMPDI %vr3, 0; CRRC:%vr7 G8RC:%vr3
6027330f729Sjoerg /// %vr8<def> = COPY %vr7:sub_eq; CRBITRC:%vr8 CRRC:%vr7
6037330f729Sjoerg /// %vr9<def> = CROR %vr6<kill>, %vr8<kill>; CRBITRC:%vr9,%vr6,%vr8
6047330f729Sjoerg /// BC %vr9<kill>, <BB#2>; CRBITRC:%vr9
6057330f729Sjoerg /// Becomes:
6067330f729Sjoerg /// %vr5<def> = CMPDI %vr2, 0; CRRC:%vr5 G8RC:%vr2
6077330f729Sjoerg /// %vr6<def> = COPY %vr5:sub_eq; CRBITRC:%vr6 CRRC:%vr5
6087330f729Sjoerg /// BC %vr6<kill>, <BB#2>; CRBITRC:%vr6
6097330f729Sjoerg ///
6107330f729Sjoerg /// %vr7<def> = CMPDI %vr3, 0; CRRC:%vr7 G8RC:%vr3
6117330f729Sjoerg /// %vr8<def> = COPY %vr7:sub_eq; CRBITRC:%vr8 CRRC:%vr7
6127330f729Sjoerg /// BC %vr9<kill>, <BB#2>; CRBITRC:%vr9
splitBlockOnBinaryCROp(CRLogicalOpInfo & CRI)6137330f729Sjoerg bool PPCReduceCRLogicals::splitBlockOnBinaryCROp(CRLogicalOpInfo &CRI) {
6147330f729Sjoerg if (CRI.CopyDefs.first == CRI.CopyDefs.second) {
6157330f729Sjoerg LLVM_DEBUG(dbgs() << "Unable to split as the two operands are the same\n");
6167330f729Sjoerg NumNotSplitIdenticalOperands++;
6177330f729Sjoerg return false;
6187330f729Sjoerg }
6197330f729Sjoerg if (CRI.TrueDefs.first->isCopy() || CRI.TrueDefs.second->isCopy() ||
6207330f729Sjoerg CRI.TrueDefs.first->isPHI() || CRI.TrueDefs.second->isPHI()) {
6217330f729Sjoerg LLVM_DEBUG(
6227330f729Sjoerg dbgs() << "Unable to split because one of the operands is a PHI or "
6237330f729Sjoerg "chain of copies.\n");
6247330f729Sjoerg NumNotSplitChainCopies++;
6257330f729Sjoerg return false;
6267330f729Sjoerg }
6277330f729Sjoerg // Note: keep in sync with computeBranchTargetAndInversion().
6287330f729Sjoerg if (CRI.MI->getOpcode() != PPC::CROR &&
6297330f729Sjoerg CRI.MI->getOpcode() != PPC::CRAND &&
6307330f729Sjoerg CRI.MI->getOpcode() != PPC::CRNOR &&
6317330f729Sjoerg CRI.MI->getOpcode() != PPC::CRNAND &&
6327330f729Sjoerg CRI.MI->getOpcode() != PPC::CRORC &&
6337330f729Sjoerg CRI.MI->getOpcode() != PPC::CRANDC) {
6347330f729Sjoerg LLVM_DEBUG(dbgs() << "Unable to split blocks on this opcode.\n");
6357330f729Sjoerg NumNotSplitWrongOpcode++;
6367330f729Sjoerg return false;
6377330f729Sjoerg }
6387330f729Sjoerg LLVM_DEBUG(dbgs() << "Splitting the following CR op:\n"; CRI.dump());
6397330f729Sjoerg MachineBasicBlock::iterator Def1It = CRI.TrueDefs.first;
6407330f729Sjoerg MachineBasicBlock::iterator Def2It = CRI.TrueDefs.second;
6417330f729Sjoerg
6427330f729Sjoerg bool UsingDef1 = false;
6437330f729Sjoerg MachineInstr *SplitBefore = &*Def2It;
6447330f729Sjoerg for (auto E = CRI.MI->getParent()->end(); Def2It != E; ++Def2It) {
6457330f729Sjoerg if (Def1It == Def2It) { // Def2 comes before Def1.
6467330f729Sjoerg SplitBefore = &*Def1It;
6477330f729Sjoerg UsingDef1 = true;
6487330f729Sjoerg break;
6497330f729Sjoerg }
6507330f729Sjoerg }
6517330f729Sjoerg
6527330f729Sjoerg LLVM_DEBUG(dbgs() << "We will split the following block:\n";);
6537330f729Sjoerg LLVM_DEBUG(CRI.MI->getParent()->dump());
6547330f729Sjoerg LLVM_DEBUG(dbgs() << "Before instruction:\n"; SplitBefore->dump());
6557330f729Sjoerg
6567330f729Sjoerg // Get the branch instruction.
6577330f729Sjoerg MachineInstr *Branch =
6587330f729Sjoerg MRI->use_nodbg_begin(CRI.MI->getOperand(0).getReg())->getParent();
6597330f729Sjoerg
6607330f729Sjoerg // We want the new block to have no code in it other than the definition
6617330f729Sjoerg // of the input to the CR logical and the CR logical itself. So we move
6627330f729Sjoerg // those to the bottom of the block (just before the branch). Then we
6637330f729Sjoerg // will split before the CR logical.
6647330f729Sjoerg MachineBasicBlock *MBB = SplitBefore->getParent();
6657330f729Sjoerg auto FirstTerminator = MBB->getFirstTerminator();
6667330f729Sjoerg MachineBasicBlock::iterator FirstInstrToMove =
6677330f729Sjoerg UsingDef1 ? CRI.TrueDefs.first : CRI.TrueDefs.second;
6687330f729Sjoerg MachineBasicBlock::iterator SecondInstrToMove =
6697330f729Sjoerg UsingDef1 ? CRI.CopyDefs.first : CRI.CopyDefs.second;
6707330f729Sjoerg
6717330f729Sjoerg // The instructions that need to be moved are not guaranteed to be
6727330f729Sjoerg // contiguous. Move them individually.
6737330f729Sjoerg // FIXME: If one of the operands is a chain of (single use) copies, they
6747330f729Sjoerg // can all be moved and we can still split.
6757330f729Sjoerg MBB->splice(FirstTerminator, MBB, FirstInstrToMove);
6767330f729Sjoerg if (FirstInstrToMove != SecondInstrToMove)
6777330f729Sjoerg MBB->splice(FirstTerminator, MBB, SecondInstrToMove);
6787330f729Sjoerg MBB->splice(FirstTerminator, MBB, CRI.MI);
6797330f729Sjoerg
6807330f729Sjoerg unsigned Opc = CRI.MI->getOpcode();
6817330f729Sjoerg bool InvertOrigBranch, InvertNewBranch, TargetIsFallThrough;
6827330f729Sjoerg computeBranchTargetAndInversion(Opc, Branch->getOpcode(), UsingDef1,
6837330f729Sjoerg InvertNewBranch, InvertOrigBranch,
6847330f729Sjoerg TargetIsFallThrough);
6857330f729Sjoerg MachineInstr *SplitCond =
6867330f729Sjoerg UsingDef1 ? CRI.CopyDefs.second : CRI.CopyDefs.first;
6877330f729Sjoerg LLVM_DEBUG(dbgs() << "We will " << (InvertNewBranch ? "invert" : "copy"));
6887330f729Sjoerg LLVM_DEBUG(dbgs() << " the original branch and the target is the "
6897330f729Sjoerg << (TargetIsFallThrough ? "fallthrough block\n"
6907330f729Sjoerg : "orig. target block\n"));
6917330f729Sjoerg LLVM_DEBUG(dbgs() << "Original branch instruction: "; Branch->dump());
6927330f729Sjoerg BlockSplitInfo BSI { Branch, SplitBefore, SplitCond, InvertNewBranch,
6937330f729Sjoerg InvertOrigBranch, TargetIsFallThrough, MBPI, CRI.MI,
6947330f729Sjoerg UsingDef1 ? CRI.CopyDefs.first : CRI.CopyDefs.second };
6957330f729Sjoerg bool Changed = splitMBB(BSI);
6967330f729Sjoerg // If we've split on a CR logical that is fed by a CR logical,
6977330f729Sjoerg // recompute the source CR logical as it may be usable for splitting.
6987330f729Sjoerg if (Changed) {
6997330f729Sjoerg bool Input1CRlogical =
7007330f729Sjoerg CRI.TrueDefs.first && isCRLogical(*CRI.TrueDefs.first);
7017330f729Sjoerg bool Input2CRlogical =
7027330f729Sjoerg CRI.TrueDefs.second && isCRLogical(*CRI.TrueDefs.second);
7037330f729Sjoerg if (Input1CRlogical)
7047330f729Sjoerg AllCRLogicalOps.push_back(createCRLogicalOpInfo(*CRI.TrueDefs.first));
7057330f729Sjoerg if (Input2CRlogical)
7067330f729Sjoerg AllCRLogicalOps.push_back(createCRLogicalOpInfo(*CRI.TrueDefs.second));
7077330f729Sjoerg }
7087330f729Sjoerg return Changed;
7097330f729Sjoerg }
7107330f729Sjoerg
collectCRLogicals()7117330f729Sjoerg void PPCReduceCRLogicals::collectCRLogicals() {
7127330f729Sjoerg for (MachineBasicBlock &MBB : *MF) {
7137330f729Sjoerg for (MachineInstr &MI : MBB) {
7147330f729Sjoerg if (isCRLogical(MI)) {
7157330f729Sjoerg AllCRLogicalOps.push_back(createCRLogicalOpInfo(MI));
7167330f729Sjoerg TotalCRLogicals++;
7177330f729Sjoerg if (AllCRLogicalOps.back().IsNullary)
7187330f729Sjoerg TotalNullaryCRLogicals++;
7197330f729Sjoerg else if (AllCRLogicalOps.back().IsBinary)
7207330f729Sjoerg TotalBinaryCRLogicals++;
7217330f729Sjoerg else
7227330f729Sjoerg TotalUnaryCRLogicals++;
7237330f729Sjoerg }
7247330f729Sjoerg }
7257330f729Sjoerg }
7267330f729Sjoerg }
7277330f729Sjoerg
7287330f729Sjoerg } // end anonymous namespace
7297330f729Sjoerg
7307330f729Sjoerg INITIALIZE_PASS_BEGIN(PPCReduceCRLogicals, DEBUG_TYPE,
7317330f729Sjoerg "PowerPC Reduce CR logical Operation", false, false)
7327330f729Sjoerg INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
7337330f729Sjoerg INITIALIZE_PASS_END(PPCReduceCRLogicals, DEBUG_TYPE,
7347330f729Sjoerg "PowerPC Reduce CR logical Operation", false, false)
7357330f729Sjoerg
7367330f729Sjoerg char PPCReduceCRLogicals::ID = 0;
7377330f729Sjoerg FunctionPass*
createPPCReduceCRLogicalsPass()7387330f729Sjoerg llvm::createPPCReduceCRLogicalsPass() { return new PPCReduceCRLogicals(); }
739