llvm-project/llvm/lib/Target/PowerPC/PPCExpandISEL.cpp

492 lines
18 KiB
C++

//===------------- PPCExpandISEL.cpp - Expand ISEL instruction ------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// A pass that expands the ISEL instruction into an if-then-else sequence.
// This pass must be run post-RA since all operands must be physical registers.
//
//===----------------------------------------------------------------------===//
#include "PPC.h"
#include "PPCInstrInfo.h"
#include "PPCSubtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "ppc-expand-isel"
STATISTIC(NumExpanded, "Number of ISEL instructions expanded");
STATISTIC(NumRemoved, "Number of ISEL instructions removed");
STATISTIC(NumFolded, "Number of ISEL instructions folded");
// If -ppc-gen-isel=false is set, we will disable generating the ISEL
// instruction on all PPC targets. Otherwise, if the user set option
// -misel or the platform supports ISEL by default, still generate the
// ISEL instruction, else expand it.
static cl::opt<bool>
GenerateISEL("ppc-gen-isel",
cl::desc("Enable generating the ISEL instruction."),
cl::init(true), cl::Hidden);
namespace {
class PPCExpandISEL : public MachineFunctionPass {
DebugLoc dl;
MachineFunction *MF;
const TargetInstrInfo *TII;
bool IsTrueBlockRequired;
bool IsFalseBlockRequired;
MachineBasicBlock *TrueBlock;
MachineBasicBlock *FalseBlock;
MachineBasicBlock *NewSuccessor;
MachineBasicBlock::iterator TrueBlockI;
MachineBasicBlock::iterator FalseBlockI;
typedef SmallVector<MachineInstr *, 4> BlockISELList;
typedef SmallDenseMap<int, BlockISELList> ISELInstructionList;
// A map of MBB numbers to their lists of contained ISEL instructions.
// Please note when we traverse this list and expand ISEL, we only remove
// the ISEL from the MBB not from this list.
ISELInstructionList ISELInstructions;
/// Initialize the object.
void initialize(MachineFunction &MFParam);
void handleSpecialCases(BlockISELList &BIL, MachineBasicBlock *MBB);
void reorganizeBlockLayout(BlockISELList &BIL, MachineBasicBlock *MBB);
void populateBlocks(BlockISELList &BIL);
void expandMergeableISELs(BlockISELList &BIL);
void expandAndMergeISELs();
bool canMerge(MachineInstr *PrevPushedMI, MachineInstr *MI);
/// Is this instruction an ISEL or ISEL8?
static bool isISEL(const MachineInstr &MI) {
return (MI.getOpcode() == PPC::ISEL || MI.getOpcode() == PPC::ISEL8);
}
/// Is this instruction an ISEL8?
static bool isISEL8(const MachineInstr &MI) {
return (MI.getOpcode() == PPC::ISEL8);
}
/// Are the two operands using the same register?
bool useSameRegister(const MachineOperand &Op1, const MachineOperand &Op2) {
return (Op1.getReg() == Op2.getReg());
}
///
/// Collect all ISEL instructions from the current function.
///
/// Walk the current function and collect all the ISEL instructions that are
/// found. The instructions are placed in the ISELInstructions vector.
///
/// \return true if any ISEL instructions were found, false otherwise
///
bool collectISELInstructions();
public:
static char ID;
PPCExpandISEL() : MachineFunctionPass(ID) {
initializePPCExpandISELPass(*PassRegistry::getPassRegistry());
}
///
/// Determine whether to generate the ISEL instruction or expand it.
///
/// Expand ISEL instruction into if-then-else sequence when one of
/// the following two conditions hold:
/// (1) -ppc-gen-isel=false
/// (2) hasISEL() return false
/// Otherwise, still generate ISEL instruction.
/// The -ppc-gen-isel option is set to true by default. Which means the ISEL
/// instruction is still generated by default on targets that support them.
///
/// \return true if ISEL should be expanded into if-then-else code sequence;
/// false if ISEL instruction should be generated, i.e. not expanded.
///
static bool isExpandISELEnabled(const MachineFunction &MF);
#ifndef NDEBUG
void DumpISELInstructions() const;
#endif
bool runOnMachineFunction(MachineFunction &MF) override {
LLVM_DEBUG(dbgs() << "Function: "; MF.dump(); dbgs() << "\n");
initialize(MF);
if (!collectISELInstructions()) {
LLVM_DEBUG(dbgs() << "No ISEL instructions in this function\n");
return false;
}
#ifndef NDEBUG
DumpISELInstructions();
#endif
expandAndMergeISELs();
return true;
}
};
} // end anonymous namespace
void PPCExpandISEL::initialize(MachineFunction &MFParam) {
MF = &MFParam;
TII = MF->getSubtarget().getInstrInfo();
ISELInstructions.clear();
}
bool PPCExpandISEL::isExpandISELEnabled(const MachineFunction &MF) {
return !GenerateISEL || !MF.getSubtarget<PPCSubtarget>().hasISEL();
}
bool PPCExpandISEL::collectISELInstructions() {
for (MachineBasicBlock &MBB : *MF) {
BlockISELList thisBlockISELs;
for (MachineInstr &MI : MBB)
if (isISEL(MI))
thisBlockISELs.push_back(&MI);
if (!thisBlockISELs.empty())
ISELInstructions.insert(std::make_pair(MBB.getNumber(), thisBlockISELs));
}
return !ISELInstructions.empty();
}
#ifndef NDEBUG
void PPCExpandISEL::DumpISELInstructions() const {
for (const auto &I : ISELInstructions) {
LLVM_DEBUG(dbgs() << printMBBReference(*MF->getBlockNumbered(I.first))
<< ":\n");
for (const auto &VI : I.second)
LLVM_DEBUG(dbgs() << " "; VI->print(dbgs()));
}
}
#endif
/// Contiguous ISELs that have the same condition can be merged.
bool PPCExpandISEL::canMerge(MachineInstr *PrevPushedMI, MachineInstr *MI) {
// Same Condition Register?
if (!useSameRegister(PrevPushedMI->getOperand(3), MI->getOperand(3)))
return false;
MachineBasicBlock::iterator PrevPushedMBBI = *PrevPushedMI;
MachineBasicBlock::iterator MBBI = *MI;
return (std::prev(MBBI) == PrevPushedMBBI); // Contiguous ISELs?
}
void PPCExpandISEL::expandAndMergeISELs() {
bool ExpandISELEnabled = isExpandISELEnabled(*MF);
for (auto &BlockList : ISELInstructions) {
LLVM_DEBUG(
dbgs() << "Expanding ISEL instructions in "
<< printMBBReference(*MF->getBlockNumbered(BlockList.first))
<< "\n");
BlockISELList &CurrentISELList = BlockList.second;
auto I = CurrentISELList.begin();
auto E = CurrentISELList.end();
while (I != E) {
assert(isISEL(**I) && "Expecting an ISEL instruction");
MachineOperand &Dest = (*I)->getOperand(0);
MachineOperand &TrueValue = (*I)->getOperand(1);
MachineOperand &FalseValue = (*I)->getOperand(2);
// Special case 1, all registers used by ISEL are the same one.
// The non-redundant isel 0, 0, 0, N would not satisfy these conditions
// as it would be ISEL %R0, %ZERO, %R0, %CRN.
if (useSameRegister(Dest, TrueValue) &&
useSameRegister(Dest, FalseValue)) {
LLVM_DEBUG(dbgs() << "Remove redundant ISEL instruction: " << **I
<< "\n");
// FIXME: if the CR field used has no other uses, we could eliminate the
// instruction that defines it. This would have to be done manually
// since this pass runs too late to run DCE after it.
NumRemoved++;
(*I)->eraseFromParent();
I++;
} else if (useSameRegister(TrueValue, FalseValue)) {
// Special case 2, the two input registers used by ISEL are the same.
// Note: the non-foldable isel RX, 0, 0, N would not satisfy this
// condition as it would be ISEL %RX, %ZERO, %R0, %CRN, which makes it
// safe to fold ISEL to MR(OR) instead of ADDI.
MachineBasicBlock *MBB = (*I)->getParent();
LLVM_DEBUG(
dbgs() << "Fold the ISEL instruction to an unconditional copy:\n");
LLVM_DEBUG(dbgs() << "ISEL: " << **I << "\n");
NumFolded++;
// Note: we're using both the TrueValue and FalseValue operands so as
// not to lose the kill flag if it is set on either of them.
BuildMI(*MBB, (*I), dl, TII->get(isISEL8(**I) ? PPC::OR8 : PPC::OR))
.add(Dest)
.add(TrueValue)
.add(FalseValue);
(*I)->eraseFromParent();
I++;
} else if (ExpandISELEnabled) { // Normal cases expansion enabled
LLVM_DEBUG(dbgs() << "Expand ISEL instructions:\n");
LLVM_DEBUG(dbgs() << "ISEL: " << **I << "\n");
BlockISELList SubISELList;
SubISELList.push_back(*I++);
// Collect the ISELs that can be merged together.
// This will eat up ISEL instructions without considering whether they
// may be redundant or foldable to a register copy. So we still keep
// the handleSpecialCases() downstream to handle them.
while (I != E && canMerge(SubISELList.back(), *I)) {
LLVM_DEBUG(dbgs() << "ISEL: " << **I << "\n");
SubISELList.push_back(*I++);
}
expandMergeableISELs(SubISELList);
} else { // Normal cases expansion disabled
I++; // leave the ISEL as it is
}
} // end while
} // end for
}
void PPCExpandISEL::handleSpecialCases(BlockISELList &BIL,
MachineBasicBlock *MBB) {
IsTrueBlockRequired = false;
IsFalseBlockRequired = false;
auto MI = BIL.begin();
while (MI != BIL.end()) {
assert(isISEL(**MI) && "Expecting an ISEL instruction");
LLVM_DEBUG(dbgs() << "ISEL: " << **MI << "\n");
MachineOperand &Dest = (*MI)->getOperand(0);
MachineOperand &TrueValue = (*MI)->getOperand(1);
MachineOperand &FalseValue = (*MI)->getOperand(2);
// If at least one of the ISEL instructions satisfy the following
// condition, we need the True Block:
// The Dest Register and True Value Register are not the same
// Similarly, if at least one of the ISEL instructions satisfy the
// following condition, we need the False Block:
// The Dest Register and False Value Register are not the same.
bool IsADDIInstRequired = !useSameRegister(Dest, TrueValue);
bool IsORIInstRequired = !useSameRegister(Dest, FalseValue);
// Special case 1, all registers used by ISEL are the same one.
if (!IsADDIInstRequired && !IsORIInstRequired) {
LLVM_DEBUG(dbgs() << "Remove redundant ISEL instruction.");
// FIXME: if the CR field used has no other uses, we could eliminate the
// instruction that defines it. This would have to be done manually
// since this pass runs too late to run DCE after it.
NumRemoved++;
(*MI)->eraseFromParent();
// Setting MI to the erase result keeps the iterator valid and increased.
MI = BIL.erase(MI);
continue;
}
// Special case 2, the two input registers used by ISEL are the same.
// Note 1: We favor merging ISEL expansions over folding a single one. If
// the passed list has multiple merge-able ISEL's, we won't fold any.
// Note 2: There is no need to test for PPC::R0/PPC::X0 because PPC::ZERO/
// PPC::ZERO8 will be used for the first operand if the value is meant to
// be zero. In this case, the useSameRegister method will return false,
// thereby preventing this ISEL from being folded.
if (useSameRegister(TrueValue, FalseValue) && (BIL.size() == 1)) {
LLVM_DEBUG(
dbgs() << "Fold the ISEL instruction to an unconditional copy.");
NumFolded++;
// Note: we're using both the TrueValue and FalseValue operands so as
// not to lose the kill flag if it is set on either of them.
BuildMI(*MBB, (*MI), dl, TII->get(isISEL8(**MI) ? PPC::OR8 : PPC::OR))
.add(Dest)
.add(TrueValue)
.add(FalseValue);
(*MI)->eraseFromParent();
// Setting MI to the erase result keeps the iterator valid and increased.
MI = BIL.erase(MI);
continue;
}
IsTrueBlockRequired |= IsADDIInstRequired;
IsFalseBlockRequired |= IsORIInstRequired;
MI++;
}
}
void PPCExpandISEL::reorganizeBlockLayout(BlockISELList &BIL,
MachineBasicBlock *MBB) {
if (BIL.empty())
return;
assert((IsTrueBlockRequired || IsFalseBlockRequired) &&
"Should have been handled by special cases earlier!");
MachineBasicBlock *Successor = nullptr;
const BasicBlock *LLVM_BB = MBB->getBasicBlock();
MachineBasicBlock::iterator MBBI = (*BIL.back());
NewSuccessor = (MBBI != MBB->getLastNonDebugInstr() || !MBB->canFallThrough())
// Another BB is needed to move the instructions that
// follow this ISEL. If the ISEL is the last instruction
// in a block that can't fall through, we also need a block
// to branch to.
? MF->CreateMachineBasicBlock(LLVM_BB)
: nullptr;
MachineFunction::iterator It = MBB->getIterator();
++It; // Point to the successor block of MBB.
// If NewSuccessor is NULL then the last ISEL in this group is the last
// non-debug instruction in this block. Find the fall-through successor
// of this block to use when updating the CFG below.
if (!NewSuccessor) {
for (auto &Succ : MBB->successors()) {
if (MBB->isLayoutSuccessor(Succ)) {
Successor = Succ;
break;
}
}
} else
Successor = NewSuccessor;
// The FalseBlock and TrueBlock are inserted after the MBB block but before
// its successor.
// Note this need to be done *after* the above setting the Successor code.
if (IsFalseBlockRequired) {
FalseBlock = MF->CreateMachineBasicBlock(LLVM_BB);
MF->insert(It, FalseBlock);
}
if (IsTrueBlockRequired) {
TrueBlock = MF->CreateMachineBasicBlock(LLVM_BB);
MF->insert(It, TrueBlock);
}
if (NewSuccessor) {
MF->insert(It, NewSuccessor);
// Transfer the rest of this block into the new successor block.
NewSuccessor->splice(NewSuccessor->end(), MBB,
std::next(MachineBasicBlock::iterator(BIL.back())),
MBB->end());
NewSuccessor->transferSuccessorsAndUpdatePHIs(MBB);
// Update the liveins for NewSuccessor.
LivePhysRegs LPR;
computeAndAddLiveIns(LPR, *NewSuccessor);
} else {
// Remove successor from MBB.
MBB->removeSuccessor(Successor);
}
// Note that this needs to be done *after* transfering the successors from MBB
// to the NewSuccessor block, otherwise these blocks will also be transferred
// as successors!
MBB->addSuccessor(IsTrueBlockRequired ? TrueBlock : Successor);
MBB->addSuccessor(IsFalseBlockRequired ? FalseBlock : Successor);
if (IsTrueBlockRequired) {
TrueBlockI = TrueBlock->begin();
TrueBlock->addSuccessor(Successor);
}
if (IsFalseBlockRequired) {
FalseBlockI = FalseBlock->begin();
FalseBlock->addSuccessor(Successor);
}
// Conditional branch to the TrueBlock or Successor
BuildMI(*MBB, BIL.back(), dl, TII->get(PPC::BC))
.add(BIL.back()->getOperand(3))
.addMBB(IsTrueBlockRequired ? TrueBlock : Successor);
// Jump over the true block to the new successor if the condition is false.
BuildMI(*(IsFalseBlockRequired ? FalseBlock : MBB),
(IsFalseBlockRequired ? FalseBlockI : BIL.back()), dl,
TII->get(PPC::B))
.addMBB(Successor);
if (IsFalseBlockRequired)
FalseBlockI = FalseBlock->begin(); // get the position of PPC::B
}
void PPCExpandISEL::populateBlocks(BlockISELList &BIL) {
for (auto &MI : BIL) {
assert(isISEL(*MI) && "Expecting an ISEL instruction");
MachineOperand &Dest = MI->getOperand(0); // location to store to
MachineOperand &TrueValue = MI->getOperand(1); // Value to store if
// condition is true
MachineOperand &FalseValue = MI->getOperand(2); // Value to store if
// condition is false
LLVM_DEBUG(dbgs() << "Dest: " << Dest << "\n");
LLVM_DEBUG(dbgs() << "TrueValue: " << TrueValue << "\n");
LLVM_DEBUG(dbgs() << "FalseValue: " << FalseValue << "\n");
LLVM_DEBUG(dbgs() << "ConditionRegister: " << MI->getOperand(3) << "\n");
// If the Dest Register and True Value Register are not the same one, we
// need the True Block.
bool IsADDIInstRequired = !useSameRegister(Dest, TrueValue);
bool IsORIInstRequired = !useSameRegister(Dest, FalseValue);
// Copy the result into the destination if the condition is true.
if (IsADDIInstRequired)
BuildMI(*TrueBlock, TrueBlockI, dl,
TII->get(isISEL8(*MI) ? PPC::ADDI8 : PPC::ADDI))
.add(Dest)
.add(TrueValue)
.add(MachineOperand::CreateImm(0));
// Copy the result into the destination if the condition is false.
if (IsORIInstRequired)
BuildMI(*FalseBlock, FalseBlockI, dl,
TII->get(isISEL8(*MI) ? PPC::ORI8 : PPC::ORI))
.add(Dest)
.add(FalseValue)
.add(MachineOperand::CreateImm(0));
MI->eraseFromParent(); // Remove the ISEL instruction.
NumExpanded++;
}
if (IsTrueBlockRequired) {
// Update the liveins for TrueBlock.
LivePhysRegs LPR;
computeAndAddLiveIns(LPR, *TrueBlock);
}
if (IsFalseBlockRequired) {
// Update the liveins for FalseBlock.
LivePhysRegs LPR;
computeAndAddLiveIns(LPR, *FalseBlock);
}
}
void PPCExpandISEL::expandMergeableISELs(BlockISELList &BIL) {
// At this stage all the ISELs of BIL are in the same MBB.
MachineBasicBlock *MBB = BIL.back()->getParent();
handleSpecialCases(BIL, MBB);
reorganizeBlockLayout(BIL, MBB);
populateBlocks(BIL);
}
INITIALIZE_PASS(PPCExpandISEL, DEBUG_TYPE, "PowerPC Expand ISEL Generation",
false, false)
char PPCExpandISEL::ID = 0;
FunctionPass *llvm::createPPCExpandISELPass() { return new PPCExpandISEL(); }