Commit 742dc66c authored by Kevin Modzelewski's avatar Kevin Modzelewski

Make DefinednessAnalysis return a bitset

Maybe not the best place to start
parent 3fe4964c
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "analysis/fpc.h" #include "analysis/fpc.h"
#include "analysis/scoping_analysis.h" #include "analysis/scoping_analysis.h"
#include "codegen/osrentry.h" #include "codegen/osrentry.h"
#include "codegen/irgen/irgenerator.h"
#include "core/ast.h" #include "core/ast.h"
#include "core/cfg.h" #include "core/cfg.h"
#include "core/common.h" #include "core/common.h"
...@@ -382,21 +383,41 @@ void DefinednessAnalysis::run(llvm::DenseMap<InternedString, DefinednessAnalysis ...@@ -382,21 +383,41 @@ void DefinednessAnalysis::run(llvm::DenseMap<InternedString, DefinednessAnalysis
// Don't run this twice: // Don't run this twice:
assert(!defined_at_end.size()); assert(!defined_at_end.size());
auto cfg = initial_block->cfg;
auto&& vreg_info = cfg->getVRegInfo();
int nvregs = vreg_info.getTotalNumOfVRegs();
ASSERT(nvregs == initial_map.size(), "%d %d", nvregs, initial_map.size());
for (auto&& p : initial_map) {
// Run it through getVReg to make sure that the vreg exists
ASSERT(vreg_info.getVReg(p.first) >= 0, "%s", p.first.c_str());
}
computeFixedPoint(std::move(initial_map), initial_block, DefinednessBBAnalyzer(scope_info), false, computeFixedPoint(std::move(initial_map), initial_block, DefinednessBBAnalyzer(scope_info), false,
defined_at_beginning, defined_at_end); defined_at_beginning, defined_at_end);
for (const auto& p : defined_at_end) { for (const auto& p : defined_at_end) {
RequiredSet& required = defined_at_end_sets[p.first]; assert(p.second.size() == nvregs);
for (const auto& p2 : p.second) {
assert(!defined_at_end_sets.count(p.first));
RequiredSet& required = defined_at_end_sets.insert(std::make_pair(p.first, RequiredSet(nvregs))).first->second;
//required.resize(nvregs, /* value= */ false);
for (int vreg = 0; vreg < nvregs; vreg++) {
// TODO shouldn't have to use name at all
InternedString name = vreg_info.getName(vreg);
#ifndef NDEBUG #ifndef NDEBUG
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(p2.first); ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(name);
assert(vst != ScopeInfo::VarScopeType::GLOBAL && vst != ScopeInfo::VarScopeType::NAME); assert(vst != ScopeInfo::VarScopeType::GLOBAL && vst != ScopeInfo::VarScopeType::NAME);
#endif #endif
// TODO: don't returned a RequiredSet here, just use a bitset assert(p.second.count(name));
assert(p2.second != DefinednessAnalysis::Unknown); auto status = p.second.find(name)->second;
if (p2.second != DefinednessAnalysis::Undefined) assert(status != DefinednessAnalysis::Unknown);
required.insert(p2.first); if (status != DefinednessAnalysis::Undefined)
required.set(vreg);
} }
} }
...@@ -414,13 +435,16 @@ DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(Interne ...@@ -414,13 +435,16 @@ DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(Interne
const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEnd(CFGBlock* block) { const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEnd(CFGBlock* block) {
assert(defined_at_end_sets.count(block)); assert(defined_at_end_sets.count(block));
return defined_at_end_sets[block]; return defined_at_end_sets.find(block)->second;
} }
PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map, PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map,
CFGBlock* initial_block, bool initials_need_phis, LivenessAnalysis* liveness, CFGBlock* initial_block, bool initials_need_phis, LivenessAnalysis* liveness,
ScopeInfo* scope_info) ScopeInfo* scope_info)
: definedness(), liveness(liveness) { : definedness(), liveness(liveness) {
auto cfg = initial_block->cfg;
auto&& vreg_info = cfg->getVRegInfo();
// I think this should always be the case -- if we're going to generate phis for the initial block, // I think this should always be the case -- if we're going to generate phis for the initial block,
// then we should include the initial arguments as an extra entry point. // then we should include the initial arguments as an extra entry point.
assert(initials_need_phis == (initial_block->predecessors.size() > 0)); assert(initials_need_phis == (initial_block->predecessors.size() > 0));
...@@ -444,8 +468,9 @@ PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::Def ...@@ -444,8 +468,9 @@ PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::Def
if (!definedness.defined_at_end.count(pred)) if (!definedness.defined_at_end.count(pred))
continue; continue;
const RequiredSet& defined = definedness.getDefinedNamesAtEnd(pred); const VRegSet& defined = definedness.getDefinedNamesAtEnd(pred);
for (const auto& s : defined) { for (int vreg : defined) {
auto s = vreg_info.getName(vreg);
if (required.count(s) == 0 && liveness->isLiveAtEnd(s, pred)) { if (required.count(s) == 0 && liveness->isLiveAtEnd(s, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str()); // printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
...@@ -520,9 +545,10 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf ...@@ -520,9 +545,10 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf
counter.log(); counter.log();
llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map; llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map;
auto&& vreg_info = cfg->getVRegInfo();
assert(cfg->hasVregsAssigned()); assert(vreg_info.hasVRegsAssigned());
for (auto p : cfg->sym_vreg_map) for (auto p : vreg_info.getSymVRegMap())
initial_map[p.first] = DefinednessAnalysis::Undefined; initial_map[p.first] = DefinednessAnalysis::Undefined;
auto maybe_add = [&](llvm::StringRef s) { auto maybe_add = [&](llvm::StringRef s) {
...@@ -531,7 +557,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf ...@@ -531,7 +557,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf
assert(vst != ScopeInfo::VarScopeType::GLOBAL); assert(vst != ScopeInfo::VarScopeType::GLOBAL);
if (vst == ScopeInfo::VarScopeType::NAME) if (vst == ScopeInfo::VarScopeType::NAME)
return; return;
assert(cfg->sym_vreg_map.count(e)); assert(vreg_info.getVReg(e) >= 0); // just run it through for the assertions
initial_map[e] = DefinednessAnalysis::Defined; initial_map[e] = DefinednessAnalysis::Defined;
}; };
...@@ -542,7 +568,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf ...@@ -542,7 +568,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf
if (args.kwarg.size()) if (args.kwarg.size())
maybe_add(args.kwarg); maybe_add(args.kwarg);
assert(initial_map.size() == cfg->sym_vreg_map.size()); assert(initial_map.size() == vreg_info.getTotalNumOfVRegs());
return std::unique_ptr<PhiAnalysis>( return std::unique_ptr<PhiAnalysis>(
new PhiAnalysis(std::move(initial_map), cfg->getStartingBlock(), false, liveness, scope_info)); new PhiAnalysis(std::move(initial_map), cfg->getStartingBlock(), false, liveness, scope_info));
...@@ -555,7 +581,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry ...@@ -555,7 +581,7 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map; llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map;
for (auto p : entry_descriptor->md->source->cfg->sym_vreg_map) { for (auto p : entry_descriptor->md->source->cfg->getVRegInfo().getSymVRegMap()) {
initial_map[p.first] = DefinednessAnalysis::Undefined; initial_map[p.first] = DefinednessAnalysis::Undefined;
} }
...@@ -569,6 +595,10 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry ...@@ -569,6 +595,10 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
for (const auto& p : entry_descriptor->args) { for (const auto& p : entry_descriptor->args) {
if (p.first.s()[0] == '!') if (p.first.s()[0] == '!')
continue; continue;
if (p.first.s() == PASSED_CLOSURE_NAME || p.first.s() == FRAME_INFO_PTR_NAME
|| p.first.s() == PASSED_GENERATOR_NAME || p.first.s() == CREATED_CLOSURE_NAME)
continue;
ASSERT(initial_map.count(p.first), "%s", p.first.c_str());
if (potentially_undefined.count(p.first.s())) if (potentially_undefined.count(p.first.s()))
initial_map[p.first] = DefinednessAnalysis::PotentiallyDefined; initial_map[p.first] = DefinednessAnalysis::PotentiallyDefined;
else else
......
...@@ -55,6 +55,50 @@ public: ...@@ -55,6 +55,50 @@ public:
class PhiAnalysis; class PhiAnalysis;
class VRegSet {
private:
// TODO: switch just to a bool*
std::vector<bool> v;
public:
VRegSet(int num_vregs) : v(num_vregs, false) {}
void set(int vreg) { v[vreg] = true; }
class iterator {
public:
const VRegSet& set;
int i;
iterator(const VRegSet& set, int i) : set(set), i(i) {}
iterator& operator++() {
do {
i++;
} while (i < set.v.size() && !set.v[i]);
return *this;
}
bool operator==(const iterator& rhs) const { return i == rhs.i; }
bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
int operator*() {
return i;
}
};
iterator begin() const {
for (int i = 0; i < v.size(); i++) {
if (v[i])
return iterator(*this, i);
}
return iterator(*this, this->v.size());
}
iterator end() const {
return iterator(*this, this->v.size());
}
};
class DefinednessAnalysis { class DefinednessAnalysis {
public: public:
enum DefinitionLevel { enum DefinitionLevel {
...@@ -63,7 +107,7 @@ public: ...@@ -63,7 +107,7 @@ public:
PotentiallyDefined, PotentiallyDefined,
Defined, Defined,
}; };
typedef llvm::DenseSet<InternedString> RequiredSet; typedef VRegSet RequiredSet;
private: private:
llvm::DenseMap<CFGBlock*, llvm::DenseMap<InternedString, DefinitionLevel>> defined_at_beginning, defined_at_end; llvm::DenseMap<CFGBlock*, llvm::DenseMap<InternedString, DefinitionLevel>> defined_at_beginning, defined_at_end;
......
...@@ -745,8 +745,11 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -745,8 +745,11 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
// Currently we pass None because the LLVM jit will decref this value even though it may not be set. // Currently we pass None because the LLVM jit will decref this value even though it may not be set.
static Box* const VAL_UNDEFINED = (Box*)None; static Box* const VAL_UNDEFINED = (Box*)None;
for (auto& name : phis->definedness.getDefinedNamesAtEnd(current_block)) { const VRegSet& defined = phis->definedness.getDefinedNamesAtEnd(current_block);
Box* val = vregs[getVRegInfo().getVReg(name)]; 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(name, current_block))
continue; continue;
......
...@@ -2681,6 +2681,7 @@ public: ...@@ -2681,6 +2681,7 @@ public:
int next_vreg; int next_vreg;
llvm::DenseMap<InternedString, int> sym_vreg_map; llvm::DenseMap<InternedString, int> sym_vreg_map;
llvm::DenseMap<InternedString, std::unordered_set<CFGBlock*>> sym_blocks_map; llvm::DenseMap<InternedString, std::unordered_set<CFGBlock*>> sym_blocks_map;
std::vector<InternedString> vreg_sym_map;
enum Step { TrackBlockUsage = 0, UserVisible, CrossBlock, SingleBlockUse } step; enum Step { TrackBlockUsage = 0, UserVisible, CrossBlock, SingleBlockUse } step;
...@@ -2750,13 +2751,21 @@ public: ...@@ -2750,13 +2751,21 @@ public:
int assignVReg(InternedString id) { int assignVReg(InternedString id) {
auto it = sym_vreg_map.find(id); auto it = sym_vreg_map.find(id);
if (sym_vreg_map.end() == it) { if (sym_vreg_map.end() == it) {
ASSERT(next_vreg == sym_vreg_map.size(), "%d %d", next_vreg, sym_vreg_map.size());
assert(next_vreg == vreg_sym_map.size());
sym_vreg_map[id] = next_vreg; sym_vreg_map[id] = next_vreg;
vreg_sym_map.push_back(id);
return next_vreg++; return next_vreg++;
} }
return it->second; return it->second;
} }
}; };
// XXX temporarily disable vreg reuse, since for the transition we want to make it very
// easy to convert between vregs and names.
#define REUSE_VREGS 0
void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* scope_info) { void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* scope_info) {
assert(!hasVRegsAssigned()); assert(!hasVRegsAssigned());
...@@ -2768,8 +2777,10 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s ...@@ -2768,8 +2777,10 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s
for (CFGBlock* b : cfg->blocks) { for (CFGBlock* b : cfg->blocks) {
visitor.current_block = b; visitor.current_block = b;
#if REUSE_VREGS
if (step == AssignVRegsVisitor::SingleBlockUse) if (step == AssignVRegsVisitor::SingleBlockUse)
visitor.next_vreg = num_vregs_cross_block; visitor.next_vreg = num_vregs_cross_block;
#endif
if (b == cfg->getStartingBlock()) { if (b == cfg->getStartingBlock()) {
for (auto* name : param_names.arg_names) { for (auto* name : param_names.arg_names) {
...@@ -2796,6 +2807,7 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s ...@@ -2796,6 +2807,7 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s
num_vregs = num_vregs_cross_block = visitor.next_vreg; num_vregs = num_vregs_cross_block = visitor.next_vreg;
} }
sym_vreg_map = std::move(visitor.sym_vreg_map); sym_vreg_map = std::move(visitor.sym_vreg_map);
vreg_sym_map = std::move(visitor.vreg_sym_map);
assert(hasVRegsAssigned()); assert(hasVRegsAssigned());
} }
......
...@@ -87,6 +87,10 @@ class VRegInfo { ...@@ -87,6 +87,10 @@ class VRegInfo {
private: private:
llvm::DenseMap<InternedString, int> sym_vreg_map_user_visible; llvm::DenseMap<InternedString, int> sym_vreg_map_user_visible;
llvm::DenseMap<InternedString, int> sym_vreg_map; llvm::DenseMap<InternedString, int> sym_vreg_map;
// Reverse map, from vreg->symbol name.
std::vector<InternedString> vreg_sym_map;
int num_vregs_cross_block = -1; int num_vregs_cross_block = -1;
int num_vregs = -1; int num_vregs = -1;
...@@ -105,6 +109,12 @@ public: ...@@ -105,6 +109,12 @@ public:
return it->second; return it->second;
} }
InternedString getName(int vreg) const {
assert(hasVRegsAssigned());
assert(vreg >= 0 && vreg < num_vregs);
return vreg_sym_map[vreg];
}
bool isUserVisibleVReg(int vreg) const { return vreg < sym_vreg_map_user_visible.size(); } bool isUserVisibleVReg(int vreg) const { return vreg < sym_vreg_map_user_visible.size(); }
bool isCrossBlockVReg(int vreg) const { return !isUserVisibleVReg(vreg) && vreg < num_vregs_cross_block; } bool isCrossBlockVReg(int vreg) const { return !isUserVisibleVReg(vreg) && vreg < num_vregs_cross_block; }
bool isBlockLocalVReg(int vreg) const { return vreg >= num_vregs_cross_block; } bool isBlockLocalVReg(int vreg) const { return vreg >= num_vregs_cross_block; }
......
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