Commit 46c382f8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Fix a bunch of non-determinism issues in the refcounter

parent 9674585f
...@@ -496,7 +496,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -496,7 +496,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
std::unordered_map<CFGBlock*, SymbolTable*> ending_symbol_tables; std::unordered_map<CFGBlock*, SymbolTable*> ending_symbol_tables;
std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables; std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables;
typedef std::unordered_map<InternedString, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable; typedef std::map<InternedString, std::pair<ConcreteCompilerType*, llvm::PHINode*>> PHITable;
std::unordered_map<CFGBlock*, PHITable*> created_phis; std::unordered_map<CFGBlock*, PHITable*> created_phis;
std::unordered_map<CFGBlock*, llvm::SmallVector<IRGenerator::ExceptionState, 2>> incoming_exception_state; std::unordered_map<CFGBlock*, llvm::SmallVector<IRGenerator::ExceptionState, 2>> incoming_exception_state;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseSet.h"
#include "llvm/IR/CFG.h" #include "llvm/IR/CFG.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
...@@ -290,6 +291,69 @@ void addDecrefs(llvm::Value* v, bool nullable, int num_refs, llvm::Instruction* ...@@ -290,6 +291,69 @@ void addDecrefs(llvm::Value* v, bool nullable, int num_refs, llvm::Instruction*
builder.SetInsertPoint(continue_block); builder.SetInsertPoint(continue_block);
} }
// TODO: this should be cleaned up and moved to src/core/
template <typename K, typename V> class OrderedMap {
private:
llvm::DenseMap<K, V> map;
std::vector<K> order;
public:
V& operator[](const K& k) {
if (map.count(k) == 0)
order.push_back(k);
return map[k];
}
const V& get(const K& k) const { return map.find(k)->second; }
size_t size() const {
assert(order.size() == map.size());
return order.size();
}
void clear() {
map.clear();
order.clear();
}
// TODO: this is slow
void erase(const K& k) {
assert(map.count(k));
map.erase(k);
order.erase(std::remove(order.begin(), order.end(), k), order.end());
}
class const_iterator {
private:
const OrderedMap* themap;
int idx;
const_iterator(const OrderedMap* themap, int idx) : themap(themap), idx(idx) {}
public:
std::pair<K, V> operator*() { return *themap->map.find(themap->order[idx]); }
std::pair<K, V> operator->() { return *this; }
bool operator==(const const_iterator& rhs) const {
assert(themap == rhs.themap);
return idx == rhs.idx;
}
bool operator!=(const const_iterator& rhs) const { return !(*this == rhs); }
const_iterator& operator++() {
idx++;
return *this;
}
friend class OrderedMap;
};
size_t count(K& k) const { return map.count(k); }
const_iterator begin() const { return const_iterator(this, 0); }
const_iterator end() const { return const_iterator(this, size()); }
};
static std::vector<llvm::BasicBlock*> computeTraversalOrder(llvm::Function* f) { static std::vector<llvm::BasicBlock*> computeTraversalOrder(llvm::Function* f) {
std::vector<llvm::BasicBlock*> ordering; std::vector<llvm::BasicBlock*> ordering;
llvm::DenseSet<llvm::BasicBlock*> added; llvm::DenseSet<llvm::BasicBlock*> added;
...@@ -329,10 +393,13 @@ static std::vector<llvm::BasicBlock*> computeTraversalOrder(llvm::Function* f) { ...@@ -329,10 +393,13 @@ static std::vector<llvm::BasicBlock*> computeTraversalOrder(llvm::Function* f) {
// The heuristic here is just to make sure to pick one in 0-successor component of the SCC // The heuristic here is just to make sure to pick one in 0-successor component of the SCC
std::vector<std::pair<llvm::BasicBlock*, int>> num_successors; std::vector<std::pair<llvm::BasicBlock*, int>> num_successors;
for (auto&& p : num_successors_added) { // TODO this could be sped up:
if (added.count(p.first)) for (auto&& BB : *f) {
if (!num_successors_added.count(&BB))
continue;
if (added.count(&BB))
continue; continue;
num_successors.push_back(p); num_successors.push_back(std::make_pair(&BB, num_successors_added[&BB]));
} }
std::sort(num_successors.begin(), num_successors.end(), std::sort(num_successors.begin(), num_successors.end(),
...@@ -397,6 +464,7 @@ private: ...@@ -397,6 +464,7 @@ private:
struct BlockComparer { struct BlockComparer {
bool operator()(std::pair<llvm::BasicBlock*, int> lhs, std::pair<llvm::BasicBlock*, int> rhs) { bool operator()(std::pair<llvm::BasicBlock*, int> lhs, std::pair<llvm::BasicBlock*, int> rhs) {
assert(lhs.second != rhs.second);
return lhs.second > rhs.second; return lhs.second > rhs.second;
} }
}; };
...@@ -408,11 +476,13 @@ private: ...@@ -408,11 +476,13 @@ private:
public: public:
BlockOrderer(std::vector<llvm::BasicBlock*> order) { BlockOrderer(std::vector<llvm::BasicBlock*> order) {
for (int i = 0; i < order.size(); i++) { for (int i = 0; i < order.size(); i++) {
// errs() << "DETERMINISM: " << order[i]->getName() << " has priority " << i << '\n';
priority[order[i]] = i; priority[order[i]] = i;
} }
} }
void add(llvm::BasicBlock* b) { void add(llvm::BasicBlock* b) {
// errs() << "DETERMINISM: adding " << b->getName() << '\n';
assert(in_queue.size() == queue.size()); assert(in_queue.size() == queue.size());
if (in_queue.count(b)) if (in_queue.count(b))
return; return;
...@@ -428,6 +498,7 @@ public: ...@@ -428,6 +498,7 @@ public:
} }
llvm::BasicBlock* b = queue.top().first; llvm::BasicBlock* b = queue.top().first;
// errs() << "DETERMINISM: popping " << b->getName() << " (priority " << priority[b] << " \n";
queue.pop(); queue.pop();
assert(in_queue.count(b)); assert(in_queue.count(b));
in_queue.erase(b); in_queue.erase(b);
...@@ -435,15 +506,14 @@ public: ...@@ -435,15 +506,14 @@ public:
} }
}; };
typedef llvm::DenseMap<llvm::Value*, int> BlockMap; typedef OrderedMap<llvm::Value*, int> BlockMap;
bool endingRefsDifferent(const BlockMap& lhs, const BlockMap& rhs) { bool endingRefsDifferent(const BlockMap& lhs, const BlockMap& rhs) {
if (lhs.size() != rhs.size()) if (lhs.size() != rhs.size())
return true; return true;
for (auto&& p : lhs) { for (auto&& p : lhs) {
auto it = rhs.find(p.first); if (rhs.count(p.first) == 0)
if (it == rhs.end())
return true; return true;
if (p.second != it->second) if (p.second != rhs.get(p.first))
return true; return true;
} }
return false; return false;
...@@ -556,8 +626,8 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -556,8 +626,8 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
// We do a backwards scan and starting/ending here refers to the scan, not the instruction sequence. // We do a backwards scan and starting/ending here refers to the scan, not the instruction sequence.
// So "starting_refs" are the refs that are inherited, ie the refstate at the end of the basic block. // So "starting_refs" are the refs that are inherited, ie the refstate at the end of the basic block.
// "ending_refs" are the refs we calculated, which corresponds to the refstate at the beginning of the block. // "ending_refs" are the refs we calculated, which corresponds to the refstate at the beginning of the block.
llvm::DenseMap<llvm::Value*, int> starting_refs; BlockMap starting_refs;
llvm::DenseMap<llvm::Value*, int> ending_refs; BlockMap ending_refs;
llvm::SmallVector<RefOp, 4> increfs; llvm::SmallVector<RefOp, 4> increfs;
llvm::SmallVector<RefOp, 4> decrefs; llvm::SmallVector<RefOp, 4> decrefs;
...@@ -570,6 +640,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -570,6 +640,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
} }
while (llvm::BasicBlock* bb = orderer.pop()) { while (llvm::BasicBlock* bb = orderer.pop()) {
// errs() << "DETERMINISM: Processing " << bb->getName() << '\n';
llvm::BasicBlock& BB = *bb; llvm::BasicBlock& BB = *bb;
#if 0 #if 0
...@@ -589,7 +660,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -589,7 +660,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
bool firsttime = (states.count(&BB) == 0); bool firsttime = (states.count(&BB) == 0);
RefState& state = states[&BB]; RefState& state = states[&BB];
llvm::DenseMap<llvm::Value*, int> orig_ending_refs = std::move(state.ending_refs); BlockMap orig_ending_refs = std::move(state.ending_refs);
state.starting_refs.clear(); state.starting_refs.clear();
state.ending_refs.clear(); state.ending_refs.clear();
...@@ -603,26 +674,34 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -603,26 +674,34 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
successors.push_back(SBB); successors.push_back(SBB);
} }
if (successors.size()) { if (successors.size()) {
llvm::DenseSet<llvm::Value*> tracked_values; std::vector<llvm::Value*> tracked_values;
std::unordered_set<llvm::Value*> in_tracked_values;
for (auto SBB : successors) { for (auto SBB : successors) {
// errs() << "DETERMINISM: successor " << SBB->getName() << '\n';
assert(states.count(SBB)); assert(states.count(SBB));
for (auto&& p : states[SBB].ending_refs) { for (auto&& p : states[SBB].ending_refs) {
// errs() << "DETERMINISM: looking at ref " << p.first->getName() << '\n';
assert(p.second > 0); assert(p.second > 0);
tracked_values.insert(p.first); if (!in_tracked_values.count(p.first)) {
in_tracked_values.insert(p.first);
tracked_values.push_back(p.first);
}
} }
} }
// size_t hash = 0;
for (auto v : tracked_values) { for (auto v : tracked_values) {
// hash = hash * 31 + std::hash<llvm::StringRef>()(v->getName());
assert(rt->vars.count(v)); assert(rt->vars.count(v));
auto refstate = rt->vars[v]; auto refstate = rt->vars[v];
int min_refs = 1000000000; int min_refs = 1000000000;
for (auto SBB : successors) { for (auto SBB : successors) {
auto it = states[SBB].ending_refs.find(v); auto&& ending_refs = states[SBB].ending_refs;
if (it != states[SBB].ending_refs.end()) { if (ending_refs.count(v)) {
//llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName() << ", have " //llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName() << ", have "
//<< it->second << " refs on " << *v << '\n'; //<< it->second << " refs on " << *v << '\n';
min_refs = std::min(it->second, min_refs); min_refs = std::min(ending_refs[v], min_refs);
} else { } else {
//llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName() //llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName()
//<< ", have 0 (missing) refs on " << *v << '\n'; //<< ", have 0 (missing) refs on " << *v << '\n';
...@@ -634,11 +713,10 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -634,11 +713,10 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
min_refs = std::max(1, min_refs); min_refs = std::max(1, min_refs);
for (auto SBB : successors) { for (auto SBB : successors) {
auto it = states[SBB].ending_refs.find(v);
int this_refs = 0; int this_refs = 0;
if (it != states[SBB].ending_refs.end()) { auto&& ending_refs = states[SBB].ending_refs;
this_refs = it->second; if (ending_refs.count(v))
} this_refs = ending_refs[v];
if (this_refs > min_refs) { if (this_refs > min_refs) {
//llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName() << ", need to add " //llvm::outs() << "Going from " << BB.getName() << " to " << SBB->getName() << ", need to add "
...@@ -655,6 +733,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -655,6 +733,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
else else
assert(state.starting_refs.count(v) == 0); assert(state.starting_refs.count(v) == 0);
} }
// errs() << "DETERMINISM: tracked value name hash: " << hash << '\n';
} }
state.ending_refs = state.starting_refs; state.ending_refs = state.starting_refs;
...@@ -669,7 +748,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -669,7 +748,7 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
continue; continue;
llvm::DenseMap<llvm::Value*, int> num_consumed_by_inst; llvm::DenseMap<llvm::Value*, int> num_consumed_by_inst;
llvm::DenseMap<llvm::Value*, int> num_times_as_op; OrderedMap<llvm::Value*, int> num_times_as_op;
for (auto v : rt->refs_consumed[&I]) { for (auto v : rt->refs_consumed[&I]) {
num_consumed_by_inst[v]++; num_consumed_by_inst[v]++;
...@@ -733,16 +812,25 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -733,16 +812,25 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
} }
} }
// size_t hash = 0;
// Handle variables that were defined in this BB: // Handle variables that were defined in this BB:
for (auto&& p : rt->vars) { // TODO shouldn't have to iterate over all instructions in the function
llvm::Instruction* inst = llvm::dyn_cast<llvm::Instruction>(p.first); for (auto&& II : llvm::inst_range(f)) {
if (!inst) //llvm::Instruction* inst = llvm::dyn_cast<llvm::Instruction>(p.first);
//if (!inst)
//continue;
llvm::Instruction* inst = &II;
if (!rt->vars.count(inst))
continue; continue;
auto&& rstate = rt->vars[inst];
// hash = hash * 31 + std::hash<llvm::StringRef>()(inst->getName());
// Invokes are special. Handle them here by treating them as if they happened in their normal-dest block. // Invokes are special. Handle them here by treating them as if they happened in their normal-dest block.
llvm::InvokeInst* ii = llvm::dyn_cast<llvm::InvokeInst>(inst); llvm::InvokeInst* ii = llvm::dyn_cast<llvm::InvokeInst>(inst);
if ((!ii && inst->getParent() == &BB) || (ii && ii->getNormalDest() == &BB)) { if ((!ii && inst->getParent() == &BB) || (ii && ii->getNormalDest() == &BB)) {
int starting_refs = (p.second.reftype == RefType::OWNED ? 1 : 0); int starting_refs = (rstate.reftype == RefType::OWNED ? 1 : 0);
if (state.ending_refs[inst] != starting_refs) { if (state.ending_refs[inst] != starting_refs) {
llvm::Instruction* insertion_pt = NULL; llvm::Instruction* insertion_pt = NULL;
llvm::BasicBlock* insertion_block = NULL, *insertion_from_block = NULL; llvm::BasicBlock* insertion_block = NULL, *insertion_from_block = NULL;
...@@ -757,19 +845,20 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -757,19 +845,20 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
} }
if (state.ending_refs[inst] < starting_refs) { if (state.ending_refs[inst] < starting_refs) {
assert(p.second.reftype == RefType::OWNED); assert(rstate.reftype == RefType::OWNED);
state.decrefs.push_back( state.decrefs.push_back(
RefOp({ inst, p.second.nullable, starting_refs - state.ending_refs[inst], insertion_pt, RefOp({ inst, rstate.nullable, starting_refs - state.ending_refs[inst], insertion_pt,
insertion_block, insertion_from_block })); insertion_block, insertion_from_block }));
} else { } else {
state.increfs.push_back( state.increfs.push_back(
RefOp({ inst, p.second.nullable, state.ending_refs[inst] - starting_refs, insertion_pt, RefOp({ inst, rstate.nullable, state.ending_refs[inst] - starting_refs, insertion_pt,
insertion_block, insertion_from_block })); insertion_block, insertion_from_block }));
} }
} }
state.ending_refs.erase(inst); state.ending_refs.erase(inst);
} }
} }
// errs() << "DETERMINISM: rt.vars name hash: " << hash << '\n';
// If this is the entry block, finish dealing with the ref state rather than handing off to a predecessor // If this is the entry block, finish dealing with the ref state rather than handing off to a predecessor
if (&BB == &BB.getParent()->front()) { if (&BB == &BB.getParent()->front()) {
...@@ -806,6 +895,10 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) { ...@@ -806,6 +895,10 @@ void RefcountTracker::addRefcounts(IRGenState* irstate) {
orderer.add(SBB); orderer.add(SBB);
} }
} }
// for (auto&& p : state.ending_refs) {
// errs() << "DETERMINISM: ending ref: " << p.first->getName() << '\n';
//}
} }
ASSERT(states.size() == f->size(), "We didn't process all nodes..."); ASSERT(states.size() == f->size(), "We didn't process all nodes...");
......
...@@ -590,8 +590,8 @@ AST_Module* read_module(BufferedReader* reader) { ...@@ -590,8 +590,8 @@ AST_Module* read_module(BufferedReader* reader) {
AST_Module* rtn = new AST_Module(reader->createInternedPool()); AST_Module* rtn = new AST_Module(reader->createInternedPool());
readStmtVector(rtn->body, reader); readStmtVector(rtn->body, reader);
rtn->col_offset = -1; rtn->col_offset = 0;
rtn->lineno = -1; rtn->lineno = 0;
return rtn; return rtn;
} }
......
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