Commit 7efd8225 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Exceptions part #2: AST and CFG support

parent a4b0c853
......@@ -283,7 +283,7 @@ $(UNITTEST_DIR)/$1: $(GTEST_DIR)/src/gtest-all.o $(NON_ENTRY_OBJS) $(BUILD_SYSTE
$(ECHO) Linking $$@
$(VERB) $(CXX) $(NON_ENTRY_OBJS) $(GTEST_DIR)/src/gtest-all.o $(GTEST_DIR)/src/gtest_main.o $(UNITTEST_DIR)/$1.o $(LDFLAGS) -o $$@
dbg_$1_unittests: $(UNITTEST_DIR)/$1
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time gdb $(GDB_CMDS) --args ./$(UNITTEST_DIR)/$1 --gtest_break_on_failure $(ARGS)'
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time $(GDB) $(GDB_CMDS) --args ./$(UNITTEST_DIR)/$1 --gtest_break_on_failure $(ARGS)'
run_$1_unittests: $(UNITTEST_DIR)/$1
zsh -c 'ulimit -v $(MAX_MEM_KB); ulimit -d $(MAX_MEM_KB); time ./$(UNITTEST_DIR)/$1 $(ARGS)'
run_unittests:: run_$1_unittests
......
......@@ -177,9 +177,11 @@ public:
virtual bool visit_branch(AST_Branch* node) { return true; }
virtual bool visit_expr(AST_Expr* node) { return true; }
virtual bool visit_global(AST_Global* node) { return true; }
virtual bool visit_invoke(AST_Invoke* node) { return false; }
virtual bool visit_jump(AST_Jump* node) { return true; }
virtual bool visit_pass(AST_Pass* node) { return true; }
virtual bool visit_print(AST_Print* node) { return true; }
virtual bool visit_raise(AST_Raise* node) { return true; }
virtual bool visit_return(AST_Return* node) { return true; }
virtual bool visit_classdef(AST_ClassDef* node) {
......
......@@ -145,6 +145,7 @@ public:
}
virtual bool visit_arguments(AST_arguments* node) { return false; }
virtual bool visit_assert(AST_Assert* node) { return false; }
virtual bool visit_assign(AST_Assign* node) { return false; }
virtual bool visit_augassign(AST_AugAssign* node) { return false; }
virtual bool visit_attribute(AST_Attribute* node) { return false; }
......@@ -157,6 +158,7 @@ public:
// virtual bool visit_classdef(AST_ClassDef *node) { return false; }
virtual bool visit_continue(AST_Continue* node) { return false; }
virtual bool visit_dict(AST_Dict* node) { return false; }
virtual bool visit_excepthandler(AST_ExceptHandler* node) { return false; }
virtual bool visit_expr(AST_Expr* node) { return false; }
virtual bool visit_for(AST_For* node) { return false; }
// virtual bool visit_functiondef(AST_FunctionDef *node) { return false; }
......@@ -172,11 +174,14 @@ public:
virtual bool visit_num(AST_Num* node) { return false; }
virtual bool visit_pass(AST_Pass* node) { return false; }
virtual bool visit_print(AST_Print* node) { return false; }
virtual bool visit_raise(AST_Raise* node) { return false; }
virtual bool visit_repr(AST_Repr* node) { return false; }
virtual bool visit_return(AST_Return* node) { return false; }
virtual bool visit_slice(AST_Slice* node) { return false; }
virtual bool visit_str(AST_Str* node) { return false; }
virtual bool visit_subscript(AST_Subscript* node) { return false; }
virtual bool visit_tryexcept(AST_TryExcept* node) { return false; }
virtual bool visit_tryfinally(AST_TryFinally* node) { return false; }
virtual bool visit_tuple(AST_Tuple* node) { return false; }
virtual bool visit_unaryop(AST_UnaryOp* node) { return false; }
virtual bool visit_while(AST_While* node) { return false; }
......
......@@ -329,6 +329,17 @@ private:
virtual void* visit_index(AST_Index* node) { return getType(node->value); }
virtual void* visit_langprimitive(AST_LangPrimitive* node) {
switch (node->opcode) {
case AST_LangPrimitive::ISINSTANCE:
return BOOL;
case AST_LangPrimitive::LANDINGPAD:
return UNKNOWN;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
}
virtual void* visit_list(AST_List* node) {
// Get all the sub-types, even though they're not necessary to
// determine the expression type, so that things like speculations
......@@ -459,6 +470,8 @@ private:
visit_alias(alias);
}
virtual void visit_invoke(AST_Invoke* node) { node->stmt->accept_stmt(this); }
virtual void visit_jump(AST_Jump* node) {}
virtual void visit_pass(AST_Pass* node) {}
......@@ -473,6 +486,17 @@ private:
}
}
virtual void visit_raise(AST_Raise* node) {
if (EXPAND_UNNEEDED) {
if (node->arg0)
getType(node->arg0);
if (node->arg1)
getType(node->arg1);
if (node->arg2)
getType(node->arg2);
}
}
virtual void visit_return(AST_Return* node) {
if (EXPAND_UNNEEDED) {
if (node->value != NULL)
......
......@@ -144,6 +144,7 @@ void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
code = I->getName(name);
assert(!code);
uint64_t address, size;
const char* type = "unknown";
bool b;
code = I->isText(b);
......@@ -162,7 +163,11 @@ void PystonJITEventListener::NotifyObjectEmitted(const llvm::ObjectImage& Obj) {
assert(!code);
if (b)
type = "rodata";
printf("Section: %s %s\n", name.data(), type);
code = I->getAddress(address);
assert(!code);
code = I->getSize(size);
assert(!code);
printf("Section: %s %s (%lx %lx)\n", name.data(), type, address, size);
#if LLVMREV < 200442
I = I.increment(code);
......
......@@ -104,9 +104,9 @@ private:
continue;
}
if (CallInst* si = dyn_cast<CallInst>(user)) {
if (llvm::isa<CallInst>(user) || llvm::isa<InvokeInst>(user)) {
if (VERBOSITY() >= 2)
errs() << "Not dead; used here: " << *si << '\n';
errs() << "Not dead; used here: " << *user << '\n';
return true;
}
......
......@@ -132,10 +132,10 @@ bool EscapeAnalysis::runOnFunction(Function& F) {
continue;
}
if (CallInst* si = dyn_cast<CallInst>(user)) {
if (llvm::isa<CallInst>(user) || llvm::isa<InvokeInst>(user)) {
if (VERBOSITY() >= 2)
errs() << "Escapes here: " << *si << '\n';
chain->escape_points.insert(si);
errs() << "Escapes here: " << *user << '\n';
chain->escape_points.insert(dyn_cast<Instruction>(user));
continue;
}
......
......@@ -790,12 +790,24 @@ AST* readASTMisc(BufferedReader* reader) {
}
}
static std::string getParserCommandLine(const char* fn) {
llvm::SmallString<128> parse_ast_fn;
// TODO supposed to pass argv0, main_addr to this function:
parse_ast_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
assert(parse_ast_fn.size() && "could not find the path to the pyston src dir");
while (llvm::sys::path::filename(parse_ast_fn) != "pyston") {
llvm::sys::path::remove_filename(parse_ast_fn);
}
llvm::sys::path::append(parse_ast_fn, "src/codegen/parse_ast.py");
return std::string("python -S ") + parse_ast_fn.str().str() + " " + fn;
}
AST_Module* parse(const char* fn) {
Timer _t("parsing");
std::string cmdline = "python codegen/parse_ast.py ";
cmdline += fn;
FILE* fp = popen(cmdline.c_str(), "r");
FILE* fp = popen(getParserCommandLine(fn).c_str(), "r");
BufferedReader* reader = new BufferedReader(fp);
AST* rtn = readASTMisc(reader);
......@@ -820,15 +832,7 @@ AST_Module* parse(const char* fn) {
#define LENGTH_SUFFIX_LENGTH 4
static void _reparse(const char* fn, const std::string& cache_fn) {
llvm::SmallString<128> parse_ast_fn;
// TODO supposed to pass argv0, main_addr to this function:
parse_ast_fn = llvm::sys::fs::getMainExecutable(NULL, NULL);
assert(parse_ast_fn.size() && "could not find the path to the pyston src dir");
llvm::sys::path::remove_filename(parse_ast_fn);
llvm::sys::path::append(parse_ast_fn, "codegen/parse_ast.py");
std::string cmdline = std::string("python -S ") + parse_ast_fn.str().str() + " " + fn;
FILE* parser = popen(cmdline.c_str(), "r");
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
FILE* cache_fp = fopen(cache_fn.c_str(), "w");
assert(cache_fp);
......
......@@ -513,6 +513,18 @@ void* AST_Index::accept_expr(ExprVisitor* v) {
return v->visit_index(this);
}
void AST_Invoke::accept(ASTVisitor* v) {
bool skip = v->visit_invoke(this);
if (skip)
return;
this->stmt->accept(v);
}
void AST_Invoke::accept_stmt(StmtVisitor* v) {
return v->visit_invoke(this);
}
void AST_keyword::accept(ASTVisitor* v) {
bool skip = v->visit_keyword(this);
if (skip)
......@@ -521,6 +533,18 @@ void AST_keyword::accept(ASTVisitor* v) {
value->accept(v);
}
void AST_LangPrimitive::accept(ASTVisitor* v) {
bool skip = v->visit_langprimitive(this);
if (skip)
return;
visitVector(args, v);
}
void* AST_LangPrimitive::accept_expr(ExprVisitor* v) {
return v->visit_langprimitive(this);
}
void AST_List::accept(ASTVisitor* v) {
bool skip = v->visit_list(this);
if (skip)
......@@ -1175,6 +1199,38 @@ bool PrintVisitor::visit_index(AST_Index* node) {
return false;
}
bool PrintVisitor::visit_invoke(AST_Invoke* node) {
// printf("invoke: ");
// node->value->accept(this);
// printf("; on success goto %d; on error goto %d", node->normal_dest->idx, node->exc_dest->idx);
printf("invoke %d %d: ", node->normal_dest->idx, node->exc_dest->idx);
node->stmt->accept(this);
return true;
}
bool PrintVisitor::visit_langprimitive(AST_LangPrimitive* node) {
printf(":");
switch (node->opcode) {
case AST_LangPrimitive::ISINSTANCE:
printf("isinstance");
break;
case AST_LangPrimitive::LANDINGPAD:
printf("landingpad");
break;
default:
RELEASE_ASSERT(0, "%d", node->opcode);
}
printf("(");
for (int i = 0, n = node->args.size(); i < n; ++i) {
if (i > 0)
printf(", ");
node->args[i]->accept(this);
}
printf(")");
return true;
}
bool PrintVisitor::visit_list(AST_List* node) {
printf("[");
for (int i = 0, n = node->elts.size(); i < n; ++i) {
......@@ -1548,6 +1604,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_excepthandler(AST_ExceptHandler* node) {
output->push_back(node);
return false;
}
virtual bool visit_expr(AST_Expr* node) {
output->push_back(node);
return false;
......@@ -1588,6 +1648,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_langprimitive(AST_LangPrimitive* node) {
output->push_back(node);
return false;
}
virtual bool visit_list(AST_List* node) {
output->push_back(node);
return false;
......@@ -1616,6 +1680,10 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_raise(AST_Raise* node) {
output->push_back(node);
return false;
}
virtual bool visit_repr(AST_Repr* node) {
output->push_back(node);
return false;
......@@ -1636,6 +1704,14 @@ public:
output->push_back(node);
return false;
}
virtual bool visit_tryexcept(AST_TryExcept* node) {
output->push_back(node);
return false;
}
virtual bool visit_tryfinally(AST_TryFinally* node) {
output->push_back(node);
return false;
}
virtual bool visit_tuple(AST_Tuple* node) {
output->push_back(node);
return false;
......
......@@ -120,6 +120,8 @@ enum AST_TYPE {
Jump = 201,
ClsAttribute = 202,
AugBinOp = 203,
Invoke = 204,
LangPrimitive = 205,
};
};
......@@ -620,7 +622,7 @@ public:
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
AST_Raise() : AST_stmt(AST_TYPE::Raise) {}
AST_Raise() : AST_stmt(AST_TYPE::Raise), arg0(NULL), arg1(NULL), arg2(NULL) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Raise;
};
......@@ -795,6 +797,41 @@ public:
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::ClsAttribute;
};
class AST_Invoke : public AST_stmt {
public:
AST_stmt* stmt;
CFGBlock* normal_dest, *exc_dest;
virtual void accept(ASTVisitor* v);
virtual void accept_stmt(StmtVisitor* v);
AST_Invoke(AST_stmt* stmt) : AST_stmt(AST_TYPE::Invoke), stmt(stmt) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::Invoke;
};
// "LangPrimitive" represents operations that "primitive" to the language,
// but aren't directly *exactly* representable as normal Python.
// ClsAttribute would fall into this category, as would isinstance (which
// is not the same as the "isinstance" name since that could get redefined).
class AST_LangPrimitive : public AST_expr {
public:
enum Opcodes {
ISINSTANCE,
LANDINGPAD,
} opcode;
std::vector<AST_expr*> args;
virtual void accept(ASTVisitor* v);
virtual void* accept_expr(ExprVisitor* v);
AST_LangPrimitive(Opcodes opcode) : AST_expr(AST_TYPE::LangPrimitive), opcode(opcode) {}
static const AST_TYPE::AST_TYPE TYPE = AST_TYPE::LangPrimitive;
};
template <typename T> T* ast_cast(AST* node) {
assert(node->type == T::TYPE);
return static_cast<T*>(node);
......@@ -834,7 +871,9 @@ public:
virtual bool visit_import(AST_Import* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_importfrom(AST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_index(AST_Index* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_invoke(AST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_keyword(AST_keyword* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_langprimitive(AST_LangPrimitive* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_list(AST_List* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_listcomp(AST_ListComp* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_module(AST_Module* node) { RELEASE_ASSERT(0, ""); }
......@@ -891,7 +930,9 @@ public:
virtual bool visit_import(AST_Import* node) { return false; }
virtual bool visit_importfrom(AST_ImportFrom* node) { return false; }
virtual bool visit_index(AST_Index* node) { return false; }
virtual bool visit_invoke(AST_Invoke* node) { return false; }
virtual bool visit_keyword(AST_keyword* node) { return false; }
virtual bool visit_langprimitive(AST_LangPrimitive* node) { return false; }
virtual bool visit_list(AST_List* node) { return false; }
virtual bool visit_listcomp(AST_ListComp* node) { return false; }
virtual bool visit_module(AST_Module* node) { return false; }
......@@ -931,6 +972,7 @@ public:
virtual void* visit_dict(AST_Dict* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_ifexp(AST_IfExp* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_index(AST_Index* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_langprimitive(AST_LangPrimitive* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_list(AST_List* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_listcomp(AST_ListComp* node) { RELEASE_ASSERT(0, ""); }
virtual void* visit_name(AST_Name* node) { RELEASE_ASSERT(0, ""); }
......@@ -961,6 +1003,7 @@ public:
virtual void visit_if(AST_If* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_import(AST_Import* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_importfrom(AST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_invoke(AST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_pass(AST_Pass* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_print(AST_Print* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_raise(AST_Raise* node) { RELEASE_ASSERT(0, ""); }
......@@ -1011,7 +1054,9 @@ public:
virtual bool visit_import(AST_Import* node);
virtual bool visit_importfrom(AST_ImportFrom* node);
virtual bool visit_index(AST_Index* node);
virtual bool visit_invoke(AST_Invoke* node);
virtual bool visit_keyword(AST_keyword* node);
virtual bool visit_langprimitive(AST_LangPrimitive* node);
virtual bool visit_list(AST_List* node);
virtual bool visit_listcomp(AST_ListComp* node);
virtual bool visit_module(AST_Module* node);
......@@ -1050,6 +1095,8 @@ template <class T, class R> void findNodes(const R& roots, std::vector<T*>& outp
output.push_back(reinterpret_cast<T*>(n));
}
}
std::string getOpSymbol(int op_type);
};
#endif
......@@ -56,6 +56,12 @@ private:
std::vector<LoopInfo> loops;
std::vector<CFGBlock*> returns;
struct ExcBlockInfo {
CFGBlock* exc_dest;
std::string exc_obj_name;
};
std::vector<ExcBlockInfo> exc_handlers;
void pushLoop(CFGBlock* continue_dest, CFGBlock* break_dest) {
LoopInfo loop;
loop.continue_dest = continue_dest;
......@@ -394,6 +400,14 @@ private:
return rtn;
}
AST_expr* remapLangPrimitive(AST_LangPrimitive* node) {
AST_LangPrimitive* rtn = new AST_LangPrimitive(node->opcode);
for (AST_expr* arg : node->args) {
rtn->args.push_back(remapExpr(arg));
}
return rtn;
}
AST_expr* remapList(AST_List* node) {
assert(node->ctx_type == AST_TYPE::Load);
......@@ -621,6 +635,9 @@ private:
case AST_TYPE::Index:
rtn = remapIndex(ast_cast<AST_Index>(node));
break;
case AST_TYPE::LangPrimitive:
rtn = remapLangPrimitive(ast_cast<AST_LangPrimitive>(node));
break;
case AST_TYPE::List:
rtn = remapList(ast_cast<AST_List>(node));
break;
......@@ -670,33 +687,88 @@ public:
~CFGVisitor() {
assert(loops.size() == 0);
assert(returns.size() == 0);
assert(exc_handlers.size() == 0);
}
void push_back(AST_stmt* node) {
if (curblock)
assert(node->type != AST_TYPE::Invoke);
if (!curblock)
return;
if (exc_handlers.size() == 0) {
curblock->push_back(node);
return;
}
AST_TYPE::AST_TYPE type = node->type;
if (type == AST_TYPE::Jump) {
curblock->push_back(node);
return;
}
if (type == AST_TYPE::Branch) {
AST_TYPE::AST_TYPE test_type = ast_cast<AST_Branch>(node)->test->type;
assert(test_type == AST_TYPE::Name || test_type == AST_TYPE::Num);
curblock->push_back(node);
return;
}
if (type == AST_TYPE::Return) {
curblock->push_back(node);
return;
}
CFGBlock* normal_dest = cfg->addBlock();
// Add an extra exc_dest trampoline to prevent critical edges:
CFGBlock* exc_dest = cfg->addBlock();
AST_Invoke* invoke = new AST_Invoke(node);
invoke->normal_dest = normal_dest;
invoke->exc_dest = exc_dest;
curblock->push_back(invoke);
curblock->connectTo(normal_dest);
curblock->connectTo(exc_dest);
ExcBlockInfo& exc_info = exc_handlers.back();
curblock = exc_dest;
curblock->push_back(makeAssign(exc_info.exc_obj_name, new AST_LangPrimitive(AST_LangPrimitive::LANDINGPAD)));
AST_Jump* j = new AST_Jump();
j->target = exc_info.exc_dest;
curblock->push_back(j);
curblock->connectTo(exc_info.exc_dest);
curblock = normal_dest;
}
virtual bool visit_classdef(AST_ClassDef* 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_import(AST_Import* node) {
push_back(node);
return true;
}
virtual bool visit_importfrom(AST_ImportFrom* node) {
push_back(node);
return true;
}
virtual bool visit_pass(AST_Pass* node) { return true; }
bool visit_assert(AST_Assert* node) override {
......@@ -749,13 +821,16 @@ public:
}
virtual bool visit_assign(AST_Assign* node) {
AST_Assign* remapped = new AST_Assign();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapExpr(node->value, false);
// TODO bad that it's reusing the AST nodes?
remapped->targets = node->targets;
push_back(remapped);
AST_expr* remapped_value = remapExpr(node->value);
for (AST_expr* target : node->targets) {
AST_Assign* remapped = new AST_Assign();
remapped->lineno = node->lineno;
remapped->col_offset = node->col_offset;
remapped->value = remapped_value;
remapped->targets.push_back(target);
push_back(remapped);
}
return true;
}
......@@ -958,7 +1033,7 @@ public:
AST_Jump* j = makeJump();
push_back(j);
assert(loops.size());
j->target = loops[loops.size() - 1].break_dest;
j->target = getBreak();
curblock->connectTo(j->target, true);
curblock = NULL;
......@@ -978,10 +1053,9 @@ public:
AST_Jump* j = makeJump();
push_back(j);
assert(loops.size());
j->target = loops[loops.size() - 1].continue_dest;
j->target = getContinue();
curblock->connectTo(j->target, true);
// See visit_break for explanation:
curblock = NULL;
return true;
}
......@@ -1155,6 +1229,111 @@ public:
return true;
}
bool visit_raise(AST_Raise* node) override {
AST_Raise* remapped = new AST_Raise();
if (node->arg0)
remapped->arg0 = remapExpr(node->arg0);
if (node->arg1)
remapped->arg1 = remapExpr(node->arg1);
if (node->arg2)
remapped->arg2 = remapExpr(node->arg2);
push_back(remapped);
return true;
}
bool visit_tryexcept(AST_TryExcept* node) override {
assert(node->handlers.size() > 0);
CFGBlock* exc_handler_block = cfg->addDeferredBlock();
std::string exc_obj_name = nodeName(node);
exc_handlers.push_back({ exc_handler_block, exc_obj_name });
for (AST_stmt* subnode : node->body) {
subnode->accept(this);
}
exc_handlers.pop_back();
for (AST_stmt* subnode : node->orelse) {
subnode->accept(this);
}
CFGBlock* join_block = cfg->addDeferredBlock();
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
if (exc_handler_block->predecessors.size() == 0) {
delete exc_handler_block;
} else {
cfg->placeBlock(exc_handler_block);
curblock = exc_handler_block;
AST_expr* exc_obj = makeName(exc_obj_name, AST_TYPE::Load);
bool caught_all = false;
for (AST_ExceptHandler* exc_handler : node->handlers) {
assert(!caught_all && "bare except clause not the last one in the list?");
CFGBlock* exc_next = nullptr;
if (exc_handler->type) {
AST_expr* handled_type = remapExpr(exc_handler->type);
AST_LangPrimitive* is_caught_here = new AST_LangPrimitive(AST_LangPrimitive::ISINSTANCE);
is_caught_here->args.push_back(exc_obj);
is_caught_here->args.push_back(handled_type);
is_caught_here->args.push_back(makeNum(1)); // flag: false_on_noncls
CFGBlock* exc_handle = cfg->addBlock();
exc_next = cfg->addDeferredBlock();
AST_Branch* br = new AST_Branch();
br->test = remapExpr(is_caught_here);
br->iftrue = exc_handle;
br->iffalse = exc_next;
curblock->connectTo(exc_handle);
curblock->connectTo(exc_next);
push_back(br);
curblock = exc_handle;
} else {
caught_all = true;
}
if (exc_handler->name) {
push_back(makeAssign(exc_handler->name, exc_obj));
}
for (AST_stmt* subnode : exc_handler->body) {
subnode->accept(this);
}
AST_Jump* j = new AST_Jump();
j->target = join_block;
push_back(j);
curblock->connectTo(join_block);
if (exc_next) {
cfg->placeBlock(exc_next);
} else {
assert(caught_all);
}
curblock = exc_next;
}
if (!caught_all) {
AST_Raise* raise = new AST_Raise();
raise->arg0 = exc_obj;
push_back(raise);
curblock = NULL;
}
}
cfg->placeBlock(join_block);
curblock = join_block;
return true;
}
virtual bool visit_with(AST_With* node) {
char ctxmgrname_buf[80];
snprintf(ctxmgrname_buf, 80, "#ctxmgr_%p", node);
......@@ -1182,13 +1361,12 @@ public:
break_dest = cfg->addDeferredBlock();
break_dest->info = "with_break";
orig_continue_dest = loops[loops.size() - 1].continue_dest;
orig_break_dest = loops[loops.size() - 1].break_dest;
orig_continue_dest = getContinue();
orig_break_dest = getBreak();
pushLoop(continue_dest, break_dest);
}
CFGBlock* orig_return_dest = getReturn();
CFGBlock* return_dest = cfg->addDeferredBlock();
return_dest->info = "with_return";
pushReturn(return_dest);
......@@ -1309,14 +1487,22 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
return_stmt->value = NULL;
visitor.push_back(return_stmt);
// rtn->print();
#ifndef NDEBUG
////
// Check some properties expected by later stages:
assert(rtn->getStartingBlock()->predecessors.size() == 0);
for (CFGBlock* b : rtn->blocks) {
ASSERT(b->idx != -1, "Forgot to place a block!");
for (CFGBlock* b2 : b->predecessors) {
ASSERT(b2->idx != -1, "Forgot to place a block!");
}
for (CFGBlock* b2 : b->successors) {
ASSERT(b2->idx != -1, "Forgot to place a block!");
}
}
// We need to generate the CFG in a way that doesn't have any critical edges,
// since the ir generation requires that.
// We could do this with a separate critical-edge-breaking pass, but for now
......@@ -1354,6 +1540,11 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
assert(rtn->blocks[i]->predecessors[0]->idx < i);
}
assert(rtn->getStartingBlock()->idx == 0);
// TODO make sure the result of Invoke nodes are not used on the exceptional path
#endif
// Prune unnecessary blocks from the CFG.
// Not strictly necessary, but makes the output easier to look at,
// and can make the analyses more efficient.
......@@ -1386,34 +1577,9 @@ CFG* computeCFG(AST_TYPE::AST_TYPE root_type, std::vector<AST_stmt*> body) {
}
}
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
// in the computation, but then again the sharing can actually be nice because
// it indicates that there are certain similarities between the points, and things such
// as type recorders will end up being shared.
std::vector<AST*> all_ast_nodes;
for (CFGBlock* block : rtn->blocks) {
flatten(block->body, all_ast_nodes, false);
}
std::unordered_set<AST*> seen_ast_nodes;
for (AST* n : all_ast_nodes) {
if (seen_ast_nodes.count(n)) {
if (VERBOSITY())
rtn->print();
printf("This node appears multiple times in the tree:\n");
print_ast(n);
printf("\n");
assert(0);
}
seen_ast_nodes.insert(n);
}
*/
#endif
return rtn;
}
}
......@@ -228,7 +228,6 @@ extern "C" Box* callCompiledFunc(CompiledFunction* cf, int64_t nargs, Box* arg1,
std::string getOpName(int op_type);
std::string getReverseOpName(int op_type);
std::string getInplaceOpName(int op_type);
std::string getOpSymbol(int op_type);
std::string getInplaceOpSymbol(int op_type);
typedef bool i1;
......
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