Commit b7a886b6 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Partial attempt at enabling dynamic type analysis tiering

In theory it's simple: we just run cheaper type analysis on lower tiers.
In practice it's more complicated, since the different tiers have to
cooperate on the types that they send back and forth.

I fixed up some of the code that didn't expect to receive a type worse
than what it knows to be true.  Ran into an issue where we have to
treat potentially-undefined symbols specially, since we can't do a class
check on them because they probably point to garbage.

Stopped there for now, since this section of the code is horrible and we
need to rewrite the tiering framework anyway.
parent b0e93d19
......@@ -778,9 +778,11 @@ public:
// public entry point:
TypeAnalysis* doTypeAnalysis(CFG* cfg, const SourceInfo::ArgNames& arg_names,
const std::vector<ConcreteCompilerType*>& arg_types,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel::EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info) {
// if (effort == EffortLevel::INTERPRETED) {
// return new NullTypeAnalysis();
//}
return PropagatingTypeAnalysis::doAnalysis(cfg, arg_names, arg_types, speculation, scope_info);
}
}
......@@ -44,7 +44,7 @@ public:
// TypeAnalysis* analyze(CFG *cfg, std::unordered_map<std::string, ConcreteCompilerType*> arg_types);
TypeAnalysis* doTypeAnalysis(CFG* cfg, const SourceInfo::ArgNames& arg_names,
const std::vector<ConcreteCompilerType*>& arg_types,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel::EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation, ScopeInfo* scope_info);
}
......
......@@ -405,6 +405,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
ASSERT(speculated_class, "%s", phi_type->debugName().c_str());
ASSERT(entry_descriptor->args.count("!is_defined_" + p.first) == 0,
"This class-check-creating behavior will segfault if the argument wasn't actually defined!");
llvm::Value* type_check = ConcreteCompilerVariable(p.second, from_arg, true)
.makeClassCheck(*entry_emitter, speculated_class);
if (guard_val) {
......@@ -760,16 +763,63 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList& out_gua
}
for (int i = 0; i < block_guards.size(); i++) {
GuardList::BlockEntryGuard* g = block_guards[i];
GuardList::BlockEntryGuard* guard = block_guards[i];
IREmitter* emitter = emitters[i];
CompilerVariable* unconverted = g->symbol_table[it->first];
ConcreteCompilerVariable* v = unconverted->makeConverted(*emitter, it->second.first);
assert(v);
assert(v->isGrabbed());
ASSERT(phis->count("!is_defined_" + it->first) == 0,
"This class-check-creating behavior will segfault if the argument wasn't actually defined!");
CompilerVariable* unconverted = guard->symbol_table[it->first];
ConcreteCompilerVariable* v;
if (unconverted->canConvertTo(it->second.first)) {
v = unconverted->makeConverted(*emitter, it->second.first);
assert(v);
assert(v->isGrabbed());
} else {
// This path is for handling the case that we did no type analysis in the previous tier,
// but in this tier we know that even in the deopt branch with no speculations, that
// the type is more refined than what we got from the previous tier.
//
// We're going to blindly assume that we're right about what the type should be.
assert(unconverted->getType() == UNKNOWN);
assert(strcmp(bb_type, "deopt") == 0);
ConcreteCompilerVariable* converted = unconverted->makeConverted(*emitter, UNKNOWN);
if (it->second.first->llvmType() == g.llvm_value_type_ptr) {
v = new ConcreteCompilerVariable(it->second.first, converted->getValue(), true);
} else if (it->second.first == FLOAT) {
llvm::Value* unboxed
= emitter->getBuilder()->CreateCall(g.funcs.unboxFloat, converted->getValue());
v = new ConcreteCompilerVariable(FLOAT, unboxed, true);
} else if (it->second.first == INT) {
llvm::Value* unboxed
= emitter->getBuilder()->CreateCall(g.funcs.unboxInt, converted->getValue());
v = new ConcreteCompilerVariable(INT, unboxed, true);
} else {
printf("%s\n", it->second.first->debugName().c_str());
abort();
}
converted->decvref(*emitter);
/*
if (speculated_class == int_cls) {
v = unbox_emitter->getBuilder()->CreateCall(g.funcs.unboxInt, from_arg);
(new ConcreteCompilerVariable(BOXED_INT, from_arg, true))->decvref(*unbox_emitter);
} else if (speculated_class == float_cls) {
v = unbox_emitter->getBuilder()->CreateCall(g.funcs.unboxFloat, from_arg);
(new ConcreteCompilerVariable(BOXED_FLOAT, from_arg, true))->decvref(*unbox_emitter);
} else {
assert(phi_type == typeFromClass(speculated_class));
v = from_arg;
}
*/
}
ASSERT(it->second.first == v->getType(), "");
assert(it->second.first->llvmType() == v->getValue()->getType());
llvm_phi->addIncoming(v->getValue(), offramps[i]);
// TODO not sure if this is right:
......@@ -971,7 +1021,7 @@ CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_
TypeAnalysis::SpeculationLevel speculation_level = TypeAnalysis::NONE;
if (ENABLE_SPECULATION && effort >= EffortLevel::MODERATE)
speculation_level = TypeAnalysis::SOME;
TypeAnalysis* types = doTypeAnalysis(source->cfg, source->arg_names, spec->arg_types, speculation_level,
TypeAnalysis* types = doTypeAnalysis(source->cfg, source->arg_names, spec->arg_types, effort, speculation_level,
source->scoping->getScopeInfoForNode(source->ast));
_t2.split();
......@@ -1010,8 +1060,9 @@ CompiledFunction* doCompile(SourceInfo* source, const OSREntryDescriptor* entry_
assert(deopt_full_blocks.size() || deopt_partial_blocks.size());
irgen_us += _t2.split();
TypeAnalysis* deopt_types = doTypeAnalysis(source->cfg, source->arg_names, spec->arg_types, TypeAnalysis::NONE,
source->scoping->getScopeInfoForNode(source->ast));
TypeAnalysis* deopt_types
= doTypeAnalysis(source->cfg, source->arg_names, spec->arg_types, effort, TypeAnalysis::NONE,
source->scoping->getScopeInfoForNode(source->ast));
_t2.split();
emitBBs(&irstate, "deopt", deopt_guards, guards, deopt_types, NULL, deopt_full_blocks, deopt_partial_blocks);
......
......@@ -47,6 +47,20 @@ extern "C" void gc_compat_free(void* ptr) {
bool recursive = false;
extern "C" void abort() {
static void (*libc_abort)() = (void (*)())dlsym(RTLD_NEXT, "abort");
// Py_FatalError is likely to call abort() itself...
static bool recursive = false;
if (!recursive) {
recursive = true;
Py_FatalError("someone called abort!\n");
}
libc_abort();
__builtin_unreachable();
}
// We may need to hook malloc as well. For now, these definitions serve
// as a reference on how to do that, and also can help with debugging malloc
// usage issues.
......
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