mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
Machine Verifier: verify FrameSetup and FrameDestroy
1> on every path through the CFG, a FrameSetup <n> is always followed by a FrameDestroy <n> and a FrameDestroy is always followed by a FrameSetup. 2> stack adjustments are identical on all CFG edges to a merge point. 3> frame is destroyed at end of a return block. PR16393 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@186350 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7126ba1ee0
commit
7310b75c8b
@ -25,6 +25,7 @@
|
||||
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/SetOperations.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||
@ -227,6 +228,8 @@ namespace {
|
||||
void verifyLiveIntervalValue(const LiveInterval&, VNInfo*);
|
||||
void verifyLiveIntervalSegment(const LiveInterval&,
|
||||
LiveInterval::const_iterator);
|
||||
|
||||
void verifyStackFrame();
|
||||
};
|
||||
|
||||
struct MachineVerifierPass : public MachineFunctionPass {
|
||||
@ -475,6 +478,8 @@ void MachineVerifier::visitMachineFunctionBefore() {
|
||||
|
||||
// Check that the register use lists are sane.
|
||||
MRI->verifyUseLists();
|
||||
|
||||
verifyStackFrame();
|
||||
}
|
||||
|
||||
// Does iterator point to a and b as the first two elements?
|
||||
@ -1606,3 +1611,130 @@ void MachineVerifier::verifyLiveInterval(const LiveInterval &LI) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// FrameSetup and FrameDestroy can have zero adjustment, so using a single
|
||||
// integer, we can't tell whether it is a FrameSetup or FrameDestroy if the
|
||||
// value is zero.
|
||||
// We use a bool plus an integer to capture the stack state.
|
||||
struct StackStateOfBB {
|
||||
StackStateOfBB() : EntryValue(0), ExitValue(0), EntryIsSetup(false),
|
||||
ExitIsSetup(false) { }
|
||||
StackStateOfBB(int EntryVal, int ExitVal, bool EntrySetup, bool ExitSetup) :
|
||||
EntryValue(EntryVal), ExitValue(ExitVal), EntryIsSetup(EntrySetup),
|
||||
ExitIsSetup(ExitSetup) { }
|
||||
// Can be negative, which means we are setting up a frame.
|
||||
int EntryValue;
|
||||
int ExitValue;
|
||||
bool EntryIsSetup;
|
||||
bool ExitIsSetup;
|
||||
};
|
||||
}
|
||||
|
||||
/// Make sure on every path through the CFG, a FrameSetup <n> is always followed
|
||||
/// by a FrameDestroy <n>, stack adjustments are identical on all
|
||||
/// CFG edges to a merge point, and frame is destroyed at end of a return block.
|
||||
void MachineVerifier::verifyStackFrame() {
|
||||
int FrameSetupOpcode = TII->getCallFrameSetupOpcode();
|
||||
int FrameDestroyOpcode = TII->getCallFrameDestroyOpcode();
|
||||
|
||||
SmallVector<StackStateOfBB, 8> SPState;
|
||||
SPState.resize(MF->getNumBlockIDs());
|
||||
SmallPtrSet<const MachineBasicBlock*, 8> Reachable;
|
||||
|
||||
// Visit the MBBs in DFS order.
|
||||
for (df_ext_iterator<const MachineFunction*,
|
||||
SmallPtrSet<const MachineBasicBlock*, 8> >
|
||||
DFI = df_ext_begin(MF, Reachable), DFE = df_ext_end(MF, Reachable);
|
||||
DFI != DFE; ++DFI) {
|
||||
const MachineBasicBlock *MBB = *DFI;
|
||||
|
||||
StackStateOfBB BBState;
|
||||
// Check the exit state of the DFS stack predecessor.
|
||||
if (DFI.getPathLength() >= 2) {
|
||||
const MachineBasicBlock *StackPred = DFI.getPath(DFI.getPathLength() - 2);
|
||||
assert(Reachable.count(StackPred) &&
|
||||
"DFS stack predecessor is already visited.\n");
|
||||
BBState.EntryValue = SPState[StackPred->getNumber()].ExitValue;
|
||||
BBState.EntryIsSetup = SPState[StackPred->getNumber()].ExitIsSetup;
|
||||
BBState.ExitValue = BBState.EntryValue;
|
||||
BBState.ExitIsSetup = BBState.EntryIsSetup;
|
||||
}
|
||||
|
||||
// Update stack state by checking contents of MBB.
|
||||
for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end();
|
||||
I != E; ++I) {
|
||||
if (I->getOpcode() == FrameSetupOpcode) {
|
||||
// The first operand of a FrameOpcode should be i32.
|
||||
int Size = I->getOperand(0).getImm();
|
||||
assert(Size >= 0 &&
|
||||
"Value should be non-negative in FrameSetup and FrameDestroy.\n");
|
||||
|
||||
if (BBState.ExitIsSetup)
|
||||
report("FrameSetup is after another FrameSetup", I);
|
||||
BBState.ExitValue -= Size;
|
||||
BBState.ExitIsSetup = true;
|
||||
}
|
||||
|
||||
if (I->getOpcode() == FrameDestroyOpcode) {
|
||||
// The first operand of a FrameOpcode should be i32.
|
||||
int Size = I->getOperand(0).getImm();
|
||||
assert(Size >= 0 &&
|
||||
"Value should be non-negative in FrameSetup and FrameDestroy.\n");
|
||||
|
||||
if (!BBState.ExitIsSetup)
|
||||
report("FrameDestroy is not after a FrameSetup", I);
|
||||
int AbsSPAdj = BBState.ExitValue < 0 ? -BBState.ExitValue :
|
||||
BBState.ExitValue;
|
||||
if (BBState.ExitIsSetup && AbsSPAdj != Size) {
|
||||
report("FrameDestroy <n> is after FrameSetup <m>", I);
|
||||
*OS << "FrameDestroy <" << Size << "> is after FrameSetup <"
|
||||
<< AbsSPAdj << ">.\n";
|
||||
}
|
||||
BBState.ExitValue += Size;
|
||||
BBState.ExitIsSetup = false;
|
||||
}
|
||||
}
|
||||
SPState[MBB->getNumber()] = BBState;
|
||||
|
||||
// Make sure the exit state of any predecessor is consistent with the entry
|
||||
// state.
|
||||
for (MachineBasicBlock::const_pred_iterator I = MBB->pred_begin(),
|
||||
E = MBB->pred_end(); I != E; ++I) {
|
||||
if (Reachable.count(*I) &&
|
||||
(SPState[(*I)->getNumber()].ExitValue != BBState.EntryValue ||
|
||||
SPState[(*I)->getNumber()].ExitIsSetup != BBState.EntryIsSetup)) {
|
||||
report("The exit stack state of a predecessor is inconsistent.", MBB);
|
||||
*OS << "Predecessor BB#" << (*I)->getNumber() << " has exit state ("
|
||||
<< SPState[(*I)->getNumber()].ExitValue << ", "
|
||||
<< SPState[(*I)->getNumber()].ExitIsSetup
|
||||
<< "), while BB#" << MBB->getNumber() << " has entry state ("
|
||||
<< BBState.EntryValue << ", " << BBState.EntryIsSetup << ").\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the entry state of any successor is consistent with the exit
|
||||
// state.
|
||||
for (MachineBasicBlock::const_succ_iterator I = MBB->succ_begin(),
|
||||
E = MBB->succ_end(); I != E; ++I) {
|
||||
if (Reachable.count(*I) &&
|
||||
(SPState[(*I)->getNumber()].EntryValue != BBState.ExitValue ||
|
||||
SPState[(*I)->getNumber()].EntryIsSetup != BBState.ExitIsSetup)) {
|
||||
report("The entry stack state of a successor is inconsistent.", MBB);
|
||||
*OS << "Successor BB#" << (*I)->getNumber() << " has entry state ("
|
||||
<< SPState[(*I)->getNumber()].EntryValue << ", "
|
||||
<< SPState[(*I)->getNumber()].EntryIsSetup
|
||||
<< "), while BB#" << MBB->getNumber() << " has exit state ("
|
||||
<< BBState.ExitValue << ", " << BBState.ExitIsSetup << ").\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure a basic block with return ends with zero stack adjustment.
|
||||
if (!MBB->empty() && MBB->back().isReturn()) {
|
||||
if (BBState.ExitIsSetup)
|
||||
report("A return block ends with a FrameSetup.", MBB);
|
||||
if (BBState.ExitValue)
|
||||
report("A return block ends with a nonzero stack adjustment.", MBB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user