void BlockSummary::GetAssumedBits(BlockMemory *mcfg, PPoint end_point, Vector<AssumeInfo> *assume_list) { BlockId *id = mcfg->GetId(); BlockCFG *cfg = mcfg->GetCFG(); BlockSummary *sum = GetBlockSummary(id); const Vector<Bit*> *assumes = sum->GetAssumes(); size_t assume_count = VectorSize<Bit*>(assumes); // pull in assumptions from the summary for mcfg. in some cases these // assumptions won't be useful, e.g. describing the state at exit // for functions. for now we're just adding all of them though. TODO: fix. for (size_t ind = 0; ind < assume_count; ind++) { Bit *bit = assumes->At(ind); bit->IncRef(assume_list); AssumeInfo info; info.bit = bit; assume_list->PushBack(info); } sum->DecRef(); Vector<BlockCFG*> *annot_list = BodyAnnotCache.Lookup(id->Function()); // add assumes at function entry for any preconditions. if (id->Kind() == B_Function) { for (size_t ind = 0; annot_list && ind < annot_list->Size(); ind++) { BlockCFG *annot_cfg = annot_list->At(ind); if (annot_cfg->GetAnnotationKind() != AK_Precondition && annot_cfg->GetAnnotationKind() != AK_PreconditionAssume) continue; Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; annot_cfg->IncRef(assume_list); bit->IncRef(assume_list); AssumeInfo info; info.annot = annot_cfg; info.bit = bit; assume_list->PushBack(info); } } // add assumptions from points within the block. for (size_t pind = 0; pind < cfg->GetPointAnnotationCount(); pind++) { PointAnnotation pann = cfg->GetPointAnnotation(pind); if (end_point && pann.point >= end_point) continue; BlockCFG *annot_cfg = GetAnnotationCFG(pann.annot); if (!annot_cfg) continue; Assert(annot_cfg->GetAnnotationKind() != AK_AssertRuntime); if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { // get the annotation bit in terms of block entry. Bit *point_bit = NULL; mcfg->TranslateBit(TRK_Point, pann.point, bit, &point_bit); point_bit->MoveRef(&point_bit, assume_list); annot_cfg->IncRef(assume_list); AssumeInfo info; info.annot = annot_cfg; info.point = pann.point; info.bit = point_bit; assume_list->PushBack(info); } annot_cfg->DecRef(); } // add assumptions from annotation edges within the block, invariants // on values accessed by the block, and from the summaries of any callees. for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); PPoint point = edge->GetSource(); if (end_point && point >= end_point) continue; InvariantAssumeVisitor visitor(mcfg, point, assume_list); edge->DoVisit(&visitor); if (PEdgeAnnotation *nedge = edge->IfAnnotation()) { // add an assumption for this annotation. BlockCFG *annot_cfg = GetAnnotationCFG(nedge->GetAnnotationId()); if (!annot_cfg) continue; Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); // don't incorporate AssertRuntimes, these are not assumed. if (bit && annot_cfg->GetAnnotationKind() != AK_AssertRuntime) { // get the annotation bit in terms of block entry. Bit *point_bit = NULL; mcfg->TranslateBit(TRK_Point, point, bit, &point_bit); point_bit->MoveRef(&point_bit, assume_list); annot_cfg->IncRef(assume_list); AssumeInfo info; info.annot = annot_cfg; info.point = point; info.bit = point_bit; assume_list->PushBack(info); } annot_cfg->DecRef(); } if (BlockId *callee = edge->GetDirectCallee()) { GetCallAssumedBits(mcfg, edge, callee, false, assume_list); callee->DecRef(); } else if (edge->IsCall()) { // add conditional assumes for the indirect targets of the call. // this is most useful for baked information and annotations, where // we sometimes need to attach information at indirect calls. CallEdgeSet *callees = CalleeCache.Lookup(id->BaseVar()); size_t old_count = assume_list->Size(); if (callees) { for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) { const CallEdge &cedge = callees->GetEdge(cind); if (cedge.where.id == id && cedge.where.point == point) { cedge.callee->IncRef(); BlockId *callee = BlockId::Make(B_Function, cedge.callee); GetCallAssumedBits(mcfg, edge, callee, true, assume_list); callee->DecRef(); } } } if (assume_list->Size() != old_count) { // we managed to do something at this indirect call site. // add another assumption restricting the possible callees to // only those identified by our callgraph. GuardExpVector receiver_list; mcfg->TranslateReceiver(point, &receiver_list); for (size_t rind = 0; rind < receiver_list.Size(); rind++) { const GuardExp &gs = receiver_list[rind]; gs.guard->IncRef(); // make a bit: !when || rcv == callee0 || rcv == callee1 || ... Bit *extra_bit = Bit::MakeNot(gs.guard); for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) { const CallEdge &cedge = callees->GetEdge(cind); if (cedge.where.id == id && cedge.where.point == point) { Variable *callee_var = cedge.callee; callee_var->IncRef(); Exp *callee_exp = Exp::MakeVar(callee_var); gs.exp->IncRef(); Bit *equal = Exp::MakeCompareBit(B_Equal, callee_exp, gs.exp); extra_bit = Bit::MakeOr(extra_bit, equal); } } extra_bit->MoveRef(NULL, assume_list); AssumeInfo info; info.bit = extra_bit; assume_list->PushBack(info); } } CalleeCache.Release(id->BaseVar()); } } BodyAnnotCache.Release(id->Function()); // add assumptions from heap invariants describing values mentioned // in added assumptions. we could keep doing this transitively but don't, // to ensure termination. size_t count = assume_list->Size(); for (size_t ind = 0; ind < count; ind++) { InvariantAssumeVisitor visitor(NULL, 0, assume_list); assume_list->At(ind).bit->DoVisit(&visitor); } CombineAssumeList(assume_list); }
void SplitLoops(BlockCFG *base_cfg, Vector<BlockCFG*> *result_cfg_list) { // get the CFG which will eventually become the loop-free outer function CFG. BlockCFG *func_cfg; if (base_cfg->GetId()->Kind() == B_FunctionWhole) { // make an ID for the outer function body. Variable *function_info = base_cfg->GetId()->BaseVar(); function_info->IncRef(); BlockId *outer_id = BlockId::Make(B_Function, function_info); // make the function CFG by cloning the base CFG with the new ID. func_cfg = BlockCFG::Make(outer_id); CopyCFGLocationsVariables(base_cfg, func_cfg); CopyCFGPointsEdges(base_cfg, func_cfg); } else if (base_cfg->GetId()->Kind() == B_Function) { // this call came from a recursive invocation of SplitLoops after we // removed an irreducible loop from the function. func_cfg = base_cfg; } else { // just destructively update the original CFG. base_cfg->IncRef(); func_cfg = base_cfg; } // add a new entry point with a skip edge to the original entry point. // loop splitting breaks if the entry point is marked as a loop head. PPoint entry = func_cfg->GetEntryPoint(); Location *loc = func_cfg->GetPointLocation(entry); loc->IncRef(); PPoint new_entry = func_cfg->AddPoint(loc); PEdge *skip_edge = PEdge::MakeSkip(new_entry, entry); func_cfg->AddEdge(skip_edge); func_cfg->SetEntryPoint(new_entry); // setup the tables we need to do loop splitting. SetupTables(); // compute the points reachable from the entry point. GetEntryReachable(func_cfg); // the real loops in the program with back edges. Vector<PPoint> loops; for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) { PPoint head = func_cfg->GetLoopHead(lind).point; if (GetLoopBackedges(func_cfg, head)) loops.PushBack(head); } // compute reachability and check for irreducible loops. for (size_t lind = 0; lind < func_cfg->GetLoopHeadCount(); lind++) { const LoopHead &head = func_cfg->GetLoopHead(lind); if (GetLoopReachable(func_cfg, head.point)) { // loop is irreducible. // get the loop's irreducible edges. Vector<PEdge*> irreducible_edges; GetLoopBody(func_cfg, head.point, &irreducible_edges); Assert(!irreducible_edges.Empty()); // clone the loop's body and remove the irreducible edges. ReduceLoop(func_cfg, head.point, irreducible_edges); // try again on the modified CFG. CleanupTables(); SplitLoops(func_cfg, result_cfg_list); return; } } // there are no irreducible loops at this point so this should // never have any entries added. Vector<PEdge*> irreducible_edges; // compute loop bodies. for (size_t lind = 0; lind < loops.Size(); lind++) { PPoint head = loops[lind]; GetLoopBody(func_cfg, head, &irreducible_edges); Assert(irreducible_edges.Empty()); } // construct a tree of all the loops. loop A contains loop B // if A != B and the head of B is in the body of A. PPointListHash loop_tree; // split off all the loops in the CFG. make sure we split inner loops // before outer, so that the Loop edges on inner loops will appear in // the split body for outer loops. while (!loops.Empty()) { // find a candidate loop to split. this is one whose loop children // have already been split off and are no longer in the loops list. PPoint loophead = 0; for (size_t lind = 0; lind < loops.Size(); lind++) { bool is_viable = true; for (size_t xlind = 0; xlind < loops.Size(); xlind++) { if (xlind == lind) continue; Assert(loops[lind] != loops[xlind]); if (body_table->Lookup(PPointPair(loops[lind], loops[xlind]))) { is_viable = false; break; } } if (is_viable) { loophead = loops[lind]; loops[lind] = loops.Back(); loops.PopBack(); break; } } Assert(loophead); BlockCFG *loop_cfg = SplitSingleLoop(loophead, loops, func_cfg); result_cfg_list->PushBack(loop_cfg); } // clear out the loopheads, we don't want them around anymore. func_cfg->ClearLoopHeads(); // trim unreachable points in the function CFG (i.e. bodies of loops that // now redirect to point zero), collapse skips and topo sort. TrimUnreachable(func_cfg, true); TopoSortCFG(func_cfg); result_cfg_list->PushBack(func_cfg); CleanupTables(); // fill in any loop parents for the inner loop CFGs, and make sure the // result CFGs are ordered correctly, with inner loops before outer loops // and the outer function. for (size_t cind = 0; cind < result_cfg_list->Size(); cind++) { BlockCFG *cfg = result_cfg_list->At(cind); for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { if (PEdgeLoop *edge = cfg->GetEdge(eind)->IfLoop()) { BlockId *target_id = edge->GetLoopId(); bool found_target = false; for (size_t xcind = 0; xcind < cind; xcind++) { BlockCFG *xcfg = result_cfg_list->At(xcind); if (xcfg->GetId() == target_id) { found_target = true; cfg->GetId()->IncRef(); BlockPPoint where(cfg->GetId(), edge->GetSource()); xcfg->AddLoopParent(where); // mark the isomorphic points in the parent CFG. GetLoopIsomorphicPoints(cfg, edge, xcfg); break; } } Assert(found_target); } } } // assign the final names to the various loop CFGs. FillLoopNames(func_cfg, "loop", *result_cfg_list); }
// 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; } } } }
void InferSummaries(const Vector<BlockSummary*> &summary_list) { static BaseTimer infer_timer("infer_summaries"); Timer _timer(&infer_timer); if (summary_list.Empty()) return; Variable *function = summary_list[0]->GetId()->BaseVar(); Vector<BlockCFG*> *annot_list = BodyAnnotCache.Lookup(function->GetName()); // all traces which might refer to the result of pointer arithmetic. Vector<Exp*> arithmetic_list; ArithmeticEscape escape(function, arithmetic_list); // initial pass over the CFGs to get traces used in pointer arithmetic. for (size_t ind = 0; ind < summary_list.Size(); ind++) { BlockSummary *sum = summary_list[ind]; BlockCFG *cfg = sum->GetMemory()->GetCFG(); for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); if (PEdgeAssign *assign_edge = edge->IfAssign()) { Exp *left = assign_edge->GetLeftSide(); Exp *right = assign_edge->GetRightSide(); ProcessArithmeticAssign(&escape, cfg->GetId(), left, right); } } } for (size_t ind = 0; ind < summary_list.Size(); ind++) { BlockSummary *sum = summary_list[ind]; BlockMemory *mcfg = sum->GetMemory(); BlockCFG *cfg = mcfg->GetCFG(); // accumulate all the assertions at points in the CFG. Vector<AssertInfo> asserts; // add assertions at function exit for any postconditions. if (cfg->GetId()->Kind() == B_Function) { for (size_t aind = 0; annot_list && aind < annot_list->Size(); aind++) { BlockCFG *annot_cfg = annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Postcondition) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = cfg->GetExitPoint(); info.bit = bit; asserts.PushBack(info); } } } // add assertions for any point annotations within the CFG. for (size_t pind = 0; pind < cfg->GetPointAnnotationCount(); pind++) { PointAnnotation pann = cfg->GetPointAnnotation(pind); BlockCFG *annot_cfg = GetAnnotationCFG(pann.annot); if (!annot_cfg) continue; if (annot_cfg->GetAnnotationKind() != AK_Assert) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = pann.point; info.bit = bit; asserts.PushBack(info); } } for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); PPoint point = edge->GetSource(); if (PEdgeAnnotation *nedge = edge->IfAnnotation()) { // add an assertion for this annotation if it not an assume. BlockCFG *annot_cfg = GetAnnotationCFG(nedge->GetAnnotationId()); if (!annot_cfg) continue; if (annot_cfg->GetAnnotationKind() != AK_Assert && annot_cfg->GetAnnotationKind() != AK_AssertRuntime) { continue; } if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { AssertInfo info; info.kind = (annot_cfg->GetAnnotationKind() == AK_Assert) ? ASK_Annotation : ASK_AnnotationRuntime; info.cls = ASC_Check; info.point = point; info.bit = bit; asserts.PushBack(info); } } // add assertions for any invariants affected by a write. Exp *left = NULL; if (PEdgeAssign *nedge = edge->IfAssign()) left = nedge->GetLeftSide(); if (PEdgeCall *nedge = edge->IfCall()) left = nedge->GetReturnValue(); // for now our detection of affected invariants is pretty crude; // writes to fields can affect type invariants on the field's type // which use that field, and writes to global variables can affect // invariants on that global. TODO: pin this down once we draw a // precise line between which invariants can and can't be checked. if (left && left->IsFld()) { ExpFld *nleft = left->AsFld(); String *csu_name = nleft->GetField()->GetCSUType()->GetCSUName(); Vector<BlockCFG*> *comp_annot_list = CompAnnotCache.Lookup(csu_name); for (size_t aind = 0; comp_annot_list && aind < comp_annot_list->Size(); aind++) { BlockCFG *annot_cfg = comp_annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Invariant) continue; Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; Vector<Exp*> lval_list; LvalListVisitor visitor(&lval_list); bit->DoVisit(&visitor); bool uses_field = false; for (size_t ind = 0; ind < lval_list.Size(); ind++) { if (ExpFld *lval = lval_list[ind]->IfFld()) { if (lval->GetField() == nleft->GetField()) uses_field = true; } } if (uses_field) { // this is a type invariant which uses the field being written // as an lvalue. we need to assert this write preserves // the invariant. BlockId *id = annot_cfg->GetId(); Variable *this_var = Variable::Make(id, VK_This, NULL, 0, NULL); Exp *this_exp = Exp::MakeVar(this_var); Exp *this_drf = Exp::MakeDrf(this_exp); Bit *new_bit = BitReplaceExp(bit, this_drf, nleft->GetTarget()); AssertInfo info; info.kind = ASK_Invariant; info.cls = ASC_Check; info.point = point; info.bit = new_bit; asserts.PushBack(info); } } CompAnnotCache.Release(csu_name); } if (left && left->IsVar()) { Variable *var = left->AsVar()->GetVariable(); if (var->Kind() == VK_Glob) { Vector<BlockCFG*> *glob_annot_list = InitAnnotCache.Lookup(var->GetName()); for (size_t aind = 0; glob_annot_list && aind < glob_annot_list->Size(); aind++) { BlockCFG *annot_cfg = glob_annot_list->At(aind); Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg); if (!bit) continue; AssertInfo info; info.kind = ASK_Invariant; info.cls = ASC_Check; info.point = point; info.bit = bit; asserts.PushBack(info); } InitAnnotCache.Release(var->GetName()); } } if (PEdgeCall *nedge = edge->IfCall()) { // add assertions for any callee preconditions. // pull preconditions from both direct and indirect calls. Vector<Variable*> callee_names; if (Variable *callee = nedge->GetDirectFunction()) { callee_names.PushBack(callee); } else { CallEdgeSet *callees = CalleeCache.Lookup(function); if (callees) { for (size_t cind = 0; cind < callees->GetEdgeCount(); cind++) { const CallEdge &edge = callees->GetEdge(cind); if (edge.where.id == cfg->GetId() && edge.where.point == point) callee_names.PushBack(edge.callee); } } // CalleeCache release is below. } for (size_t cind = 0; cind < callee_names.Size(); cind++) { String *callee = callee_names[cind]->GetName(); Vector<BlockCFG*> *call_annot_list = BodyAnnotCache.Lookup(callee); for (size_t aind = 0; call_annot_list && aind < call_annot_list->Size(); aind++) { BlockCFG *annot_cfg = call_annot_list->At(aind); if (annot_cfg->GetAnnotationKind() != AK_Precondition) continue; if (Bit *bit = BlockMemory::GetAnnotationBit(annot_cfg)) { ConvertCallsiteMapper mapper(cfg, point, false); Bit *caller_bit = bit->DoMap(&mapper); if (!caller_bit) continue; AssertInfo info; info.kind = ASK_Annotation; info.cls = ASC_Check; info.point = point; info.bit = caller_bit; asserts.PushBack(info); } } BodyAnnotCache.Release(callee); } if (!nedge->GetDirectFunction()) CalleeCache.Release(function); } BufferScanVisitor write_visitor(asserts, arithmetic_list, point, true); BufferScanVisitor read_visitor(asserts, arithmetic_list, point, false); IntegerScanVisitor integer_visitor(asserts, point); GCScanVisitor gcsafe_visitor(asserts, point); // only look at the written lvalues for the write visitor. if (PEdgeAssign *assign = edge->IfAssign()) write_visitor.Visit(assign->GetLeftSide()); if (PEdgeCall *call = edge->IfCall()) { if (Exp *returned = call->GetReturnValue()) write_visitor.Visit(returned); } edge->DoVisit(&read_visitor); // disable integer overflow visitor for now. // edge->DoVisit(&integer_visitor); edge->DoVisit(&gcsafe_visitor); } if (cfg->GetId()->Kind() == B_Function) { BlockModset *modset = GetBlockModset(cfg->GetId()); if (modset->CanGC()) { AssertInfo info; info.kind = ASK_CanGC; info.cls = ASC_Check; info.point = cfg->GetExitPoint(); String *name = cfg->GetId()->BaseVar()->GetName(); Variable *var = Variable::Make(NULL, VK_Glob, name, 0, name); Exp *varexp = Exp::MakeVar(var); Exp *gcsafe = Exp::MakeGCSafe(varexp, false); info.bit = Bit::MakeVar(gcsafe); asserts.PushBack(info); } } MarkRedundantAssertions(mcfg, asserts); // move the finished assertion list into the summary. for (size_t ind = 0; ind < asserts.Size(); ind++) { const AssertInfo &info = asserts[ind]; sum->AddAssert(info.kind, info.cls, info.point, info.bit); } } // infer delta and termination invariants for all summaries. for (size_t ind = 0; ind < summary_list.Size(); ind++) InferInvariants(summary_list[ind], arithmetic_list); BodyAnnotCache.Release(function->GetName()); }
void BlockModset::ComputeModset(BlockMemory *mcfg, bool indirect) { static BaseTimer compute_timer("modset_compute"); Timer _timer(&compute_timer); // get any indirect callees for this function, provided they have been // computed and stored in the callee database (indirect is set). CallEdgeSet *indirect_callees = NULL; if (indirect) indirect_callees = CalleeCache.Lookup(m_id->BaseVar()); BlockCFG *cfg = mcfg->GetCFG(); for (size_t eind = 0; eind < cfg->GetEdgeCount(); eind++) { PEdge *edge = cfg->GetEdge(eind); PPoint point = edge->GetSource(); if (edge->IsAssign() || edge->IsCall()) { // process direct assignments along this edge. const Vector<GuardAssign>* assigns = mcfg->GetAssigns(point); if (assigns) { for (size_t aind = 0; aind < assigns->Size(); aind++) { const GuardAssign &gasn = assigns->At(aind); ProcessUpdatedLval(mcfg, gasn.left, NULL, true, false); Exp *use_lval = NULL; Exp *kind = mcfg->GetTerminateAssign(point, gasn.left, gasn.right, &use_lval); if (kind) { ProcessUpdatedLval(mcfg, use_lval, kind, false, false); kind->DecRef(); } } } } // pull in modsets from the direct and indirect callees of the edge. if (BlockId *callee = edge->GetDirectCallee()) { ComputeModsetCall(mcfg, edge, callee, NULL); callee->DecRef(); } else if (edge->IsCall() && indirect_callees) { for (size_t ind = 0; ind < indirect_callees->GetEdgeCount(); ind++) { const CallEdge &cedge = indirect_callees->GetEdge(ind); // when comparing watch out for the case that this is a temporary // modset and does not share the same block kind as the edge point. if (cedge.where.version == cfg->GetVersion() && cedge.where.point == point && cedge.where.id->Function() == m_id->Function() && cedge.where.id->Loop() == m_id->Loop()) { cedge.callee->IncRef(); BlockId *callee = BlockId::Make(B_Function, cedge.callee); ComputeModsetCall(mcfg, edge, callee, cedge.rfld_chain); callee->DecRef(); } } } } // sort the modset exps to ensure a consistent representation. if (m_modset_list) SortVector<PointValue,compare_PointValue>(m_modset_list); if (m_assign_list) SortVector<GuardAssign,compare_GuardAssign>(m_assign_list); if (indirect) CalleeCache.Release(m_id->BaseVar()); }