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
const VRegSet& defined = definedness.getDefinedVregsAtEnd(pred);
for (int vreg : defined) {
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);
}
}
}
}
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");
......@@ -573,22 +581,13 @@ std::unique_ptr<PhiAnalysis> computeRequiredPhis(const OSREntryDescriptor* entry
initial_map[vreg] = DefinednessAnalysis::Undefined;
}
llvm::StringSet<> potentially_undefined;
for (const auto& p : entry_descriptor->args) {
if (!startswith(p.first.s(), "!is_defined_"))
if (!p.second)
continue;
potentially_undefined.insert(p.first.s().substr(12));
}
for (const auto& p : entry_descriptor->args) {
if (p.first.s()[0] == '!')
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);
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()))
int vreg = p.first;
ASSERT(initial_map[vreg] == DefinednessAnalysis::Undefined, "%d %d", vreg, initial_map[vreg]);
if (entry_descriptor->potentially_undefined[vreg])
initial_map[vreg] = DefinednessAnalysis::PotentiallyDefined;
else
initial_map[vreg] = DefinednessAnalysis::Defined;
......
......@@ -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"
......@@ -33,68 +34,6 @@ class CFGBlock;
class ScopeInfo;
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 {
private:
CFG* cfg;
......@@ -117,62 +56,6 @@ public:
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 {
public:
enum DefinitionLevel {
......
......@@ -158,6 +158,7 @@ private:
if (VERBOSITY() >= 3) {
printf("Type of ");
fflush(stdout);
print_ast(node);
printf(" is %s\n", rtn->debugName().c_str());
}
......@@ -790,8 +791,9 @@ public:
printf("before:\n");
TypeMap& starting = starting_types.find(block)->second;
for (const auto& p : starting) {
if (!p.second)
continue;
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());
}
}
......@@ -803,14 +805,16 @@ public:
printf("before (after):\n");
TypeMap& starting = starting_types.find(block)->second;
for (const auto& p : starting) {
if (!p.second)
continue;
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("after:\n");
for (const auto& p : ending) {
if (!p.second)
continue;
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());
}
}
......@@ -839,8 +843,9 @@ public:
const TypeMap& starting = p.second;
for (const auto& p : starting) {
if (!p.second)
continue;
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());
}
}
......@@ -901,12 +906,7 @@ TypeAnalysis* doTypeAnalysis(const OSREntryDescriptor* entry_descriptor, EffortL
TypeMap initial_types(vreg_info.getTotalNumOfVRegs());
for (auto&& p : entry_descriptor->args) {
if (p.first.s()[0] == '!')
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;
initial_types[p.first] = p.second;
}
return PropagatingTypeAnalysis::doAnalysis(speculation, scope_info, std::move(initial_types),
......
......@@ -739,9 +739,12 @@ 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;
......@@ -751,16 +754,14 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
if (!liveness->isLiveAtEnd(vreg, current_block))
continue;
InternedString name = source_info->cfg->getVRegInfo().getName(vreg);
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);
}
}
......@@ -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),
// 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;
......@@ -778,24 +779,28 @@ Box* ASTInterpreter::doOSR(AST_Jump* node) {
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 {
assert(it.first.s()[0] != '!');
entry->args[it.first] = UNKNOWN;
}
// TODO can we just get rid of this?
for (auto&& p : sorted_symbol_table) {
if (p.second)
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) {
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");
......
......@@ -286,15 +286,10 @@ static std::vector<std::pair<CFGBlock*, CFGBlock*>> computeBlockTraversalOrder(c
return rtn;
}
static ConcreteCompilerType* getTypeAtBlockStart(TypeAnalysis* types, InternedString name, const VRegInfo& vreg_info,
CFGBlock* block) {
if (isIsDefinedName(name))
return BOOL;
else {
// This could crash if we call getTypeAtBlockStart on something that doesn't have a type or vreg.
// Luckily it looks like we don't do that.
return types->getTypeAtBlockStart(vreg_info.getVReg(name), block);
}
static ConcreteCompilerType* getTypeAtBlockStart(TypeAnalysis* types, int vreg, CFGBlock* block) {
// This could crash if we call getTypeAtBlockStart on something that doesn't have a type or vreg.
// Luckily it looks like we don't do that.
return types->getTypeAtBlockStart(vreg, block);
}
llvm::Value* handlePotentiallyUndefined(ConcreteCompilerVariable* is_defined_var, llvm::Type* rtn_type,
......@@ -377,7 +372,8 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// the function entry block, where we add the type guards [no guards anymore]
llvm::BasicBlock* osr_entry_block = NULL;
llvm::BasicBlock* osr_unbox_block_end = NULL; // the block after type guards where we up/down-convert things
std::unordered_map<InternedString, ConcreteCompilerVariable*>* osr_syms = NULL; // syms after conversion
VRegMap<ConcreteCompilerVariable*> osr_syms(num_vregs);
VRegMap<llvm::Value*> osr_definedness(num_vregs);
if (entry_descriptor != NULL) {
llvm::BasicBlock* osr_unbox_block = llvm::BasicBlock::Create(g.context, "osr_unbox", irstate->getLLVMFunction(),
&irstate->getLLVMFunction()->getEntryBlock());
......@@ -385,8 +381,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
&irstate->getLLVMFunction()->getEntryBlock());
assert(&irstate->getLLVMFunction()->getEntryBlock() == osr_entry_block);
osr_syms = new std::unordered_map<InternedString, ConcreteCompilerVariable*>();
auto initial_syms = new std::unordered_map<InternedString, CompilerVariable*>();
VRegMap<CompilerVariable*> initial_syms(num_vregs);
// llvm::BranchInst::Create(llvm_entry_blocks[entry_descriptor->backedge->target->idx], entry_block);
llvm::BasicBlock* osr_entry_block_end = osr_entry_block;
......@@ -418,6 +413,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
int arg_num = -1;
for (const auto& p : entry_descriptor->args) {
if (!p.second)
continue;
llvm::Value* from_arg;
arg_num++;
......@@ -442,12 +440,12 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
assert(from_arg->getType() == p.second->llvmType());
ConcreteCompilerType* phi_type;
phi_type = getTypeAtBlockStart(types, p.first, vreg_info, target_block);
phi_type = getTypeAtBlockStart(types, p.first, target_block);
irstate->getRefcounts()->setType(from_arg, RefType::BORROWED);
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(p.second, from_arg);
(*initial_syms)[p.first] = var;
initial_syms[p.first] = var;
// It's possible to OSR into a version of the function with a higher speculation level;
// this means that the types of the OSR variables are potentially higher (more unspecialized)
......@@ -469,19 +467,31 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
phi_type->debugName().c_str());
}
if (VERBOSITY("irgen") >= 2)
v->setName("prev_" + p.first.s());
if (VERBOSITY("irgen") >= 2) {
v->setName("prev_" + vreg_info.getName(p.first).s());
}
osr_syms[p.first] = new ConcreteCompilerVariable(phi_type, v);
}
(*osr_syms)[p.first] = new ConcreteCompilerVariable(phi_type, v);
for (int vreg : entry_descriptor->potentially_undefined) {
arg_num++;
llvm::Value* ptr = entry_emitter->getBuilder()->CreateConstGEP1_32(passed_vars, arg_num);
ptr = entry_emitter->getBuilder()->CreateBitCast(ptr, BOOL->llvmType()->getPointerTo());
llvm::Value* from_arg = entry_emitter->getBuilder()->CreateLoad(ptr);
osr_definedness[vreg] = from_arg;
// osr_definedness[vreg] = getConstantInt(0, BOOL->llvmType());
}
entry_emitter->getBuilder()->CreateBr(osr_unbox_block);
unbox_emitter->getBuilder()->CreateBr(llvm_entry_blocks[entry_descriptor->backedge->target]);
for (const auto& p : *initial_syms) {
delete p.second;
for (const auto& p : initial_syms) {
if (p.second)
delete p.second;
}
delete initial_syms;
}
// In a similar vein, we need to keep track of the exit blocks for each cfg block,
......@@ -611,41 +621,31 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
irstate->setupFrameInfoVarOSR(osr_frame_info_arg);
for (const auto& vreg : entry_descriptor->potentially_undefined) {
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(BOOL->llvmType(), block->predecessors.size() + 1);
generator->giveDefinednessVar(vreg, phi);
(*definedness_phis)[vreg] = phi;
}
for (const auto& p : entry_descriptor->args) {
assert(p.first.s() != FRAME_INFO_PTR_NAME);
assert(p.first.s() != PASSED_CLOSURE_NAME);
assert(p.first.s() != CREATED_CLOSURE_NAME);
assert(p.first.s() != PASSED_GENERATOR_NAME);
if (p.first.s()[0] == '!') {
assert(startswith(p.first.s(), "!is_defined_"));
assert(p.second == BOOL);
auto base_name = source->getInternedStrings().get(p.first.s().substr(12));
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(BOOL->llvmType(),
block->predecessors.size() + 1, p.first.s());
int vreg = vreg_info.getVReg(base_name);
generator->giveDefinednessVar(vreg, phi);
(*definedness_phis)[vreg] = phi;
} else {
int vreg = vreg_info.getVReg(p.first);
if (!p.second)
continue;
ConcreteCompilerType* analyzed_type = getTypeAtBlockStart(types, p.first, vreg_info, block);
int vreg = p.first;
// printf("For %s, given %s, analyzed for %s\n", p.first.c_str(), p.second->debugName().c_str(),
// analyzed_type->debugName().c_str());
ConcreteCompilerType* analyzed_type = getTypeAtBlockStart(types, p.first, block);
llvm::PHINode* phi = emitter->getBuilder()->CreatePHI(analyzed_type->llvmType(),
block->predecessors.size() + 1, p.first.s());
if (analyzed_type->getBoxType() == analyzed_type) {
irstate->getRefcounts()->setType(phi, RefType::OWNED);
}
// printf("For %s, given %s, analyzed for %s\n", p.first.c_str(), p.second->debugName().c_str(),
// analyzed_type->debugName().c_str());
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(analyzed_type, phi);
generator->giveLocalSymbol(vreg, var);
(*phis)[vreg] = std::make_pair(analyzed_type, phi);
llvm::PHINode* phi
= emitter->getBuilder()->CreatePHI(analyzed_type->llvmType(), block->predecessors.size() + 1);
if (analyzed_type->getBoxType() == analyzed_type) {
irstate->getRefcounts()->setType(phi, RefType::OWNED);
}
ConcreteCompilerVariable* var = new ConcreteCompilerVariable(analyzed_type, phi);
generator->giveLocalSymbol(vreg, var);
(*phis)[vreg] = std::make_pair(analyzed_type, phi);
}
} else if (pred == NULL) {
assert(traversal_order.size() < cfg->blocks.size());
......@@ -673,7 +673,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
for (const InternedString& s : names) {
// printf("adding guessed phi for %s\n", s.c_str());
ConcreteCompilerType* type = getTypeAtBlockStart(types, s, vreg_info, block);
ConcreteCompilerType* type = getTypeAtBlockStart(types, s, block);
llvm::PHINode* phi
= emitter->getBuilder()->CreatePHI(type->llvmType(), block->predecessors.size(), s.s());
if (type->getBoxType() == type) {
......@@ -875,12 +875,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
if (this_is_osr_entry) {
int nondefined_syms = 0;
for (auto&& p : *osr_syms) {
if (p.first.s()[0] != '!')
nondefined_syms++;
}
assert(nondefined_syms == phis->numSet());
assert(osr_syms.numSet() == phis->numSet());
}
#endif // end checking phi agreement.
......@@ -920,15 +915,16 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
if (this_is_osr_entry) {
ConcreteCompilerVariable* v;
if (!is_defined_name)
v = (*osr_syms)[vreg_info.getName(vreg)];
else
v = (*osr_syms)[getIsDefinedName(vreg_info.getName(vreg), source->getInternedStrings())];
assert(v);
ASSERT(phi_type == phi_type, "");
llvm_phi->addIncoming(v->getValue(), osr_unbox_block_end);
if (!is_defined_name) {
ConcreteCompilerVariable* v = osr_syms[vreg];
assert(v);
ASSERT(v->getType() == phi_type, "");
llvm_phi->addIncoming(v->getValue(), osr_unbox_block_end);
} else {
llvm::Value* v = osr_definedness[vreg];
assert(v);
llvm_phi->addIncoming(v, osr_unbox_block_end);
}
}
};
......@@ -962,10 +958,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
}
if (entry_descriptor) {
for (const auto& p : *osr_syms) {
for (const auto& p : osr_syms) {
delete p.second;
}
delete osr_syms;
}
}
......
......@@ -261,7 +261,9 @@ 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';
if (!p.second)
continue;
ss << p.first << ": " << p.second->debugName() << '\n';
}
}
......
......@@ -21,7 +21,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/IR/Instructions.h"
#include "analysis/function_analysis.h"
#include "core/cfg.h"
#include "core/stringpool.h"
#include "core/types.h"
......
......@@ -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);
......
......@@ -191,6 +191,124 @@ 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()); }
};
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;
CFG* computeCFG(SourceInfo* source, std::vector<AST_stmt*> body, const ParamNames& param_names);
void printCFG(CFG* cfg);
......
# I think we have some other similar tests to this, but it's hard to find them.
# Reopt:
def f(x):
if x:
y = 1
if '':
pass
print y
y
for i in xrange(10000):
f(1)
......@@ -15,3 +16,23 @@ try:
except UnboundLocalError:
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