Commit 74ee55c8 authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by GitHub

Merge pull request #1239 from undingen/bjit_opt2_with_vreg_reuse

vregs: reuse block local vregs
parents 53466770 f1424848
...@@ -66,7 +66,7 @@ extern "C" Box* executeInnerAndSetupFrame(ASTInterpreter& interpreter, CFGBlock* ...@@ -66,7 +66,7 @@ extern "C" Box* executeInnerAndSetupFrame(ASTInterpreter& interpreter, CFGBlock*
*/ */
class ASTInterpreter { class ASTInterpreter {
public: public:
ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs, FrameInfo* deopt_frame_info = NULL); ASTInterpreter(FunctionMetadata* md, Box** vregs, FrameInfo* deopt_frame_info = NULL);
void initArguments(BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3, Box** args); void initArguments(BoxedClosure* closure, BoxedGenerator* generator, Box* arg1, Box* arg2, Box* arg3, Box** args);
...@@ -154,9 +154,9 @@ private: ...@@ -154,9 +154,9 @@ private:
public: public:
~ASTInterpreter() { Py_XDECREF(this->created_closure); } ~ASTInterpreter() { Py_XDECREF(this->created_closure); }
llvm::DenseMap<InternedString, int>& getSymVRegMap() { const VRegInfo& getVRegInfo() const { return source_info->cfg->getVRegInfo(); }
assert(source_info->cfg); const llvm::DenseMap<InternedString, int>& getSymVRegMap() const {
return source_info->cfg->sym_vreg_map; return source_info->cfg->getVRegInfo().getSymVRegMap();
} }
AST_stmt* getCurrentStatement() { AST_stmt* getCurrentStatement() {
...@@ -183,8 +183,7 @@ public: ...@@ -183,8 +183,7 @@ public:
}; };
void ASTInterpreter::addSymbol(InternedString name, Box* new_value, bool allow_duplicates) { void ASTInterpreter::addSymbol(InternedString name, Box* new_value, bool allow_duplicates) {
assert(getSymVRegMap().count(name)); Box*& value = vregs[getVRegInfo().getVReg(name)];
Box*& value = vregs[getSymVRegMap()[name]];
Box* old_value = value; Box* old_value = value;
value = incref(new_value); value = incref(new_value);
if (allow_duplicates) if (allow_duplicates)
...@@ -222,7 +221,7 @@ void ASTInterpreter::setGlobals(Box* globals) { ...@@ -222,7 +221,7 @@ void ASTInterpreter::setGlobals(Box* globals) {
this->frame_info.globals = incref(globals); this->frame_info.globals = incref(globals);
} }
ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs, FrameInfo* deopt_frame_info) ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, FrameInfo* deopt_frame_info)
: current_block(0), : current_block(0),
frame_info(ExcInfo(NULL, NULL, NULL)), frame_info(ExcInfo(NULL, NULL, NULL)),
edgecount(0), edgecount(0),
...@@ -255,7 +254,7 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs, ...@@ -255,7 +254,7 @@ ASTInterpreter::ASTInterpreter(FunctionMetadata* md, Box** vregs, int num_vregs,
frame_info.vregs = vregs; frame_info.vregs = vregs;
frame_info.md = md; frame_info.md = md;
frame_info.num_vregs = num_vregs; frame_info.num_vregs = getVRegInfo().getNumOfCrossBlockVRegs();
assert(scope_info); assert(scope_info);
} }
...@@ -482,8 +481,8 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) { ...@@ -482,8 +481,8 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
if (closure) { if (closure) {
ASTInterpreterJitInterface::setLocalClosureHelper(this, node->vreg, name, value.o); ASTInterpreterJitInterface::setLocalClosureHelper(this, node->vreg, name, value.o);
} else { } else {
assert(getSymVRegMap().count(name)); assert(getVRegInfo().getVReg(node->id) == node->vreg);
assert(getSymVRegMap()[name] == node->vreg); frame_info.num_vregs = std::max(frame_info.num_vregs, node->vreg + 1);
Box* prev = vregs[node->vreg]; Box* prev = vregs[node->vreg];
vregs[node->vreg] = value.o; vregs[node->vreg] = value.o;
Py_XDECREF(prev); Py_XDECREF(prev);
...@@ -712,23 +711,16 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -712,23 +711,16 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
std::unique_ptr<PhiAnalysis> phis std::unique_ptr<PhiAnalysis> phis
= computeRequiredPhis(getMD()->param_names, source_info->cfg, liveness, scope_info); = computeRequiredPhis(getMD()->param_names, source_info->cfg, liveness, scope_info);
llvm::DenseMap<int, InternedString> offset_name_map; llvm::SmallVector<int, 16> dead_vregs;
for (auto&& v : getSymVRegMap()) { for (auto&& sym : getSymVRegMap()) {
offset_name_map[v.second] = v.first; if (!liveness->isLiveAtEnd(sym.first, current_block)) {
} dead_vregs.push_back(sym.second);
} else if (phis->isRequiredAfter(sym.first, current_block)) {
std::vector<InternedString> dead_symbols; assert(scope_info->getScopeTypeOfName(sym.first) != ScopeInfo::VarScopeType::GLOBAL);
for (int i = 0; i < getSymVRegMap().size(); ++i) {
if (!liveness->isLiveAtEnd(offset_name_map[i], current_block)) {
dead_symbols.push_back(offset_name_map[i]);
} else if (phis->isRequiredAfter(offset_name_map[i], current_block)) {
assert(scope_info->getScopeTypeOfName(offset_name_map[i]) != ScopeInfo::VarScopeType::GLOBAL);
} else { } else {
} }
} }
for (auto&& dead : dead_symbols) { for (auto&& vreg_num : dead_vregs) {
assert(getSymVRegMap().count(dead));
int vreg_num = getSymVRegMap()[dead];
Py_CLEAR(vregs[vreg_num]); Py_CLEAR(vregs[vreg_num]);
} }
...@@ -747,8 +739,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -747,8 +739,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
static Box* const VAL_UNDEFINED = (Box*)None; static Box* const VAL_UNDEFINED = (Box*)None;
for (auto& name : phis->definedness.getDefinedNamesAtEnd(current_block)) { for (auto& name : phis->definedness.getDefinedNamesAtEnd(current_block)) {
assert(getSymVRegMap().count(name)); Box* val = vregs[getVRegInfo().getVReg(name)];
Box* val = vregs[getSymVRegMap()[name]];
if (!liveness->isLiveAtEnd(name, current_block)) if (!liveness->isLiveAtEnd(name, current_block))
continue; continue;
...@@ -1343,8 +1334,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -1343,8 +1334,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
} else { } else {
assert(vst == ScopeInfo::VarScopeType::FAST); assert(vst == ScopeInfo::VarScopeType::FAST);
assert(getSymVRegMap().count(target->id)); assert(getVRegInfo().getVReg(target->id) == target->vreg);
assert(getSymVRegMap()[target->id] == target->vreg);
if (target->id.s()[0] == '#') { if (target->id.s()[0] == '#') {
assert(vregs[target->vreg] != NULL); assert(vregs[target->vreg] != NULL);
...@@ -1358,6 +1348,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) { ...@@ -1358,6 +1348,7 @@ Value ASTInterpreter::visit_delete(AST_Delete* node) {
} }
} }
frame_info.num_vregs = std::max(frame_info.num_vregs, target->vreg + 1);
Py_DECREF(vregs[target->vreg]); Py_DECREF(vregs[target->vreg]);
vregs[target->vreg] = NULL; vregs[target->vreg] = NULL;
} }
...@@ -1690,8 +1681,8 @@ Value ASTInterpreter::visit_name(AST_Name* node) { ...@@ -1690,8 +1681,8 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
} }
assert(node->vreg >= 0); assert(node->vreg >= 0);
assert(getSymVRegMap().count(node->id)); assert(getVRegInfo().getVReg(node->id) == node->vreg);
assert(getSymVRegMap()[node->id] == node->vreg); frame_info.num_vregs = std::max(frame_info.num_vregs, node->vreg + 1);
Box* val = vregs[node->vreg]; Box* val = vregs[node->vreg];
if (val) { if (val) {
...@@ -1867,8 +1858,8 @@ void ASTInterpreterJitInterface::setExcInfoHelper(void* _interpreter, STOLEN(Box ...@@ -1867,8 +1858,8 @@ void ASTInterpreterJitInterface::setExcInfoHelper(void* _interpreter, STOLEN(Box
void ASTInterpreterJitInterface::setLocalClosureHelper(void* _interpreter, long vreg, InternedString id, Box* v) { void ASTInterpreterJitInterface::setLocalClosureHelper(void* _interpreter, long vreg, InternedString id, Box* v) {
ASTInterpreter* interpreter = (ASTInterpreter*)_interpreter; ASTInterpreter* interpreter = (ASTInterpreter*)_interpreter;
assert(interpreter->getSymVRegMap().count(id)); interpreter->frame_info.num_vregs = std::max(interpreter->frame_info.num_vregs, (int)vreg + 1);
assert(interpreter->getSymVRegMap()[id] == vreg); assert(interpreter->getVRegInfo().getVReg(id) == vreg);
Box* prev = interpreter->vregs[vreg]; Box* prev = interpreter->vregs[vreg];
interpreter->vregs[vreg] = v; interpreter->vregs[vreg] = v;
auto closure_offset = interpreter->scope_info->getClosureOffset(id); auto closure_offset = interpreter->scope_info->getClosureOffset(id);
...@@ -1980,17 +1971,17 @@ Box* astInterpretFunction(FunctionMetadata* md, Box* closure, Box* generator, Bo ...@@ -1980,17 +1971,17 @@ Box* astInterpretFunction(FunctionMetadata* md, Box* closure, Box* generator, Bo
// (For instance, throwing the exception will try to fetch the current statement, but we determine // (For instance, throwing the exception will try to fetch the current statement, but we determine
// that by looking at the cfg.) // that by looking at the cfg.)
if (!source_info->cfg) if (!source_info->cfg)
source_info->cfg = computeCFG(source_info, source_info->body); source_info->cfg = computeCFG(source_info, source_info->body, md->param_names);
Box** vregs = NULL; Box** vregs = NULL;
int num_vregs = md->calculateNumVRegs(); int num_vregs = source_info->cfg->getVRegInfo().getTotalNumOfVRegs();
if (num_vregs > 0) { if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs); vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs); memset(vregs, 0, sizeof(Box*) * num_vregs);
} }
++md->times_interpreted; ++md->times_interpreted;
ASTInterpreter interpreter(md, vregs, num_vregs); ASTInterpreter interpreter(md, vregs);
ScopeInfo* scope_info = md->source->getScopeInfo(); ScopeInfo* scope_info = md->source->getScopeInfo();
...@@ -2022,16 +2013,16 @@ Box* astInterpretFunctionEval(FunctionMetadata* md, Box* globals, Box* boxedLoca ...@@ -2022,16 +2013,16 @@ Box* astInterpretFunctionEval(FunctionMetadata* md, Box* globals, Box* boxedLoca
// that by looking at the cfg.) // that by looking at the cfg.)
SourceInfo* source_info = md->source.get(); SourceInfo* source_info = md->source.get();
if (!source_info->cfg) if (!source_info->cfg)
source_info->cfg = computeCFG(source_info, source_info->body); source_info->cfg = computeCFG(source_info, source_info->body, md->param_names);
Box** vregs = NULL; Box** vregs = NULL;
int num_vregs = md->calculateNumVRegs(); int num_vregs = source_info->cfg->getVRegInfo().getTotalNumOfVRegs();
if (num_vregs > 0) { if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs); vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs); memset(vregs, 0, sizeof(Box*) * num_vregs);
} }
ASTInterpreter interpreter(md, vregs, num_vregs); ASTInterpreter interpreter(md, vregs);
interpreter.initArguments(NULL, NULL, NULL, NULL, NULL, NULL); interpreter.initArguments(NULL, NULL, NULL, NULL, NULL, NULL);
interpreter.setBoxedLocals(incref(boxedLocals)); interpreter.setBoxedLocals(incref(boxedLocals));
...@@ -2060,7 +2051,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e ...@@ -2060,7 +2051,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
// there wouldn't be enough space for the compiler generated ones which the interpreter (+bjit) stores inside the // there wouldn't be enough space for the compiler generated ones which the interpreter (+bjit) stores inside the
// vreg array. // vreg array.
Box** vregs = NULL; Box** vregs = NULL;
int num_vregs = md->calculateNumVRegs(); int num_vregs = source_info->cfg->getVRegInfo().getTotalNumOfVRegs();
if (num_vregs > 0) { if (num_vregs > 0) {
vregs = (Box**)alloca(sizeof(Box*) * num_vregs); vregs = (Box**)alloca(sizeof(Box*) * num_vregs);
memset(vregs, 0, sizeof(Box*) * num_vregs); memset(vregs, 0, sizeof(Box*) * num_vregs);
...@@ -2071,7 +2062,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e ...@@ -2071,7 +2062,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
RELEASE_ASSERT(cur_thread_state.frame_info == frame_state.frame_info, ""); RELEASE_ASSERT(cur_thread_state.frame_info == frame_state.frame_info, "");
cur_thread_state.frame_info = frame_state.frame_info->back; cur_thread_state.frame_info = frame_state.frame_info->back;
ASTInterpreter interpreter(md, vregs, num_vregs, frame_state.frame_info); ASTInterpreter interpreter(md, vregs, frame_state.frame_info);
for (const auto& p : *frame_state.locals) { for (const auto& p : *frame_state.locals) {
assert(p.first->cls == str_cls); assert(p.first->cls == str_cls);
......
...@@ -634,7 +634,9 @@ void JitFragmentWriter::emitSetBlockLocal(InternedString s, int vreg, STOLEN(Rew ...@@ -634,7 +634,9 @@ void JitFragmentWriter::emitSetBlockLocal(InternedString s, int vreg, STOLEN(Rew
if (LOG_BJIT_ASSEMBLY) if (LOG_BJIT_ASSEMBLY)
comment("BJIT: emitSetBlockLocal() start"); comment("BJIT: emitSetBlockLocal() start");
RewriterVar* prev = local_syms[s]; RewriterVar* prev = local_syms[s];
if (!prev) // if we never set this sym before in this BB and the symbol gets accessed in several blocks clear it because it
// could have been set in a previous block.
if (!prev && !block->cfg->getVRegInfo().isBlockLocalVReg(vreg))
emitSetLocal(s, vreg, false, imm(nullptr)); // clear out the vreg emitSetLocal(s, vreg, false, imm(nullptr)); // clear out the vreg
local_syms[s] = v; local_syms[s] = v;
if (LOG_BJIT_ASSEMBLY) if (LOG_BJIT_ASSEMBLY)
...@@ -690,6 +692,7 @@ void JitFragmentWriter::emitSetLocal(InternedString s, int vreg, bool set_closur ...@@ -690,6 +692,7 @@ void JitFragmentWriter::emitSetLocal(InternedString s, int vreg, bool set_closur
// but I suspect is not that big a deal as long as the llvm jit implements this kind of optimization. // but I suspect is not that big a deal as long as the llvm jit implements this kind of optimization.
bool prev_nullable = true; bool prev_nullable = true;
assert(!block->cfg->getVRegInfo().isBlockLocalVReg(vreg));
vregs_array->replaceAttr(8 * vreg, v, prev_nullable); vregs_array->replaceAttr(8 * vreg, v, prev_nullable);
} }
if (LOG_BJIT_ASSEMBLY) if (LOG_BJIT_ASSEMBLY)
......
...@@ -73,34 +73,6 @@ BORROWED(BoxedCode*) FunctionMetadata::getCode() { ...@@ -73,34 +73,6 @@ BORROWED(BoxedCode*) FunctionMetadata::getCode() {
return code_obj; return code_obj;
} }
int FunctionMetadata::calculateNumVRegs() {
SourceInfo* source_info = source.get();
CFG* cfg = source_info->cfg;
assert(cfg && "We don't calculate the CFG inside this function because it can raise an exception and its "
"therefore not safe to call at every point");
if (!cfg->hasVregsAssigned()) {
ScopeInfo* scope_info = source->getScopeInfo();
cfg->assignVRegs(param_names, scope_info);
}
return cfg->sym_vreg_map.size();
}
int FunctionMetadata::calculateNumUserVisibleVRegs() {
SourceInfo* source_info = source.get();
CFG* cfg = source_info->cfg;
assert(cfg && "We don't calculate the CFG inside this function because it can raise an exception and its "
"therefore not safe to call at every point");
if (!cfg->hasVregsAssigned()) {
ScopeInfo* scope_info = source->getScopeInfo();
cfg->assignVRegs(param_names, scope_info);
}
return cfg->sym_vreg_map_user_visible.size();
}
void FunctionMetadata::addVersion(CompiledFunction* compiled) { void FunctionMetadata::addVersion(CompiledFunction* compiled) {
assert(compiled); assert(compiled);
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1); assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
......
...@@ -1009,8 +1009,6 @@ CompiledFunction* doCompile(FunctionMetadata* md, SourceInfo* source, ParamNames ...@@ -1009,8 +1009,6 @@ CompiledFunction* doCompile(FunctionMetadata* md, SourceInfo* source, ParamNames
assert((entry_descriptor != NULL) + (spec != NULL) == 1); assert((entry_descriptor != NULL) + (spec != NULL) == 1);
md->calculateNumVRegs();
if (VERBOSITY("irgen") >= 2) if (VERBOSITY("irgen") >= 2)
source->cfg->print(); source->cfg->print();
......
...@@ -271,7 +271,7 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s ...@@ -271,7 +271,7 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s
// Do the analysis now if we had deferred it earlier: // Do the analysis now if we had deferred it earlier:
if (source->cfg == NULL) { if (source->cfg == NULL) {
source->cfg = computeCFG(source, source->body); source->cfg = computeCFG(source, source->body, f->param_names);
} }
......
...@@ -244,7 +244,7 @@ void IRGenState::setupFrameInfoVar(llvm::Value* passed_closure, llvm::Value* pas ...@@ -244,7 +244,7 @@ void IRGenState::setupFrameInfoVar(llvm::Value* passed_closure, llvm::Value* pas
assert(al->isStaticAlloca()); assert(al->isStaticAlloca());
assert(!vregs); assert(!vregs);
int num_user_visible_vregs = getMD()->calculateNumUserVisibleVRegs(); int num_user_visible_vregs = getSourceInfo()->cfg->getVRegInfo().getNumOfUserVisibleVRegs();
if (num_user_visible_vregs > 0) { if (num_user_visible_vregs > 0) {
auto* vregs_alloca auto* vregs_alloca
= builder.CreateAlloca(g.llvm_value_type_ptr, getConstantInt(num_user_visible_vregs), "vregs"); = builder.CreateAlloca(g.llvm_value_type_ptr, getConstantInt(num_user_visible_vregs), "vregs");
...@@ -1896,7 +1896,7 @@ private: ...@@ -1896,7 +1896,7 @@ private:
auto cfg = irstate->getSourceInfo()->cfg; auto cfg = irstate->getSourceInfo()->cfg;
assert(vreg >= 0); assert(vreg >= 0);
if (vreg < cfg->sym_vreg_map_user_visible.size()) { if (cfg->getVRegInfo().isUserVisibleVReg(vreg)) {
// looks like this store don't have to be volatile because llvm knows that the vregs are visible thru the // looks like this store don't have to be volatile because llvm knows that the vregs are visible thru the
// FrameInfo which escapes. // FrameInfo which escapes.
auto* gep = emitter.getBuilder()->CreateConstInBoundsGEP1_64(irstate->getVRegsVar(), vreg); auto* gep = emitter.getBuilder()->CreateConstInBoundsGEP1_64(irstate->getVRegsVar(), vreg);
...@@ -2617,8 +2617,7 @@ private: ...@@ -2617,8 +2617,7 @@ private:
auto vst = irstate->getScopeInfo()->getScopeTypeOfName(name); auto vst = irstate->getScopeInfo()->getScopeTypeOfName(name);
int vreg = -1; int vreg = -1;
if (vst == ScopeInfo::VarScopeType::FAST || vst == ScopeInfo::VarScopeType::CLOSURE) { if (vst == ScopeInfo::VarScopeType::FAST || vst == ScopeInfo::VarScopeType::CLOSURE) {
assert(cfg->sym_vreg_map.count(name)); vreg = cfg->getVRegInfo().getVReg(name);
vreg = cfg->sym_vreg_map[name];
} }
_doSet(vreg, name, vst, var, unw_info); _doSet(vreg, name, vst, var, unw_info);
} }
......
...@@ -892,10 +892,9 @@ DeoptState getDeoptState() { ...@@ -892,10 +892,9 @@ DeoptState getDeoptState() {
// and assigning them to the new vregs array... // and assigning them to the new vregs array...
// But deopts are so rare it's not really worth it. // But deopts are so rare it's not really worth it.
Box** vregs = frame_iter->getFrameInfo()->vregs; Box** vregs = frame_iter->getFrameInfo()->vregs;
for (const auto& p : cf->md->source->cfg->sym_vreg_map_user_visible) { for (const auto& p : cf->md->source->cfg->getVRegInfo().getUserVisibleSymVRegMap()) {
if (is_undefined.count(p.first.s())) if (is_undefined.count(p.first.s()))
continue; continue;
assert(p.second >= 0 && p.second < cf->md->source->cfg->sym_vreg_map_user_visible.size());
Box* v = vregs[p.second]; Box* v = vregs[p.second];
if (!v) if (!v)
...@@ -950,8 +949,8 @@ BORROWED(Box*) fastLocalsToBoxedLocals() { ...@@ -950,8 +949,8 @@ BORROWED(Box*) fastLocalsToBoxedLocals() {
static BoxedDict* localsForFrame(Box** vregs, CFG* cfg) { static BoxedDict* localsForFrame(Box** vregs, CFG* cfg) {
BoxedDict* rtn = new BoxedDict(); BoxedDict* rtn = new BoxedDict();
rtn->d.grow(cfg->sym_vreg_map_user_visible.size()); rtn->d.grow(cfg->getVRegInfo().getNumOfUserVisibleVRegs());
for (auto& l : cfg->sym_vreg_map_user_visible) { for (auto& l : cfg->getVRegInfo().getUserVisibleSymVRegMap()) {
Box* val = vregs[l.second]; Box* val = vregs[l.second];
if (val) { if (val) {
assert(!rtn->d.count(l.first.getBox())); assert(!rtn->d.count(l.first.getBox()));
......
...@@ -181,7 +181,7 @@ private: ...@@ -181,7 +181,7 @@ private:
unsigned int next_var_index = 0; unsigned int next_var_index = 0;
friend CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body); friend CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names);
public: public:
CFGVisitor(SourceInfo* source, AST_TYPE::AST_TYPE root_type, FutureFlags future_flags, CFGVisitor(SourceInfo* source, AST_TYPE::AST_TYPE root_type, FutureFlags future_flags,
...@@ -2556,13 +2556,15 @@ void CFG::print(llvm::raw_ostream& stream) { ...@@ -2556,13 +2556,15 @@ void CFG::print(llvm::raw_ostream& stream) {
class AssignVRegsVisitor : public NoopASTVisitor { class AssignVRegsVisitor : public NoopASTVisitor {
public: public:
int index = 0;
bool only_user_visible;
llvm::DenseMap<InternedString, int> sym_vreg_map;
ScopeInfo* scope_info; ScopeInfo* scope_info;
CFGBlock* current_block;
int next_vreg;
llvm::DenseMap<InternedString, int> sym_vreg_map;
llvm::DenseMap<InternedString, std::unordered_set<CFGBlock*>> sym_blocks_map;
enum Step { TrackBlockUsage = 0, UserVisible, CrossBlock, SingleBlockUse } step;
AssignVRegsVisitor(ScopeInfo* scope_info, bool only_user_visible) AssignVRegsVisitor(ScopeInfo* scope_info) : scope_info(scope_info), current_block(0), next_vreg(0) {}
: only_user_visible(only_user_visible), scope_info(scope_info) {}
bool visit_arguments(AST_arguments* node) override { bool visit_arguments(AST_arguments* node) override {
for (AST_expr* d : node->defaults) for (AST_expr* d : node->defaults)
...@@ -2590,66 +2592,94 @@ public: ...@@ -2590,66 +2592,94 @@ public:
return true; return true;
} }
bool isNameUsedInSingleBlock(InternedString id) {
assert(step != TrackBlockUsage);
assert(sym_blocks_map.count(id));
return sym_blocks_map[id].size() == 1;
}
bool visit_name(AST_Name* node) override { bool visit_name(AST_Name* node) override {
if (node->vreg != -1) if (node->vreg != -1)
return true; return true;
if (only_user_visible && node->id.isCompilerCreatedName())
return true;
if (node->lookup_type == ScopeInfo::VarScopeType::UNKNOWN) if (node->lookup_type == ScopeInfo::VarScopeType::UNKNOWN)
node->lookup_type = scope_info->getScopeTypeOfName(node->id); node->lookup_type = scope_info->getScopeTypeOfName(node->id);
if (node->lookup_type == ScopeInfo::VarScopeType::FAST || node->lookup_type == ScopeInfo::VarScopeType::CLOSURE) if (node->lookup_type != ScopeInfo::VarScopeType::FAST && node->lookup_type != ScopeInfo::VarScopeType::CLOSURE)
node->vreg = assignVReg(node->id); return true;
if (step == TrackBlockUsage) {
sym_blocks_map[node->id].insert(current_block);
return true;
} else if (step == UserVisible) {
if (node->id.isCompilerCreatedName())
return true;
} else {
bool is_block_local = node->lookup_type == ScopeInfo::VarScopeType::FAST
&& isNameUsedInSingleBlock(node->id);
if (step == CrossBlock && is_block_local)
return true;
if (step == SingleBlockUse && !is_block_local)
return true;
}
node->vreg = assignVReg(node->id);
return true; return true;
} }
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) {
sym_vreg_map[id] = index; sym_vreg_map[id] = next_vreg;
return index++; return next_vreg++;
} }
return it->second; return it->second;
} }
}; };
void CFG::assignVRegs(const ParamNames& param_names, ScopeInfo* scope_info) { void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* scope_info) {
if (has_vregs_assigned) assert(!hasVRegsAssigned());
return;
// warning: don't rearrange the steps, they need to be run in this exact order!
AssignVRegsVisitor visitor(scope_info);
for (auto step : { AssignVRegsVisitor::TrackBlockUsage, AssignVRegsVisitor::UserVisible,
AssignVRegsVisitor::CrossBlock, AssignVRegsVisitor::SingleBlockUse }) {
visitor.step = step;
for (CFGBlock* b : cfg->blocks) {
visitor.current_block = b;
if (step == AssignVRegsVisitor::SingleBlockUse)
visitor.next_vreg = num_vregs_cross_block;
if (b == cfg->getStartingBlock()) {
for (auto* name : param_names.arg_names) {
name->accept(&visitor);
}
if (param_names.vararg_name)
param_names.vararg_name->accept(&visitor);
AssignVRegsVisitor visitor(scope_info, true); if (param_names.kwarg_name)
param_names.kwarg_name->accept(&visitor);
}
// we need todo two passes: first we assign the user visible vars a vreg and then the compiler created get there
// value.
for (int i = 0; i < 2; ++i) {
for (CFGBlock* b : blocks) {
for (AST_stmt* stmt : b->body) { for (AST_stmt* stmt : b->body) {
stmt->accept(&visitor); stmt->accept(&visitor);
} }
}
for (auto* name : param_names.arg_names) { if (step == AssignVRegsVisitor::SingleBlockUse)
name->accept(&visitor); num_vregs = std::max(num_vregs, visitor.next_vreg);
} }
if (param_names.vararg_name) if (step == AssignVRegsVisitor::UserVisible)
param_names.vararg_name->accept(&visitor);
if (param_names.kwarg_name)
param_names.kwarg_name->accept(&visitor);
if (visitor.only_user_visible) {
visitor.only_user_visible = false;
sym_vreg_map_user_visible = visitor.sym_vreg_map; sym_vreg_map_user_visible = visitor.sym_vreg_map;
} else if (step == AssignVRegsVisitor::CrossBlock)
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);
has_vregs_assigned = true; assert(hasVRegsAssigned());
} }
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) { CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names) {
STAT_TIMER(t0, "us_timer_computecfg", 0); STAT_TIMER(t0, "us_timer_computecfg", 0);
CFG* rtn = new CFG(); CFG* rtn = new CFG();
...@@ -2890,6 +2920,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) { ...@@ -2890,6 +2920,7 @@ CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body) {
rtn->print(); rtn->print();
} }
rtn->getVRegInfo().assignVRegs(rtn, param_names, source->getScopeInfo());
return rtn; return rtn;
} }
......
...@@ -43,10 +43,9 @@ class ParamNames; ...@@ -43,10 +43,9 @@ class ParamNames;
class ScopeInfo; class ScopeInfo;
class CFGBlock { class CFGBlock {
private: public:
CFG* cfg; CFG* cfg;
public:
// Baseline JIT helper fields: // Baseline JIT helper fields:
// contains address to the start of the code of this basic block // contains address to the start of the code of this basic block
void* code; void* code;
...@@ -70,23 +69,68 @@ public: ...@@ -70,23 +69,68 @@ public:
void _print() { print(); } void _print() { print(); }
}; };
// the vregs are split into three parts.
// user visible: used for all non compiler generated names, name could be used in a single block or multiple
// all frames contain atleast this vregs in order to do frame introspection
// cross block : used for compiler generated names which get used in several blocks or which have closure scope
// single block: used by compiler created names which are only used in a single block.
// get reused for different names
//
// we assign the lowest numbers to the user visible ones, followed by the cross block ones and finally the single block
// ones. we do this because not all tiers use all of the vregs and it still makes it fast to switch between tiers.
//
// usage by our different tiers:
// interpreter : [user visible] [cross block] [single block]
// baseline jit: [user visible] [cross block]
// llvm jit : [user visible]
class VRegInfo {
private:
llvm::DenseMap<InternedString, int> sym_vreg_map_user_visible;
llvm::DenseMap<InternedString, int> sym_vreg_map;
int num_vregs_cross_block = -1;
int num_vregs = -1;
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; }
int getVReg(InternedString name) const {
assert(hasVRegsAssigned());
assert(sym_vreg_map.count(name));
auto it = sym_vreg_map.find(name);
assert(it != sym_vreg_map.end());
assert(it->second != -1);
return it->second;
}
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 isBlockLocalVReg(int vreg) const { return vreg >= num_vregs_cross_block; }
int getTotalNumOfVRegs() const { return num_vregs; }
int getNumOfUserVisibleVRegs() const { return sym_vreg_map_user_visible.size(); }
int getNumOfCrossBlockVRegs() const { return num_vregs_cross_block; }
bool hasVRegsAssigned() const { return num_vregs != -1; }
void assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* scope_info);
};
// Control Flow Graph // Control Flow Graph
class CFG { class CFG {
private: private:
int next_idx; int next_idx;
bool has_vregs_assigned; VRegInfo vreg_info;
public: public:
std::vector<CFGBlock*> blocks; std::vector<CFGBlock*> blocks;
// Contains the vreg assignment for every name including the user visible ones public:
// (which will have lower ids than the compiler generated ones). CFG() : next_idx(0) {}
llvm::DenseMap<InternedString, int> sym_vreg_map;
llvm::DenseMap<InternedString, int> sym_vreg_map_user_visible;
CFG() : next_idx(0), has_vregs_assigned(false) {}
CFGBlock* getStartingBlock() { return blocks[0]; } CFGBlock* getStartingBlock() { return blocks[0]; }
VRegInfo& getVRegInfo() { return vreg_info; }
CFGBlock* addBlock() { CFGBlock* addBlock() {
int idx = next_idx; int idx = next_idx;
...@@ -113,13 +157,10 @@ public: ...@@ -113,13 +157,10 @@ public:
} }
void print(llvm::raw_ostream& stream = llvm::outs()); void print(llvm::raw_ostream& stream = llvm::outs());
bool hasVregsAssigned() { return has_vregs_assigned; }
void assignVRegs(const ParamNames& param_names, ScopeInfo* scope_info);
}; };
class SourceInfo; class SourceInfo;
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body); CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names);
void printCFG(CFG* cfg); void printCFG(CFG* cfg);
} }
......
...@@ -508,9 +508,6 @@ public: ...@@ -508,9 +508,6 @@ public:
void addVersion(void* f, ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*>& arg_types, void addVersion(void* f, ConcreteCompilerType* rtn_type, const std::vector<ConcreteCompilerType*>& arg_types,
ExceptionStyle exception_style = CXX); ExceptionStyle exception_style = CXX);
int calculateNumVRegs();
int calculateNumUserVisibleVRegs();
// Helper function, meant for the C++ runtime, which allocates a FunctionMetadata object and calls addVersion // Helper function, meant for the C++ runtime, which allocates a FunctionMetadata object and calls addVersion
// once to it. // once to it.
static FunctionMetadata* create(void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs, static FunctionMetadata* create(void* f, ConcreteCompilerType* rtn_type, int nargs, bool takes_varargs,
......
...@@ -43,7 +43,8 @@ TEST_F(AnalysisTest, augassign) { ...@@ -43,7 +43,8 @@ TEST_F(AnalysisTest, augassign) {
SourceInfo* si = new SourceInfo(createModule(boxString("augassign"), fn.c_str()), scoping, future_flags, func, SourceInfo* si = new SourceInfo(createModule(boxString("augassign"), fn.c_str()), scoping, future_flags, func,
func->body, boxString(fn)); func->body, boxString(fn));
CFG* cfg = computeCFG(si, func->body); ParamNames param_names(si->ast, si->getInternedStrings());
CFG* cfg = computeCFG(si, func->body, param_names);
std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg); std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
//cfg->print(); //cfg->print();
...@@ -74,7 +75,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) { ...@@ -74,7 +75,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) {
fn.c_str()), scoping, future_flags, func, func->body, boxString(fn))); fn.c_str()), scoping, future_flags, func, func->body, boxString(fn)));
FunctionMetadata* clfunc = new FunctionMetadata(0, false, false, std::move(si)); FunctionMetadata* clfunc = new FunctionMetadata(0, false, false, std::move(si));
CFG* cfg = computeCFG(clfunc->source.get(), func->body); CFG* cfg = computeCFG(clfunc->source.get(), func->body, clfunc->param_names);
std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg); std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
// cfg->print(); // cfg->print();
......
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