24cb23f21b
Left one implicit, but it's arguable. Inspected manually.
655 linhas
20 KiB
C++
655 linhas
20 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include <compiler/analysis/alias_manager.h>
|
|
#include <compiler/analysis/function_scope.h>
|
|
#include <compiler/analysis/live_dict.h>
|
|
#include <compiler/analysis/variable_table.h>
|
|
|
|
#include <compiler/expression/expression.h>
|
|
#include <compiler/expression/assignment_expression.h>
|
|
#include <compiler/expression/simple_variable.h>
|
|
|
|
#include <compiler/statement/statement.h>
|
|
#include <compiler/statement/block_statement.h>
|
|
#include <compiler/statement/exp_statement.h>
|
|
#include <compiler/statement/method_statement.h>
|
|
#include <compiler/statement/statement_list.h>
|
|
|
|
using namespace HPHP;
|
|
using std::vector;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void LiveDict::build(MethodStatementPtr m) {
|
|
m_coalesce = false;
|
|
m_am.clear();
|
|
m_getVars = true;
|
|
Dictionary::build(m);
|
|
m_getVars = false;
|
|
int s = size();
|
|
Dictionary::build(m);
|
|
resize(s);
|
|
|
|
static int rows[] =
|
|
{
|
|
DataFlow::Altered, DataFlow::Available,
|
|
DataFlow::Anticipated, DataFlow::Dying, DataFlow::Used,
|
|
DataFlow::PAvailIn, DataFlow::PAvailOut,
|
|
DataFlow::PAntIn, DataFlow::PAntOut,
|
|
DataFlow::PDieIn, DataFlow::PDieOut
|
|
};
|
|
m_am.graph()->allocateDataFlow(size() + 1,
|
|
sizeof(rows)/sizeof(rows[0]), rows);
|
|
}
|
|
|
|
void LiveDict::visit(ExpressionPtr e) {
|
|
if (m_coalesce) {
|
|
if (e->is(Expression::KindOfSimpleVariable)) {
|
|
int id = e->getCanonID();
|
|
int rid = m_remap[id];
|
|
if (rid && rid != id) {
|
|
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
|
|
SimpleVariablePtr rv(static_pointer_cast<SimpleVariable>(get(rid)));
|
|
sv->coalesce(rv);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (m_getVars != e->is(Expression::KindOfSimpleVariable)) return;
|
|
|
|
if (m_am.insertForDict(e) && m_getVars) {
|
|
record(e);
|
|
}
|
|
}
|
|
|
|
void LiveDict::coalesce(MethodStatementPtr m) {
|
|
m_coalesce = true;
|
|
Dictionary::build(m);
|
|
m_coalesce = false;
|
|
}
|
|
|
|
void LiveDict::updateParams() {
|
|
ControlFlowGraph *g = m_am.graph();
|
|
ControlBlock *b = g->getDfBlock(1);
|
|
size_t width = g->bitWidth();
|
|
|
|
BitOps::Bits *avlin = b->getRow(DataFlow::PAvailIn);
|
|
BitOps::Bits *dieout = m_am.graph()->getTempBits(0);
|
|
BitOps::set(width, dieout, 0);
|
|
for (int i = size(); i--; ) {
|
|
if (ExpressionPtr e = get(i)) {
|
|
always_assert(e->is(Expression::KindOfSimpleVariable));
|
|
Symbol *sym = static_pointer_cast<SimpleVariable>(e)->getSymbol();
|
|
if (sym) {
|
|
if (sym->isParameter() || sym->isClosureVar() || e->isThis()) {
|
|
BitOps::set_bit(e->getCanonID(), avlin, true);
|
|
}
|
|
if (sym->isNeeded() || sym->isReferenced()) {
|
|
BitOps::set_bit(e->getCanonID(), dieout, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (int i = g->getNumBlocks(); i; i--) {
|
|
b = g->getDfBlock(i);
|
|
if (!b->out_size()) {
|
|
BitOps::bit_or(width, b->getRow(DataFlow::PDieOut),
|
|
b->getRow(DataFlow::PDieOut), dieout);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LiveDict::beginBlock(ControlBlock *b) {
|
|
Dictionary::beginBlock(b);
|
|
m_dying = b->getRow(DataFlow::Dying);
|
|
|
|
m_refs.reset();
|
|
for (int i = size(); i--; ) {
|
|
if (ExpressionPtr e = get(i)) {
|
|
always_assert(e->is(Expression::KindOfSimpleVariable));
|
|
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
|
|
if (m_am.hasWildRefs() || sv->couldBeAliased()) {
|
|
sv->setCanonPtr(m_refs);
|
|
m_refs = sv;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void LiveDict::endBlock(ControlBlock *b) {
|
|
}
|
|
|
|
void LiveDict::addConflicts(size_t width,
|
|
BitOps::Bits *live, BitOps::Bits *dying) {
|
|
BitSetBlock b = m_conflicts.getBlock(0);
|
|
for (int i = width; i--; ) {
|
|
if (BitOps::get_bit(i, live)) {
|
|
BitOps::Bits *row = b.getRow(i);
|
|
BitOps::bit_or_or(width, row, row, live, dying);
|
|
} else if (BitOps::get_bit(i, dying)) {
|
|
BitOps::Bits *row = b.getRow(i);
|
|
BitOps::bit_or(width, row, row, live);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LiveDict::buildConflicts() {
|
|
ControlFlowGraph &g = *m_am.graph();
|
|
int num = g.getNumBlocks();
|
|
size_t width = g.bitWidth();
|
|
|
|
m_conflicts.alloc(1, width, -width, 0);
|
|
|
|
BitOps::Bits *live = g.getTempBits(0);
|
|
BitOps::Bits *dying = g.getTempBits(1);
|
|
|
|
BitOps::Bits *params = g.getDfBlock(1)->getRow(DataFlow::PAvailIn);
|
|
BitOps::set(width, dying, true);
|
|
addConflicts(width, params, dying);
|
|
|
|
for (int i = num; i ; i--) {
|
|
ControlBlock *b = g.getDfBlock(i);
|
|
BitOps::bit_and(width, live,
|
|
b->getRow(DataFlow::PAvailIn), b->getRow(DataFlow::PAntIn));
|
|
BitOps::bit_and(width, dying,
|
|
b->getRow(DataFlow::PAvailIn), b->getRow(DataFlow::PDieIn));
|
|
|
|
addConflicts(width, live, dying);
|
|
BitOps::bit_or(width, dying, dying, live);
|
|
addConflicts(width, b->getRow(DataFlow::Used), dying);
|
|
BitOps::bit_and(width, live,
|
|
b->getRow(DataFlow::PAvailOut),
|
|
b->getRow(DataFlow::PAntOut));
|
|
BitOps::bit_and(width, dying,
|
|
b->getRow(DataFlow::PAvailOut),
|
|
b->getRow(DataFlow::PDieOut));
|
|
addConflicts(width, live, dying);
|
|
}
|
|
}
|
|
|
|
/*
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Colorizer {
|
|
explicit Colorizer(int w) : toNode(w) {}
|
|
|
|
struct NodeInfo {
|
|
explicit NodeInfo(int index) : originalIndex(index), size(0), color(-1) {}
|
|
int originalIndex;
|
|
int size;
|
|
int color;
|
|
std::set<int> conflicts;
|
|
};
|
|
|
|
typedef std::vector<NodeInfo>::iterator NodeIterator;
|
|
NodeIterator begin() { return nodes.begin(); }
|
|
NodeIterator end() { return nodes.end(); }
|
|
|
|
std::vector<int> toNode; // map canonId to node index
|
|
std::vector<NodeInfo> nodes;
|
|
void addNode(int i) {
|
|
nodes.push_back(NodeInfo(i));
|
|
toNode[i] = nodes.size();
|
|
}
|
|
|
|
void addConflict(NodeInfo &ni, int i) {
|
|
int ix = toNode[i];
|
|
if (ix) {
|
|
std::pair<std::set<int>::iterator, bool> ret =
|
|
ni.conflicts.insert(ix-1);
|
|
always_assert(ret.second);
|
|
ni.size++;
|
|
}
|
|
}
|
|
|
|
class NodeCmp {
|
|
public:
|
|
explicit NodeCmp(const Colorizer *c) : m_c(c) {}
|
|
bool operator()(int a, int b) {
|
|
const NodeInfo &n1 = m_c->nodes[a];
|
|
const NodeInfo &n2 = m_c->nodes[b];
|
|
return n1.size < n2.size;
|
|
}
|
|
private:
|
|
const Colorizer *m_c;
|
|
};
|
|
|
|
void sort(bool tryHarder, BitOps::Bits *tmp) {
|
|
// First, sort on increasing size
|
|
int size = nodes.size();
|
|
std::vector<int> sorted(size);
|
|
for (int i = size; i--; sorted[i] = i)
|
|
;
|
|
std::sort(sorted.begin(), sorted.end(), NodeCmp(this));
|
|
if (tryHarder) {
|
|
/*
|
|
We have sorted the nodes by number of conflicts. Coloring
|
|
them from most conflicts to fewest should produce reasonable
|
|
results. But we can do better with a dynamic order.
|
|
Repeatedly remove a node with fewest conflicts from the graph
|
|
until there are none left, then color them in the reverse order
|
|
*/
|
|
std::vector<int> isorted(size);
|
|
std::vector<int> buckets;
|
|
|
|
for (int i = 0, j = -1; i < size; i++) {
|
|
isorted[sorted[i]] = i;
|
|
const NodeInfo &n = nodes[sorted[i]];
|
|
while (j < n.size) {
|
|
buckets.push_back(i);
|
|
j++;
|
|
}
|
|
}
|
|
buckets.push_back(size);
|
|
|
|
// Repeatedly move the next node into bucket zero,
|
|
// decrementing the sizes of all its not-yet-chosen
|
|
// conflicts, and adjusting their position in
|
|
// the list accordingly
|
|
for (int i = 0; i < size; i++) {
|
|
NodeInfo &node = nodes[sorted[i]];
|
|
int bucket = node.size;
|
|
for (int j = 0; j <= bucket; j++) {
|
|
always_assert(buckets[j] == i);
|
|
buckets[j]++;
|
|
}
|
|
for (std::set<int>::iterator it = node.conflicts.begin(),
|
|
end = node.conflicts.end(); it != end; ++it) {
|
|
int ix = *it;
|
|
int si = isorted[ix];
|
|
if (si > i) {
|
|
NodeInfo &n = nodes[ix];
|
|
int &bi = buckets[n.size];
|
|
if (si != bi) {
|
|
always_assert(si > bi);
|
|
sorted[si] = sorted[bi];
|
|
sorted[bi] = ix;
|
|
isorted[sorted[si]] = si;
|
|
isorted[ix] = bi;
|
|
}
|
|
bi++;
|
|
n.size--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// now choose the colors
|
|
for (int i = size; i--; ) {
|
|
NodeInfo &n = nodes[sorted[i]];
|
|
BitOps::set(size, tmp, 0);
|
|
for (std::set<int>::iterator it = n.conflicts.begin(),
|
|
end = n.conflicts.end(); it != end; ++it) {
|
|
NodeInfo &n2 = nodes[*it];
|
|
if (n2.color >= 0) BitOps::set_bit(n2.color, tmp, true);
|
|
}
|
|
int j = 0;
|
|
while (BitOps::get_bit(j, tmp)) {
|
|
j++;
|
|
always_assert(j < size);
|
|
}
|
|
n.color = j;
|
|
}
|
|
}
|
|
};
|
|
|
|
bool LiveDict::color(TypePtr type) {
|
|
ControlFlowGraph &g = *m_am.graph();
|
|
size_t width = g.bitWidth();
|
|
|
|
Colorizer col(width);
|
|
|
|
BitSetBlock b = m_conflicts.getBlock(0);
|
|
|
|
for (int i = size(); i--; ) {
|
|
if (ExpressionPtr e = get(i)) {
|
|
if (Type::SameType(type, e->getCPPType())) {
|
|
SimpleVariablePtr sv(
|
|
static_pointer_cast<SimpleVariable>(e));
|
|
Symbol *sym = sv->getSymbol();
|
|
if (sym &&
|
|
!sym->isGlobal() &&
|
|
!sym->isParameter() &&
|
|
!sym->isGeneratorParameter() &&
|
|
!sym->isClosureVar() &&
|
|
!sym->isStatic() &&
|
|
!e->isThis()) {
|
|
col.addNode(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Colorizer::NodeIterator it = col.begin(), end = col.end();
|
|
it != end; ++it) {
|
|
Colorizer::NodeInfo &ni = *it;
|
|
BitOps::Bits *row = b.getRow(ni.originalIndex);
|
|
for (int i = width; i--; ) {
|
|
if (i != ni.originalIndex && BitOps::get_bit(i, row)) {
|
|
col.addConflict(ni, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
BitOps::Bits *tmp = g.getTempBits(0);
|
|
col.sort(true, tmp);
|
|
|
|
std::map<int,int> cmap;
|
|
|
|
bool doit = false;
|
|
for (Colorizer::NodeIterator it = col.begin(), end = col.end();
|
|
it != end; ++it) {
|
|
Colorizer::NodeInfo &ni = *it;
|
|
int &ix = cmap[ni.color];
|
|
if (!ix) {
|
|
ix = ni.originalIndex;
|
|
} else {
|
|
doit = true;
|
|
}
|
|
m_remap[ni.originalIndex] = ix;
|
|
}
|
|
return doit;
|
|
}
|
|
|
|
typedef std::pair<AstWalkerStateVec,int> RootEntry;
|
|
static bool reCmp(const RootEntry &re1, const RootEntry &re2) {
|
|
if (!re1.second || !re2.second) return re2.second < re1.second;
|
|
int sz1 = re1.first.size(), sz2 = re2.first.size();
|
|
if (sz1 > sz2) return true;
|
|
if (sz1 < sz2) return false;
|
|
return re1.first[sz1-1].index > re2.first[sz1-1].index;
|
|
}
|
|
|
|
class ShrinkWrapWalker : public FunctionWalker {
|
|
typedef std::vector<RootEntry> RootEntryVec;
|
|
public:
|
|
ShrinkWrapWalker(LiveDict &dict, int size, std::map<int,int> &remap) :
|
|
m_dict(dict), m_size(size), m_remap(remap), m_rootEntries(size) {}
|
|
void walk(ControlBlock *b, BitOps::Bits *tmp) {
|
|
const AstWalkerStateVec &start = b->getStartState();
|
|
if (!start.size()) return;
|
|
|
|
BitOps::Bits *pantin = b->getRow(DataFlow::PAntIn);
|
|
BitOps::Bits *pavlin = b->getRow(DataFlow::PAvailIn);
|
|
BitOps::Bits *pdiein = b->getRow(DataFlow::PDieIn);
|
|
|
|
BitOps::bit_or_and(m_size, tmp, pantin, pdiein, pavlin);
|
|
|
|
m_state = start;
|
|
|
|
for (int i = m_size; i--; ) {
|
|
if (BitOps::get_bit(i, tmp)) {
|
|
mark(i);
|
|
}
|
|
}
|
|
|
|
AstWalker::walk(*this, m_state, b->getEndBefore(), b->getEndAfter());
|
|
}
|
|
|
|
int after(ConstructRawPtr cp) {
|
|
SimpleVariableRawPtr e(dynamic_pointer_cast<SimpleVariable>(cp));
|
|
if (e) mark(e->getCanonID());
|
|
return WalkContinue;
|
|
}
|
|
|
|
void mark(int i) {
|
|
int j = m_remap[i] ? m_remap[i] : i;
|
|
RootEntry &re = m_rootEntries[j];
|
|
int reSize = re.first.size();
|
|
int sz = m_state.size();
|
|
if (reSize && reSize < sz) sz = reSize + 1;
|
|
while (sz--) {
|
|
const AstWalkerState &s = m_state[sz];
|
|
if (reSize && re.first[sz].cp != s.cp) {
|
|
continue;
|
|
}
|
|
StatementPtr sp(
|
|
dynamic_pointer_cast<Statement>(s.cp));
|
|
if (!sp) continue;
|
|
if (!sp->is(Statement::KindOfBlockStatement) || s.index) {
|
|
if (!sp->is(Statement::KindOfStatementList) ||
|
|
(sz && !dynamic_pointer_cast<BlockStatement>(m_state[sz-1].cp))) {
|
|
continue;
|
|
}
|
|
}
|
|
if (reSize) {
|
|
if (reSize > sz) {
|
|
re.first.resize(sz+1);
|
|
}
|
|
if (re.first[sz].index > s.index) {
|
|
re.first[sz].index = s.index;
|
|
}
|
|
} else {
|
|
re.second = j;
|
|
for (int k = 0; k <= sz; k++) {
|
|
re.first.push_back(m_state[k]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
always_assert(sz >= 0);
|
|
}
|
|
|
|
void execute() {
|
|
std::sort(m_rootEntries.begin(), m_rootEntries.end(), reCmp);
|
|
|
|
for (int i = 0; i < m_size; i++) {
|
|
RootEntry &re = m_rootEntries[i];
|
|
if (!re.second) break;
|
|
const AstWalkerState &s = re.first[re.first.size() - 1];
|
|
StatementPtr sp(dynamic_pointer_cast<Statement>(s.cp));
|
|
always_assert(sp);
|
|
StatementListPtr sl;
|
|
int ix;
|
|
if (sp->is(Statement::KindOfStatementList)) {
|
|
sl = static_pointer_cast<StatementList>(sp);
|
|
ix = (s.index - 1) / 2;
|
|
} else {
|
|
always_assert(sp->is(Statement::KindOfBlockStatement));
|
|
sl = static_pointer_cast<BlockStatement>(sp)->getStmts();
|
|
if (!sl) continue;
|
|
ix = 0;
|
|
}
|
|
ExpressionPtr e = m_dict.get(re.second);
|
|
always_assert(e && e->is(Expression::KindOfSimpleVariable));
|
|
SimpleVariablePtr sv(static_pointer_cast<SimpleVariable>(e));
|
|
Symbol *sym = sv->getSymbol();
|
|
if (!sym || sym->isGlobal() || sym->isStatic() || sym->isParameter() ||
|
|
sym->isGeneratorParameter() || sym->isClosureVar() || sv->isThis()) {
|
|
continue;
|
|
}
|
|
|
|
sym->setShrinkWrapped();
|
|
e = e->clone();
|
|
e->clearContext();
|
|
e->recomputeEffects();
|
|
e->setContext(Expression::Declaration);
|
|
StatementPtr sub = (*sl)[ix];
|
|
e->setLocation(sub->getLocation());
|
|
e->setBlockScope(sub->getScope());
|
|
ExpStatementPtr exp(
|
|
new ExpStatement(sub->getScope(), sub->getLocation(), e));
|
|
sl->insertElement(exp, ix);
|
|
}
|
|
}
|
|
|
|
private:
|
|
LiveDict &m_dict;
|
|
int m_size;
|
|
std::map<int,int> &m_remap;
|
|
RootEntryVec m_rootEntries;
|
|
AstWalkerStateVec m_state;
|
|
};
|
|
|
|
bool LiveDict::shrinkWrap() {
|
|
ControlFlowGraph &g = *m_am.graph();
|
|
BitOps::Bits *tmp = g.getTempBits(0);
|
|
int size = g.bitWidth();
|
|
|
|
ShrinkWrapWalker sw(*this, size, m_remap);
|
|
|
|
for (int dfn = g.getNumBlocks(); dfn; dfn--) {
|
|
ControlBlock *b = g.getDfBlock(dfn);
|
|
sw.walk(b, tmp);
|
|
}
|
|
|
|
sw.execute();
|
|
|
|
return false;
|
|
}
|