+ ConnectedVNInfoEqClasses ConEQ(*LiveInts);
+ unsigned NumComp = ConEQ.Classify(&LI);
+ if (NumComp > 1) {
+ report("Multiple connected components in live interval", MF, LI);
+ for (unsigned comp = 0; comp != NumComp; ++comp) {
+ errs() << comp << ": valnos";
+ for (LiveInterval::const_vni_iterator I = LI.vni_begin(),
+ E = LI.vni_end(); I!=E; ++I)
+ if (comp == ConEQ.getEqClass(*I))
+ errs() << ' ' << (*I)->id;
+ errs() << '\n';
+ }
+ }
+}
+
+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() {
+ unsigned FrameSetupOpcode = TII->getCallFrameSetupOpcode();
+ unsigned 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 (const auto &I : *MBB) {
+ 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);
+ errs() << "FrameDestroy <" << Size << "> is after FrameSetup <"
+ << AbsSPAdj << ">.\n";
+ }
+ BBState.ExitValue += Size;
+ BBState.ExitIsSetup = false;