// mark the trivial/redundant assertions in the specified list. void MarkRedundantAssertions(BlockMemory *mcfg, Vector<AssertInfo> &asserts) { BlockCFG *cfg = mcfg->GetCFG(); // assertions are marked redundant in two passes: // 1. for each path reaching the assertion, the validity of the assertion is // implied by one or more prior or future assertions. // this pass also picks up assertions which trivially hold, where the // assertion is valid due to the conditions along the paths themselves. // 2. there is an isomorphic assertion within an inner loop. it is // sufficient to check just the inner assertion. // implication works differently for invariants vs. other assertions, // since the invariant condition will be asserted at block exit. // for regular assertions, an bit is redundant if (guard ==> bit) // is implied by the (oguard ==> obit) for other assertions: // VALID((oguard ==> obit) ==> (guard ==> bit)) // !SAT(!((oguard ==> obit) ==> (guard ==> bit))) // !SAT(!(!(oguard ==> obit) || (guard ==> bit))) // !SAT((oguard ==> obit) && !(guard ==> bit)) // !SAT((oguard ==> obit) && !(!guard || bit)) // !SAT((oguard ==> obit) && guard && !bit) // for invariants, a bit is redundant if guard implies the oguard // for other invariants with the same asserted bit: // VALID(guard ==> oguard) // !SAT(!(guard ==> oguard)) // !SAT(!(!guard || oguard)) // !SAT(guard && !oguard) Solver *solver = new Solver("redundant"); for (size_t ind = 0; ind < asserts.Size(); ind++) { AssertInfo &info = asserts[ind]; solver->PushContext(); Assert(info.cls == ASC_Check); // assert guard. Bit *guard = mcfg->GetGuard(info.point); solver->AddAssert(0, guard); if (info.kind != ASK_Invariant) { // assert !bit. Bit *not_bit = Bit::MakeNot(info.bit); Bit *result_not_bit; mcfg->TranslateBit(TRK_Point, info.point, not_bit, &result_not_bit); solver->AddAssert(0, result_not_bit); } if (!solver->IsSatisfiable()) { // the assert is tautological or is proved by the guard, thus trivial. info.cls = ASC_Trivial; solver->PopContext(); continue; } // assert the remaining assertions in the summary hold. for (size_t aind = 0; aind < asserts.Size(); aind++) { const AssertInfo &oinfo = asserts[aind]; // skip this assertion itself. if (info.point == oinfo.point && info.bit == oinfo.bit) continue; // skip assertions already marked as trivial or redundant. if (oinfo.cls != ASC_Check) continue; // skip assertions for a different kind than the original. // this avoids interference between the different kinds of assertions, // though it is unlikely to affect whether we actually mark an // assert as redundant. if (oinfo.kind != info.kind) continue; Bit *oguard = mcfg->GetGuard(oinfo.point); if (info.kind == ASK_Invariant) { // only compare with other invariants for the same bit. if (oinfo.bit != info.bit) continue; // assert !oguard Bit *not_oguard = Bit::MakeNot(oguard); solver->AddAssert(0, not_oguard); } else { // assert (oguard ==> obit). Bit *result_obit; mcfg->TranslateBit(TRK_Point, oinfo.point, oinfo.bit, &result_obit); Bit *imply_bit = Bit::MakeImply(oguard, result_obit); solver->AddAssert(0, imply_bit); } } if (!solver->IsSatisfiable()) { // the assert is implied by the remaining assertions, thus redundant. info.cls = ASC_Redundant; } solver->PopContext(); } solver->Clear(); delete solver; for (size_t ind = 0; ind < cfg->GetEdgeCount(); ind++) { PEdgeLoop *loop_edge = cfg->GetEdge(ind)->IfLoop(); if (!loop_edge) continue; for (size_t aind = 0; aind < asserts.Size(); aind++) { AssertInfo &info = asserts[aind]; if (info.cls != ASC_Check) continue; if (cfg->IsLoopIsomorphic(info.point)) { // this assertion's point is isomorphic to a point within the // loop body, so there will be an equivalent loop assertion. info.cls = ASC_Redundant; } } } }