Commit 6831ec0a authored by Kevin Modzelewski's avatar Kevin Modzelewski

Switch all graph work to be based on Blocks, not their indices

This means we can have non-consecutive block indices, which
is a prereq for things like merging blocks.
Not sure how worth it this was
parent e94df26f
...@@ -43,8 +43,8 @@ typename BBAnalyzer<T>::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer<T> & ...@@ -43,8 +43,8 @@ typename BBAnalyzer<T>::AllMap computeFixedPoint(CFG* cfg, const BBAnalyzer<T> &
std::vector<CFGBlock*> q; std::vector<CFGBlock*> q;
states.insert(make_pair(cfg->blocks[0], Map())); states.insert(make_pair(cfg->getStartingBlock(), Map()));
q.push_back(cfg->blocks[0]); q.push_back(cfg->getStartingBlock());
while (q.size()) { while (q.size()) {
CFGBlock *block = q.back(); CFGBlock *block = q.back();
......
...@@ -120,9 +120,10 @@ class DefinednessBBAnalyzer : public BBAnalyzer<DefinednessAnalysis::DefinitionL ...@@ -120,9 +120,10 @@ class DefinednessBBAnalyzer : public BBAnalyzer<DefinednessAnalysis::DefinitionL
private: private:
typedef DefinednessAnalysis::DefinitionLevel DefinitionLevel; typedef DefinednessAnalysis::DefinitionLevel DefinitionLevel;
CFG* cfg;
AST_arguments* arguments; AST_arguments* arguments;
public: public:
DefinednessBBAnalyzer(AST_arguments* arguments) : arguments(arguments) { DefinednessBBAnalyzer(CFG* cfg, AST_arguments* arguments) : cfg(cfg), arguments(arguments) {
} }
virtual DefinitionLevel merge(DefinitionLevel from, DefinitionLevel into) const { virtual DefinitionLevel merge(DefinitionLevel from, DefinitionLevel into) const {
...@@ -225,7 +226,7 @@ void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const { ...@@ -225,7 +226,7 @@ void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const {
for (int i = 0; i < block->body.size(); i++) { for (int i = 0; i < block->body.size(); i++) {
block->body[i]->accept(&visitor); block->body[i]->accept(&visitor);
} }
if (block->idx == 0 && arguments) { if (block == cfg->getStartingBlock() && arguments) {
arguments->accept(&visitor); arguments->accept(&visitor);
} }
...@@ -238,7 +239,7 @@ void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const { ...@@ -238,7 +239,7 @@ void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const {
} }
DefinednessAnalysis::DefinednessAnalysis(AST_arguments *args, CFG* cfg, ScopeInfo *scope_info) : scope_info(scope_info) { DefinednessAnalysis::DefinednessAnalysis(AST_arguments *args, CFG* cfg, ScopeInfo *scope_info) : scope_info(scope_info) {
results = computeFixedPoint(cfg, DefinednessBBAnalyzer(args), false); results = computeFixedPoint(cfg, DefinednessBBAnalyzer(cfg, args), false);
for (auto p : results) { for (auto p : results) {
RequiredSet required; RequiredSet required;
...@@ -267,9 +268,7 @@ const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(C ...@@ -267,9 +268,7 @@ const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(C
PhiAnalysis::PhiAnalysis(AST_arguments* args, CFG* cfg, LivenessAnalysis *liveness, ScopeInfo *scope_info) : PhiAnalysis::PhiAnalysis(AST_arguments* args, CFG* cfg, LivenessAnalysis *liveness, ScopeInfo *scope_info) :
definedness(args, cfg, scope_info), liveness(liveness) { definedness(args, cfg, scope_info), liveness(liveness) {
for (int i = 0; i < cfg->blocks.size(); i++) { for (CFGBlock *block : cfg->blocks) {
CFGBlock *block = cfg->blocks[i];
RequiredSet required; RequiredSet required;
if (block->predecessors.size() < 2) if (block->predecessors.size() < 2)
continue; continue;
......
...@@ -73,7 +73,7 @@ static BoxedClass* simpleCallSpeculation(AST_Call* node, CompilerType* rtn_type, ...@@ -73,7 +73,7 @@ static BoxedClass* simpleCallSpeculation(AST_Call* node, CompilerType* rtn_type,
} }
typedef std::unordered_map<std::string, CompilerType*> TypeMap; typedef std::unordered_map<std::string, CompilerType*> TypeMap;
typedef std::unordered_map<int, TypeMap> AllTypeMap; typedef std::unordered_map<CFGBlock*, TypeMap> AllTypeMap;
typedef std::unordered_map<AST_expr*, CompilerType*> ExprTypeMap; typedef std::unordered_map<AST_expr*, CompilerType*> ExprTypeMap;
typedef std::unordered_map<AST_expr*, BoxedClass*> TypeSpeculations; typedef std::unordered_map<AST_expr*, BoxedClass*> TypeSpeculations;
class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor { class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
...@@ -479,7 +479,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis { ...@@ -479,7 +479,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
return getTypeAtBlockStart(name, block->successors[0]); return getTypeAtBlockStart(name, block->successors[0]);
} }
virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string &name, CFGBlock* block) { virtual ConcreteCompilerType* getTypeAtBlockStart(const std::string &name, CFGBlock* block) {
CompilerType *base = starting_types[block->idx][name]; CompilerType *base = starting_types[block][name];
ASSERT(base != NULL, "%s %d", name.c_str(), block->idx); ASSERT(base != NULL, "%s %d", name.c_str(), block->idx);
ConcreteCompilerType *rtn = base->getConcreteType(); ConcreteCompilerType *rtn = base->getConcreteType();
...@@ -538,7 +538,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis { ...@@ -538,7 +538,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
assert(arg_names.size() == arg_types.size()); assert(arg_names.size() == arg_types.size());
{ {
TypeMap &initial_types = starting_types[0]; TypeMap &initial_types = starting_types[cfg->getStartingBlock()];
for (int i = 0; i < arg_names.size(); i++) { for (int i = 0; i < arg_names.size(); i++) {
AST_expr* arg = arg_names[i]; AST_expr* arg = arg_names[i];
assert(arg->type == AST_TYPE::Name); assert(arg->type == AST_TYPE::Name);
...@@ -547,36 +547,34 @@ class PropagatingTypeAnalysis : public TypeAnalysis { ...@@ -547,36 +547,34 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
} }
} }
std::unordered_set<int> in_queue; std::unordered_set<CFGBlock*> in_queue;
std::deque<int> queue; std::deque<CFGBlock*> queue;
queue.push_back(0); queue.push_back(cfg->getStartingBlock());
while (queue.size()) { while (queue.size()) {
int block_id = queue.front(); CFGBlock *block = queue.front();
queue.pop_front(); queue.pop_front();
in_queue.erase(block_id); in_queue.erase(block);
CFGBlock *block = cfg->blocks[block_id];
TypeMap ending; TypeMap ending;
if (VERBOSITY("types")) { if (VERBOSITY("types")) {
printf("processing types for block %d\n", block_id); printf("processing types for block %d\n", block->idx);
} }
if (VERBOSITY("types") >= 2) { if (VERBOSITY("types") >= 2) {
printf("before:\n"); printf("before:\n");
TypeMap &starting = starting_types[block_id]; TypeMap &starting = starting_types[block];
for (auto p : starting) { for (auto p : starting) {
ASSERT(p.second, "%s", p.first.c_str()); ASSERT(p.second, "%s", p.first.c_str());
printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str());
} }
} }
BasicBlockTypePropagator::propagate(block, starting_types[block_id], ending, expr_types, type_speculations, speculation, scope_info); BasicBlockTypePropagator::propagate(block, starting_types[block], ending, expr_types, type_speculations, speculation, scope_info);
if (VERBOSITY("types") >= 2) { if (VERBOSITY("types") >= 2) {
printf("before (after):\n"); printf("before (after):\n");
TypeMap &starting = starting_types[block_id]; TypeMap &starting = starting_types[block];
for (auto p : starting) { for (auto p : starting) {
ASSERT(p.second, "%s", p.first.c_str()); ASSERT(p.second, "%s", p.first.c_str());
printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str());
...@@ -589,21 +587,20 @@ class PropagatingTypeAnalysis : public TypeAnalysis { ...@@ -589,21 +587,20 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
} }
for (int i = 0; i < block->successors.size(); i++) { for (int i = 0; i < block->successors.size(); i++) {
int next_id = block->successors[i]->idx; CFGBlock *next_block = block->successors[i];
bool first = (starting_types.count(next_id) == 0); bool first = (starting_types.count(next_block) == 0);
bool changed = merge(ending, starting_types[next_id]); bool changed = merge(ending, starting_types[next_block]);
if ((first || changed) && in_queue.insert(next_id).second) { if ((first || changed) && in_queue.insert(next_block).second) {
queue.push_back(next_id); queue.push_back(next_block);
} }
} }
} }
if (VERBOSITY("types") >= 2) { if (VERBOSITY("types") >= 2) {
for (int i = 0; i < cfg->blocks.size(); i++) { for (CFGBlock *b : cfg->blocks) {
printf("Types at beginning of block %d:\n", i); printf("Types at beginning of block %d:\n", b->idx);
CFGBlock *b = cfg->blocks[i];
TypeMap &starting = starting_types[i]; TypeMap &starting = starting_types[b];
for (auto p : starting) { for (auto p : starting) {
ASSERT(p.second, "%s", p.first.c_str()); ASSERT(p.second, "%s", p.first.c_str());
printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str()); printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str());
......
...@@ -280,20 +280,19 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -280,20 +280,19 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
llvm::MDNode* func_info = irstate->getFuncDbgInfo(); llvm::MDNode* func_info = irstate->getFuncDbgInfo();
if (entry_descriptor != NULL) if (entry_descriptor != NULL)
assert(full_blocks.count(source->cfg->blocks[0]) == 0); assert(full_blocks.count(source->cfg->getStartingBlock()) == 0);
// We need the entry blocks pre-allocated so that we can jump forward to them. // We need the entry blocks pre-allocated so that we can jump forward to them.
std::vector<llvm::BasicBlock*> llvm_entry_blocks; std::unordered_map<CFGBlock*, llvm::BasicBlock*> llvm_entry_blocks;
for (int i = 0; i < source->cfg->blocks.size(); i++) { for (CFGBlock* block : source->cfg->blocks) {
CFGBlock *block = source->cfg->blocks[i];
if (partial_blocks.count(block) == 0 && full_blocks.count(block) == 0) { if (partial_blocks.count(block) == 0 && full_blocks.count(block) == 0) {
llvm_entry_blocks.push_back(NULL); llvm_entry_blocks[block] = NULL;
continue; continue;
} }
char buf[40]; char buf[40];
snprintf(buf, 40, "%s_block%d", bb_type, i); snprintf(buf, 40, "%s_block%d", bb_type, block->idx);
llvm_entry_blocks.push_back(llvm::BasicBlock::Create(g.context, buf, irstate->getLLVMFunction())); llvm_entry_blocks[block] = llvm::BasicBlock::Create(g.context, buf, irstate->getLLVMFunction());
} }
llvm::BasicBlock *osr_entry_block = NULL; // the function entry block, where we add the type guards llvm::BasicBlock *osr_entry_block = NULL; // the function entry block, where we add the type guards
...@@ -416,7 +415,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -416,7 +415,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
} else { } else {
entry_emitter->getBuilder()->CreateBr(osr_unbox_block); entry_emitter->getBuilder()->CreateBr(osr_unbox_block);
} }
unbox_emitter->getBuilder()->CreateBr(llvm_entry_blocks[entry_descriptor->backedge->target->idx]); unbox_emitter->getBuilder()->CreateBr(llvm_entry_blocks[entry_descriptor->backedge->target]);
for (auto p : *initial_syms) { for (auto p : *initial_syms) {
delete p.second; delete p.second;
...@@ -428,21 +427,21 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -428,21 +427,21 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
// so that we can construct phi nodes later. // so that we can construct phi nodes later.
// Originally I preallocated these blocks as well, but we can construct the phi's // Originally I preallocated these blocks as well, but we can construct the phi's
// after the fact, so we can just record the exit blocks as we go along. // after the fact, so we can just record the exit blocks as we go along.
std::unordered_map<int, llvm::BasicBlock*> llvm_exit_blocks; std::unordered_map<CFGBlock*, llvm::BasicBlock*> llvm_exit_blocks;
//// ////
// Main ir generation: go through each basic block in the CFG and emit the code // Main ir generation: go through each basic block in the CFG and emit the code
std::unordered_map<int, SymbolTable*> ending_symbol_tables; std::unordered_map<CFGBlock*, SymbolTable*> ending_symbol_tables;
std::unordered_map<int, ConcreteSymbolTable*> phi_ending_symbol_tables; std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables;
typedef std::unordered_map<std::string, std::pair<ConcreteCompilerType*, llvm::PHINode*> > PHITable; typedef std::unordered_map<std::string, std::pair<ConcreteCompilerType*, llvm::PHINode*> > PHITable;
std::unordered_map<int, PHITable*> created_phis; std::unordered_map<CFGBlock*, PHITable*> created_phis;
CFGBlock* initial_block = NULL; CFGBlock* initial_block = NULL;
if (entry_descriptor) { if (entry_descriptor) {
initial_block = entry_descriptor->backedge->target; initial_block = entry_descriptor->backedge->target;
} else if (full_blocks.count(source->cfg->blocks[0])) { } else if (full_blocks.count(source->cfg->getStartingBlock())) {
initial_block = source->cfg->blocks[0]; initial_block = source->cfg->getStartingBlock();
} }
// The rest of this code assumes that for each non-entry block that gets evaluated, // The rest of this code assumes that for each non-entry block that gets evaluated,
...@@ -458,11 +457,6 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -458,11 +457,6 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
for (int _i = 0; _i < traversal_order.size(); _i++) { for (int _i = 0; _i < traversal_order.size(); _i++) {
CFGBlock *block = traversal_order[_i].first; CFGBlock *block = traversal_order[_i].first;
CFGBlock *pred = traversal_order[_i].second; CFGBlock *pred = traversal_order[_i].second;
//for (int _i = 0; _i < source->cfg->blocks.size(); _i++) {
//CFGBlock *block = source->cfg->blocks[_i];
//CFGBlock *pred = NULL;
//if (block->predecessors.size())
//CFGBlock *pred = block->predecessors[0];
if (VERBOSITY("irgen") >= 1) printf("processing %s block %d\n", bb_type, block->idx); if (VERBOSITY("irgen") >= 1) printf("processing %s block %d\n", bb_type, block->idx);
...@@ -472,27 +466,27 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -472,27 +466,27 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
is_partial = true; is_partial = true;
} else if (!full_blocks.count(block)) { } else if (!full_blocks.count(block)) {
if (VERBOSITY("irgen") >= 1) printf("Skipping this block\n"); if (VERBOSITY("irgen") >= 1) printf("Skipping this block\n");
//created_phis[block->idx] = NULL; //created_phis[block] = NULL;
//ending_symbol_tables[block->idx] = NULL; //ending_symbol_tables[block] = NULL;
//phi_ending_symbol_tables[block->idx] = NULL; //phi_ending_symbol_tables[block] = NULL;
//llvm_exit_blocks[block->idx] = NULL; //llvm_exit_blocks[block] = NULL;
continue; continue;
} }
std::unique_ptr<IRGenerator> generator(createIRGenerator(irstate, llvm_entry_blocks, block, types, out_guards, in_guards, is_partial)); std::unique_ptr<IRGenerator> generator(createIRGenerator(irstate, llvm_entry_blocks, block, types, out_guards, in_guards, is_partial));
std::unique_ptr<IREmitter> emitter(createIREmitter(irstate)); std::unique_ptr<IREmitter> emitter(createIREmitter(irstate));
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[block->idx]); emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[block]);
PHITable* phis = NULL; PHITable* phis = NULL;
if (!is_partial) { if (!is_partial) {
phis = new PHITable(); phis = new PHITable();
created_phis[block->idx] = phis; created_phis[block] = phis;
} }
// Set initial symbol table: // Set initial symbol table:
if (is_partial) { if (is_partial) {
// pass // pass
} else if (block->idx == 0) { } else if (block == source->cfg->getStartingBlock()) {
assert(entry_descriptor == NULL); assert(entry_descriptor == NULL);
// number of times a function needs to be called to be reoptimized: // number of times a function needs to be called to be reoptimized:
static const int REOPT_THRESHOLDS[] = { static const int REOPT_THRESHOLDS[] = {
...@@ -504,7 +498,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -504,7 +498,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
assert(strcmp("opt", bb_type) == 0); assert(strcmp("opt", bb_type) == 0);
if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast != NULL && source->ast->type != AST_TYPE::Module) { if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast != NULL && source->ast->type != AST_TYPE::Module) {
llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create(g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[0]); llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create(g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[source->cfg->getStartingBlock()]);
llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction()); llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction());
emitter->getBuilder()->SetInsertPoint(preentry_bb); emitter->getBuilder()->SetInsertPoint(preentry_bb);
...@@ -517,7 +511,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -517,7 +511,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
llvm::Value* md_vals[] = {llvm::MDString::get(g.context, "branch_weights"), getConstantInt(1), getConstantInt(1000)}; llvm::Value* md_vals[] = {llvm::MDString::get(g.context, "branch_weights"), getConstantInt(1), getConstantInt(1000)};
llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef<llvm::Value*>(md_vals)); llvm::MDNode* branch_weights = llvm::MDNode::get(g.context, llvm::ArrayRef<llvm::Value*>(md_vals));
llvm::BranchInst* guard = emitter->getBuilder()->CreateCondBr(reopt_test, reopt_bb, llvm_entry_blocks[0], branch_weights); llvm::BranchInst* guard = emitter->getBuilder()->CreateCondBr(reopt_test, reopt_bb, llvm_entry_blocks[source->cfg->getStartingBlock()], branch_weights);
emitter->getBuilder()->SetInsertPoint(reopt_bb); emitter->getBuilder()->SetInsertPoint(reopt_bb);
//emitter->getBuilder()->CreateCall(g.funcs.my_assert, getConstantInt(0, g.i1)); //emitter->getBuilder()->CreateCall(g.funcs.my_assert, getConstantInt(0, g.i1));
...@@ -542,7 +536,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -542,7 +536,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
emitter->getBuilder()->CreateRet(postcall); emitter->getBuilder()->CreateRet(postcall);
} }
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[0]); emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[source->cfg->getStartingBlock()]);
} }
generator->unpackArguments(arg_names, cf->sig->arg_types); generator->unpackArguments(arg_names, cf->sig->arg_types);
} else if (entry_descriptor && block == entry_descriptor->backedge->target) { } else if (entry_descriptor && block == entry_descriptor->backedge->target) {
...@@ -570,7 +564,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -570,7 +564,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
assert(block->predecessors.size()); assert(block->predecessors.size());
for (int i = 0; i < block->predecessors.size(); i++) { for (int i = 0; i < block->predecessors.size(); i++) {
CFGBlock *b2 = block->predecessors[i]; CFGBlock *b2 = block->predecessors[i];
assert(ending_symbol_tables.count(b2->idx) == 0); assert(ending_symbol_tables.count(b2) == 0);
into_hax.insert(b2); into_hax.insert(b2);
} }
...@@ -604,19 +598,19 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -604,19 +598,19 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
if (block->predecessors.size() == 1) { if (block->predecessors.size() == 1) {
// If this block has only one predecessor, it by definition doesn't need any phi nodes. // If this block has only one predecessor, it by definition doesn't need any phi nodes.
// Assert that the phi_st is empty, and just create the symbol table from the non-phi st: // Assert that the phi_st is empty, and just create the symbol table from the non-phi st:
ASSERT(phi_ending_symbol_tables[pred->idx]->size() == 0, "%d %d", block->idx, pred->idx); ASSERT(phi_ending_symbol_tables[pred]->size() == 0, "%d %d", block->idx, pred->idx);
assert(ending_symbol_tables.count(pred->idx)); assert(ending_symbol_tables.count(pred));
generator->copySymbolsFrom(ending_symbol_tables[pred->idx]); generator->copySymbolsFrom(ending_symbol_tables[pred]);
} else { } else {
// With multiple predecessors, the symbol tables at the end of each predecessor should be *exactly* the same. // With multiple predecessors, the symbol tables at the end of each predecessor should be *exactly* the same.
// (this should be satisfied by the post-run() code in this function) // (this should be satisfied by the post-run() code in this function)
// With multiple predecessors, we have to combine the non-phi and phi symbol tables. // With multiple predecessors, we have to combine the non-phi and phi symbol tables.
// Start off with the non-phi ones: // Start off with the non-phi ones:
generator->copySymbolsFrom(ending_symbol_tables[pred->idx]); generator->copySymbolsFrom(ending_symbol_tables[pred]);
// And go through and add phi nodes: // And go through and add phi nodes:
ConcreteSymbolTable *pred_st = phi_ending_symbol_tables[pred->idx]; ConcreteSymbolTable *pred_st = phi_ending_symbol_tables[pred];
for (ConcreteSymbolTable::iterator it = pred_st->begin(); it != pred_st->end(); it++) { for (ConcreteSymbolTable::iterator it = pred_st->begin(); it != pred_st->end(); it++) {
//printf("adding phi for %s\n", it->first.c_str()); //printf("adding phi for %s\n", it->first.c_str());
llvm::PHINode *phi = emitter->getBuilder()->CreatePHI(it->second->getType()->llvmType(), block->predecessors.size(), it->first); llvm::PHINode *phi = emitter->getBuilder()->CreatePHI(it->second->getType()->llvmType(), block->predecessors.size(), it->first);
...@@ -632,9 +626,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -632,9 +626,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
generator->run(block); generator->run(block);
const IRGenerator::EndingState &ending_st = generator->getEndingSymbolTable(); const IRGenerator::EndingState &ending_st = generator->getEndingSymbolTable();
ending_symbol_tables[block->idx] = ending_st.symbol_table; ending_symbol_tables[block] = ending_st.symbol_table;
phi_ending_symbol_tables[block->idx] = ending_st.phi_symbol_table; phi_ending_symbol_tables[block] = ending_st.phi_symbol_table;
llvm_exit_blocks[block->idx] = ending_st.ending_block; llvm_exit_blocks[block] = ending_st.ending_block;
if (into_hax.count(block)) if (into_hax.count(block))
ASSERT(ending_st.symbol_table->size() == 0, "%d", block->idx); ASSERT(ending_st.symbol_table->size() == 0, "%d", block->idx);
...@@ -646,14 +640,12 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -646,14 +640,12 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
// the relevant IR, so after we have done all of it, go back through and populate the phi nodes. // the relevant IR, so after we have done all of it, go back through and populate the phi nodes.
// Also, do some checking to make sure that the phi analysis stuff worked out, and that all blocks // Also, do some checking to make sure that the phi analysis stuff worked out, and that all blocks
// agreed on what symbols + types they should be propagating for the phis. // agreed on what symbols + types they should be propagating for the phis.
for (int i = 0; i < source->cfg->blocks.size(); i++) { for (CFGBlock *b : source->cfg->blocks) {
PHITable *phis = created_phis[i]; PHITable *phis = created_phis[b];
if (phis == NULL) if (phis == NULL)
continue; continue;
bool this_is_osr_entry = (entry_descriptor && i == entry_descriptor->backedge->target->idx); bool this_is_osr_entry = (entry_descriptor && b == entry_descriptor->backedge->target);
CFGBlock *b = source->cfg->blocks[i];
const std::vector<GuardList::BlockEntryGuard*> &block_guards = in_guards.getGuardsForBlock(b); const std::vector<GuardList::BlockEntryGuard*> &block_guards = in_guards.getGuardsForBlock(b);
//printf("Found %ld guards for block %p, for %p\n", block_guards.size(), b, &in_guards); //printf("Found %ld guards for block %p, for %p\n", block_guards.size(), b, &in_guards);
...@@ -663,9 +655,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -663,9 +655,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0) if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0)
continue; continue;
//printf("%d %d %ld %ld\n", i, b2->idx, phi_ending_symbol_tables[b2->idx]->size(), phis->size()); //printf("%d %d %ld %ld\n", i, b2->idx, phi_ending_symbol_tables[b2]->size(), phis->size());
compareKeyset(phi_ending_symbol_tables[b2->idx], phis); compareKeyset(phi_ending_symbol_tables[b2], phis);
assert(phi_ending_symbol_tables[b2->idx]->size() == phis->size()); assert(phi_ending_symbol_tables[b2]->size() == phis->size());
} }
if (this_is_osr_entry) { if (this_is_osr_entry) {
...@@ -693,14 +685,14 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -693,14 +685,14 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0) if (full_blocks.count(b2) == 0 && partial_blocks.count(b2) == 0)
continue; continue;
ConcreteCompilerVariable *v = (*phi_ending_symbol_tables[b2->idx])[it->first]; ConcreteCompilerVariable *v = (*phi_ending_symbol_tables[b2])[it->first];
assert(v); assert(v);
assert(v->isGrabbed()); assert(v->isGrabbed());
// Make sure they all prepared for the same type: // Make sure they all prepared for the same type:
ASSERT(it->second.first == v->getType(), "%d %d: %s %s %s", b->idx, b2->idx, it->first.c_str(), it->second.first->debugName().c_str(), v->getType()->debugName().c_str()); ASSERT(it->second.first == v->getType(), "%d %d: %s %s %s", b->idx, b2->idx, it->first.c_str(), it->second.first->debugName().c_str(), v->getType()->debugName().c_str());
llvm_phi->addIncoming(v->getValue(), llvm_exit_blocks[b->predecessors[j]->idx]); llvm_phi->addIncoming(v->getValue(), llvm_exit_blocks[b->predecessors[j]]);
} }
if (this_is_osr_entry) { if (this_is_osr_entry) {
...@@ -732,24 +724,24 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua ...@@ -732,24 +724,24 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
} }
for (int i = 0; i < block_guards.size(); i++) { for (int i = 0; i < block_guards.size(); i++) {
emitters[i]->getBuilder()->CreateBr(llvm_entry_blocks[b->idx]); emitters[i]->getBuilder()->CreateBr(llvm_entry_blocks[b]);
delete emitters[i]; delete emitters[i];
} }
} }
for (int i = 0; i < source->cfg->blocks.size(); i++) { for (CFGBlock *b : source->cfg->blocks) {
if (ending_symbol_tables[i] == NULL) if (ending_symbol_tables[b] == NULL)
continue; continue;
for (SymbolTable::iterator it = ending_symbol_tables[i]->begin(); it != ending_symbol_tables[i]->end(); it++) { for (SymbolTable::iterator it = ending_symbol_tables[b]->begin(); it != ending_symbol_tables[b]->end(); it++) {
it->second->decvrefNodrop(); it->second->decvrefNodrop();
} }
for (ConcreteSymbolTable::iterator it = phi_ending_symbol_tables[i]->begin(); it != phi_ending_symbol_tables[i]->end(); it++) { for (ConcreteSymbolTable::iterator it = phi_ending_symbol_tables[b]->begin(); it != phi_ending_symbol_tables[b]->end(); it++) {
it->second->decvrefNodrop(); it->second->decvrefNodrop();
} }
delete phi_ending_symbol_tables[i]; delete phi_ending_symbol_tables[b];
delete ending_symbol_tables[i]; delete ending_symbol_tables[b];
delete created_phis[i]; delete created_phis[b];
} }
if (entry_descriptor) { if (entry_descriptor) {
...@@ -907,8 +899,8 @@ CompiledFunction* compileFunction(SourceInfo *source, const OSREntryDescriptor * ...@@ -907,8 +899,8 @@ CompiledFunction* compileFunction(SourceInfo *source, const OSREntryDescriptor *
BlockSet full_blocks, partial_blocks; BlockSet full_blocks, partial_blocks;
if (entry_descriptor == NULL) { if (entry_descriptor == NULL) {
for (int i = 0; i < source->cfg->blocks.size(); i++) { for (CFGBlock *b : source->cfg->blocks) {
full_blocks.insert(source->cfg->blocks[i]); full_blocks.insert(b);
} }
} else { } else {
full_blocks.insert(entry_descriptor->backedge->target); full_blocks.insert(entry_descriptor->backedge->target);
......
...@@ -163,7 +163,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -163,7 +163,7 @@ class IRGeneratorImpl : public IRGenerator {
IREmitterImpl emitter; IREmitterImpl emitter;
SymbolTable symbol_table; SymbolTable symbol_table;
std::vector<llvm::BasicBlock*> &entry_blocks; std::unordered_map<CFGBlock*, llvm::BasicBlock*> &entry_blocks;
llvm::BasicBlock *curblock; llvm::BasicBlock *curblock;
CFGBlock *myblock; CFGBlock *myblock;
TypeAnalysis *types; TypeAnalysis *types;
...@@ -178,8 +178,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -178,8 +178,8 @@ class IRGeneratorImpl : public IRGenerator {
} state; } state;
public: public:
IRGeneratorImpl(IRGenState *irstate, std::vector<llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial) : irstate(irstate), emitter(irstate), entry_blocks(entry_blocks), myblock(myblock), types(types), out_guards(out_guards), in_guards(in_guards), state(is_partial ? PARTIAL : RUNNING) { IRGeneratorImpl(IRGenState *irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial) : irstate(irstate), emitter(irstate), entry_blocks(entry_blocks), myblock(myblock), types(types), out_guards(out_guards), in_guards(in_guards), state(is_partial ? PARTIAL : RUNNING) {
llvm::BasicBlock* entry_block = entry_blocks[myblock->idx]; llvm::BasicBlock* entry_block = entry_blocks[myblock];
emitter.getBuilder()->SetInsertPoint(entry_block); emitter.getBuilder()->SetInsertPoint(entry_block);
curblock = entry_block; curblock = entry_block;
} }
...@@ -1286,8 +1286,8 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1286,8 +1286,8 @@ class IRGeneratorImpl : public IRGenerator {
val->decvref(emitter); val->decvref(emitter);
llvm::Value *llvm_nonzero = nonzero->getValue(); llvm::Value *llvm_nonzero = nonzero->getValue();
llvm::BasicBlock *iftrue = entry_blocks[node->iftrue->idx]; llvm::BasicBlock *iftrue = entry_blocks[node->iftrue];
llvm::BasicBlock *iffalse = entry_blocks[node->iffalse->idx]; llvm::BasicBlock *iffalse = entry_blocks[node->iffalse];
nonzero->decvref(emitter); nonzero->decvref(emitter);
...@@ -1461,7 +1461,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1461,7 +1461,7 @@ class IRGeneratorImpl : public IRGenerator {
endBlock(FINISHED); endBlock(FINISHED);
llvm::BasicBlock *target = entry_blocks[node->target->idx]; llvm::BasicBlock *target = entry_blocks[node->target];
if (ENABLE_OSR && node->target->idx < myblock->idx && irstate->getEffortLevel() < EffortLevel::MAXIMAL) { if (ENABLE_OSR && node->target->idx < myblock->idx && irstate->getEffortLevel() < EffortLevel::MAXIMAL) {
assert(node->target->predecessors.size() > 1); assert(node->target->predecessors.size() > 1);
...@@ -1714,7 +1714,7 @@ class IRGeneratorImpl : public IRGenerator { ...@@ -1714,7 +1714,7 @@ class IRGeneratorImpl : public IRGenerator {
}; };
IRGenerator *createIRGenerator(IRGenState *irstate, std::vector<llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial) { IRGenerator *createIRGenerator(IRGenState *irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial) {
return new IRGeneratorImpl(irstate, entry_blocks, myblock, types, out_guards, in_guards, is_partial); return new IRGeneratorImpl(irstate, entry_blocks, myblock, types, out_guards, in_guards, is_partial);
} }
......
...@@ -198,7 +198,7 @@ class IRGenerator { ...@@ -198,7 +198,7 @@ class IRGenerator {
}; };
IREmitter *createIREmitter(IRGenState *irstate); IREmitter *createIREmitter(IRGenState *irstate);
IRGenerator *createIRGenerator(IRGenState *irstate, std::vector<llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial); IRGenerator *createIRGenerator(IRGenState *irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*> &entry_blocks, CFGBlock *myblock, TypeAnalysis *types, GuardList &out_guards, const GuardList &in_guards, bool is_partial);
} }
......
...@@ -63,7 +63,7 @@ class BufferedReader { ...@@ -63,7 +63,7 @@ class BufferedReader {
uint8_t readByte() { uint8_t readByte() {
ensure(1); ensure(1);
assert(end > start); assert(end > start && "premature eof");
if (VERBOSITY("parsing") >= 2) if (VERBOSITY("parsing") >= 2)
printf("readByte, now %d %d\n", start+1, end); printf("readByte, now %d %d\n", start+1, end);
return buf[start++]; return buf[start++];
......
...@@ -29,10 +29,20 @@ void CFGBlock::connectTo(CFGBlock *successor, bool allow_backedge) { ...@@ -29,10 +29,20 @@ void CFGBlock::connectTo(CFGBlock *successor, bool allow_backedge) {
assert(this->idx >= 0); assert(this->idx >= 0);
ASSERT(successor->idx == -1 || successor->idx > this->idx, "edge from %d to %d", this->idx, successor->idx); ASSERT(successor->idx == -1 || successor->idx > this->idx, "edge from %d to %d", this->idx, successor->idx);
} }
//assert(successors.count(successor) == 0);
//assert(successor->predecessors.count(this) == 0);
successors.push_back(successor); successors.push_back(successor);
successor->predecessors.push_back(this); successor->predecessors.push_back(this);
} }
void CFGBlock::unconnectFrom(CFGBlock *successor) {
//assert(successors.count(successor));
//assert(successor->predecessors.count(this));
successors.erase(std::remove(successors.begin(), successors.end(), successor), successors.end());
successor->predecessors.erase(std::remove(successor->predecessors.begin(), successor->predecessors.end(), this), successor->predecessors.end());
}
class CFGVisitor : public ASTVisitor { class CFGVisitor : public ASTVisitor {
private: private:
AST_TYPE::AST_TYPE root_type; AST_TYPE::AST_TYPE root_type;
...@@ -664,7 +674,7 @@ class CFGVisitor : public ASTVisitor { ...@@ -664,7 +674,7 @@ class CFGVisitor : public ASTVisitor {
virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; } virtual bool visit_functiondef(AST_FunctionDef* node) { push_back(node); return true; }
virtual bool visit_global(AST_Global* node) { push_back(node); return true; } virtual bool visit_global(AST_Global* node) { push_back(node); return true; }
virtual bool visit_import(AST_Import* node) { push_back(node); return true; } virtual bool visit_import(AST_Import* node) { push_back(node); return true; }
virtual bool visit_pass(AST_Pass* node) { push_back(node); return true; } virtual bool visit_pass(AST_Pass* node) { return true; }
virtual bool visit_assign(AST_Assign* node) { virtual bool visit_assign(AST_Assign* node) {
AST_Assign* remapped = new AST_Assign(); AST_Assign* remapped = new AST_Assign();
...@@ -1184,8 +1194,8 @@ void CFG::print() { ...@@ -1184,8 +1194,8 @@ void CFG::print() {
printf("%ld blocks\n", blocks.size()); printf("%ld blocks\n", blocks.size());
PrintVisitor *pv = new PrintVisitor(4); PrintVisitor *pv = new PrintVisitor(4);
for (int i = 0; i < blocks.size(); i++) { for (int i = 0; i < blocks.size(); i++) {
printf("Block %d", i);
CFGBlock *b = blocks[i]; CFGBlock *b = blocks[i];
printf("Block %d", b->idx);
if (b->info) if (b->info)
printf(" '%s'", b->info); printf(" '%s'", b->info);
...@@ -1228,9 +1238,7 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) { ...@@ -1228,9 +1238,7 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
//// ////
// Check some properties expected by later stages: // Check some properties expected by later stages:
// Block 0 is hard-coded to be the entry block, and shouldn't have any assert(rtn->getStartingBlock()->predecessors.size() == 0);
// predecessors:
assert(rtn->blocks[0]->predecessors.size() == 0);
// We need to generate the CFG in a way that doesn't have any critical edges, // We need to generate the CFG in a way that doesn't have any critical edges,
// since the ir generation requires that. // since the ir generation requires that.
...@@ -1268,6 +1276,40 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) { ...@@ -1268,6 +1276,40 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
assert(rtn->blocks[i]->predecessors[0]->idx < i); assert(rtn->blocks[i]->predecessors[0]->idx < i);
} }
// Prune unnecessary blocks from the CFG.
// Not strictly necessary, but makes the output easier to look at,
// and can make the analyses more efficient.
// The extra blocks would get merged by LLVM passes, so I'm not sure
// how much overall improvement there is.
for (CFGBlock* b : rtn->blocks) {
while (b->successors.size() == 1) {
CFGBlock *b2 = b->successors[0];
if (b2->predecessors.size() != 1)
break;
if (VERBOSITY()) {
//rtn->print();
printf("Joining blocks %d and %d\n", b->idx, b2->idx);
}
assert(b->body[b->body.size()-1]->type == AST_TYPE::Jump);
b->body.pop_back();
b->body.insert(b->body.end(), b2->body.begin(), b2->body.end());
b->unconnectFrom(b2);
for (CFGBlock *b3 : b2->successors) {
b->connectTo(b3, true);
b2->unconnectFrom(b3);
}
rtn->blocks.erase(std::remove(rtn->blocks.begin(), rtn->blocks.end(), b2), rtn->blocks.end());
delete b2;
}
}
assert(rtn->getStartingBlock()->idx == 0);
/* /*
// I keep on going back and forth about whether or not it's ok to reuse AST nodes. // I keep on going back and forth about whether or not it's ok to reuse AST nodes.
// On the one hand, it's nice to say that an AST* pointer uniquely identifies a spot // On the one hand, it's nice to say that an AST* pointer uniquely identifies a spot
......
...@@ -51,6 +51,7 @@ class CFGBlock { ...@@ -51,6 +51,7 @@ class CFGBlock {
} }
void connectTo(CFGBlock *successor, bool allow_backedge=false); void connectTo(CFGBlock *successor, bool allow_backedge=false);
void unconnectFrom(CFGBlock *successor);
void push_back(AST_stmt* node) { void push_back(AST_stmt* node) {
body.push_back(node); body.push_back(node);
...@@ -60,11 +61,19 @@ class CFGBlock { ...@@ -60,11 +61,19 @@ class CFGBlock {
// Control Flow Graph // Control Flow Graph
class CFG { class CFG {
private: private:
int next_idx;
public: public:
std::vector<CFGBlock*> blocks; std::vector<CFGBlock*> blocks;
CFG() : next_idx(0) {}
CFGBlock* getStartingBlock() {
return blocks[0];
}
CFGBlock* addBlock() { CFGBlock* addBlock() {
int idx = blocks.size(); int idx = next_idx;
next_idx++;
CFGBlock* block = new CFGBlock(this, idx); CFGBlock* block = new CFGBlock(this, idx);
blocks.push_back(block); blocks.push_back(block);
...@@ -78,7 +87,8 @@ class CFG { ...@@ -78,7 +87,8 @@ class CFG {
void placeBlock(CFGBlock *block) { void placeBlock(CFGBlock *block) {
assert(block->idx == -1); assert(block->idx == -1);
block->idx = blocks.size(); block->idx = next_idx;
next_idx++;
blocks.push_back(block); blocks.push_back(block);
} }
......
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