Skip to content

Commit 3667d87

Browse files
author
serge-sans-paille
committed
Double check that passes correctly set their Modified status
The approach is simple: if a pass reports that it's not modifying a Function/Module, compute a loose hash of that Function/Module and compare it with the original one. If we report no change but there's a hash change, then we have an error. This approach misses a lot of change but it's not super intrusive and can detect most of the simple mistakes. Differential Revision: https://reviews.llvm.org/D80916
1 parent e2b75ca commit 3667d87

File tree

2 files changed

+88
-1
lines changed

2 files changed

+88
-1
lines changed

llvm/lib/IR/LegacyPassManager.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,74 @@ void FPPassManager::dumpPassStructure(unsigned Offset) {
14751475
}
14761476
}
14771477

1478+
#ifdef EXPENSIVE_CHECKS
1479+
namespace {
1480+
namespace details {
1481+
1482+
// Basic hashing mechanism to detect structural change to the IR, used to verify
1483+
// pass return status consistency with actual change. Loosely copied from
1484+
// llvm/lib/Transforms/Utils/FunctionComparator.cpp
1485+
1486+
class StructuralHash {
1487+
uint64_t Hash = 0x6acaa36bef8325c5ULL;
1488+
1489+
void update(uint64_t V) { Hash = hashing::detail::hash_16_bytes(Hash, V); }
1490+
1491+
public:
1492+
StructuralHash() = default;
1493+
1494+
void update(Function &F) {
1495+
if (F.empty())
1496+
return;
1497+
1498+
update(F.isVarArg());
1499+
update(F.arg_size());
1500+
1501+
SmallVector<const BasicBlock *, 8> BBs;
1502+
SmallPtrSet<const BasicBlock *, 16> VisitedBBs;
1503+
1504+
BBs.push_back(&F.getEntryBlock());
1505+
VisitedBBs.insert(BBs[0]);
1506+
while (!BBs.empty()) {
1507+
const BasicBlock *BB = BBs.pop_back_val();
1508+
update(45798); // Block header
1509+
for (auto &Inst : *BB)
1510+
update(Inst.getOpcode());
1511+
1512+
const Instruction *Term = BB->getTerminator();
1513+
for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
1514+
if (!VisitedBBs.insert(Term->getSuccessor(i)).second)
1515+
continue;
1516+
BBs.push_back(Term->getSuccessor(i));
1517+
}
1518+
}
1519+
}
1520+
1521+
void update(Module &M) {
1522+
for (Function &F : M)
1523+
update(F);
1524+
}
1525+
1526+
uint64_t getHash() const { return Hash; }
1527+
};
1528+
1529+
} // namespace details
1530+
1531+
uint64_t StructuralHash(Function &F) {
1532+
details::StructuralHash H;
1533+
H.update(F);
1534+
return H.getHash();
1535+
}
1536+
1537+
uint64_t StructuralHash(Module &M) {
1538+
details::StructuralHash H;
1539+
H.update(M);
1540+
return H.getHash();
1541+
}
1542+
1543+
} // end anonymous namespace
1544+
1545+
#endif
14781546

14791547
/// Execute all of the passes scheduled for execution by invoking
14801548
/// runOnFunction method. Keep track of whether any of the passes modifies
@@ -1513,7 +1581,16 @@ bool FPPassManager::runOnFunction(Function &F) {
15131581
{
15141582
PassManagerPrettyStackEntry X(FP, F);
15151583
TimeRegion PassTimer(getPassTimer(FP));
1584+
#ifdef EXPENSIVE_CHECKS
1585+
uint64_t RefHash = StructuralHash(F);
1586+
#endif
15161587
LocalChanged |= FP->runOnFunction(F);
1588+
1589+
#ifdef EXPENSIVE_CHECKS
1590+
assert((LocalChanged || (RefHash == StructuralHash(F))) &&
1591+
"Pass modifies its input and doesn't report it.");
1592+
#endif
1593+
15171594
if (EmitICRemark) {
15181595
unsigned NewSize = F.getInstructionCount();
15191596

@@ -1614,7 +1691,17 @@ MPPassManager::runOnModule(Module &M) {
16141691
PassManagerPrettyStackEntry X(MP, M);
16151692
TimeRegion PassTimer(getPassTimer(MP));
16161693

1694+
#ifdef EXPENSIVE_CHECKS
1695+
uint64_t RefHash = StructuralHash(M);
1696+
#endif
1697+
16171698
LocalChanged |= MP->runOnModule(M);
1699+
1700+
#ifdef EXPENSIVE_CHECKS
1701+
assert((LocalChanged || (RefHash == StructuralHash(M))) &&
1702+
"Pass modifies its input and doesn't report it.");
1703+
#endif
1704+
16181705
if (EmitICRemark) {
16191706
// Update the size of the module.
16201707
unsigned ModuleCount = M.getInstructionCount();

llvm/unittests/IR/LegacyPassManagerTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ namespace llvm {
680680
ASSERT_EQ(M->getFunctionList().size(), 4U);
681681
Function *F = M->getFunction("test2");
682682
Function *SF = splitSimpleFunction(*F);
683-
CallInst::Create(F, "", &SF->getEntryBlock());
683+
CallInst::Create(F, "", &*SF->getEntryBlock().getFirstInsertionPt());
684684
ASSERT_EQ(M->getFunctionList().size(), 5U);
685685
CGModifierPass *P = new CGModifierPass();
686686
legacy::PassManager Passes;

0 commit comments

Comments
 (0)