// Substitute s into all members of the set void LocationSet::substitute(Assign& a) { Exp* lhs = a.getLeft(); if (lhs == NULL) return; Exp* rhs = a.getRight(); if (rhs == NULL) return; // ? Will this ever happen? std::set<Exp*, lessExpStar>::iterator it; // Note: it's important not to change the pointer in the set of pointers to expressions, without removing and // inserting again. Otherwise, the set becomes out of order, and operations such as set comparison fail! // To avoid any funny behaviour when iterating the loop, we use the following two sets LocationSet removeSet; // These will be removed after the loop LocationSet removeAndDelete; // These will be removed then deleted LocationSet insertSet; // These will be inserted after the loop bool change; for (it = lset.begin(); it != lset.end(); it++) { Exp* loc = *it; Exp* replace; if (loc->search(lhs, replace)) { if (rhs->isTerminal()) { // This is no longer a location of interest (e.g. %pc) removeSet.insert(loc); continue; } loc = loc->clone()->searchReplaceAll(lhs, rhs, change); if (change) { loc = loc->simplifyArith(); loc = loc->simplify(); // If the result is no longer a register or memory (e.g. // r[28]-4), then delete this expression and insert any // components it uses (in the example, just r[28]) if (!loc->isRegOf() && !loc->isMemOf()) { // Note: can't delete the expression yet, because the // act of insertion into the remove set requires silent // calls to the compare function removeAndDelete.insert(*it); loc->addUsedLocs(insertSet); continue; } // Else we just want to replace it // Regardless of whether the top level expression pointer has // changed, remove and insert it from the set of pointers removeSet.insert(*it); // Note: remove the unmodified ptr insertSet.insert(loc); } } } makeDiff(removeSet); // Remove the items to be removed makeDiff(removeAndDelete); // These are to be removed as well makeUnion(insertSet); // Insert the items to be added // Now delete the expressions that are no longer needed std::set<Exp*, lessExpStar>::iterator dd; for (dd = removeAndDelete.lset.begin(); dd != removeAndDelete.lset.end(); dd++) delete *dd; // Plug that memory leak }
void LocationSetTest::testFindDifferentRef() { LocationSet set; SharedExp result; QVERIFY(!set.findDifferentRef(nullptr, result)); set.insert(Location::regOf(REG_PENT_EAX)); QVERIFY(!set.findDifferentRef(RefExp::get(Location::regOf(REG_PENT_EAX), nullptr), result)); set.insert(RefExp::get(Location::regOf(REG_PENT_EAX), nullptr)); QVERIFY(!set.findDifferentRef(RefExp::get(Location::regOf(REG_PENT_EAX), nullptr), result)); Assign as1(Location::regOf(REG_PENT_ECX), Location::regOf(REG_PENT_EDX)); Assign as2(Location::regOf(REG_PENT_ECX), Location::regOf(REG_PENT_EDX)); as1.setNumber(10); as2.setNumber(20); set.insert(RefExp::get(Location::regOf(REG_PENT_ECX), &as1)); // no other ref QVERIFY(!set.findDifferentRef(RefExp::get(Location::regOf(REG_PENT_ECX), &as1), result)); set.insert(RefExp::get(Location::regOf(REG_PENT_ECX), &as2)); // return a different ref QVERIFY(set.findDifferentRef(RefExp::get(Location::regOf(REG_PENT_ECX), &as1), result)); QCOMPARE(result->toString(), QString("r25{20}")); // should work even when the ref is not in the set set.remove(RefExp::get(Location::regOf(REG_PENT_ECX), &as1)); QVERIFY(set.findDifferentRef(RefExp::get(Location::regOf(REG_PENT_ECX), &as1), result)); QCOMPARE(result->toString(), QString("r25{20}")); }
// Helper function for UserProc::propagateStatements() // Works on basic block n; call from UserProc with n=0 (entry BB) // If an SSA location is in usedByDomPhi it means it is used in a phi that dominates its assignment // However, it could turn out that the phi is dead, in which case we don't want to keep the associated entries in // usedByDomPhi. So we maintain the map defdByPhi which maps locations defined at a phi to the phi statements. Every // time we see a use of a location in defdByPhi, we remove that map entry. At the end of the procedure we therefore have // only dead phi statements in the map, so we can delete the associated entries in defdByPhi and also remove the dead // phi statements. // We add to the set usedByDomPhi0 whenever we see a location referenced by a phi parameter. When we see a definition // for such a location, we remove it from the usedByDomPhi0 set (to save memory) and add it to the usedByDomPhi set. // For locations defined before they are used in a phi parameter, there will be no entry in usedByDomPhi, so we ignore // it. Remember that each location is defined only once, so that's the time to decide if it is dominated by a phi use or // not. void DataFlow::findLiveAtDomPhi(int n, LocationSet& usedByDomPhi, LocationSet& usedByDomPhi0, std::map<Exp*, PhiAssign*, lessExpStar>& defdByPhi) { // For each statement this BB BasicBlock::rtlit rit; StatementList::iterator sit; PBB bb = BBs[n]; Statement* S; for (S = bb->getFirstStmt(rit, sit); S; S = bb->getNextStmt(rit, sit)) { if (S->isPhi()) { // For each phi parameter, insert an entry into usedByDomPhi0 PhiAssign* pa = (PhiAssign*)S; PhiAssign::iterator it; for (it = pa->begin(); it != pa->end(); ++it) { if (it->e) { RefExp* re = new RefExp(it->e, it->def); usedByDomPhi0.insert(re); } } // Insert an entry into the defdByPhi map RefExp* wrappedLhs = new RefExp(pa->getLeft(), pa); defdByPhi[wrappedLhs] = pa; // Fall through to the below, because phi uses are also legitimate uses } LocationSet ls; S->addUsedLocs(ls); // Consider uses of this statement LocationSet::iterator it; for (it = ls.begin(); it != ls.end(); ++it) { // Remove this entry from the map, since it is not unused defdByPhi.erase(*it); } // Now process any definitions ls.clear(); S->getDefinitions(ls); for (it = ls.begin(); it != ls.end(); ++it) { RefExp* wrappedDef = new RefExp(*it, S); // If this definition is in the usedByDomPhi0 set, then it is in fact dominated by a phi use, so move it to // the final usedByDomPhi set if (usedByDomPhi0.find(wrappedDef) != usedByDomPhi0.end()) { usedByDomPhi0.remove(wrappedDef); usedByDomPhi.insert(wrappedDef); } } } // Visit each child in the dominator graph // Note: this is a linear search! // Note also that usedByDomPhi0 may have some irrelevant entries, but this will do no harm, and attempting to erase // the irrelevant ones would probably cost more than leaving them alone int sz = idom.size(); for (int c = 0; c < sz; ++c) { if (idom[c] != n) continue; // Recurse to the child findLiveAtDomPhi(c, usedByDomPhi, usedByDomPhi0, defdByPhi); } }
void LocationSetTest::testSize() { LocationSet set; QVERIFY(set.size() == 0); set.insert(Location::regOf(REG_PENT_ESI)); QVERIFY(set.size() == 1); set.insert(Location::regOf(REG_PENT_EDI)); QVERIFY(set.size() == 2); }
void LocationSetTest::testInsert() { LocationSet set; set.insert(Location::regOf(REG_PENT_ESI)); QCOMPARE(set, LocationSet({ Location::regOf(REG_PENT_ESI) })); set.insert(Location::regOf(REG_PENT_ESI)); QCOMPARE(set, LocationSet({ Location::regOf(REG_PENT_ESI) })); set.insert(Location::regOf(REG_PENT_EDI)); QCOMPARE(set, LocationSet({ Location::regOf(REG_PENT_ESI), Location::regOf(REG_PENT_EDI) })); }
void LocationSetTest::testContainsImplicit() { LocationSet set; QVERIFY(!set.containsImplicit(nullptr)); set.insert(Location::regOf(REG_PENT_ESI)); QVERIFY(!set.containsImplicit(Location::regOf(REG_PENT_ESI))); QVERIFY(!set.containsImplicit(Location::regOf(REG_PENT_EDI))); set.insert(RefExp::get(Location::regOf(REG_PENT_EDI), nullptr)); QVERIFY(set.containsImplicit(Location::regOf(REG_PENT_EDI))); QVERIFY(!set.containsImplicit(Location::regOf(REG_PENT_ESI))); }
void LocationSetTest::testFindNS() { LocationSet set; QVERIFY(set.findNS(nullptr) == nullptr); set.insert(Location::regOf(REG_PENT_ESI)); SharedExp e = set.findNS(Location::regOf(REG_PENT_ESI)); QVERIFY(e == nullptr); set.insert(RefExp::get(Location::regOf(REG_PENT_EDI), nullptr)); e = set.findNS(Location::regOf(REG_PENT_EDI)); QVERIFY(e != nullptr); QCOMPARE(e->toString(), QString("r31{-}")); }
void LocationSetTest::testEmpty() { LocationSet set; QVERIFY(set.empty()); set.insert(Location::regOf(REG_PENT_EDI)); QVERIFY(!set.empty()); }
void LocationSetTest::testAddSubscript() { LocationSet set; set.addSubscript(nullptr); QCOMPARE(set, LocationSet()); set.insert(Location::regOf(REG_PENT_ECX)); set.addSubscript(nullptr); QCOMPARE(set, LocationSet({ RefExp::get(Location::regOf(REG_PENT_ECX), nullptr) })); set.insert(Location::regOf(REG_PENT_ECX)); Assign as(Location::regOf(REG_PENT_ECX), Location::regOf(REG_PENT_EDX)); as.setNumber(42); set.addSubscript(&as); QCOMPARE(set, LocationSet({ RefExp::get(Location::regOf(REG_PENT_ECX), nullptr), RefExp::get(Location::regOf(REG_PENT_ECX), &as) })); }
void LocationSetTest::testContains() { LocationSet set; QVERIFY(!set.contains(nullptr)); set.insert(Location::regOf(REG_PENT_ESI)); QVERIFY(set.contains(Location::regOf(REG_PENT_ESI))); QVERIFY(!set.contains(Location::regOf(REG_PENT_EDI))); }
void LocationSetTest::testRemove() { LocationSet set; set.remove(nullptr); QVERIFY(set.empty()); set.insert(Location::regOf(REG_PENT_ESI)); set.remove(Location::regOf(REG_PENT_ESI)); QVERIFY(set.empty()); set.insert(Location::regOf(REG_PENT_ESI)); set.insert(Location::regOf(REG_PENT_EDI)); set.remove(Location::regOf(REG_PENT_EDI)); QCOMPARE(set, LocationSet({ Location::regOf(REG_PENT_ESI) })); // removing element that does not exist set.remove(Location::regOf(REG_PENT_EDI)); QCOMPARE(set, LocationSet({ Location::regOf(REG_PENT_ESI) })); }
void LocationSetTest::testClear() { LocationSet set; set.clear(); QVERIFY(set.empty()); set.insert(Location::regOf(REG_PENT_ESI)); set.clear(); QVERIFY(set.empty()); }
void BoolAssign::getDefinitions(LocationSet &defs, bool) const { defs.insert(getLeft()); }