Commit 9f17a19e authored by Kevin Modzelewski's avatar Kevin Modzelewski

Switch PhiAnalysis to use VRegSets

parent 84b05dab
......@@ -378,32 +378,26 @@ void DefinednessBBAnalyzer::processBB(Map& starting, CFGBlock* block) const {
}
}
void DefinednessAnalysis::run(llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map,
CFGBlock* initial_block, ScopeInfo* scope_info) {
void DefinednessAnalysis::run(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_map, CFGBlock* initial_block,
ScopeInfo* scope_info) {
Timer _t("DefinednessAnalysis()", 10);
// Don't run this twice:
assert(!defined_at_end.size());
auto cfg = initial_block->cfg;
int nvregs = cfg->getVRegInfo().getTotalNumOfVRegs();
assert(initial_map.numVregs() == nvregs);
auto&& vreg_info = cfg->getVRegInfo();
int nvregs = vreg_info.getTotalNumOfVRegs();
ASSERT(nvregs == initial_map.size(), "%d %d", nvregs, initial_map.size());
VRegMap<DefinednessAnalysis::DefinitionLevel> real_initial_map(nvregs);
for (auto&& p : initial_map) {
real_initial_map[vreg_info.getVReg(p.first)] = p.second;
}
computeFixedPoint(std::move(real_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);
for (const auto& p : defined_at_end) {
assert(p.second.numVregs() == nvregs);
assert(!defined_at_end_sets.count(p.first));
RequiredSet& required = defined_at_end_sets.insert(std::make_pair(p.first, RequiredSet(nvregs))).first->second;
VRegSet& required = defined_at_end_sets.insert(std::make_pair(p.first, VRegSet(nvregs))).first->second;
// required.resize(nvregs, /* value= */ false);
......@@ -434,15 +428,14 @@ DefinednessAnalysis::DefinitionLevel DefinednessAnalysis::isDefinedAtEnd(Interne
return map[cfg->getVRegInfo().getVReg(name)];
}
const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAtEnd(CFGBlock* block) {
const VRegSet& DefinednessAnalysis::getDefinedVregsAtEnd(CFGBlock* block) {
assert(defined_at_end_sets.count(block));
return defined_at_end_sets.find(block)->second;
}
PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map,
CFGBlock* initial_block, bool initials_need_phis, LivenessAnalysis* liveness,
ScopeInfo* scope_info)
: definedness(), liveness(liveness) {
PhiAnalysis::PhiAnalysis(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_map, CFGBlock* initial_block,
bool initials_need_phis, LivenessAnalysis* liveness, ScopeInfo* scope_info)
: definedness(), empty_set(initial_map.numVregs()), liveness(liveness) {
auto cfg = initial_block->cfg;
auto&& vreg_info = cfg->getVRegInfo();
......@@ -450,13 +443,17 @@ PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::Def
// then we should include the initial arguments as an extra entry point.
assert(initials_need_phis == (initial_block->predecessors.size() > 0));
int num_vregs = initial_map.numVregs();
assert(num_vregs == vreg_info.getTotalNumOfVRegs());
definedness.run(std::move(initial_map), initial_block, scope_info);
Timer _t("PhiAnalysis()", 10);
for (const auto& p : definedness.defined_at_end) {
CFGBlock* block = p.first;
RequiredSet& required = required_phis[block];
assert(!required_phis.count(block));
VRegSet& required = required_phis.insert(std::make_pair(block, VRegSet(num_vregs))).first->second;
int npred = 0;
for (CFGBlock* pred : block->predecessors) {
......@@ -469,13 +466,13 @@ PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::Def
if (!definedness.defined_at_end.count(pred))
continue;
const VRegSet& defined = definedness.getDefinedNamesAtEnd(pred);
const VRegSet& defined = definedness.getDefinedVregsAtEnd(pred);
for (int vreg : defined) {
auto s = vreg_info.getName(vreg);
if (required.count(s) == 0 && liveness->isLiveAtEnd(s, pred)) {
if (!required[vreg] && liveness->isLiveAtEnd(s, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str());
required.insert(s);
required.set(vreg);
}
}
}
......@@ -486,23 +483,23 @@ PhiAnalysis::PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::Def
us_phis.log(_t.end());
}
const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block) {
static RequiredSet empty;
const VRegSet& PhiAnalysis::getAllRequiredAfter(CFGBlock* block) {
if (block->successors.size() == 0)
return empty;
return empty_set;
assert(required_phis.count(block->successors[0]));
return required_phis[block->successors[0]];
return required_phis.find(block->successors[0])->second;
}
const PhiAnalysis::RequiredSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) {
const VRegSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) {
assert(required_phis.count(block));
return required_phis[block];
return required_phis.find(block)->second;
}
// TODO: switch this to taking a vreg
bool PhiAnalysis::isRequired(InternedString name, CFGBlock* block) {
assert(!startswith(name.s(), "!"));
assert(required_phis.count(block));
return required_phis[block].count(name) != 0;
return required_phis.find(block)->second[block->cfg->getVRegInfo().getVReg(name)];
}
bool PhiAnalysis::isRequiredAfter(InternedString name, CFGBlock* block) {
......@@ -548,31 +545,34 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const ParamNames& args, CFG* cf
static StatCounter counter("num_phi_analysis");
counter.log();
llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map;
auto&& vreg_info = cfg->getVRegInfo();
int num_vregs = vreg_info.getTotalNumOfVRegs();
VRegMap<DefinednessAnalysis::DefinitionLevel> initial_map(num_vregs);
assert(vreg_info.hasVRegsAssigned());
for (auto p : vreg_info.getSymVRegMap())
initial_map[p.first] = DefinednessAnalysis::Undefined;
for (int vreg = 0; vreg < num_vregs; vreg++) {
initial_map[vreg] = DefinednessAnalysis::Undefined;
}
auto maybe_add = [&](llvm::StringRef s) {
InternedString e = scope_info->internString(s);
ScopeInfo::VarScopeType vst = scope_info->getScopeTypeOfName(e);
auto maybe_add = [&](AST_Name* n) {
ScopeInfo::VarScopeType vst = n->lookup_type;
assert(vst != ScopeInfo::VarScopeType::UNKNOWN);
assert(vst != ScopeInfo::VarScopeType::GLOBAL);
if (vst == ScopeInfo::VarScopeType::NAME)
return;
assert(vreg_info.getVReg(e) >= 0); // just run it through for the assertions
initial_map[e] = DefinednessAnalysis::Defined;
assert(n->vreg >= 0);
initial_map[n->vreg] = DefinednessAnalysis::Defined;
};
for (auto e : args.args)
for (auto e : args.arg_names)
maybe_add(e);
if (args.vararg.size())
maybe_add(args.vararg);
if (args.kwarg.size())
maybe_add(args.kwarg);
if (args.vararg_name)
maybe_add(args.vararg_name);
if (args.kwarg_name)
maybe_add(args.kwarg_name);
assert(initial_map.size() == vreg_info.getTotalNumOfVRegs());
assert(initial_map.numVregs() == vreg_info.getTotalNumOfVRegs());
return std::unique_ptr<PhiAnalysis>(
new PhiAnalysis(std::move(initial_map), cfg->getStartingBlock(), false, liveness, scope_info));
......@@ -583,10 +583,12 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
static StatCounter counter("num_phi_analysis");
counter.log();
llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map;
auto cfg = entry_descriptor->md->source->cfg;
int num_vregs = cfg->getVRegInfo().getTotalNumOfVRegs();
VRegMap<DefinednessAnalysis::DefinitionLevel> initial_map(num_vregs);
for (auto p : entry_descriptor->md->source->cfg->getVRegInfo().getSymVRegMap()) {
initial_map[p.first] = DefinednessAnalysis::Undefined;
for (int vreg = 0; vreg < num_vregs; vreg++) {
initial_map[vreg] = DefinednessAnalysis::Undefined;
}
llvm::StringSet<> potentially_undefined;
......@@ -602,11 +604,12 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
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());
int vreg = cfg->getVRegInfo().getVReg(p.first);
ASSERT(initial_map[vreg] == DefinednessAnalysis::Undefined, "%s %d", p.first.c_str(), initial_map[vreg]);
if (potentially_undefined.count(p.first.s()))
initial_map[p.first] = DefinednessAnalysis::PotentiallyDefined;
initial_map[vreg] = DefinednessAnalysis::PotentiallyDefined;
else
initial_map[p.first] = DefinednessAnalysis::Defined;
initial_map[vreg] = DefinednessAnalysis::Defined;
}
return std::unique_ptr<PhiAnalysis>(
......
......@@ -63,7 +63,15 @@ private:
public:
VRegSet(int num_vregs) : v(num_vregs, false) {}
void set(int vreg) { v[vreg] = true; }
// TODO: what is the referenc type here?
bool operator[](int vreg) {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
void set(int vreg) {
assert(vreg >= 0 && vreg < v.size());
v[vreg] = true;
}
class iterator {
public:
......@@ -145,44 +153,44 @@ public:
PotentiallyDefined,
Defined,
};
typedef VRegSet RequiredSet;
private:
llvm::DenseMap<CFGBlock*, VRegMap<DefinitionLevel>> defined_at_beginning, defined_at_end;
llvm::DenseMap<CFGBlock*, RequiredSet> defined_at_end_sets;
llvm::DenseMap<CFGBlock*, VRegSet> defined_at_end_sets;
public:
DefinednessAnalysis() {}
void run(llvm::DenseMap<InternedString, DefinitionLevel> initial_map, CFGBlock* initial_block,
ScopeInfo* scope_info);
void run(VRegMap<DefinitionLevel> initial_map, CFGBlock* initial_block, ScopeInfo* scope_info);
DefinitionLevel isDefinedAtEnd(InternedString name, CFGBlock* block);
const RequiredSet& getDefinedNamesAtEnd(CFGBlock* block);
const VRegSet& getDefinedVregsAtEnd(CFGBlock* block);
friend class PhiAnalysis;
};
class PhiAnalysis {
public:
typedef llvm::DenseSet<InternedString> RequiredSet;
DefinednessAnalysis definedness;
VRegSet empty_set;
private:
LivenessAnalysis* liveness;
llvm::DenseMap<CFGBlock*, RequiredSet> required_phis;
llvm::DenseMap<CFGBlock*, VRegSet> required_phis;
public:
// Initials_need_phis specifies that initial_map should count as an additional entry point
// that may require phis.
PhiAnalysis(llvm::DenseMap<InternedString, DefinednessAnalysis::DefinitionLevel> initial_map,
CFGBlock* initial_block, bool initials_need_phis, LivenessAnalysis* liveness, ScopeInfo* scope_info);
PhiAnalysis(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_map, CFGBlock* initial_block,
bool initials_need_phis, LivenessAnalysis* liveness, ScopeInfo* scope_info);
// TODO: convert these to taking vregs
bool isRequired(InternedString name, CFGBlock* block);
bool isRequiredAfter(InternedString name, CFGBlock* block);
const RequiredSet& getAllRequiredAfter(CFGBlock* block);
const RequiredSet& getAllRequiredFor(CFGBlock* block);
const VRegSet& getAllRequiredAfter(CFGBlock* block);
const VRegSet& getAllRequiredFor(CFGBlock* block);
// TODO: convert these to taking vregs
// If "name" may be undefined at the beginning of any immediate successor block of "block":
bool isPotentiallyUndefinedAfter(InternedString name, CFGBlock* block);
// If "name" may be undefined at the beginning of "block"
......
......@@ -155,7 +155,7 @@ public:
~ASTInterpreter() { Py_XDECREF(this->created_closure); }
const VRegInfo& getVRegInfo() const { return source_info->cfg->getVRegInfo(); }
const llvm::DenseMap<InternedString, int>& getSymVRegMap() const {
const llvm::DenseMap<InternedString, DefaultedInt<-1>>& getSymVRegMap() const {
return source_info->cfg->getVRegInfo().getSymVRegMap();
}
......@@ -745,7 +745,7 @@ 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.
static Box* const VAL_UNDEFINED = (Box*)None;
const VRegSet& defined = phis->definedness.getDefinedNamesAtEnd(current_block);
const VRegSet& defined = phis->definedness.getDefinedVregsAtEnd(current_block);
for (int vreg : defined) {
InternedString name = source_info->cfg->getVRegInfo().getName(vreg);
......
......@@ -361,12 +361,14 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
PhiAnalysis* phi_analysis = irstate->getPhis();
assert(phi_analysis);
CFG* cfg = source->cfg;
if (entry_descriptor != NULL)
assert(blocks.count(source->cfg->getStartingBlock()) == 0);
assert(blocks.count(cfg->getStartingBlock()) == 0);
// We need the entry blocks pre-allocated so that we can jump forward to them.
std::unordered_map<CFGBlock*, llvm::BasicBlock*> llvm_entry_blocks;
for (CFGBlock* block : source->cfg->blocks) {
for (CFGBlock* block : cfg->blocks) {
if (blocks.count(block) == 0) {
llvm_entry_blocks[block] = NULL;
continue;
......@@ -514,8 +516,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
CFGBlock* initial_block = NULL;
if (entry_descriptor) {
initial_block = entry_descriptor->backedge->target;
} else if (blocks.count(source->cfg->getStartingBlock())) {
initial_block = source->cfg->getStartingBlock();
} else if (blocks.count(cfg->getStartingBlock())) {
initial_block = cfg->getStartingBlock();
}
// The rest of this code assumes that for each non-entry block that gets evaluated,
......@@ -548,14 +550,13 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// Set initial symbol table:
// If we're in the starting block, no phis or symbol table changes for us.
// Generate function entry code instead.
if (block == source->cfg->getStartingBlock()) {
if (block == cfg->getStartingBlock()) {
assert(entry_descriptor == NULL);
if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast != NULL
&& source->ast->type != AST_TYPE::Module) {
llvm::BasicBlock* preentry_bb
= llvm::BasicBlock::Create(g.context, "pre_entry", irstate->getLLVMFunction(),
llvm_entry_blocks[source->cfg->getStartingBlock()]);
llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create(
g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[cfg->getStartingBlock()]);
llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction());
emitter->getBuilder()->SetInsertPoint(preentry_bb);
......@@ -580,7 +581,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef<llvm::Metadata*>(md_vals));
llvm::BranchInst* guard = emitter->getBuilder()->CreateCondBr(
reopt_test, reopt_bb, llvm_entry_blocks[source->cfg->getStartingBlock()], branch_weights);
reopt_test, reopt_bb, llvm_entry_blocks[cfg->getStartingBlock()], branch_weights);
emitter->getBuilder()->SetInsertPoint(reopt_bb);
// emitter->getBuilder()->CreateCall(g.funcs.my_assert, getConstantInt(0, g.i1));
......@@ -603,7 +604,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
postcall->setTailCall(true);
emitter->getBuilder()->CreateRet(postcall);
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[source->cfg->getStartingBlock()]);
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[cfg->getStartingBlock()]);
}
generator->doFunctionEntry(*irstate->getParamNames(), cf->spec->arg_types);
......@@ -640,7 +641,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
(*phis)[p.first] = std::make_pair(analyzed_type, phi);
}
} else if (pred == NULL) {
assert(traversal_order.size() < source->cfg->blocks.size());
assert(traversal_order.size() < cfg->blocks.size());
assert(phis);
assert(block->predecessors.size());
for (int i = 0; i < block->predecessors.size(); i++) {
......@@ -651,7 +652,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
std::set<InternedString> names;
for (const auto& s : phi_analysis->getAllRequiredFor(block)) {
for (const int vreg : phi_analysis->getAllRequiredFor(block)) {
auto s = cfg->getVRegInfo().getName(vreg);
names.insert(s);
if (phi_analysis->isPotentiallyUndefinedAfter(s, block->predecessors[0])) {
names.insert(getIsDefinedName(s, source->getInternedStrings()));
......@@ -832,7 +834,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// the relevant IR, so after we have done all of it, go back through and populate the phi nodes.
// Also, do some checking to make sure that the phi analysis stuff worked out, and that all blocks
// agreed on what symbols + types they should be propagating for the phis.
for (CFGBlock* b : source->cfg->blocks) {
for (CFGBlock* b : cfg->blocks) {
PHITable* phis = created_phis[b];
if (phis == NULL)
continue;
......@@ -910,7 +912,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
// deallocate/dereference memory
for (CFGBlock* b : source->cfg->blocks) {
for (CFGBlock* b : cfg->blocks) {
if (ending_symbol_tables[b] == NULL)
continue;
......
......@@ -2682,8 +2682,9 @@ private:
}
}
const PhiAnalysis::RequiredSet& all_phis = irstate->getPhis()->getAllRequiredAfter(myblock);
for (PhiAnalysis::RequiredSet::const_iterator it = all_phis.begin(), end = all_phis.end(); it != end; ++it) {
for (int vreg : irstate->getPhis()->getAllRequiredAfter(myblock)) {
auto name = irstate->getCFG()->getVRegInfo().getName(vreg);
auto it = &name; // hack, remove
if (VERBOSITY() >= 3)
printf("phi will be required for %s\n", it->c_str());
assert(scope_info->getScopeTypeOfName(*it) != ScopeInfo::VarScopeType::GLOBAL);
......
......@@ -82,6 +82,8 @@ public:
ParamNames* param_names, GCBuilder* gc, llvm::MDNode* func_dbg_info, RefcountTracker* refcount_tracker);
~IRGenState();
CFG* getCFG() { return getSourceInfo()->cfg; }
CompiledFunction* getCurFunction() { return cf; }
FunctionMetadata* getMD() { return md; }
......
......@@ -2677,7 +2677,7 @@ public:
ScopeInfo* scope_info;
CFGBlock* current_block;
int next_vreg;
llvm::DenseMap<InternedString, int> sym_vreg_map;
llvm::DenseMap<InternedString, DefaultedInt<-1>> sym_vreg_map;
llvm::DenseMap<InternedString, std::unordered_set<CFGBlock*>> sym_blocks_map;
std::vector<InternedString> vreg_sym_map;
......@@ -2685,9 +2685,7 @@ public:
AssignVRegsVisitor(ScopeInfo* scope_info) : scope_info(scope_info), current_block(0), next_vreg(0) {}
bool visit_alias(AST_alias* node) override {
RELEASE_ASSERT(0, "these should be removed by the cfg");
}
bool visit_alias(AST_alias* node) override { RELEASE_ASSERT(0, "these should be removed by the cfg"); }
bool visit_arguments(AST_arguments* node) override {
for (AST_expr* d : node->defaults)
......
......@@ -42,6 +42,26 @@ class CFG;
class ParamNames;
class ScopeInfo;
// Simple class to override the default value of an int.
template <int D = -1> class DefaultedInt {
private:
int x;
public:
DefaultedInt() : x(D) {}
DefaultedInt(int x) : x(x) {}
DefaultedInt(const DefaultedInt& rhs) : x(rhs.x) {}
DefaultedInt(DefaultedInt&& rhs) : x(rhs.x) {}
void operator=(const DefaultedInt& rhs) { x = rhs.x; }
void operator=(DefaultedInt&& rhs) { x = rhs.x; }
template <typename T> bool operator<(T rhs) const { return x < rhs; }
template <typename T> bool operator>(T rhs) const { return x > rhs; }
template <typename T> bool operator<=(T rhs) const { return x <= rhs; }
template <typename T> bool operator>=(T rhs) const { return x >= rhs; }
operator int() const { return x; }
};
class CFGBlock {
public:
CFG* cfg;
......@@ -85,8 +105,8 @@ public:
// llvm jit : [user visible]
class VRegInfo {
private:
llvm::DenseMap<InternedString, int> sym_vreg_map_user_visible;
llvm::DenseMap<InternedString, int> sym_vreg_map;
llvm::DenseMap<InternedString, DefaultedInt<-1>> sym_vreg_map_user_visible;
llvm::DenseMap<InternedString, DefaultedInt<-1>> sym_vreg_map;
// Reverse map, from vreg->symbol name.
std::vector<InternedString> vreg_sym_map;
......@@ -97,8 +117,10 @@ private:
public:
// map of all assigned names. if the name is block local the vreg number is not unique because this vregs get reused
// between blocks.
const llvm::DenseMap<InternedString, int>& getSymVRegMap() { return sym_vreg_map; }
const llvm::DenseMap<InternedString, int>& getUserVisibleSymVRegMap() { return sym_vreg_map_user_visible; }
const llvm::DenseMap<InternedString, DefaultedInt<-1>>& getSymVRegMap() { return sym_vreg_map; }
const llvm::DenseMap<InternedString, DefaultedInt<-1>>& getUserVisibleSymVRegMap() {
return sym_vreg_map_user_visible;
}
int getVReg(InternedString name) const {
assert(hasVRegsAssigned());
......
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