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> &
std::vector<CFGBlock*> q;
states.insert(make_pair(cfg->blocks[0], Map()));
q.push_back(cfg->blocks[0]);
states.insert(make_pair(cfg->getStartingBlock(), Map()));
q.push_back(cfg->getStartingBlock());
while (q.size()) {
CFGBlock *block = q.back();
......
......@@ -120,9 +120,10 @@ class DefinednessBBAnalyzer : public BBAnalyzer<DefinednessAnalysis::DefinitionL
private:
typedef DefinednessAnalysis::DefinitionLevel DefinitionLevel;
CFG* cfg;
AST_arguments* arguments;
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 {
......@@ -225,7 +226,7 @@ void DefinednessBBAnalyzer::processBB(Map &starting, CFGBlock *block) const {
for (int i = 0; i < block->body.size(); i++) {
block->body[i]->accept(&visitor);
}
if (block->idx == 0 && arguments) {
if (block == cfg->getStartingBlock() && arguments) {
arguments->accept(&visitor);
}
......@@ -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) {
results = computeFixedPoint(cfg, DefinednessBBAnalyzer(args), false);
results = computeFixedPoint(cfg, DefinednessBBAnalyzer(cfg, args), false);
for (auto p : results) {
RequiredSet required;
......@@ -267,9 +268,7 @@ const DefinednessAnalysis::RequiredSet& DefinednessAnalysis::getDefinedNamesAt(C
PhiAnalysis::PhiAnalysis(AST_arguments* args, CFG* cfg, LivenessAnalysis *liveness, ScopeInfo *scope_info) :
definedness(args, cfg, scope_info), liveness(liveness) {
for (int i = 0; i < cfg->blocks.size(); i++) {
CFGBlock *block = cfg->blocks[i];
for (CFGBlock *block : cfg->blocks) {
RequiredSet required;
if (block->predecessors.size() < 2)
continue;
......
......@@ -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<int, TypeMap> AllTypeMap;
typedef std::unordered_map<CFGBlock*, TypeMap> AllTypeMap;
typedef std::unordered_map<AST_expr*, CompilerType*> ExprTypeMap;
typedef std::unordered_map<AST_expr*, BoxedClass*> TypeSpeculations;
class BasicBlockTypePropagator : public ExprVisitor, public StmtVisitor {
......@@ -479,7 +479,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
return getTypeAtBlockStart(name, block->successors[0]);
}
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);
ConcreteCompilerType *rtn = base->getConcreteType();
......@@ -538,7 +538,7 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
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++) {
AST_expr* arg = arg_names[i];
assert(arg->type == AST_TYPE::Name);
......@@ -547,36 +547,34 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
}
}
std::unordered_set<int> in_queue;
std::deque<int> queue;
queue.push_back(0);
std::unordered_set<CFGBlock*> in_queue;
std::deque<CFGBlock*> queue;
queue.push_back(cfg->getStartingBlock());
while (queue.size()) {
int block_id = queue.front();
CFGBlock *block = queue.front();
queue.pop_front();
in_queue.erase(block_id);
CFGBlock *block = cfg->blocks[block_id];
in_queue.erase(block);
TypeMap ending;
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) {
printf("before:\n");
TypeMap &starting = starting_types[block_id];
TypeMap &starting = starting_types[block];
for (auto p : starting) {
ASSERT(p.second, "%s", p.first.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) {
printf("before (after):\n");
TypeMap &starting = starting_types[block_id];
TypeMap &starting = starting_types[block];
for (auto p : starting) {
ASSERT(p.second, "%s", p.first.c_str());
printf("%s: %s\n", p.first.c_str(), p.second->debugName().c_str());
......@@ -589,21 +587,20 @@ class PropagatingTypeAnalysis : public TypeAnalysis {
}
for (int i = 0; i < block->successors.size(); i++) {
int next_id = block->successors[i]->idx;
bool first = (starting_types.count(next_id) == 0);
bool changed = merge(ending, starting_types[next_id]);
if ((first || changed) && in_queue.insert(next_id).second) {
queue.push_back(next_id);
CFGBlock *next_block = block->successors[i];
bool first = (starting_types.count(next_block) == 0);
bool changed = merge(ending, starting_types[next_block]);
if ((first || changed) && in_queue.insert(next_block).second) {
queue.push_back(next_block);
}
}
}
if (VERBOSITY("types") >= 2) {
for (int i = 0; i < cfg->blocks.size(); i++) {
printf("Types at beginning of block %d:\n", i);
CFGBlock *b = cfg->blocks[i];
for (CFGBlock *b : cfg->blocks) {
printf("Types at beginning of block %d:\n", b->idx);
TypeMap &starting = starting_types[i];
TypeMap &starting = starting_types[b];
for (auto p : starting) {
ASSERT(p.second, "%s", p.first.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
llvm::MDNode* func_info = irstate->getFuncDbgInfo();
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.
std::vector<llvm::BasicBlock*> llvm_entry_blocks;
for (int i = 0; i < source->cfg->blocks.size(); i++) {
CFGBlock *block = source->cfg->blocks[i];
std::unordered_map<CFGBlock*, llvm::BasicBlock*> llvm_entry_blocks;
for (CFGBlock* block : source->cfg->blocks) {
if (partial_blocks.count(block) == 0 && full_blocks.count(block) == 0) {
llvm_entry_blocks.push_back(NULL);
llvm_entry_blocks[block] = NULL;
continue;
}
char buf[40];
snprintf(buf, 40, "%s_block%d", bb_type, i);
llvm_entry_blocks.push_back(llvm::BasicBlock::Create(g.context, buf, irstate->getLLVMFunction()));
snprintf(buf, 40, "%s_block%d", bb_type, block->idx);
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
......@@ -416,7 +415,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
} else {
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) {
delete p.second;
......@@ -428,21 +427,21 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
// so that we can construct phi nodes later.
// 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.
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
std::unordered_map<int, SymbolTable*> ending_symbol_tables;
std::unordered_map<int, ConcreteSymbolTable*> phi_ending_symbol_tables;
std::unordered_map<CFGBlock*, SymbolTable*> ending_symbol_tables;
std::unordered_map<CFGBlock*, ConcreteSymbolTable*> phi_ending_symbol_tables;
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;
if (entry_descriptor) {
initial_block = entry_descriptor->backedge->target;
} else if (full_blocks.count(source->cfg->blocks[0])) {
initial_block = source->cfg->blocks[0];
} else if (full_blocks.count(source->cfg->getStartingBlock())) {
initial_block = source->cfg->getStartingBlock();
}
// 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
for (int _i = 0; _i < traversal_order.size(); _i++) {
CFGBlock *block = traversal_order[_i].first;
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);
......@@ -472,27 +466,27 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
is_partial = true;
} else if (!full_blocks.count(block)) {
if (VERBOSITY("irgen") >= 1) printf("Skipping this block\n");
//created_phis[block->idx] = NULL;
//ending_symbol_tables[block->idx] = NULL;
//phi_ending_symbol_tables[block->idx] = NULL;
//llvm_exit_blocks[block->idx] = NULL;
//created_phis[block] = NULL;
//ending_symbol_tables[block] = NULL;
//phi_ending_symbol_tables[block] = NULL;
//llvm_exit_blocks[block] = NULL;
continue;
}
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));
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[block->idx]);
emitter->getBuilder()->SetInsertPoint(llvm_entry_blocks[block]);
PHITable* phis = NULL;
if (!is_partial) {
phis = new PHITable();
created_phis[block->idx] = phis;
created_phis[block] = phis;
}
// Set initial symbol table:
if (is_partial) {
// pass
} else if (block->idx == 0) {
} else if (block == source->cfg->getStartingBlock()) {
assert(entry_descriptor == NULL);
// number of times a function needs to be called to be reoptimized:
static const int REOPT_THRESHOLDS[] = {
......@@ -504,7 +498,7 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
assert(strcmp("opt", bb_type) == 0);
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());
emitter->getBuilder()->SetInsertPoint(preentry_bb);
......@@ -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::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()->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
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);
} 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
assert(block->predecessors.size());
for (int i = 0; i < block->predecessors.size(); 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);
}
......@@ -604,19 +598,19 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
if (block->predecessors.size() == 1) {
// 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(phi_ending_symbol_tables[pred->idx]->size() == 0, "%d %d", block->idx, pred->idx);
assert(ending_symbol_tables.count(pred->idx));
generator->copySymbolsFrom(ending_symbol_tables[pred->idx]);
ASSERT(phi_ending_symbol_tables[pred]->size() == 0, "%d %d", block->idx, pred->idx);
assert(ending_symbol_tables.count(pred));
generator->copySymbolsFrom(ending_symbol_tables[pred]);
} else {
// 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)
// With multiple predecessors, we have to combine the non-phi and phi symbol tables.
// 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:
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++) {
//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);
......@@ -632,9 +626,9 @@ static void emitBBs(IRGenState* irstate, const char* bb_type, GuardList &out_gua
generator->run(block);
const IRGenerator::EndingState &ending_st = generator->getEndingSymbolTable();
ending_symbol_tables[block->idx] = ending_st.symbol_table;
phi_ending_symbol_tables[block->idx] = ending_st.phi_symbol_table;
llvm_exit_blocks[block->idx] = ending_st.ending_block;
ending_symbol_tables[block] = ending_st.symbol_table;
phi_ending_symbol_tables[block] = ending_st.phi_symbol_table;
llvm_exit_blocks[block] = ending_st.ending_block;
if (into_hax.count(block))
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
// 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
// agreed on what symbols + types they should be propagating for the phis.
for (int i = 0; i < source->cfg->blocks.size(); i++) {
PHITable *phis = created_phis[i];
for (CFGBlock *b : source->cfg->blocks) {
PHITable *phis = created_phis[b];
if (phis == NULL)
continue;
bool this_is_osr_entry = (entry_descriptor && i == entry_descriptor->backedge->target->idx);
CFGBlock *b = source->cfg->blocks[i];
bool this_is_osr_entry = (entry_descriptor && b == entry_descriptor->backedge->target);
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);
......@@ -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)
continue;
//printf("%d %d %ld %ld\n", i, b2->idx, phi_ending_symbol_tables[b2->idx]->size(), phis->size());
compareKeyset(phi_ending_symbol_tables[b2->idx], phis);
assert(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], phis);
assert(phi_ending_symbol_tables[b2]->size() == phis->size());
}
if (this_is_osr_entry) {
......@@ -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)
continue;
ConcreteCompilerVariable *v = (*phi_ending_symbol_tables[b2->idx])[it->first];
ConcreteCompilerVariable *v = (*phi_ending_symbol_tables[b2])[it->first];
assert(v);
assert(v->isGrabbed());
// 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());
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) {
......@@ -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++) {
emitters[i]->getBuilder()->CreateBr(llvm_entry_blocks[b->idx]);
emitters[i]->getBuilder()->CreateBr(llvm_entry_blocks[b]);
delete emitters[i];
}
}
for (int i = 0; i < source->cfg->blocks.size(); i++) {
if (ending_symbol_tables[i] == NULL)
for (CFGBlock *b : source->cfg->blocks) {
if (ending_symbol_tables[b] == NULL)
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();
}
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();
}
delete phi_ending_symbol_tables[i];
delete ending_symbol_tables[i];
delete created_phis[i];
delete phi_ending_symbol_tables[b];
delete ending_symbol_tables[b];
delete created_phis[b];
}
if (entry_descriptor) {
......@@ -907,8 +899,8 @@ CompiledFunction* compileFunction(SourceInfo *source, const OSREntryDescriptor *
BlockSet full_blocks, partial_blocks;
if (entry_descriptor == NULL) {
for (int i = 0; i < source->cfg->blocks.size(); i++) {
full_blocks.insert(source->cfg->blocks[i]);
for (CFGBlock *b : source->cfg->blocks) {
full_blocks.insert(b);
}
} else {
full_blocks.insert(entry_descriptor->backedge->target);
......
......@@ -163,7 +163,7 @@ class IRGeneratorImpl : public IRGenerator {
IREmitterImpl emitter;
SymbolTable symbol_table;
std::vector<llvm::BasicBlock*> &entry_blocks;
std::unordered_map<CFGBlock*, llvm::BasicBlock*> &entry_blocks;
llvm::BasicBlock *curblock;
CFGBlock *myblock;
TypeAnalysis *types;
......@@ -178,8 +178,8 @@ class IRGeneratorImpl : public IRGenerator {
} state;
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) {
llvm::BasicBlock* entry_block = entry_blocks[myblock->idx];
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];
emitter.getBuilder()->SetInsertPoint(entry_block);
curblock = entry_block;
}
......@@ -1286,8 +1286,8 @@ class IRGeneratorImpl : public IRGenerator {
val->decvref(emitter);
llvm::Value *llvm_nonzero = nonzero->getValue();
llvm::BasicBlock *iftrue = entry_blocks[node->iftrue->idx];
llvm::BasicBlock *iffalse = entry_blocks[node->iffalse->idx];
llvm::BasicBlock *iftrue = entry_blocks[node->iftrue];
llvm::BasicBlock *iffalse = entry_blocks[node->iffalse];
nonzero->decvref(emitter);
......@@ -1461,7 +1461,7 @@ class IRGeneratorImpl : public IRGenerator {
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) {
assert(node->target->predecessors.size() > 1);
......@@ -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);
}
......
......@@ -198,7 +198,7 @@ class IRGenerator {
};
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 {
uint8_t readByte() {
ensure(1);
assert(end > start);
assert(end > start && "premature eof");
if (VERBOSITY("parsing") >= 2)
printf("readByte, now %d %d\n", start+1, end);
return buf[start++];
......
......@@ -29,10 +29,20 @@ void CFGBlock::connectTo(CFGBlock *successor, bool allow_backedge) {
assert(this->idx >= 0);
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);
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 {
private:
AST_TYPE::AST_TYPE root_type;
......@@ -664,7 +674,7 @@ class CFGVisitor : public ASTVisitor {
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_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) {
AST_Assign* remapped = new AST_Assign();
......@@ -1184,8 +1194,8 @@ void CFG::print() {
printf("%ld blocks\n", blocks.size());
PrintVisitor *pv = new PrintVisitor(4);
for (int i = 0; i < blocks.size(); i++) {
printf("Block %d", i);
CFGBlock *b = blocks[i];
printf("Block %d", b->idx);
if (b->info)
printf(" '%s'", b->info);
......@@ -1228,9 +1238,7 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
////
// Check some properties expected by later stages:
// Block 0 is hard-coded to be the entry block, and shouldn't have any
// predecessors:
assert(rtn->blocks[0]->predecessors.size() == 0);
assert(rtn->getStartingBlock()->predecessors.size() == 0);
// We need to generate the CFG in a way that doesn't have any critical edges,
// since the ir generation requires that.
......@@ -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);
}
// 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.
// On the one hand, it's nice to say that an AST* pointer uniquely identifies a spot
......
......@@ -51,6 +51,7 @@ class CFGBlock {
}
void connectTo(CFGBlock *successor, bool allow_backedge=false);
void unconnectFrom(CFGBlock *successor);
void push_back(AST_stmt* node) {
body.push_back(node);
......@@ -60,11 +61,19 @@ class CFGBlock {
// Control Flow Graph
class CFG {
private:
int next_idx;
public:
std::vector<CFGBlock*> blocks;
CFG() : next_idx(0) {}
CFGBlock* getStartingBlock() {
return blocks[0];
}
CFGBlock* addBlock() {
int idx = blocks.size();
int idx = next_idx;
next_idx++;
CFGBlock* block = new CFGBlock(this, idx);
blocks.push_back(block);
......@@ -78,7 +87,8 @@ class CFG {
void placeBlock(CFGBlock *block) {
assert(block->idx == -1);
block->idx = blocks.size();
block->idx = next_idx;
next_idx++;
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