/* The classical use/def isnt quite enough here. There are two unusual issues: - the ref/non-ref issue. An assignment to a var which is referenced doesnt end its lifetime. In fact it could just be a "use" of the var. But it also counts as a def. - the destructor issue. variables which might need to be destroyed later are technically alive, but dont interfere with any other variables in the same state. They /do/ interfere with any truly "live" variables, however. These are "dying". So we end up defining, use, kill, def and dying. use : a read of the variable, an ordinary assignment if it could be referenced kill : an unset, a ref assignment, or, for non referenced vars, any assignment def : ref or normal assignment dying : a variable whose destructor is (partially/locally) anticipated. */ void LiveDict::updateAccess(ExpressionPtr e) { int cls = e->getExprClass(); if (cls & Expression::Store) { /* Handled when we see the lhs */ return; } int eid = e->getCanonID(); int context = e->getContext(); bool unset = false; bool store = false; if (context & Expression::LValue && context & Expression::UnsetContext) { unset = true; } else if (context & Expression::AssignmentLHS) { store = true; } if (e->is(Expression::KindOfSimpleVariable)) { SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e)); bool use = false, kill = false, def = false; Symbol *sym = sv->getSymbol(); bool isReferenced = e->isReferencedValid() ? e->isReferenced() : sym && sym->isReferenced(); bool isNeeded = e->isNeededValid() ? e->isNeeded() : sym && sym->isNeeded(); if (unset) { kill = true; } else if (store) { if (context & Expression::RefAssignmentLHS || (!m_am.hasWildRefs() && !isReferenced)) { kill = true; } def = true; } else if ((context & Expression::Declaration) == Expression::Declaration) { // a global declaration def = kill = true; } else if (context & (Expression::LValue| Expression::RefValue| Expression::DeepReference| Expression::UnsetContext| Expression::OprLValue)) { use = def = true; } else { use = true; } if (kill && (!sym || isNeeded || isReferenced) && !BitOps::get_bit(eid, m_altered) && !BitOps::get_bit(eid, m_available)) { BitOps::set_bit(eid, m_dying, true); } if (use && !BitOps::get_bit(eid, m_altered) && !BitOps::get_bit(eid, m_available)) { BitOps::set_bit(eid, m_anticipated, true); e->setAnticipated(); } if (kill) { BitOps::set_bit(eid, m_altered, true); BitOps::set_bit(eid, m_available, def); } else if (def) { BitOps::set_bit(eid, m_available, true); } if (!m_am.couldBeAliased(sv)) { return; } } else if (!e->is(Expression::KindOfDynamicVariable) && (unset || (context & Expression::RefAssignmentLHS))) { // An unset, or a reference assignment to anything other // than a simple or dynamic variable can never affect a simple // variable (outside of pseudoMain). return; } if (store || cls & (Expression::Load|Expression::Call)) { bool mod = store || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference| Expression::OprLValue)); ExpressionPtr cur = m_refs, prev; bool isLoad; int depth = 0, effects = 0; while (cur) { ExpressionPtr next = cur->getCanonLVal(); int cid = cur->getCanonID(); if (cid != eid && m_am.checkAnyInterf(e, cur, isLoad, depth, effects) != AliasManager::DisjointAccess) { if (mod) { BitOps::set_bit(cid, m_available, true); } if (!BitOps::get_bit(cid, m_altered) && !BitOps::get_bit(cid, m_available)) { BitOps::set_bit(cid, m_anticipated, true); } if (!prev) { m_refs = next; } else { prev->setCanonPtr(next); } } else { prev = cur; } cur = next; } } }
void ExprDict::updateAccess(ExpressionPtr e) { int cls = e->getExprClass(); int eid = e->getCanonID(); e->clearAnticipated(); e->clearAvailable(); // bail on non-canonical expressions if (!isCanonicalStructure(eid)) { // but record we saw a type assertion belonging to this block m_avlTypeAsserts.push_back(eid); return; } if (m_anticipated && (cls & Expression::Update ? !BitOps::get_bit(eid, m_altered) : !e->getLocalEffects())) { /* Anticipated can be computed bottom up as we go. But note that we only know altered for Load/Store expressions. */ int i = e->getKidCount(); while (true) { if (!i--) { e->setAnticipated(); if (!e->hasContext(Expression::AssignmentLHS)) { setStructureOps(eid, m_anticipated, true); } break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAnticipated()) { break; } } } } if (m_available) { /* Available has to be computed optimistically, because we dont yet know what is going to be altered between here and the end of the block So keep a list of the potentially-available accesses (avlAccess), and for each id, the last potentially-available expression (avlExpr). For each modifying expression that we process, we remove expressions from avlAccess, and at the end, we build up the available expressions bottom up. */ if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { bool isLoad; int depth = 0, effects = 0; for (int i = 0, n = m_avlAccess.size(); i < n; ) { ExpressionRawPtr a = m_avlAccess[i]; if (m_am.checkAnyInterf(e, a, isLoad, depth, effects) != AliasManager::DisjointAccess) { int aid = a->getCanonID(); assert(isCanonicalStructure(aid)); if (eid != aid || cls == Expression::Load) { BitOps::set_bit(aid, m_altered, true); } if (!(cls & Expression::Store) || a != e->getStoreVariable()) { a->clearAvailable(); m_avlAccess[i] = m_avlAccess[--n]; m_avlAccess.resize(n); continue; } } i++; } } if (cls & Expression::Update || !e->getContainedEffects()) { int i = e->getKidCount(); while (true) { if (!i--) { e->setAvailable(); if (cls & Expression::Update) { m_avlAccess.push_back(e); } m_avlExpr[eid] = e; break; } if (ExpressionPtr k = e->getNthExpr(i)) { if (!isCanonicalStructure(k->getCanonID())) continue; if (!k->isAvailable()) { break; } } } } } if ((cls & (Expression::Store|Expression::Call)) || (cls & Expression::Load && e->getContext() & (Expression::LValue| Expression::RefValue| Expression::UnsetContext| Expression::DeepReference))) { ExpressionPtr cur = m_active, prev; bool isLoad; int depth = 0, effects = 0; while (cur) { ExpressionPtr next = cur->getCanonLVal(); int cid = cur->getCanonID(); assert(isCanonicalStructure(cid)); if ((cid != eid || cls == Expression::Load) && (BitOps::get_bit(cid, m_altered) || m_am.checkAnyInterf(e, cur, isLoad, depth, effects) != AliasManager::DisjointAccess)) { BitOps::set_bit(cid, m_altered, true); if (!prev) { m_active = next; } else { prev->setCanonPtr(next); } } else { prev = cur; } cur = next; } } }