Commit 2e030372 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge branch 'deopt'

Fully switch to the new deopt system, and clean up a lot of stuff.
parents a8ff0670 1bfb56e8
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "analysis/scoping_analysis.h" #include "analysis/scoping_analysis.h"
#include "codegen/codegen.h" #include "codegen/codegen.h"
#include "codegen/compvars.h" #include "codegen/compvars.h"
#include "codegen/osrentry.h"
#include "codegen/type_recording.h" #include "codegen/type_recording.h"
#include "core/ast.h" #include "core/ast.h"
#include "core/cfg.h" #include "core/cfg.h"
...@@ -622,6 +623,7 @@ public: ...@@ -622,6 +623,7 @@ public:
return getTypeAtBlockStart(name, block->successors[0]); return getTypeAtBlockStart(name, block->successors[0]);
} }
ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) override { ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) override {
assert(starting_types.count(block));
CompilerType* base = starting_types[block][name]; CompilerType* base = starting_types[block][name];
ASSERT(base != NULL, "%s %d", name.c_str(), block->idx); ASSERT(base != NULL, "%s %d", name.c_str(), block->idx);
...@@ -672,40 +674,20 @@ public: ...@@ -672,40 +674,20 @@ public:
return changed; return changed;
} }
static PropagatingTypeAnalysis* doAnalysis(CFG* cfg, const ParamNames& arg_names, static PropagatingTypeAnalysis* doAnalysis(CFG* cfg, SpeculationLevel speculation, ScopeInfo* scope_info,
const std::vector<ConcreteCompilerType*>& arg_types, TypeMap&& initial_types, CFGBlock* initial_block) {
SpeculationLevel speculation, ScopeInfo* scope_info) {
Timer _t("PropagatingTypeAnalysis::doAnalysis()"); Timer _t("PropagatingTypeAnalysis::doAnalysis()");
AllTypeMap starting_types; AllTypeMap starting_types;
ExprTypeMap expr_types; ExprTypeMap expr_types;
TypeSpeculations type_speculations; TypeSpeculations type_speculations;
assert(arg_names.totalParameters() == arg_types.size());
TypeMap& initial_types = starting_types[cfg->getStartingBlock()];
int i = 0;
for (; i < arg_names.args.size(); i++) {
initial_types[scope_info->internString(arg_names.args[i])] = unboxedType(arg_types[i]);
}
if (arg_names.vararg.size()) {
initial_types[scope_info->internString(arg_names.vararg)] = unboxedType(arg_types[i]);
i++;
}
if (arg_names.kwarg.size()) {
initial_types[scope_info->internString(arg_names.kwarg)] = unboxedType(arg_types[i]);
i++;
}
assert(i == arg_types.size());
std::unordered_set<CFGBlock*> in_queue; std::unordered_set<CFGBlock*> in_queue;
std::priority_queue<CFGBlock*, std::vector<CFGBlock*>, CFGBlockMinIndex> queue; std::priority_queue<CFGBlock*, std::vector<CFGBlock*>, CFGBlockMinIndex> queue;
queue.push(cfg->getStartingBlock());
in_queue.insert(cfg->getStartingBlock()); starting_types[initial_block] = std::move(initial_types);
queue.push(initial_block);
in_queue.insert(initial_block);
int num_evaluations = 0; int num_evaluations = 0;
while (!queue.empty()) { while (!queue.empty()) {
...@@ -787,6 +769,38 @@ TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& arg_names, const std::v ...@@ -787,6 +769,38 @@ TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& arg_names, const std::v
// if (effort == EffortLevel::INTERPRETED) { // if (effort == EffortLevel::INTERPRETED) {
// return new NullTypeAnalysis(); // return new NullTypeAnalysis();
//} //}
return PropagatingTypeAnalysis::doAnalysis(cfg, arg_names, arg_types, speculation, scope_info); assert(arg_names.totalParameters() == arg_types.size());
TypeMap initial_types;
int i = 0;
for (; i < arg_names.args.size(); i++) {
initial_types[scope_info->internString(arg_names.args[i])] = unboxedType(arg_types[i]);
}
if (arg_names.vararg.size()) {
initial_types[scope_info->internString(arg_names.vararg)] = unboxedType(arg_types[i]);
i++;
}
if (arg_names.kwarg.size()) {
initial_types[scope_info->internString(arg_names.kwarg)] = unboxedType(arg_types[i]);
i++;
}
assert(i == arg_types.size());
return PropagatingTypeAnalysis::doAnalysis(cfg, speculation, scope_info, std::move(initial_types),
cfg->getStartingBlock());
}
TypeAnalysis* doTypeAnalysis(CFG* cfg, const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info) {
// if (effort == EffortLevel::INTERPRETED) {
// return new NullTypeAnalysis();
//}
TypeMap initial_types(entry_descriptor->args.begin(), entry_descriptor->args.end());
return PropagatingTypeAnalysis::doAnalysis(cfg, speculation, scope_info, std::move(initial_types),
entry_descriptor->backedge->target);
} }
} }
...@@ -27,6 +27,7 @@ class ScopeInfo; ...@@ -27,6 +27,7 @@ class ScopeInfo;
class CFGBlock; class CFGBlock;
class BoxedClass; class BoxedClass;
class AST_expr; class AST_expr;
class OSREntryDescriptor;
class TypeAnalysis { class TypeAnalysis {
public: public:
...@@ -45,6 +46,8 @@ public: ...@@ -45,6 +46,8 @@ public:
TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& param_names, TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& param_names,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel effort, const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info); TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
TypeAnalysis* doTypeAnalysis(CFG* cfg, const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
} }
#endif #endif
This diff is collapsed.
...@@ -166,9 +166,10 @@ static void compileIR(CompiledFunction* cf, EffortLevel effort) { ...@@ -166,9 +166,10 @@ static void compileIR(CompiledFunction* cf, EffortLevel effort) {
// should only be called after checking to see if the other versions would work. // should only be called after checking to see if the other versions would work.
// The codegen_lock needs to be held in W mode before calling this function: // The codegen_lock needs to be held in W mode before calling this function:
CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, EffortLevel effort, CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, EffortLevel effort,
const OSREntryDescriptor* entry) { const OSREntryDescriptor* entry_descriptor) {
Timer _t("for compileFunction()"); Timer _t("for compileFunction()");
assert(spec);
assert((entry_descriptor != NULL) + (spec != NULL) == 1);
ASSERT(f->versions.size() < 20, "%ld", f->versions.size()); ASSERT(f->versions.size() < 20, "%ld", f->versions.size());
SourceInfo* source = f->source; SourceInfo* source = f->source;
...@@ -180,6 +181,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -180,6 +181,7 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
std::string s; std::string s;
llvm::raw_string_ostream ss(s); llvm::raw_string_ostream ss(s);
if (spec) {
ss << "\033[34;1mJIT'ing " << name << " with signature ("; ss << "\033[34;1mJIT'ing " << name << " with signature (";
for (int i = 0; i < spec->arg_types.size(); i++) { for (int i = 0; i < spec->arg_types.size(); i++) {
if (i > 0) if (i > 0)
...@@ -189,12 +191,11 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -189,12 +191,11 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
} }
ss << ") -> "; ss << ") -> ";
ss << spec->rtn_type->debugName(); ss << spec->rtn_type->debugName();
// spec->rtn_type->llvmType()->print(ss); } else {
ss << " at effort level " << (int)effort; ss << "\nDoing OSR-entry partial compile of " << name << ", starting with backedge to block "
if (entry != NULL) { << entry_descriptor->backedge->target->idx << '\n';
ss << "\nDoing OSR-entry partial compile, starting with backedge to block " << entry->backedge->target->idx
<< '\n';
} }
ss << " at effort level " << (int)effort;
ss << "\033[0m"; ss << "\033[0m";
printf("%s\n", ss.str().c_str()); printf("%s\n", ss.str().c_str());
} }
...@@ -216,9 +217,10 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E ...@@ -216,9 +217,10 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
CompiledFunction* cf = 0; CompiledFunction* cf = 0;
if (effort == EffortLevel::INTERPRETED) { if (effort == EffortLevel::INTERPRETED) {
assert(!entry_descriptor);
cf = new CompiledFunction(0, spec, true, NULL, NULL, effort, 0); cf = new CompiledFunction(0, spec, true, NULL, NULL, effort, 0);
} else { } else {
cf = doCompile(source, &f->param_names, entry, effort, spec, name); cf = doCompile(source, &f->param_names, entry_descriptor, effort, spec, name);
compileIR(cf, effort); compileIR(cf, effort);
} }
...@@ -327,6 +329,12 @@ void CompiledFunction::speculationFailed() { ...@@ -327,6 +329,12 @@ void CompiledFunction::speculationFailed() {
} }
} }
ConcreteCompilerType* CompiledFunction::getReturnType() {
if (spec)
return spec->rtn_type;
return entry_descriptor->cf->getReturnType();
}
/// Reoptimizes the given function version at the new effort level. /// Reoptimizes the given function version at the new effort level.
/// The cf must be an active version in its parents CLFunction; the given /// The cf must be an active version in its parents CLFunction; the given
/// version will be replaced by the new version, which will be returned. /// version will be replaced by the new version, which will be returned.
...@@ -385,8 +393,7 @@ CompiledFunction* compilePartialFuncInternal(OSRExit* exit) { ...@@ -385,8 +393,7 @@ CompiledFunction* compilePartialFuncInternal(OSRExit* exit) {
EffortLevel new_effort = EffortLevel::MAXIMAL; EffortLevel new_effort = EffortLevel::MAXIMAL;
if (exit->parent_cf->effort == EffortLevel::INTERPRETED) if (exit->parent_cf->effort == EffortLevel::INTERPRETED)
new_effort = EffortLevel::MINIMAL; new_effort = EffortLevel::MINIMAL;
CompiledFunction* compiled CompiledFunction* compiled = compileFunction(exit->parent_cf->clfunc, NULL, new_effort, exit->entry);
= compileFunction(exit->parent_cf->clfunc, exit->parent_cf->spec, new_effort, exit->entry);
assert(compiled == new_cf); assert(compiled == new_cf);
stat_osr_compiles.log(); stat_osr_compiles.log();
......
This diff is collapsed.
...@@ -83,10 +83,7 @@ public: ...@@ -83,10 +83,7 @@ public:
llvm::Value* getScratchSpace(int min_bytes); llvm::Value* getScratchSpace(int min_bytes);
llvm::Value* getFrameInfoVar(); llvm::Value* getFrameInfoVar();
ConcreteCompilerType* getReturnType() { ConcreteCompilerType* getReturnType() { return cf->getReturnType(); }
assert(cf->spec);
return cf->spec->rtn_type;
}
SourceInfo* getSourceInfo() { return source_info; } SourceInfo* getSourceInfo() { return source_info; }
...@@ -98,94 +95,6 @@ public: ...@@ -98,94 +95,6 @@ public:
ParamNames* getParamNames() { return param_names; } ParamNames* getParamNames() { return param_names; }
}; };
class GuardList {
public:
struct ExprTypeGuard {
CFGBlock* cfg_block;
llvm::BranchInst* branch;
AST_expr* ast_node;
CompilerVariable* val;
SymbolTable st;
ExprTypeGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val,
const SymbolTable& st);
};
struct BlockEntryGuard {
CFGBlock* cfg_block;
llvm::BranchInst* branch;
SymbolTable symbol_table;
BlockEntryGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, const SymbolTable& symbol_table);
};
private:
std::unordered_map<AST_expr*, ExprTypeGuard*> expr_type_guards;
std::unordered_map<CFGBlock*, std::vector<BlockEntryGuard*>> block_begin_guards;
// typedef std::unordered_map<AST_expr*, ExprTypeGuard*>::iterator expr_type_guard_iterator;
// typedef std::unordered_map<AST_expr*, ExprTypeGuard*>::const_iterator expr_type_guard_const_iterator;
typedef decltype(expr_type_guards)::iterator expr_type_guard_iterator;
typedef decltype(expr_type_guards)::const_iterator expr_type_guard_const_iterator;
public:
llvm::iterator_range<expr_type_guard_iterator> exprGuards() {
return llvm::iterator_range<expr_type_guard_iterator>(expr_type_guards.begin(), expr_type_guards.end());
}
void getBlocksWithGuards(std::unordered_set<CFGBlock*>& add_to) {
for (const auto& p : block_begin_guards) {
add_to.insert(p.first);
}
}
void assertGotPatched() {
#ifndef NDEBUG
for (const auto& p : block_begin_guards) {
for (const auto g : p.second) {
assert(g->branch->getSuccessor(0) != g->branch->getSuccessor(1));
}
}
for (const auto& p : expr_type_guards) {
assert(p.second->branch->getSuccessor(0) != p.second->branch->getSuccessor(1));
}
#endif
}
ExprTypeGuard* getNodeTypeGuard(AST_expr* node) const {
expr_type_guard_const_iterator it = expr_type_guards.find(node);
if (it == expr_type_guards.end())
return NULL;
return it->second;
}
bool isEmpty() const { return expr_type_guards.size() == 0 && block_begin_guards.size() == 0; }
void addExprTypeGuard(CFGBlock* cfg_block, llvm::BranchInst* branch, AST_expr* ast_node, CompilerVariable* val,
const SymbolTable& st) {
abort();
ExprTypeGuard*& g = expr_type_guards[ast_node];
assert(g == NULL);
g = new ExprTypeGuard(cfg_block, branch, ast_node, val, st);
}
void registerGuardForBlockEntry(CFGBlock* cfg_block, llvm::BranchInst* branch, const SymbolTable& st) {
// printf("Adding guard for block %p, in %p\n", cfg_block, this);
std::vector<BlockEntryGuard*>& v = block_begin_guards[cfg_block];
v.push_back(new BlockEntryGuard(cfg_block, branch, st));
}
const std::vector<BlockEntryGuard*>& getGuardsForBlock(CFGBlock* block) const {
std::unordered_map<CFGBlock*, std::vector<BlockEntryGuard*>>::const_iterator it
= block_begin_guards.find(block);
if (it != block_begin_guards.end())
return it->second;
static std::vector<BlockEntryGuard*> empty_list;
return empty_list;
}
};
class IRGenerator { class IRGenerator {
private: private:
public: public:
...@@ -214,8 +123,7 @@ public: ...@@ -214,8 +123,7 @@ public:
class IREmitter; class IREmitter;
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL); IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL);
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks, IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types, GuardList& out_guards, CFGBlock* myblock, TypeAnalysis* types);
const GuardList& in_guards, bool is_partial);
CLFunction* wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body, SourceInfo* source); CLFunction* wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body, SourceInfo* source);
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifndef PYSTON_CODEGEN_OSRENTRY_H #ifndef PYSTON_CODEGEN_OSRENTRY_H
#define PYSTON_CODEGEN_OSRENTRY_H #define PYSTON_CODEGEN_OSRENTRY_H
#include <map>
#include <vector> #include <vector>
#include "core/stringpool.h" #include "core/stringpool.h"
......
...@@ -203,7 +203,11 @@ public: ...@@ -203,7 +203,11 @@ public:
llvm::Value* llvm_code, EffortLevel effort, const OSREntryDescriptor* entry_descriptor) llvm::Value* llvm_code, EffortLevel effort, const OSREntryDescriptor* entry_descriptor)
: clfunc(NULL), func(func), spec(spec), entry_descriptor(entry_descriptor), is_interpreted(is_interpreted), : clfunc(NULL), func(func), spec(spec), entry_descriptor(entry_descriptor), is_interpreted(is_interpreted),
code(code), llvm_code(llvm_code), effort(effort), times_called(0), times_speculation_failed(0), code(code), llvm_code(llvm_code), effort(effort), times_called(0), times_speculation_failed(0),
location_map(nullptr) {} location_map(nullptr) {
assert((spec != NULL) + (entry_descriptor != NULL) == 1);
}
ConcreteCompilerType* getReturnType();
// TODO this will need to be implemented eventually; things to delete: // TODO this will need to be implemented eventually; things to delete:
// - line_table if it exists // - line_table if it exists
...@@ -297,17 +301,18 @@ public: ...@@ -297,17 +301,18 @@ public:
void addVersion(CompiledFunction* compiled) { void addVersion(CompiledFunction* compiled) {
assert(compiled); assert(compiled);
assert(compiled->spec); assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
assert(compiled->spec->arg_types.size() == num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0));
assert(compiled->clfunc == NULL); assert(compiled->clfunc == NULL);
assert(compiled->is_interpreted == (compiled->code == NULL)); assert(compiled->is_interpreted == (compiled->code == NULL));
assert(compiled->is_interpreted == (compiled->llvm_code == NULL)); assert(compiled->is_interpreted == (compiled->llvm_code == NULL));
compiled->clfunc = this; compiled->clfunc = this;
if (compiled->entry_descriptor == NULL) if (compiled->entry_descriptor == NULL) {
assert(compiled->spec->arg_types.size() == num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0));
versions.push_back(compiled); versions.push_back(compiled);
else } else {
osr_versions[compiled->entry_descriptor] = compiled; osr_versions[compiled->entry_descriptor] = compiled;
} }
}
}; };
CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs, CLFunction* createRTFunction(int num_args, int num_defaults, bool takes_varargs, bool takes_kwargs,
......
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