mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 19:23:23 +01:00
Add a PPCCTRLoops verification pass
When asserts are enabled, this adds a verification pass for PPC counter-loop formation. Unfortunately, without sacrificing code quality, there is no better way of forming counter-based loops except at the (late) IR level. This means that we need to recognize, at the IR level, anything which might turn into a function call (or indirect branch). Because this is currently a finite set of things, and because SelectionDAG lowering is basic-block local, this can be done. Nevertheless, it is fragile, and failure results in a miscompile. This verification pass checks that all (reachable) counter-based branches are dominated by a loop mtctr instruction, and that no instructions in between clobber the counter register. If these conditions are not satisfied, then an ICE will be triggered. In short, this is to help us sleep better at night. llvm-svn: 182295
This commit is contained in:
parent
66d4343951
commit
e230e28ec5
@ -31,6 +31,9 @@ namespace llvm {
|
|||||||
class MCInst;
|
class MCInst;
|
||||||
|
|
||||||
FunctionPass *createPPCCTRLoops(PPCTargetMachine &TM);
|
FunctionPass *createPPCCTRLoops(PPCTargetMachine &TM);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
FunctionPass *createPPCCTRLoopsVerify();
|
||||||
|
#endif
|
||||||
FunctionPass *createPPCEarlyReturnPass();
|
FunctionPass *createPPCEarlyReturnPass();
|
||||||
FunctionPass *createPPCBranchSelectionPass();
|
FunctionPass *createPPCBranchSelectionPass();
|
||||||
FunctionPass *createPPCISelDag(PPCTargetMachine &TM);
|
FunctionPass *createPPCISelDag(PPCTargetMachine &TM);
|
||||||
|
@ -48,6 +48,13 @@
|
|||||||
#include "PPCTargetMachine.h"
|
#include "PPCTargetMachine.h"
|
||||||
#include "PPC.h"
|
#include "PPC.h"
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#include "llvm/CodeGen/MachineDominators.h"
|
||||||
|
#include "llvm/CodeGen/MachineFunction.h"
|
||||||
|
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||||
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -61,6 +68,9 @@ STATISTIC(NumCTRLoops, "Number of loops converted to CTR loops");
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
void initializePPCCTRLoopsPass(PassRegistry&);
|
void initializePPCCTRLoopsPass(PassRegistry&);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
void initializePPCCTRLoopsVerifyPass(PassRegistry&);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -112,6 +122,29 @@ namespace {
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
int PPCCTRLoops::Counter = 0;
|
int PPCCTRLoops::Counter = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
struct PPCCTRLoopsVerify : public MachineFunctionPass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
PPCCTRLoopsVerify() : MachineFunctionPass(ID) {
|
||||||
|
initializePPCCTRLoopsVerifyPass(*PassRegistry::getPassRegistry());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||||
|
AU.addRequired<MachineDominatorTree>();
|
||||||
|
MachineFunctionPass::getAnalysisUsage(AU);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool runOnMachineFunction(MachineFunction &MF);
|
||||||
|
|
||||||
|
private:
|
||||||
|
MachineDominatorTree *MDT;
|
||||||
|
};
|
||||||
|
|
||||||
|
char PPCCTRLoopsVerify::ID = 0;
|
||||||
|
#endif // NDEBUG
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
|
||||||
INITIALIZE_PASS_BEGIN(PPCCTRLoops, "ppc-ctr-loops", "PowerPC CTR Loops",
|
INITIALIZE_PASS_BEGIN(PPCCTRLoops, "ppc-ctr-loops", "PowerPC CTR Loops",
|
||||||
@ -126,6 +159,18 @@ FunctionPass *llvm::createPPCCTRLoops(PPCTargetMachine &TM) {
|
|||||||
return new PPCCTRLoops(TM);
|
return new PPCCTRLoops(TM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
INITIALIZE_PASS_BEGIN(PPCCTRLoopsVerify, "ppc-ctr-loops-verify",
|
||||||
|
"PowerPC CTR Loops Verify", false, false)
|
||||||
|
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
|
||||||
|
INITIALIZE_PASS_END(PPCCTRLoopsVerify, "ppc-ctr-loops-verify",
|
||||||
|
"PowerPC CTR Loops Verify", false, false)
|
||||||
|
|
||||||
|
FunctionPass *llvm::createPPCCTRLoopsVerify() {
|
||||||
|
return new PPCCTRLoopsVerify();
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
bool PPCCTRLoops::runOnFunction(Function &F) {
|
bool PPCCTRLoops::runOnFunction(Function &F) {
|
||||||
LI = &getAnalysis<LoopInfo>();
|
LI = &getAnalysis<LoopInfo>();
|
||||||
SE = &getAnalysis<ScalarEvolution>();
|
SE = &getAnalysis<ScalarEvolution>();
|
||||||
@ -545,3 +590,113 @@ void PPCCTRLoops::PlaceSplitBlockCarefully(BasicBlock *NewBB,
|
|||||||
NewBB->moveAfter(FoundBB);
|
NewBB->moveAfter(FoundBB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static bool clobbersCTR(const MachineInstr *MI) {
|
||||||
|
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
|
||||||
|
const MachineOperand &MO = MI->getOperand(i);
|
||||||
|
if (MO.isReg()) {
|
||||||
|
if (MO.isDef() && (MO.getReg() == PPC::CTR || MO.getReg() == PPC::CTR8))
|
||||||
|
return true;
|
||||||
|
} else if (MO.isRegMask()) {
|
||||||
|
if (MO.clobbersPhysReg(PPC::CTR) || MO.clobbersPhysReg(PPC::CTR8))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool verifyCTRBranch(MachineBasicBlock *MBB,
|
||||||
|
MachineBasicBlock::iterator I) {
|
||||||
|
MachineBasicBlock::iterator BI = I;
|
||||||
|
SmallSet<MachineBasicBlock *, 16> Visited;
|
||||||
|
SmallVector<MachineBasicBlock *, 8> Preds;
|
||||||
|
bool CheckPreds;
|
||||||
|
|
||||||
|
if (I == MBB->begin()) {
|
||||||
|
Visited.insert(MBB);
|
||||||
|
goto queue_preds;
|
||||||
|
} else
|
||||||
|
--I;
|
||||||
|
|
||||||
|
check_block:
|
||||||
|
Visited.insert(MBB);
|
||||||
|
if (I == MBB->end())
|
||||||
|
goto queue_preds;
|
||||||
|
|
||||||
|
CheckPreds = true;
|
||||||
|
for (MachineBasicBlock::iterator IE = MBB->begin();; --I) {
|
||||||
|
unsigned Opc = I->getOpcode();
|
||||||
|
if (Opc == PPC::MTCTRse || Opc == PPC::MTCTR8se) {
|
||||||
|
CheckPreds = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (I != BI && clobbersCTR(I)) {
|
||||||
|
DEBUG(dbgs() << "BB#" << MBB->getNumber() << " (" <<
|
||||||
|
MBB->getFullName() << ") instruction " << *I <<
|
||||||
|
" clobbers CTR, invalidating " << "BB#" <<
|
||||||
|
BI->getParent()->getNumber() << " (" <<
|
||||||
|
BI->getParent()->getFullName() << ") instruction " <<
|
||||||
|
*BI << "\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (I == IE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CheckPreds && Preds.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (CheckPreds) {
|
||||||
|
queue_preds:
|
||||||
|
if (MachineFunction::iterator(MBB) == MBB->getParent()->begin()) {
|
||||||
|
DEBUG(dbgs() << "Unable to find a MTCTR instruction for BB#" <<
|
||||||
|
BI->getParent()->getNumber() << " (" <<
|
||||||
|
BI->getParent()->getFullName() << ") instruction " <<
|
||||||
|
*BI << "\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
|
||||||
|
PIE = MBB->pred_end(); PI != PIE; ++PI)
|
||||||
|
Preds.push_back(*PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
MBB = Preds.pop_back_val();
|
||||||
|
if (!Visited.count(MBB)) {
|
||||||
|
I = MBB->getLastNonDebugInstr();
|
||||||
|
goto check_block;
|
||||||
|
}
|
||||||
|
} while (!Preds.empty());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PPCCTRLoopsVerify::runOnMachineFunction(MachineFunction &MF) {
|
||||||
|
MDT = &getAnalysis<MachineDominatorTree>();
|
||||||
|
|
||||||
|
// Verify that all bdnz/bdz instructions are dominated by a loop mtctr before
|
||||||
|
// any other instructions that might clobber the ctr register.
|
||||||
|
for (MachineFunction::iterator I = MF.begin(), IE = MF.end();
|
||||||
|
I != IE; ++I) {
|
||||||
|
MachineBasicBlock *MBB = I;
|
||||||
|
if (!MDT->isReachableFromEntry(MBB))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (MachineBasicBlock::iterator MII = MBB->getFirstTerminator(),
|
||||||
|
MIIE = MBB->end(); MII != MIIE; ++MII) {
|
||||||
|
unsigned Opc = MII->getOpcode();
|
||||||
|
if (Opc == PPC::BDNZ8 || Opc == PPC::BDNZ ||
|
||||||
|
Opc == PPC::BDZ8 || Opc == PPC::BDZ)
|
||||||
|
if (!verifyCTRBranch(MBB, MII))
|
||||||
|
llvm_unreachable("Invalid PPC CTR loop!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
@ -122,6 +122,12 @@ bool PPCPassConfig::addILPOpts() {
|
|||||||
bool PPCPassConfig::addInstSelector() {
|
bool PPCPassConfig::addInstSelector() {
|
||||||
// Install an instruction selector.
|
// Install an instruction selector.
|
||||||
addPass(createPPCISelDag(getPPCTargetMachine()));
|
addPass(createPPCISelDag(getPPCTargetMachine()));
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (!DisableCTRLoops && getOptLevel() != CodeGenOpt::None)
|
||||||
|
addPass(createPPCCTRLoopsVerify());
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user