Commit d686cbfb authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by Kevin Modzelewski

Switch LivenessAnalysis to vregs

parent 9f17a19e
......@@ -53,40 +53,35 @@ private:
}
};
llvm::DenseMap<InternedString, Status> statuses;
VRegMap<Status> statuses;
LivenessAnalysis* analysis;
void _doLoad(InternedString name, AST_Name* node) {
Status& status = statuses[name];
void _doLoad(int vreg, AST_Name* node) {
Status& status = statuses[vreg];
status.addUsage(Status::USED);
}
void _doStore(InternedString name) {
Status& status = statuses[name];
void _doStore(int vreg) {
assert(vreg >= 0);
Status& status = statuses[vreg];
status.addUsage(Status::DEFINED);
}
Status::Usage getStatusFirst(InternedString name) const {
auto it = statuses.find(name);
if (it == statuses.end())
return Status::NONE;
return it->second.first;
}
Status::Usage getStatusFirst(int vreg) const { return statuses[vreg].first; }
public:
LivenessBBVisitor(LivenessAnalysis* analysis) : analysis(analysis) {}
LivenessBBVisitor(LivenessAnalysis* analysis)
: statuses(analysis->cfg->getVRegInfo().getTotalNumOfVRegs()), analysis(analysis) {}
bool firstIsUse(InternedString name) const { return getStatusFirst(name) == Status::USED; }
bool firstIsUse(int vreg) const { return getStatusFirst(vreg) == Status::USED; }
bool firstIsDef(InternedString name) const { return getStatusFirst(name) == Status::DEFINED; }
bool firstIsDef(int vreg) const { return getStatusFirst(vreg) == Status::DEFINED; }
bool isKilledAt(AST_Name* node, bool is_live_at_end) { return node->is_kill; }
bool visit_import(AST_Import* node) { RELEASE_ASSERT(0, "these should all get removed by the cfg"); }
bool visit_classdef(AST_ClassDef* node) {
_doStore(node->name);
for (auto e : node->bases)
e->accept(this);
for (auto e : node->decorator_list)
......@@ -94,12 +89,13 @@ public:
return true;
}
bool visit_functiondef(AST_FunctionDef* node) {
for (auto* d : node->decorator_list)
d->accept(this);
node->args->accept(this);
for (auto* d : node->args->defaults)
d->accept(this);
_doStore(node->name);
return true;
}
......@@ -110,16 +106,19 @@ public:
}
bool visit_name(AST_Name* node) {
if (node->vreg == -1)
return true;
if (node->ctx_type == AST_TYPE::Load)
_doLoad(node->id, node);
_doLoad(node->vreg, node);
else if (node->ctx_type == AST_TYPE::Del) {
// Hack: we don't have a bytecode for temporary-kills:
if (node->id.s()[0] == '#')
if (node->vreg >= analysis->cfg->getVRegInfo().getNumOfUserVisibleVRegs())
return true;
_doLoad(node->id, node);
_doStore(node->id);
_doLoad(node->vreg, node);
_doStore(node->vreg);
} else if (node->ctx_type == AST_TYPE::Store || node->ctx_type == AST_TYPE::Param)
_doStore(node->id);
_doStore(node->vreg);
else {
ASSERT(0, "%d", node->ctx_type);
abort();
......@@ -127,17 +126,10 @@ public:
return true;
}
bool visit_alias(AST_alias* node) {
InternedString name = node->name;
if (node->asname.s().size())
name = node->asname;
_doStore(name);
return true;
}
bool visit_alias(AST_alias* node) { RELEASE_ASSERT(0, "these should be removed by the cfg"); }
};
LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg) {
LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg), result_cache(cfg->getVRegInfo().getTotalNumOfVRegs()) {
Timer _t("LivenessAnalysis()", 100);
for (CFGBlock* b : cfg->blocks) {
......@@ -159,27 +151,28 @@ bool LivenessAnalysis::isKill(AST_Name* node, CFGBlock* parent_block) {
if (node->id.s()[0] != '#')
return false;
return liveness_cache[parent_block]->isKilledAt(node, isLiveAtEnd(node->id, parent_block));
return liveness_cache[parent_block]->isKilledAt(node, isLiveAtEnd(node->vreg, parent_block));
}
bool LivenessAnalysis::isLiveAtEnd(InternedString name, CFGBlock* block) {
if (name.s()[0] != '#')
bool LivenessAnalysis::isLiveAtEnd(int vreg, CFGBlock* block) {
// Is a user-visible name, always live:
if (vreg < block->cfg->getVRegInfo().getNumOfUserVisibleVRegs())
return true;
if (block->successors.size() == 0)
return false;
if (!result_cache.count(name)) {
if (!result_cache[vreg].size()) {
Timer _t("LivenessAnalysis()", 10);
llvm::DenseMap<CFGBlock*, bool>& map = result_cache[name];
llvm::DenseMap<CFGBlock*, bool>& map = result_cache[vreg];
// Approach:
// - Find all uses (blocks where the status is USED)
// - Trace backwards, marking all blocks as live-at-end
// - If we hit a block that is DEFINED, stop
for (CFGBlock* b : cfg->blocks) {
if (!liveness_cache[b]->firstIsUse(name))
if (!liveness_cache[b]->firstIsUse(vreg))
continue;
std::deque<CFGBlock*> q;
......@@ -195,7 +188,7 @@ bool LivenessAnalysis::isLiveAtEnd(InternedString name, CFGBlock* block) {
continue;
map[thisblock] = true;
if (!liveness_cache[thisblock]->firstIsDef(name)) {
if (!liveness_cache[thisblock]->firstIsDef(vreg)) {
for (CFGBlock* pred : thisblock->predecessors) {
q.push_back(pred);
}
......@@ -208,7 +201,7 @@ bool LivenessAnalysis::isLiveAtEnd(InternedString name, CFGBlock* block) {
us_liveness.log(_t.end());
}
return result_cache[name][block];
return result_cache[vreg][block];
}
class DefinednessBBAnalyzer : public BBAnalyzer<DefinednessAnalysis::DefinitionLevel> {
......@@ -468,8 +461,7 @@ PhiAnalysis::PhiAnalysis(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_m
const VRegSet& defined = definedness.getDefinedVregsAtEnd(pred);
for (int vreg : defined) {
auto s = vreg_info.getName(vreg);
if (!required[vreg] && liveness->isLiveAtEnd(s, pred)) {
if (!required[vreg] && liveness->isLiveAtEnd(vreg, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
required.set(vreg);
......
......@@ -33,6 +33,48 @@ class CFGBlock;
class ScopeInfo;
class LivenessBBVisitor;
template <typename T> class VRegMap {
private:
// TODO: switch just to a T*
std::vector<T> v;
public:
VRegMap(int num_vregs) : v(num_vregs) {}
T& operator[](int vreg) {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
const T& operator[](int vreg) const {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
class iterator {
public:
const VRegMap<T>& map;
int i;
iterator(const VRegMap<T>& map, int i) : map(map), i(i) {}
iterator& operator++() {
i++;
return *this;
}
bool operator==(const iterator& rhs) const { return i == rhs.i; }
bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
std::pair<int, const T&> operator*() { return std::pair<int, const T&>(i, map[i]); }
};
int numVregs() const { return v.size(); }
iterator begin() const { return iterator(*this, 0); }
iterator end() const { return iterator(*this, this->v.size()); }
};
class LivenessAnalysis {
private:
CFG* cfg;
......@@ -41,7 +83,7 @@ private:
typedef llvm::DenseMap<CFGBlock*, std::unique_ptr<LivenessBBVisitor>> LivenessCacheMap;
LivenessCacheMap liveness_cache;
llvm::DenseMap<InternedString, llvm::DenseMap<CFGBlock*, bool>> result_cache;
VRegMap<llvm::DenseMap<CFGBlock*, bool>> result_cache;
public:
LivenessAnalysis(CFG* cfg);
......@@ -50,7 +92,7 @@ public:
// we don't keep track of node->parent_block relationships, so you have to pass both:
bool isKill(AST_Name* node, CFGBlock* parent_block);
bool isLiveAtEnd(InternedString name, CFGBlock* block);
bool isLiveAtEnd(int vreg, CFGBlock* block);
};
class PhiAnalysis;
......@@ -103,48 +145,6 @@ public:
iterator end() const { return iterator(*this, this->v.size()); }
};
template <typename T> class VRegMap {
private:
// TODO: switch just to a T*
std::vector<T> v;
public:
VRegMap(int num_vregs) : v(num_vregs) {}
T& operator[](int vreg) {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
const T& operator[](int vreg) const {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
class iterator {
public:
const VRegMap<T>& map;
int i;
iterator(const VRegMap<T>& map, int i) : map(map), i(i) {}
iterator& operator++() {
i++;
return *this;
}
bool operator==(const iterator& rhs) const { return i == rhs.i; }
bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
std::pair<int, const T&> operator*() { return std::pair<int, const T&>(i, map[i]); }
};
int numVregs() const { return v.size(); }
iterator begin() const { return iterator(*this, 0); }
iterator end() const { return iterator(*this, this->v.size()); }
};
class DefinednessAnalysis {
public:
enum DefinitionLevel {
......
......@@ -478,7 +478,7 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
if (jit) {
bool is_live = true;
if (!closure)
is_live = source_info->getLiveness()->isLiveAtEnd(name, current_block);
is_live = source_info->getLiveness()->isLiveAtEnd(node->vreg, current_block);
if (is_live)
jit->emitSetLocal(name, node->vreg, closure, value);
else
......@@ -720,7 +720,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
llvm::SmallVector<int, 16> dead_vregs;
for (auto&& sym : getSymVRegMap()) {
if (!liveness->isLiveAtEnd(sym.first, current_block)) {
if (!liveness->isLiveAtEnd(sym.second, current_block)) {
dead_vregs.push_back(sym.second);
} else if (phis->isRequiredAfter(sym.first, current_block)) {
assert(scope_info->getScopeTypeOfName(sym.first) != ScopeInfo::VarScopeType::GLOBAL);
......@@ -747,12 +747,12 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
const VRegSet& defined = phis->definedness.getDefinedVregsAtEnd(current_block);
for (int vreg : defined) {
InternedString name = source_info->cfg->getVRegInfo().getName(vreg);
Box* val = vregs[vreg];
if (!liveness->isLiveAtEnd(name, current_block))
if (!liveness->isLiveAtEnd(vreg, current_block))
continue;
InternedString name = source_info->cfg->getVRegInfo().getName(vreg);
Box* val = vregs[vreg];
if (phis->isPotentiallyUndefinedAfter(name, current_block)) {
bool is_defined = val != NULL;
// TODO only mangle once
......@@ -1690,8 +1690,10 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
bool is_live = true;
if (node->is_kill) {
is_live = false;
} else if (node->lookup_type == ScopeInfo::VarScopeType::FAST)
is_live = source_info->getLiveness()->isLiveAtEnd(node->id, current_block);
} else if (node->lookup_type == ScopeInfo::VarScopeType::FAST) {
assert(node->vreg != -1);
is_live = source_info->getLiveness()->isLiveAtEnd(node->vreg, current_block);
}
if (is_live) {
assert(!node->is_kill);
......
......@@ -2643,6 +2643,7 @@ private:
// cf->func->dump();
SourceInfo* source = irstate->getSourceInfo();
auto cfg = source->cfg;
ScopeInfo* scope_info = irstate->getScopeInfo();
// Sort the names here to make the process deterministic:
......@@ -2656,7 +2657,7 @@ private:
// ASSERT(p.first[0] != '!' || isIsDefinedName(p.first), "left a fake variable in the real
// symbol table? '%s'", p.first.c_str());
if (!irstate->getLiveness()->isLiveAtEnd(p.first, myblock)) {
if (!irstate->getLiveness()->isLiveAtEnd(cfg->getVRegInfo().getVReg(p.first), myblock)) {
symbol_table.erase(getIsDefinedName(p.first));
symbol_table.erase(p.first);
} else if (irstate->getPhis()->isRequiredAfter(p.first, myblock)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment