Commit 31f263f2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Convert OSR to use vregs

The benefit here is indirect, of letting us get rid of some
of the compatibility shims for moving between vregs and names.
parent 0999d34a
...@@ -462,13 +462,21 @@ PhiAnalysis::PhiAnalysis(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_m ...@@ -462,13 +462,21 @@ PhiAnalysis::PhiAnalysis(VRegMap<DefinednessAnalysis::DefinitionLevel> initial_m
const VRegSet& defined = definedness.getDefinedVregsAtEnd(pred); const VRegSet& defined = definedness.getDefinedVregsAtEnd(pred);
for (int vreg : defined) { for (int vreg : defined) {
if (!required[vreg] && liveness->isLiveAtEnd(vreg, pred)) { if (!required[vreg] && liveness->isLiveAtEnd(vreg, pred)) {
// printf("%d-%d %s\n", pred->idx, block->idx, s.c_str()); // printf("%d-%d %s\n", pred->idx, block->idx, vreg_info.getName(vreg).c_str());
required.set(vreg); required.set(vreg);
} }
} }
} }
} }
if (VERBOSITY() >= 3) {
printf("Phis required at end of %d:", block->idx);
for (auto vreg : required) {
printf(" %s", vreg_info.getName(vreg).c_str());
}
printf("\n");
}
} }
static StatCounter us_phis("us_compiling_analysis_phis"); static StatCounter us_phis("us_compiling_analysis_phis");
...@@ -573,22 +581,13 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry ...@@ -573,22 +581,13 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
initial_map[vreg] = DefinednessAnalysis::Undefined; initial_map[vreg] = DefinednessAnalysis::Undefined;
} }
llvm::StringSet<> potentially_undefined;
for (const auto& p : entry_descriptor->args) { for (const auto& p : entry_descriptor->args) {
if (!startswith(p.first.s(), "!is_defined_")) if (!p.second)
continue; continue;
potentially_undefined.insert(p.first.s().substr(12));
}
for (const auto& p : entry_descriptor->args) { int vreg = p.first;
if (p.first.s()[0] == '!') ASSERT(initial_map[vreg] == DefinednessAnalysis::Undefined, "%d %d", vreg, initial_map[vreg]);
continue; if (entry_descriptor->potentially_undefined[vreg])
if (p.first.s() == PASSED_CLOSURE_NAME || p.first.s() == FRAME_INFO_PTR_NAME
|| p.first.s() == PASSED_GENERATOR_NAME || p.first.s() == CREATED_CLOSURE_NAME)
assert(0);
int vreg = cfg->getVRegInfo().getVReg(p.first);
ASSERT(initial_map[vreg] == DefinednessAnalysis::Undefined, "%s %d", p.first.c_str(), initial_map[vreg]);
if (potentially_undefined.count(p.first.s()))
initial_map[vreg] = DefinednessAnalysis::PotentiallyDefined; initial_map[vreg] = DefinednessAnalysis::PotentiallyDefined;
else else
initial_map[vreg] = DefinednessAnalysis::Defined; initial_map[vreg] = DefinednessAnalysis::Defined;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseSet.h"
#include "core/cfg.h"
#include "core/stringpool.h" #include "core/stringpool.h"
#include "core/types.h" #include "core/types.h"
...@@ -33,68 +34,6 @@ class CFGBlock; ...@@ -33,68 +34,6 @@ class CFGBlock;
class ScopeInfo; class ScopeInfo;
class LivenessBBVisitor; class LivenessBBVisitor;
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++() {
i++;
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 { return iterator(*this, 0); }
iterator end() const { return iterator(*this, this->v.size()); }
};
class LivenessAnalysis { class LivenessAnalysis {
private: private:
CFG* cfg; CFG* cfg;
...@@ -117,62 +56,6 @@ public: ...@@ -117,62 +56,6 @@ public:
class PhiAnalysis; class PhiAnalysis;
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) {
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()); }
};
class DefinednessAnalysis { class DefinednessAnalysis {
public: public:
enum DefinitionLevel { enum DefinitionLevel {
......
...@@ -158,6 +158,7 @@ private: ...@@ -158,6 +158,7 @@ private:
if (VERBOSITY() >= 3) { if (VERBOSITY() >= 3) {
printf("Type of "); printf("Type of ");
fflush(stdout);
print_ast(node); print_ast(node);
printf(" is %s\n", rtn->debugName().c_str()); printf(" is %s\n", rtn->debugName().c_str());
} }
...@@ -790,8 +791,9 @@ public: ...@@ -790,8 +791,9 @@ public:
printf("before:\n"); printf("before:\n");
TypeMap& starting = starting_types.find(block)->second; TypeMap& starting = starting_types.find(block)->second;
for (const auto& p : starting) { for (const auto& p : starting) {
if (!p.second)
continue;
auto name = vreg_info.getName(p.first); auto name = vreg_info.getName(p.first);
ASSERT(p.second, "%s", name.c_str());
printf("%s: %s\n", name.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", name.c_str(), p.second->debugName().c_str());
} }
} }
...@@ -803,14 +805,16 @@ public: ...@@ -803,14 +805,16 @@ public:
printf("before (after):\n"); printf("before (after):\n");
TypeMap& starting = starting_types.find(block)->second; TypeMap& starting = starting_types.find(block)->second;
for (const auto& p : starting) { for (const auto& p : starting) {
if (!p.second)
continue;
auto name = vreg_info.getName(p.first); auto name = vreg_info.getName(p.first);
ASSERT(p.second, "%s", name.c_str());
printf("%s: %s\n", name.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", name.c_str(), p.second->debugName().c_str());
} }
printf("after:\n"); printf("after:\n");
for (const auto& p : ending) { for (const auto& p : ending) {
if (!p.second)
continue;
auto name = vreg_info.getName(p.first); auto name = vreg_info.getName(p.first);
ASSERT(p.second, "%s", name.c_str());
printf("%s: %s\n", name.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", name.c_str(), p.second->debugName().c_str());
} }
} }
...@@ -839,8 +843,9 @@ public: ...@@ -839,8 +843,9 @@ public:
const TypeMap& starting = p.second; const TypeMap& starting = p.second;
for (const auto& p : starting) { for (const auto& p : starting) {
if (!p.second)
continue;
auto name = vreg_info.getName(p.first); auto name = vreg_info.getName(p.first);
ASSERT(p.second, "%s", name.c_str());
printf("%s: %s\n", name.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", name.c_str(), p.second->debugName().c_str());
} }
} }
...@@ -901,12 +906,7 @@ TypeAnalysis* doTypeAnalysis(const OSREntryDescriptor* entry_descriptor, EffortL ...@@ -901,12 +906,7 @@ TypeAnalysis* doTypeAnalysis(const OSREntryDescriptor* entry_descriptor, EffortL
TypeMap initial_types(vreg_info.getTotalNumOfVRegs()); TypeMap initial_types(vreg_info.getTotalNumOfVRegs());
for (auto&& p : entry_descriptor->args) { for (auto&& p : entry_descriptor->args) {
if (p.first.s()[0] == '!') initial_types[p.first] = p.second;
continue;
if (p.first.s() == PASSED_CLOSURE_NAME || p.first.s() == FRAME_INFO_PTR_NAME
|| p.first.s() == PASSED_GENERATOR_NAME || p.first.s() == CREATED_CLOSURE_NAME)
assert(0);
initial_types[vreg_info.getVReg(p.first)] = p.second;
} }
return PropagatingTypeAnalysis::doAnalysis(speculation, scope_info, std::move(initial_types), return PropagatingTypeAnalysis::doAnalysis(speculation, scope_info, std::move(initial_types),
......
...@@ -739,9 +739,12 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -739,9 +739,12 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
found_entry = p.first; 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)? // 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. // 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; static Box* const VAL_UNDEFINED = (Box*)None;
...@@ -751,16 +754,14 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -751,16 +754,14 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
if (!liveness->isLiveAtEnd(vreg, current_block)) if (!liveness->isLiveAtEnd(vreg, current_block))
continue; continue;
InternedString name = source_info->cfg->getVRegInfo().getName(vreg);
Box* val = vregs[vreg]; Box* val = vregs[vreg];
if (phis->isPotentiallyUndefinedAfter(vreg, current_block)) { if (phis->isPotentiallyUndefinedAfter(vreg, current_block)) {
potentially_undefined.set(vreg);
bool is_defined = val != NULL; bool is_defined = val != NULL;
// TODO only mangle once sorted_symbol_table[vreg] = is_defined ? incref(val) : incref(VAL_UNDEFINED);
sorted_symbol_table[getIsDefinedName(name, source_info->getInternedStrings())] = (Box*)is_defined;
sorted_symbol_table[name] = is_defined ? incref(val) : incref(VAL_UNDEFINED);
} else { } else {
ASSERT(val != NULL, "%s", name.c_str()); assert(val != NULL);
sorted_symbol_table[name] = incref(val); sorted_symbol_table[vreg] = incref(val);
} }
} }
...@@ -769,7 +770,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -769,7 +770,7 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
// LLVM has a limit on the number of operands a machine instruction can have (~255), // 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. // 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"); static StatCounter times_osr_cancel("num_osr_cancel_too_many_syms");
times_osr_cancel.log(); times_osr_cancel.log();
return nullptr; return nullptr;
...@@ -778,24 +779,28 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) { ...@@ -778,24 +779,28 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
if (found_entry == nullptr) { if (found_entry == nullptr) {
OSREntryDescriptor* entry = OSREntryDescriptor::create(getMD(), node, CXX); OSREntryDescriptor* entry = OSREntryDescriptor::create(getMD(), node, CXX);
for (auto& it : sorted_symbol_table) { // TODO can we just get rid of this?
if (isIsDefinedName(it.first)) for (auto&& p : sorted_symbol_table) {
entry->args[it.first] = BOOL; if (p.second)
else { entry->args[p.first] = UNKNOWN;
assert(it.first.s()[0] != '!');
entry->args[it.first] = UNKNOWN;
}
} }
entry->potentially_undefined = potentially_undefined;
found_entry = entry; found_entry = entry;
} }
OSRExit exit(found_entry); OSRExit exit(found_entry);
std::vector<Box*> arg_array; std::vector<Box*> arg_array;
arg_array.reserve(sorted_symbol_table.size()); arg_array.reserve(sorted_symbol_table.numSet() + potentially_undefined.numSet());
for (auto& it : sorted_symbol_table) { for (auto&& p : sorted_symbol_table) {
arg_array.push_back(it.second); if (p.second)
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"); UNAVOIDABLE_STAT_TIMER(t0, "us_timer_in_jitted_code");
......
This diff is collapsed.
...@@ -261,7 +261,9 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s ...@@ -261,7 +261,9 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s
if (entry_descriptor && VERBOSITY("irgen") >= 2) { if (entry_descriptor && VERBOSITY("irgen") >= 2) {
for (const auto& p : entry_descriptor->args) { for (const auto& p : entry_descriptor->args) {
ss << p.first.s() << ": " << p.second->debugName() << '\n'; if (!p.second)
continue;
ss << p.first << ": " << p.second->debugName() << '\n';
} }
} }
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "analysis/function_analysis.h" #include "core/cfg.h"
#include "core/stringpool.h" #include "core/stringpool.h"
#include "core/types.h" #include "core/types.h"
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include "core/cfg.h"
#include "core/stringpool.h" #include "core/stringpool.h"
namespace llvm { namespace llvm {
...@@ -32,7 +33,11 @@ struct StackMap; ...@@ -32,7 +33,11 @@ struct StackMap;
class OSREntryDescriptor { class OSREntryDescriptor {
private: private:
OSREntryDescriptor(FunctionMetadata* md, AST_Jump* backedge, ExceptionStyle exception_style) 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); assert(md);
} }
...@@ -40,8 +45,9 @@ public: ...@@ -40,8 +45,9 @@ public:
FunctionMetadata* md; FunctionMetadata* md;
AST_Jump* const backedge; AST_Jump* const backedge;
ExceptionStyle exception_style; ExceptionStyle exception_style;
typedef std::map<InternedString, ConcreteCompilerType*> ArgMap; typedef VRegMap<ConcreteCompilerType*> ArgMap;
ArgMap args; ArgMap args;
VRegSet potentially_undefined;
static OSREntryDescriptor* create(FunctionMetadata* md, AST_Jump* backedge, ExceptionStyle exception_style) { static OSREntryDescriptor* create(FunctionMetadata* md, AST_Jump* backedge, ExceptionStyle exception_style) {
return new OSREntryDescriptor(md, backedge, exception_style); return new OSREntryDescriptor(md, backedge, exception_style);
......
...@@ -191,6 +191,124 @@ public: ...@@ -191,6 +191,124 @@ public:
void print(llvm::raw_ostream& stream = llvm::outs()); 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()); }
};
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++() {
i++;
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 { return iterator(*this, 0); }
iterator end() const { return iterator(*this, this->v.size()); }
};
class SourceInfo; class SourceInfo;
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names); CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names);
void printCFG(CFG* cfg); void printCFG(CFG* cfg);
......
# I think we have some other similar tests to this, but it's hard to find them. # I think we have some other similar tests to this, but it's hard to find them.
# Reopt:
def f(x): def f(x):
if x: if x:
y = 1 y = 1
if '': if '':
pass pass
print y y
for i in xrange(10000): for i in xrange(10000):
f(1) f(1)
...@@ -15,3 +16,23 @@ try: ...@@ -15,3 +16,23 @@ try:
except UnboundLocalError: except UnboundLocalError:
pass pass
# OSR:
s = """
def f(x):
if x:
y = 1
for i in xrange(10000):
pass
print y
"""
exec s
f(1)
exec s
try:
f(0)
assert 0
except UnboundLocalError:
pass
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