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 @@
#include "analysis/scoping_analysis.h"
#include "codegen/codegen.h"
#include "codegen/compvars.h"
#include "codegen/osrentry.h"
#include "codegen/type_recording.h"
#include "core/ast.h"
#include "core/cfg.h"
......@@ -622,6 +623,7 @@ public:
return getTypeAtBlockStart(name, block->successors[0]);
}
ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) override {
assert(starting_types.count(block));
CompilerType* base = starting_types[block][name];
ASSERT(base != NULL, "%s %d", name.c_str(), block->idx);
......@@ -672,40 +674,20 @@ public:
return changed;
}
static PropagatingTypeAnalysis* doAnalysis(CFG* cfg, const ParamNames& arg_names,
const std::vector<ConcreteCompilerType*>& arg_types,
SpeculationLevel speculation, ScopeInfo* scope_info) {
static PropagatingTypeAnalysis* doAnalysis(CFG* cfg, SpeculationLevel speculation, ScopeInfo* scope_info,
TypeMap&& initial_types, CFGBlock* initial_block) {
Timer _t("PropagatingTypeAnalysis::doAnalysis()");
AllTypeMap starting_types;
ExprTypeMap expr_types;
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::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;
while (!queue.empty()) {
......@@ -787,6 +769,38 @@ TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& arg_names, const std::v
// if (effort == EffortLevel::INTERPRETED) {
// 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;
class CFGBlock;
class BoxedClass;
class AST_expr;
class OSREntryDescriptor;
class TypeAnalysis {
public:
......@@ -45,6 +46,8 @@ public:
TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& param_names,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
TypeAnalysis* doTypeAnalysis(CFG* cfg, const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
}
#endif
This diff is collapsed.
......@@ -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.
// The codegen_lock needs to be held in W mode before calling this function:
CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, EffortLevel effort,
const OSREntryDescriptor* entry) {
const OSREntryDescriptor* entry_descriptor) {
Timer _t("for compileFunction()");
assert(spec);
assert((entry_descriptor != NULL) + (spec != NULL) == 1);
ASSERT(f->versions.size() < 20, "%ld", f->versions.size());
SourceInfo* source = f->source;
......@@ -180,21 +181,21 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
std::string s;
llvm::raw_string_ostream ss(s);
ss << "\033[34;1mJIT'ing " << name << " with signature (";
for (int i = 0; i < spec->arg_types.size(); i++) {
if (i > 0)
ss << ", ";
ss << spec->arg_types[i]->debugName();
// spec->arg_types[i]->llvmType()->print(ss);
if (spec) {
ss << "\033[34;1mJIT'ing " << name << " with signature (";
for (int i = 0; i < spec->arg_types.size(); i++) {
if (i > 0)
ss << ", ";
ss << spec->arg_types[i]->debugName();
// spec->arg_types[i]->llvmType()->print(ss);
}
ss << ") -> ";
ss << spec->rtn_type->debugName();
} else {
ss << "\nDoing OSR-entry partial compile of " << name << ", starting with backedge to block "
<< entry_descriptor->backedge->target->idx << '\n';
}
ss << ") -> ";
ss << spec->rtn_type->debugName();
// spec->rtn_type->llvmType()->print(ss);
ss << " at effort level " << (int)effort;
if (entry != NULL) {
ss << "\nDoing OSR-entry partial compile, starting with backedge to block " << entry->backedge->target->idx
<< '\n';
}
ss << "\033[0m";
printf("%s\n", ss.str().c_str());
}
......@@ -216,9 +217,10 @@ CompiledFunction* compileFunction(CLFunction* f, FunctionSpecialization* spec, E
CompiledFunction* cf = 0;
if (effort == EffortLevel::INTERPRETED) {
assert(!entry_descriptor);
cf = new CompiledFunction(0, spec, true, NULL, NULL, effort, 0);
} 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);
}
......@@ -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.
/// 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.
......@@ -385,8 +393,7 @@ CompiledFunction* compilePartialFuncInternal(OSRExit* exit) {
EffortLevel new_effort = EffortLevel::MAXIMAL;
if (exit->parent_cf->effort == EffortLevel::INTERPRETED)
new_effort = EffortLevel::MINIMAL;
CompiledFunction* compiled
= compileFunction(exit->parent_cf->clfunc, exit->parent_cf->spec, new_effort, exit->entry);
CompiledFunction* compiled = compileFunction(exit->parent_cf->clfunc, NULL, new_effort, exit->entry);
assert(compiled == new_cf);
stat_osr_compiles.log();
......
This diff is collapsed.
......@@ -83,10 +83,7 @@ public:
llvm::Value* getScratchSpace(int min_bytes);
llvm::Value* getFrameInfoVar();
ConcreteCompilerType* getReturnType() {
assert(cf->spec);
return cf->spec->rtn_type;
}
ConcreteCompilerType* getReturnType() { return cf->getReturnType(); }
SourceInfo* getSourceInfo() { return source_info; }
......@@ -98,94 +95,6 @@ public:
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 {
private:
public:
......@@ -214,8 +123,7 @@ public:
class IREmitter;
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL);
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types, GuardList& out_guards,
const GuardList& in_guards, bool is_partial);
CFGBlock* myblock, TypeAnalysis* types);
CLFunction* wrapFunction(AST* node, AST_arguments* args, const std::vector<AST_stmt*>& body, SourceInfo* source);
}
......
......@@ -15,6 +15,7 @@
#ifndef PYSTON_CODEGEN_OSRENTRY_H
#define PYSTON_CODEGEN_OSRENTRY_H
#include <map>
#include <vector>
#include "core/stringpool.h"
......
......@@ -203,7 +203,11 @@ public:
llvm::Value* llvm_code, EffortLevel effort, const OSREntryDescriptor* entry_descriptor)
: 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),
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:
// - line_table if it exists
......@@ -297,16 +301,17 @@ public:
void addVersion(CompiledFunction* compiled) {
assert(compiled);
assert(compiled->spec);
assert(compiled->spec->arg_types.size() == num_args + (takes_varargs ? 1 : 0) + (takes_kwargs ? 1 : 0));
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
assert(compiled->clfunc == NULL);
assert(compiled->is_interpreted == (compiled->code == NULL));
assert(compiled->is_interpreted == (compiled->llvm_code == NULL));
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);
else
} else {
osr_versions[compiled->entry_descriptor] = compiled;
}
}
};
......
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