Commit 1923d116 authored by Kevin Modzelewski's avatar Kevin Modzelewski Committed by GitHub

Merge pull request #1277 from kmod/vregs_everywhere

Switch almost everything to use vregs when possible
parents 44ccbe1b a044540d
......@@ -337,7 +337,7 @@ STDOBJECT_SRCS := \
iterobject.c \
bufferobject.c \
cobject.c \
dictproxy.c \
descrobject.c \
$(EXTRA_STDOBJECT_SRCS)
STDPYTHON_SRCS := \
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "analysis/function_analysis.h"
#include "core/cfg.h"
#include "core/common.h"
#include "core/options.h"
......@@ -29,13 +30,12 @@ namespace pyston {
template <typename T> class BBAnalyzer {
public:
typedef llvm::DenseMap<InternedString, T> Map;
typedef VRegMap<T> Map;
typedef llvm::DenseMap<CFGBlock*, Map> AllMap;
virtual ~BBAnalyzer() {}
virtual T merge(T from, T into) const = 0;
virtual T mergeBlank(T into) const = 0;
virtual void processBB(Map& starting, CFGBlock* block) const = 0;
};
......@@ -56,10 +56,12 @@ void computeFixedPoint(typename BBAnalyzer<T>::Map&& initial_map, CFGBlock* init
assert(!starting_states.size());
assert(!ending_states.size());
int num_vregs = initial_map.numVregs();
llvm::SmallPtrSet<CFGBlock*, 32> in_queue;
std::priority_queue<CFGBlock*, llvm::SmallVector<CFGBlock*, 32>, CFGBlockMinIndex> q;
starting_states.insert(make_pair(initial_block, std::move(initial_map)));
starting_states.insert(std::make_pair(initial_block, std::move(initial_map)));
q.push(initial_block);
in_queue.insert(initial_block);
......@@ -70,9 +72,10 @@ void computeFixedPoint(typename BBAnalyzer<T>::Map&& initial_map, CFGBlock* init
q.pop();
in_queue.erase(block);
Map& initial = starting_states[block];
assert(starting_states.count(block));
Map& initial = starting_states.find(block)->second;
if (VERBOSITY("analysis") >= 2)
printf("fpc on block %d - %d entries\n", block->idx, initial.size());
printf("fpc on block %d - %d entries\n", block->idx, initial.numVregs());
Map ending = Map(initial);
......@@ -87,43 +90,34 @@ void computeFixedPoint(typename BBAnalyzer<T>::Map&& initial_map, CFGBlock* init
initial = true;
}
Map& next = starting_states[next_block];
for (const auto& p : ending) {
if (next.count(p.first) == 0) {
changed = true;
if (initial) {
next[p.first] = p.second;
} else {
next[p.first] = analyzer.mergeBlank(p.second);
}
} else {
T& next_elt = next[p.first];
auto it = starting_states.find(next_block);
if (it == starting_states.end())
it = starting_states.insert(std::make_pair(next_block, Map(num_vregs))).first;
Map& next = it->second;
// merge ending->next
for (int vreg = 0; vreg < num_vregs; vreg++) {
T& next_elt = next[vreg];
T new_elt = analyzer.merge(ending[vreg], next_elt);
T new_elt = analyzer.merge(p.second, next_elt);
if (next_elt != new_elt) {
next_elt = new_elt;
changed = true;
}
}
}
for (const auto& p : next) {
if (ending.count(p.first))
continue;
T next_elt = analyzer.mergeBlank(p.second);
if (next_elt != p.second) {
next[p.first] = next_elt;
changed = true;
}
}
#ifndef NDEBUG
assert(next.numVregs() == ending.numVregs());
#endif
if (changed && in_queue.insert(next_block).second) {
q.push(next_block);
}
}
ending_states[block] = std::move(ending);
ending_states.erase(block);
ending_states.insert(std::make_pair(block, std::move(ending)));
}
if (VERBOSITY("analysis")) {
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "core/cfg.h"
#include "core/stringpool.h"
#include "core/types.h"
......@@ -41,7 +42,7 @@ private:
typedef llvm::DenseMap<CFGBlock*, std::unique_ptr<LivenessBBVisitor>> LivenessCacheMap;
LivenessCacheMap liveness_cache;
llvm::DenseMap<InternedString, llvm::DenseMap<CFGBlock*, bool>> result_cache;
VRegMap<llvm::DenseMap<CFGBlock*, bool>> result_cache;
public:
LivenessAnalysis(CFG* cfg);
......@@ -50,60 +51,59 @@ public:
// we don't keep track of node->parent_block relationships, so you have to pass both:
bool isKill(AST_Name* node, CFGBlock* parent_block);
bool isLiveAtEnd(InternedString name, CFGBlock* block);
bool isLiveAtEnd(int vreg, CFGBlock* block);
};
class PhiAnalysis;
class DefinednessAnalysis {
public:
enum DefinitionLevel {
enum DefinitionLevel : char {
Unknown,
Undefined,
PotentiallyDefined,
Defined,
};
typedef llvm::DenseSet<InternedString> RequiredSet;
private:
llvm::DenseMap<CFGBlock*, llvm::DenseMap<InternedString, DefinitionLevel>> defined_at_beginning, defined_at_end;
llvm::DenseMap<CFGBlock*, RequiredSet> defined_at_end_sets;
llvm::DenseMap<CFGBlock*, VRegMap<DefinitionLevel>> defined_at_beginning, defined_at_end;
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);
DefinitionLevel isDefinedAtEnd(int vreg, 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);
bool isRequired(InternedString name, CFGBlock* block);
bool isRequiredAfter(InternedString name, CFGBlock* block);
const RequiredSet& getAllRequiredAfter(CFGBlock* block);
const RequiredSet& getAllRequiredFor(CFGBlock* block);
bool isRequired(int vreg, CFGBlock* block);
bool isRequiredAfter(int vreg, CFGBlock* block);
const VRegSet& getAllRequiredAfter(CFGBlock* block);
const VRegSet& getAllRequiredFor(CFGBlock* block);
// If "name" may be undefined at the beginning of any immediate successor block of "block":
bool isPotentiallyUndefinedAfter(InternedString name, CFGBlock* block);
bool isPotentiallyUndefinedAfter(int vreg, CFGBlock* block);
// If "name" may be undefined at the beginning of "block"
bool isPotentiallyUndefinedAt(InternedString name, CFGBlock* block);
bool isPotentiallyUndefinedAt(int vreg, CFGBlock* block);
};
std::unique_ptr<LivenessAnalysis> computeLivenessInfo(CFG*);
......
......@@ -587,12 +587,11 @@ public:
}
}
bool visit_functiondef(AST_FunctionDef* node) override {
if (node == orig_node) {
void visitOrignodeArgs(AST_arguments* args) {
this->currently_visiting_functiondef_args = true;
int counter = 0;
for (AST_expr* e : node->args->args) {
for (AST_expr* e : args->args) {
if (e->type == AST_TYPE::Tuple) {
doWrite(scoping->getInternedStrings().get("." + std::to_string(counter)));
}
......@@ -600,16 +599,21 @@ public:
e->accept(this);
}
if (node->args->vararg.s().size()) {
mangleNameInPlace(node->args->vararg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->vararg);
if (args->vararg) {
mangleNameInPlace(args->vararg->id, cur->private_name, scoping->getInternedStrings());
doWrite(args->vararg->id);
}
if (node->args->kwarg.s().size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->kwarg);
if (args->kwarg) {
mangleNameInPlace(args->kwarg->id, cur->private_name, scoping->getInternedStrings());
doWrite(args->kwarg->id);
}
this->currently_visiting_functiondef_args = false;
}
bool visit_functiondef(AST_FunctionDef* node) override {
if (node == orig_node) {
visitOrignodeArgs(node->args);
for (AST_stmt* s : node->body)
s->accept(this);
......@@ -666,16 +670,7 @@ public:
bool visit_lambda(AST_Lambda* node) override {
if (node == orig_node) {
for (AST_expr* e : node->args->args)
e->accept(this);
if (node->args->vararg.s().size()) {
mangleNameInPlace(node->args->vararg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->vararg);
}
if (node->args->kwarg.s().size()) {
mangleNameInPlace(node->args->kwarg, cur->private_name, scoping->getInternedStrings());
doWrite(node->args->kwarg);
}
visitOrignodeArgs(node->args);
node->body->accept(this);
} else {
for (auto* e : node->args->defaults)
......
This diff is collapsed.
......@@ -39,8 +39,8 @@ public:
virtual ~TypeAnalysis() {}
virtual ConcreteCompilerType* getTypeAtBlockStart(InternedString name, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockEnd(InternedString name, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockStart(int vreg, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockEnd(int vreg, CFGBlock* block) = 0;
virtual BoxedClass* speculatedExprClass(AST_expr*) = 0;
virtual BoxedClass* speculatedExprClass(AST_slice*) = 0;
};
......
......@@ -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();
}
......@@ -172,7 +172,7 @@ public:
Box** getVRegs() { return vregs; }
const ScopeInfo* getScopeInfo() { return scope_info; }
void addSymbol(InternedString name, Box* value, bool allow_duplicates);
void addSymbol(int vreg, Box* value, bool allow_duplicates);
void setGenerator(Box* gen);
void setPassedClosure(Box* closure);
void setCreatedClosure(Box* closure);
......@@ -182,8 +182,8 @@ public:
friend struct pyston::ASTInterpreterJitInterface;
};
void ASTInterpreter::addSymbol(InternedString name, Box* new_value, bool allow_duplicates) {
Box*& value = vregs[getVRegInfo().getVReg(name)];
void ASTInterpreter::addSymbol(int vreg, Box* new_value, bool allow_duplicates) {
Box*& value = vregs[vreg];
Box* old_value = value;
value = incref(new_value);
if (allow_duplicates)
......@@ -478,7 +478,7 @@ void ASTInterpreter::doStore(AST_Name* node, STOLEN(Value) value) {
if (jit) {
bool is_live = true;
if (!closure)
is_live = source_info->getLiveness()->isLiveAtEnd(name, current_block);
is_live = source_info->getLiveness()->isLiveAtEnd(node->vreg, current_block);
if (is_live)
jit->emitSetLocal(name, node->vreg, closure, value);
else
......@@ -720,9 +720,9 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
llvm::SmallVector<int, 16> dead_vregs;
for (auto&& sym : getSymVRegMap()) {
if (!liveness->isLiveAtEnd(sym.first, current_block)) {
if (!liveness->isLiveAtEnd(sym.second, current_block)) {
dead_vregs.push_back(sym.second);
} else if (phis->isRequiredAfter(sym.first, current_block)) {
} else if (phis->isRequiredAfter(sym.second, current_block)) {
assert(scope_info->getScopeTypeOfName(sym.first) != ScopeInfo::VarScopeType::GLOBAL);
} else {
}
......@@ -739,25 +739,29 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
found_entry = p.first;
}
std::map<InternedString, Box*> sorted_symbol_table;
int num_vregs = source_info->cfg->getVRegInfo().getTotalNumOfVRegs();
VRegMap<Box*> sorted_symbol_table(num_vregs);
VRegSet potentially_undefined(num_vregs);
// TODO: maybe use a different placeholder (=NULL)?
// - new issue with that -- we can no longer distinguish NULL from unset-in-sorted_symbol_table
// 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;
for (auto& name : phis->definedness.getDefinedNamesAtEnd(current_block)) {
Box* val = vregs[getVRegInfo().getVReg(name)];
if (!liveness->isLiveAtEnd(name, current_block))
const VRegSet& defined = phis->definedness.getDefinedVregsAtEnd(current_block);
for (int vreg : defined) {
if (!liveness->isLiveAtEnd(vreg, current_block))
continue;
if (phis->isPotentiallyUndefinedAfter(name, current_block)) {
Box* val = vregs[vreg];
if (phis->isPotentiallyUndefinedAfter(vreg, current_block)) {
potentially_undefined.set(vreg);
bool is_defined = val != NULL;
// TODO only mangle once
sorted_symbol_table[getIsDefinedName(name, source_info->getInternedStrings())] = (Box*)is_defined;
sorted_symbol_table[name] = is_defined ? incref(val) : incref(VAL_UNDEFINED);
sorted_symbol_table[vreg] = is_defined ? incref(val) : incref(VAL_UNDEFINED);
} else {
ASSERT(val != NULL, "%s", name.c_str());
sorted_symbol_table[name] = incref(val);
assert(val != NULL);
sorted_symbol_table[vreg] = incref(val);
}
}
......@@ -766,61 +770,42 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
// LLVM has a limit on the number of operands a machine instruction can have (~255),
// in order to not hit the limit with the patchpoints cancel OSR when we have a high number of symbols.
if (sorted_symbol_table.size() > 225) {
if (sorted_symbol_table.numSet() > 225) {
static StatCounter times_osr_cancel("num_osr_cancel_too_many_syms");
times_osr_cancel.log();
return nullptr;
}
if (generator) {
// generated is only borrowed in order to not introduce cycles
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_GENERATOR_NAME)] = generator;
}
if (frame_info.passed_closure)
sorted_symbol_table[source_info->getInternedStrings().get(PASSED_CLOSURE_NAME)]
= incref(frame_info.passed_closure);
if (created_closure)
sorted_symbol_table[source_info->getInternedStrings().get(CREATED_CLOSURE_NAME)] = incref(created_closure);
sorted_symbol_table[source_info->getInternedStrings().get(FRAME_INFO_PTR_NAME)] = (Box*)&frame_info;
if (found_entry == nullptr) {
OSREntryDescriptor* entry = OSREntryDescriptor::create(getMD(), node, CXX);
for (auto& it : sorted_symbol_table) {
if (isIsDefinedName(it.first))
entry->args[it.first] = BOOL;
else if (it.first.s() == PASSED_GENERATOR_NAME)
entry->args[it.first] = GENERATOR;
else if (it.first.s() == PASSED_CLOSURE_NAME || it.first.s() == CREATED_CLOSURE_NAME)
entry->args[it.first] = CLOSURE;
else if (it.first.s() == FRAME_INFO_PTR_NAME)
entry->args[it.first] = FRAME_INFO;
else {
assert(it.first.s()[0] != '!');
entry->args[it.first] = UNKNOWN;
}
// TODO can we just get rid of this?
for (auto&& p : sorted_symbol_table) {
entry->args[p.first] = UNKNOWN;
}
entry->potentially_undefined = potentially_undefined;
found_entry = entry;
}
OSRExit exit(found_entry);
std::vector<Box*> arg_array;
arg_array.reserve(sorted_symbol_table.size());
for (auto& it : sorted_symbol_table) {
arg_array.push_back(it.second);
arg_array.reserve(sorted_symbol_table.numSet() + potentially_undefined.numSet());
for (auto&& p : sorted_symbol_table) {
arg_array.push_back(p.second);
}
for (int vreg : potentially_undefined) {
bool is_defined = sorted_symbol_table[vreg] != VAL_UNDEFINED;
arg_array.push_back((Box*)is_defined);
}
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
CompiledFunction* partial_func = compilePartialFuncInternal(&exit);
auto arg_tuple = getTupleFromArgsArray(&arg_array[0], arg_array.size());
Box* r = partial_func->call(std::get<0>(arg_tuple), std::get<1>(arg_tuple), std::get<2>(arg_tuple),
std::get<3>(arg_tuple));
// generated is only borrowed in order to not introduce cycles
Box* r = partial_func->call_osr(generator, created_closure, &frame_info, &arg_array[0]);
if (partial_func->exception_style == CXX) {
assert(r);
......@@ -1687,8 +1672,10 @@ Value ASTInterpreter::visit_name(AST_Name* node) {
bool is_live = true;
if (node->is_kill) {
is_live = false;
} else if (node->lookup_type == ScopeInfo::VarScopeType::FAST)
is_live = source_info->getLiveness()->isLiveAtEnd(node->id, current_block);
} else if (node->lookup_type == ScopeInfo::VarScopeType::FAST) {
assert(node->vreg != -1);
is_live = source_info->getLiveness()->isLiveAtEnd(node->vreg, current_block);
}
if (is_live) {
assert(!node->is_kill);
......@@ -2087,6 +2074,10 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
ASTInterpreter interpreter(md, vregs, frame_state.frame_info);
for (const auto& p : *frame_state.locals) {
if (p.first->cls == int_cls) {
int vreg = static_cast<BoxedInt*>(p.first)->n;
interpreter.addSymbol(vreg, p.second, false);
} else {
assert(p.first->cls == str_cls);
auto name = static_cast<BoxedString*>(p.first)->s();
if (name == PASSED_GENERATOR_NAME) {
......@@ -2097,8 +2088,8 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
} else if (name == CREATED_CLOSURE_NAME) {
interpreter.setCreatedClosure(p.second);
} else {
InternedString interned = md->source->getInternedStrings().get(name);
interpreter.addSymbol(interned, p.second, false);
RELEASE_ASSERT(0, "");
}
}
}
......@@ -2112,7 +2103,7 @@ extern "C" Box* astInterpretDeoptFromASM(FunctionMetadata* md, AST_expr* after_e
assert(asgn->targets[0]->type == AST_TYPE::Name);
auto name = ast_cast<AST_Name>(asgn->targets[0]);
assert(name->id.s()[0] == '#');
interpreter.addSymbol(name->id, expr_val, true);
interpreter.addSymbol(name->vreg, expr_val, true);
break;
} else if (enclosing_stmt->type == AST_TYPE::Expr) {
auto expr = ast_cast<AST_Expr>(enclosing_stmt);
......
......@@ -76,9 +76,8 @@ BORROWED(BoxedCode*) FunctionMetadata::getCode() {
void FunctionMetadata::addVersion(CompiledFunction* compiled) {
assert(compiled);
assert((compiled->spec != NULL) + (compiled->entry_descriptor != NULL) == 1);
assert(compiled->md == NULL);
assert(compiled->md);
assert(compiled->code);
compiled->md = this;
if (compiled->entry_descriptor == NULL) {
bool could_have_speculations = (source.get() != NULL);
......
......@@ -821,19 +821,15 @@ ConcreteCompilerVariable* UnknownType::hasnext(IREmitter& emitter, const OpInfo&
return boolFromI1(emitter, rtn_val);
}
CompilerVariable* makeFunction(IREmitter& emitter, FunctionMetadata* f, CompilerVariable* closure, llvm::Value* globals,
CompilerVariable* makeFunction(IREmitter& emitter, FunctionMetadata* f, llvm::Value* closure, llvm::Value* globals,
const std::vector<ConcreteCompilerVariable*>& defaults) {
// Unlike the FunctionMetadata*, which can be shared between recompilations, the Box* around it
// should be created anew every time the functiondef is encountered
llvm::Value* closure_v;
ConcreteCompilerVariable* convertedClosure = NULL;
if (closure) {
convertedClosure = closure->makeConverted(emitter, closure->getConcreteType());
closure_v = convertedClosure->getValue();
} else {
closure_v = getNullPtr(g.llvm_closure_type_ptr);
emitter.setType(closure_v, RefType::BORROWED);
if (!closure) {
closure = getNullPtr(g.llvm_closure_type_ptr);
emitter.setType(closure, RefType::BORROWED);
}
llvm::SmallVector<llvm::Value*, 4> array_passed_args;
......@@ -860,8 +856,8 @@ CompilerVariable* makeFunction(IREmitter& emitter, FunctionMetadata* f, Compiler
// emitter.createCall().
llvm::Instruction* boxed = emitter.getBuilder()->CreateCall(
g.funcs.createFunctionFromMetadata,
std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_functionmetadata_type_ptr), closure_v, globals,
scratch, getConstantInt(defaults.size(), g.i64) });
std::vector<llvm::Value*>{ embedRelocatablePtr(f, g.llvm_functionmetadata_type_ptr), closure, globals, scratch,
getConstantInt(defaults.size(), g.i64) });
emitter.setType(boxed, RefType::OWNED);
// The refcounter needs to know that this call "uses" the arguments that got passed via scratch.
......@@ -2433,8 +2429,11 @@ public:
}
};
ConcreteCompilerType* BOOL = new BoolType();
llvm::Value* makeLLVMBool(bool b) {
return llvm::ConstantInt::get(BOOL->llvmType(), b, false);
}
ConcreteCompilerVariable* makeBool(bool b) {
return new ConcreteCompilerVariable(BOOL, llvm::ConstantInt::get(BOOL->llvmType(), b, false));
return new ConcreteCompilerVariable(BOOL, makeLLVMBool(b));
}
ConcreteCompilerVariable* doIs(IREmitter& emitter, CompilerVariable* lhs, CompilerVariable* rhs, bool negate) {
......@@ -2862,6 +2861,17 @@ llvm::Value* i1FromBool(IREmitter& emitter, ConcreteCompilerVariable* v) {
}
}
llvm::Value* i1FromLLVMBool(IREmitter& emitter, llvm::Value* v) {
if (BOOLS_AS_I64) {
assert(v->getType() == BOOL->llvmType());
assert(BOOL->llvmType() == g.i64);
llvm::Value* v2 = emitter.getBuilder()->CreateTrunc(v, g.i1);
return v2;
} else {
return v;
}
}
ConcreteCompilerType* LIST, *SLICE, *MODULE, *DICT, *SET, *FROZENSET, *LONG, *BOXED_COMPLEX;
......
......@@ -346,6 +346,7 @@ CompilerVariable* makeFloat(double);
CompilerVariable* makeUnboxedFloat(IREmitter&, ConcreteCompilerVariable*);
CompilerVariable* makeUnboxedFloat(IREmitter&, llvm::Value*);
llvm::Value* makeLLVMBool(bool b);
ConcreteCompilerVariable* makeBool(bool);
ConcreteCompilerVariable* makeLong(IREmitter&, Box*);
ConcreteCompilerVariable* makePureImaginary(IREmitter&, Box*);
......@@ -361,7 +362,7 @@ UnboxedSlice extractSlice(CompilerVariable* slice);
#if 0
CompilerVariable* makeUnicode(IREmitter& emitter, llvm::StringRef);
#endif
CompilerVariable* makeFunction(IREmitter& emitter, FunctionMetadata*, CompilerVariable* closure, llvm::Value* globals,
CompilerVariable* makeFunction(IREmitter& emitter, FunctionMetadata*, llvm::Value* closure, llvm::Value* globals,
const std::vector<ConcreteCompilerVariable*>& defaults);
ConcreteCompilerVariable* undefVariable();
CompilerVariable* makeTuple(const std::vector<CompilerVariable*>& elts);
......@@ -372,6 +373,7 @@ CompilerType* makeFuncType(ConcreteCompilerType* rtn_type, const std::vector<Con
ConcreteCompilerVariable* boolFromI1(IREmitter&, llvm::Value*);
llvm::Value* i1FromBool(IREmitter&, ConcreteCompilerVariable*);
llvm::Value* i1FromLLVMBool(IREmitter&, llvm::Value*);
template <typename V>
CompilerVariable* _ValuedCompilerType<V>::getPystonIter(IREmitter& emitter, const OpInfo& info, VAR* var) {
......
......@@ -97,26 +97,32 @@ public:
return pool->get(static_cast<BoxedString*>(ident)->s());
}
AST_Name* convertToName(identifier ident) {
if (!ident)
return NULL;
return new AST_Name(convert(ident), AST_TYPE::Store, -1, -1);
}
AST_arguments* convert(arguments_ty ident, AST* parent) {
auto r = new AST_arguments();
convertAll<expr_ty>(ident->args, r->args);
convertAll<expr_ty>(ident->defaults, r->defaults);
r->vararg = convert(ident->vararg);
r->kwarg = convert(ident->kwarg);
r->vararg = convertToName(ident->vararg);
r->kwarg = convertToName(ident->kwarg);
if ((!r->vararg.s().empty()) && (!r->kwarg.s().empty()) && (r->vararg == r->kwarg)) {
if (r->vararg && r->kwarg && (r->vararg->id == r->kwarg->id)) {
char buf[1024];
snprintf(buf, sizeof(buf), "duplicate argument '%s' in function definition", r->vararg.c_str());
snprintf(buf, sizeof(buf), "duplicate argument '%s' in function definition", r->vararg->id.c_str());
raiseSyntaxError(buf, parent->lineno, parent->col_offset, fn, "", true);
}
std::set<InternedString> seen;
if (!r->vararg.s().empty()) {
seen.insert(r->vararg);
if (r->vararg) {
seen.insert(r->vararg->id);
}
if (!r->kwarg.s().empty()) {
seen.insert(r->kwarg);
if (r->kwarg) {
seen.insert(r->kwarg->id);
}
checkDuplicateArgs(parent, r->args, &seen);
......
This diff is collapsed.
......@@ -77,13 +77,13 @@ ParamNames::ParamNames(AST* ast, InternedStringPool& pool)
}
}
vararg = arguments->vararg.s();
if (vararg.size())
vararg_name = new AST_Name(pool.get(vararg), AST_TYPE::Param, arguments->lineno, arguments->col_offset);
vararg_name = arguments->vararg;
if (vararg_name)
vararg = vararg_name->id.s();
kwarg = arguments->kwarg.s();
if (kwarg.size())
kwarg_name = new AST_Name(pool.get(kwarg), AST_TYPE::Param, arguments->lineno, arguments->col_offset);
kwarg_name = arguments->kwarg;
if (kwarg_name)
kwarg = kwarg_name->id.s();
} else {
RELEASE_ASSERT(0, "%d", ast->type);
}
......@@ -261,7 +261,7 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s
if (entry_descriptor && VERBOSITY("irgen") >= 2) {
for (const auto& p : entry_descriptor->args) {
ss << p.first.s() << ": " << p.second->debugName() << '\n';
ss << p.first << ": " << p.second->debugName() << '\n';
}
}
......@@ -680,10 +680,10 @@ void CompiledFunction::speculationFailed() {
}
std::unordered_set<CompiledFunction*> all_compiled_functions;
CompiledFunction::CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort,
CompiledFunction::CompiledFunction(FunctionMetadata* md, FunctionSpecialization* spec, void* code, EffortLevel effort,
ExceptionStyle exception_style, const OSREntryDescriptor* entry_descriptor)
: md(NULL),
func(func),
: md(md),
func(NULL),
effort(effort),
exception_style(exception_style),
spec(spec),
......@@ -827,6 +827,6 @@ void FunctionMetadata::addVersion(void* f, ConcreteCompilerType* rtn_type,
#endif
FunctionSpecialization* spec = new FunctionSpecialization(processType(rtn_type), arg_types);
addVersion(new CompiledFunction(NULL, spec, f, EffortLevel::MAXIMAL, exception_style, NULL));
addVersion(new CompiledFunction(this, spec, f, EffortLevel::MAXIMAL, exception_style, NULL));
}
}
This diff is collapsed.
......@@ -21,6 +21,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Instructions.h"
#include "core/cfg.h"
#include "core/stringpool.h"
#include "core/types.h"
......@@ -43,9 +44,9 @@ class TypeAnalysis;
class RefcountTracker;
class UnwindInfo;
typedef std::unordered_map<InternedString, CompilerVariable*> SymbolTable;
typedef std::map<InternedString, CompilerVariable*> SortedSymbolTable;
typedef std::unordered_map<InternedString, ConcreteCompilerVariable*> ConcreteSymbolTable;
typedef VRegMap<CompilerVariable*> SymbolTable;
typedef VRegMap<llvm::Value*> DefinednessTable;
typedef VRegMap<ConcreteCompilerVariable*> ConcreteSymbolTable;
extern const std::string CREATED_CLOSURE_NAME;
extern const std::string PASSED_CLOSURE_NAME;
......@@ -75,6 +76,9 @@ private:
llvm::Value* globals;
llvm::Value* vregs;
llvm::Value* stmt;
llvm::Value* passed_closure = NULL, * created_closure = NULL, * passed_generator = NULL;
int scratch_size;
public:
......@@ -82,6 +86,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; }
......@@ -119,6 +125,14 @@ public:
ParamNames* getParamNames() { return param_names; }
llvm::Value* getPassedClosure();
llvm::Value* getCreatedClosure();
llvm::Value* getPassedGenerator();
void setPassedClosure(llvm::Value*);
void setCreatedClosure(llvm::Value*);
void setPassedGenerator(llvm::Value*);
// Returns the custom globals, or the module if the globals come from the module.
llvm::Value* getGlobals();
// Returns the custom globals, or null if the globals come from the module.
......@@ -140,15 +154,20 @@ public:
// symbol_table records which Python variables are bound to what CompilerVariables at the end of this block.
// phi_symbol_table records the ones that will need to be `phi'd.
// both only record non-globals.
// TODO: switch these to unique_ptr's
SymbolTable* symbol_table;
ConcreteSymbolTable* phi_symbol_table;
DefinednessTable* definedness_vars;
llvm::BasicBlock* ending_block;
llvm::SmallVector<ExceptionState, 2> exception_state;
EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table, llvm::BasicBlock* ending_block,
EndingState(SymbolTable* symbol_table, ConcreteSymbolTable* phi_symbol_table,
DefinednessTable* definedness_vars, llvm::BasicBlock* ending_block,
llvm::ArrayRef<ExceptionState> exception_state)
: symbol_table(symbol_table),
phi_symbol_table(phi_symbol_table),
definedness_vars(definedness_vars),
ending_block(ending_block),
exception_state(exception_state.begin(), exception_state.end()) {}
};
......@@ -159,6 +178,8 @@ public:
= 0;
virtual void giveLocalSymbol(InternedString name, CompilerVariable* var) = 0;
virtual void giveLocalSymbol(int vreg, CompilerVariable* var) = 0;
virtual void giveDefinednessVar(int vreg, llvm::Value* val) = 0;
virtual void copySymbolsFrom(SymbolTable* st) = 0;
virtual void run(const CFGBlock* block) = 0; // primary entry point
virtual EndingState getEndingSymbolTable() = 0;
......
......@@ -18,6 +18,7 @@
#include <map>
#include <vector>
#include "core/cfg.h"
#include "core/stringpool.h"
namespace llvm {
......@@ -32,7 +33,11 @@ struct StackMap;
class OSREntryDescriptor {
private:
OSREntryDescriptor(FunctionMetadata* md, AST_Jump* backedge, ExceptionStyle exception_style)
: md(md), backedge(backedge), exception_style(exception_style) {
: md(md),
backedge(backedge),
exception_style(exception_style),
args(md->source->cfg->getVRegInfo().getTotalNumOfVRegs()),
potentially_undefined(md->source->cfg->getVRegInfo().getTotalNumOfVRegs()) {
assert(md);
}
......@@ -40,8 +45,9 @@ public:
FunctionMetadata* md;
AST_Jump* const backedge;
ExceptionStyle exception_style;
typedef std::map<InternedString, ConcreteCompilerType*> ArgMap;
typedef VRegMap<ConcreteCompilerType*> ArgMap;
ArgMap args;
VRegSet potentially_undefined;
static OSREntryDescriptor* create(FunctionMetadata* md, AST_Jump* backedge, ExceptionStyle exception_style) {
return new OSREntryDescriptor(md, backedge, exception_style);
......
......@@ -218,9 +218,9 @@ AST_arguments* read_arguments(BufferedReader* reader) {
readExprVector(rtn->args, reader);
rtn->col_offset = -1;
readExprVector(rtn->defaults, reader);
rtn->kwarg = reader->readAndInternString();
rtn->kwarg = ast_cast<AST_Name>(readASTExpr(reader));
rtn->lineno = -1;
rtn->vararg = reader->readAndInternString();
rtn->vararg = ast_cast<AST_Name>(readASTExpr(reader));
return rtn;
}
......@@ -1042,9 +1042,9 @@ AST_Module* parse_file(const char* fn, FutureFlags inherited_flags) {
const char* getMagic() {
if (ENABLE_PYPA_PARSER)
return "a\ncQ";
return "a\ncR";
else
return "a\nCQ";
return "a\nCR";
}
#define MAGIC_STRING_LENGTH 4
......
......@@ -30,10 +30,6 @@
namespace pyston {
void PatchpointInfo::addFrameVar(llvm::StringRef name, CompilerType* type) {
frame_vars.push_back(FrameVarInfo({.name = name, .type = type }));
}
int ICSetupInfo::totalSize() const {
if (isDeopt())
return DEOPT_CALL_ONLY_SIZE;
......@@ -74,30 +70,46 @@ bool StackMap::Record::Location::operator==(const StackMap::Record::Location& rh
}
void PatchpointInfo::parseLocationMap(StackMap::Record* r, LocationMap* map) {
if (!this->isDeopt())
return;
assert(r->locations.size() == totalStackmapArgs());
int cur_arg = frameStackmapArgsStart();
// printf("parsing pp %ld:\n", reinterpret_cast<int64_t>(this));
for (FrameVarInfo& frame_var : frame_vars) {
int num_args = frame_var.type->numFrameArgs();
auto parse_type = [&](CompilerType* type) {
int num_args = type->numFrameArgs();
llvm::SmallVector<StackMap::Record::Location, 1> locations;
locations.append(r->locations.data() + cur_arg, r->locations.data() + cur_arg + num_args);
cur_arg += num_args;
// printf("%s %d %d\n", frame_var.name.c_str(), r->locations[cur_arg].type, r->locations[cur_arg].regnum);
map->names[frame_var.name].locations.push_back(
LocationMap::LocationTable::LocationEntry({._debug_pp_id = (uint64_t) this,
return LocationMap::LocationTable::LocationEntry({._debug_pp_id = (uint64_t) this,
.offset = r->offset,
.length = patchpointSize(),
.type = frame_var.type,
.locations = std::move(locations) }));
cur_arg += num_args;
.type = type,
.locations = std::move(locations) });
};
auto&& source = parentFunction()->md->source;
if (source->is_generator)
map->generator.locations.push_back(parse_type(GENERATOR));
if (source->getScopeInfo()->takesClosure())
map->passed_closure.locations.push_back(parse_type(CLOSURE));
if (source->getScopeInfo()->createsClosure())
map->created_closure.locations.push_back(parse_type(CLOSURE));
for (FrameVarInfo& frame_var : frame_info_desc.vars) {
map->vars[frame_var.vreg].locations.push_back(parse_type(frame_var.type));
}
assert(cur_arg - frameStackmapArgsStart() == numFrameStackmapArgs());
for (int vreg : frame_info_desc.potentially_undefined) {
map->definedness_vars[vreg].locations.push_back(parse_type(BOOL));
}
ASSERT(cur_arg - frameStackmapArgsStart() == numFrameStackmapArgs(), "%d %d %d", cur_arg, frameStackmapArgsStart(),
numFrameStackmapArgs());
}
static int extractScratchOffset(PatchpointInfo* pp, StackMap::Record* r) {
......
......@@ -96,9 +96,13 @@ public:
struct PatchpointInfo {
public:
struct FrameVarInfo {
llvm::StringRef name;
int vreg;
CompilerType* type;
};
struct FrameInfoDesc {
std::vector<FrameVarInfo> vars;
llvm::SmallVector<int, 2> potentially_undefined;
};
private:
CompiledFunction* const parent_cf;
......@@ -106,10 +110,10 @@ private:
int num_ic_stackmap_args;
int num_frame_stackmap_args;
bool is_frame_info_stackmap;
std::vector<FrameVarInfo> frame_vars;
unsigned int id;
FrameInfoDesc frame_info_desc;
PatchpointInfo(CompiledFunction* parent_cf, const ICSetupInfo* icinfo, int num_ic_stackmap_args)
: parent_cf(parent_cf),
icinfo(icinfo),
......@@ -125,7 +129,7 @@ public:
int patchpointSize();
CompiledFunction* parentFunction() { return parent_cf; }
const std::vector<FrameVarInfo>& getFrameVars() { return frame_vars; }
FrameInfoDesc& getFrameDesc() { return frame_info_desc; }
int scratchStackmapArg() { return 0; }
int scratchSize() { return isDeopt() ? MAX_FRAME_SPILLS * sizeof(void*) : 96; }
......@@ -133,7 +137,11 @@ public:
bool isFrameInfoStackmap() const { return is_frame_info_stackmap; }
int numFrameSpillsSupported() const { return isDeopt() ? MAX_FRAME_SPILLS : 0; }
void addFrameVar(llvm::StringRef name, CompilerType* type);
void addFrameVar(int vreg, CompilerType* type) {
frame_info_desc.vars.push_back(FrameVarInfo({.vreg = vreg, .type = type }));
}
void addPotentiallyUndefined(int vreg) { frame_info_desc.potentially_undefined.push_back(vreg); }
void setNumFrameArgs(int num_frame_args) {
assert(num_frame_stackmap_args == -1);
num_frame_stackmap_args = num_frame_args;
......
......@@ -301,8 +301,12 @@ AST_arguments* readItem(pypa::AstArguments& a, InternedStringPool& interned_stri
readVector(ptr->defaults, a.defaults, interned_strings);
ptr->defaults.erase(std::remove(ptr->defaults.begin(), ptr->defaults.end(), nullptr), ptr->defaults.end());
readVector(ptr->args, a.arguments, interned_strings);
ptr->kwarg = readName(a.kwargs, interned_strings);
ptr->vararg = readName(a.args, interned_strings);
InternedString kwarg_name = readName(a.kwargs, interned_strings);
if (kwarg_name.s().size())
ptr->kwarg = new AST_Name(kwarg_name, AST_TYPE::Store, -1, -1);
InternedString vararg_name = readName(a.args, interned_strings);
if (vararg_name.s().size())
ptr->vararg = new AST_Name(vararg_name, AST_TYPE::Store, -1, -1);
return ptr;
}
......
......@@ -176,8 +176,8 @@ private:
virtual bool visit_arguments(AST_arguments* node) {
writeExprVector(node->args);
writeExprVector(node->defaults);
writeString(node->kwarg);
writeString(node->vararg);
writeExpr(node->kwarg);
writeExpr(node->vararg);
return true;
}
virtual bool visit_assert(AST_Assert* node) {
......
......@@ -19,6 +19,7 @@
#include <unordered_map>
#include <vector>
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
......@@ -101,7 +102,9 @@ public:
}
};
llvm::StringMap<LocationTable> names;
llvm::DenseMap<int, LocationTable> vars;
LocationTable generator, passed_closure, created_closure;
llvm::DenseMap<int, LocationTable> definedness_vars;
};
StackMap* parseStackMap();
......
......@@ -329,25 +329,6 @@ public:
}
}
llvm::ArrayRef<StackMap::Record::Location> findLocations(llvm::StringRef name) {
assert(id.type == PythonFrameId::COMPILED);
CompiledFunction* cf = getCF();
uint64_t ip = getId().ip;
assert(ip > cf->code_start);
unsigned offset = ip - cf->code_start;
assert(cf->location_map);
const LocationMap::LocationTable& table = cf->location_map->names[name];
auto entry = table.findEntry(offset);
if (!entry)
return {};
assert(entry->locations.size());
return entry->locations;
}
AST_stmt* getCurrentStatement() {
assert(getFrameInfo()->stmt);
return getFrameInfo()->stmt;
......@@ -870,20 +851,37 @@ DeoptState getDeoptState() {
// We have to detect + ignore any entries for variables that
// could have been defined (so they have entries) but aren't (so the
// entries point to uninitialized memory).
std::unordered_set<std::string> is_undefined;
std::unordered_set<int> is_undefined;
for (const auto& p : cf->location_map->names) {
if (!startswith(p.first(), "!is_defined_"))
continue;
auto readEntry = [&](const LocationMap::LocationTable::LocationEntry* e) {
auto locs = e->locations;
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
for (auto& loc : locs) {
vals.push_back(frame_iter->readLocation(loc));
}
// this returns an owned reference so we don't incref it
Box* v = e->type->deserializeFromFrame(vals);
return v;
};
if (auto e = cf->location_map->generator.findEntry(offset))
d->d[boxString(PASSED_GENERATOR_NAME)] = readEntry(e);
if (auto e = cf->location_map->passed_closure.findEntry(offset))
d->d[boxString(PASSED_CLOSURE_NAME)] = readEntry(e);
if (auto e = cf->location_map->created_closure.findEntry(offset))
d->d[boxString(CREATED_CLOSURE_NAME)] = readEntry(e);
for (const auto& p : cf->location_map->definedness_vars) {
auto e = p.second.findEntry(offset);
if (e) {
auto locs = e->locations;
assert(locs.size() == 1);
uint64_t v = frame_iter->readLocation(locs[0]);
if ((v & 1) == 0)
is_undefined.insert(p.first().substr(12));
Box* b = readEntry(e);
AUTO_DECREF(b);
if (b == Py_False)
is_undefined.insert(p.first);
}
}
......@@ -893,40 +891,23 @@ DeoptState getDeoptState() {
// But deopts are so rare it's not really worth it.
Box** vregs = frame_iter->getFrameInfo()->vregs;
for (const auto& p : cf->md->source->cfg->getVRegInfo().getUserVisibleSymVRegMap()) {
if (is_undefined.count(p.first.s()))
continue;
if (is_undefined.count(p.second))
assert(0);
Box* v = vregs[p.second];
if (!v)
continue;
assert(!d->d.count(p.first.getBox()));
d->d[incref(p.first.getBox())] = incref(v);
d->d[boxInt(p.second)] = incref(v);
}
for (const auto& p : cf->location_map->names) {
if (p.first()[0] == '!')
continue;
if (is_undefined.count(p.first()))
for (const auto& p : cf->location_map->vars) {
if (is_undefined.count(p.first))
continue;
auto e = p.second.findEntry(offset);
if (e) {
auto locs = e->locations;
llvm::SmallVector<uint64_t, 1> vals;
// printf("%s: %s\n", p.first().c_str(), e.type->debugName().c_str());
for (auto& loc : locs) {
vals.push_back(frame_iter->readLocation(loc));
}
// this returns an owned reference so we don't incref it
Box* v = e->type->deserializeFromFrame(vals);
// printf("%s: (pp id %ld) %p\n", p.first().c_str(), e._debug_pp_id, v);
d->d[boxString(p.first())] = v;
}
if (e)
d->d[boxInt(p.first)] = readEntry(e);
}
} else {
abort();
......@@ -1093,6 +1074,10 @@ extern "C" void abort() {
// In case displaying the traceback recursively calls abort:
static bool recursive = false;
if (recursive) {
fprintf(stderr, "Recursively called abort! Make sure to check the stack trace\n");
}
if (!recursive && !IN_SHUTDOWN) {
recursive = true;
Stats::dump();
......
......@@ -256,6 +256,10 @@ void AST_arguments::accept(ASTVisitor* v) {
visitVector(defaults, v);
visitVector(args, v);
if (kwarg)
kwarg->accept(v);
if (vararg)
vararg->accept(v);
}
void AST_Assert::accept(ASTVisitor* v) {
......
......@@ -217,6 +217,7 @@ public:
class AST_alias : public AST {
public:
InternedString name, asname;
int name_vreg = -1, asname_vreg = -1;
virtual void accept(ASTVisitor* v);
......@@ -225,14 +226,14 @@ public:
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::alias;
};
class AST_Name;
class AST_arguments : public AST {
public:
// no lineno, col_offset attributes
std::vector<AST_expr*> args, defaults;
// These are represented as strings, not names; not sure why.
// If they don't exist, the string is empty.
InternedString kwarg, vararg;
AST_Name* kwarg = NULL, * vararg = NULL;
virtual void accept(ASTVisitor* v);
......@@ -1116,7 +1117,7 @@ public:
};
template <typename T> T* ast_cast(AST* node) {
assert(node->type == T::TYPE);
assert(!node || node->type == T::TYPE);
return static_cast<T*>(node);
}
......
......@@ -232,6 +232,9 @@ private:
CFGBlock* exc_dest;
// variable names to store the exception (type, value, traceback) in
InternedString exc_type_name, exc_value_name, exc_traceback_name;
// Similar to did_why: says whether the block might have been jumped-to
bool maybe_taken;
};
// ---------- Member fields ----------
......@@ -517,9 +520,11 @@ private:
return node;
}
void pushJump(CFGBlock* target, bool allow_backedge = false) {
void pushJump(CFGBlock* target, bool allow_backedge = false, int lineno = 0) {
AST_Jump* rtn = new AST_Jump();
rtn->target = target;
rtn->lineno = lineno;
push_back(rtn);
curblock->connectTo(target, allow_backedge);
curblock = nullptr;
......@@ -1007,8 +1012,8 @@ private:
InternedString func_name = internString("<comprehension>");
func->name = func_name;
func->args = new AST_arguments();
func->args->vararg = internString("");
func->args->kwarg = internString("");
func->args->vararg = NULL;
func->args->kwarg = NULL;
scoping_analysis->registerScopeReplacement(node, func); // critical bit
return new AST_MakeFunction(func);
}
......@@ -1574,6 +1579,7 @@ public:
curblock->connectTo(exc_dest);
ExcBlockInfo& exc_info = exc_handlers.back();
exc_info.maybe_taken = true;
curblock = exc_dest;
// TODO: need to clear some temporaries here
......@@ -1613,7 +1619,6 @@ public:
auto tmp = nodeName();
pushAssign(tmp, new AST_MakeClass(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno, 0, true));
return true;
......@@ -1635,7 +1640,6 @@ public:
auto tmp = nodeName();
pushAssign(tmp, new AST_MakeFunction(def));
// is this name mangling correct?
pushAssign(source->mangleName(def->name), makeName(tmp, AST_TYPE::Load, node->lineno, node->col_offset, true));
return true;
......@@ -2266,7 +2270,7 @@ public:
curblock->connectTo(end_false);
curblock = end_true;
pushJump(loop_block, true);
pushJump(loop_block, true, getLastLinenoSub(node->body.back()));
curblock = end_false;
pushJump(else_block);
......@@ -2341,7 +2345,7 @@ public:
InternedString exc_type_name = nodeName("type");
InternedString exc_value_name = nodeName("value");
InternedString exc_traceback_name = nodeName("traceback");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name, false });
for (AST_stmt* subnode : node->body) {
subnode->accept(this);
......@@ -2464,7 +2468,7 @@ public:
InternedString exc_value_name = nodeName("value");
InternedString exc_traceback_name = nodeName("traceback");
InternedString exc_why_name = nodeName("why");
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name });
exc_handlers.push_back({ exc_handler_block, exc_type_name, exc_value_name, exc_traceback_name, false });
CFGBlock* finally_block = cfg->addDeferredBlock();
pushFinallyContinuation(finally_block, exc_why_name);
......@@ -2475,6 +2479,7 @@ public:
break;
}
bool maybe_exception = exc_handlers.back().maybe_taken;
exc_handlers.pop_back();
int did_why = continuations.back().did_why; // bad to just reach in like this
......@@ -2512,16 +2517,18 @@ public:
exitFinallyIf(node, Why::BREAK, exc_why_name);
if (did_why & (1 << Why::CONTINUE))
exitFinallyIf(node, Why::CONTINUE, exc_why_name);
if (maybe_exception) {
CFGBlock* reraise = cfg->addDeferredBlock();
CFGBlock* noexc = makeFinallyCont(Why::EXCEPTION, makeLoad(exc_why_name, node, true), reraise);
cfg->placeBlock(reraise);
curblock = reraise;
pushReraise(getLastLinenoSub(node->finalbody.back()), exc_type_name, exc_value_name, exc_traceback_name);
pushReraise(getLastLinenoSub(node->finalbody.back()), exc_type_name, exc_value_name,
exc_traceback_name);
curblock = noexc;
}
}
return true;
}
......@@ -2585,7 +2592,7 @@ public:
CFGBlock* exc_block = cfg->addDeferredBlock();
exc_block->info = "with_exc";
exc_handlers.push_back({ exc_block, exc_type_name, exc_value_name, exc_traceback_name });
exc_handlers.push_back({ exc_block, exc_type_name, exc_value_name, exc_traceback_name, false });
for (int i = 0; i < node->body.size(); i++) {
node->body[i]->accept(this);
......@@ -2679,13 +2686,16 @@ 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;
enum Step { TrackBlockUsage = 0, UserVisible, CrossBlock, SingleBlockUse } step;
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_arguments(AST_arguments* node) override {
for (AST_expr* d : node->defaults)
d->accept(this);
......@@ -2748,9 +2758,16 @@ public:
}
int assignVReg(InternedString id) {
assert(id.s().size());
auto it = sym_vreg_map.find(id);
if (sym_vreg_map.end() == it) {
sym_vreg_map[id] = next_vreg;
if (!REUSE_VREGS || step == UserVisible || step == CrossBlock) {
assert(next_vreg == vreg_sym_map.size());
vreg_sym_map.push_back(id);
}
return next_vreg++;
}
return it->second;
......@@ -2768,8 +2785,10 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s
for (CFGBlock* b : cfg->blocks) {
visitor.current_block = b;
#if REUSE_VREGS
if (step == AssignVRegsVisitor::SingleBlockUse)
visitor.next_vreg = num_vregs_cross_block;
#endif
if (b == cfg->getStartingBlock()) {
for (auto* name : param_names.arg_names) {
......@@ -2796,7 +2815,13 @@ void VRegInfo::assignVRegs(CFG* cfg, const ParamNames& param_names, ScopeInfo* s
num_vregs = num_vregs_cross_block = visitor.next_vreg;
}
sym_vreg_map = std::move(visitor.sym_vreg_map);
vreg_sym_map = std::move(visitor.vreg_sym_map);
assert(hasVRegsAssigned());
#if REUSE_VREGS
assert(vreg_sym_map.size() == num_vregs_cross_block);
#else
assert(vreg_sym_map.size() == num_vregs);
#endif
}
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names) {
......
......@@ -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,26 +105,48 @@ 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.
// Entries won't exist for all vregs
std::vector<InternedString> vreg_sym_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; }
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());
assert(sym_vreg_map.count(name));
ASSERT(sym_vreg_map.count(name), "%s", name.c_str());
auto it = sym_vreg_map.find(name);
assert(it != sym_vreg_map.end());
assert(it->second != -1);
return it->second;
}
// Not all vregs correspond to a name; many are our compiler-generated variables.
bool vregHasName(int vreg) const { return vreg < num_vregs_cross_block; }
// Testing flag to turn off the "vreg reuse" optimization.
#define REUSE_VREGS 1
InternedString getName(int vreg) const {
assert(hasVRegsAssigned());
assert(vreg >= 0 && vreg < num_vregs);
#if REUSE_VREGS
assert(vregHasName(vreg));
#endif
return vreg_sym_map[vreg];
}
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; }
......@@ -159,6 +201,138 @@ public:
void print(llvm::raw_ostream& stream = llvm::outs());
};
class VRegSet {
private:
// TODO: switch just to a bool*?
std::vector<bool> v;
public:
VRegSet(int num_vregs) : v(num_vregs, false) {}
// TODO: what is the referenc type here?
bool operator[](int vreg) const {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
void set(int vreg) {
assert(vreg >= 0 && vreg < v.size());
v[vreg] = true;
}
int numSet() const {
int r = 0;
for (auto b : v)
if (b)
r++;
return r;
}
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()); }
};
// VRegMap: A compact way of representing a value per vreg.
//
// One thing to note is that every vreg will get a value by default
// (the default value of T()), and fetching an unset vreg will return
// that value.
//
// Iterating will skip over these values though. If you want to see them,
// you can iterate from 0 to numVregs().
template <typename T> class VRegMap {
private:
// TODO: switch just to a T*?
std::vector<T> v;
public:
VRegMap(int num_vregs) : v(num_vregs) {}
T& operator[](int vreg) {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
const T& operator[](int vreg) const {
assert(vreg >= 0 && vreg < v.size());
return v[vreg];
}
void clear() {
int n = v.size();
for (int i = 0; i < n; i++) {
v[i] = T();
}
}
int numSet() {
int n = v.size();
int r = 0;
for (int i = 0; i < n; i++) {
if (v[i] != T())
r++;
}
return r;
}
class iterator {
public:
const VRegMap<T>& map;
int i;
iterator(const VRegMap<T>& map, int i) : map(map), i(i) {}
// TODO: make this skip unset values?
iterator& operator++() {
do {
i++;
} while (i < map.numVregs() && map[i] == T());
return *this;
}
bool operator==(const iterator& rhs) const { return i == rhs.i; }
bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
std::pair<int, const T&> operator*() { return std::pair<int, const T&>(i, map[i]); }
int first() const { return i; }
const T& second() const { return map[i]; }
};
int numVregs() const { return v.size(); }
iterator begin() const {
iterator it = iterator(*this, -1);
++it;
return it;
}
iterator end() const { return iterator(*this, this->v.size()); }
};
class SourceInfo;
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names);
void printCFG(CFG* cfg);
......
......@@ -316,6 +316,7 @@ class BoxedGenerator;
class ICInfo;
class LocationMap;
class JitCodeBlock;
class FrameInfo;
extern std::vector<Box*> constants;
extern std::vector<Box*> late_constants; // constants that should be freed after normal constants
......@@ -346,6 +347,8 @@ public:
// The function pointer to the generated code. For convenience, it can be accessed
// as one of many different types.
// TODO: we instead make these accessor-functions that make sure that the code actually
// matches the C signature that we would return.
union {
Box* (*call)(Box*, Box*, Box*, Box**);
Box* (*closure_call)(BoxedClosure*, Box*, Box*, Box*, Box**);
......@@ -354,6 +357,7 @@ public:
Box* (*call1)(Box*, Box*, Box*, Box*, Box**);
Box* (*call2)(Box*, Box*, Box*, Box*, Box*, Box**);
Box* (*call3)(Box*, Box*, Box*, Box*, Box*, Box*, Box**);
Box* (*call_osr)(BoxedGenerator*, BoxedClosure*, FrameInfo*, Box**);
void* code;
uintptr_t code_start;
};
......@@ -375,7 +379,7 @@ public:
// List of metadata objects for ICs inside this compilation
std::vector<ICInfo*> ics;
CompiledFunction(llvm::Function* func, FunctionSpecialization* spec, void* code, EffortLevel effort,
CompiledFunction(FunctionMetadata* func, FunctionSpecialization* spec, void* code, EffortLevel effort,
ExceptionStyle exception_style, const OSREntryDescriptor* entry_descriptor);
ConcreteCompilerType* getReturnType();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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