Commit 40cb8002 authored by Marius Wachtler's avatar Marius Wachtler

BST: switch to a gapless bytecode

- all instructions of the CFG are directly emitted a single memory region
- all instructions are packed and follow each other directly
- the CFGBlock just stores the offset into the bytecode where the first instruction of the block is located
- invokes are only a bit in the opcode field which when set means that the pointers to the normal and exc CFGBlocks* directly follow the normal instruction
parent 138433d8
......@@ -102,7 +102,7 @@ LivenessAnalysis::LivenessAnalysis(CFG* cfg, const CodeConstants& code_constants
for (CFGBlock* b : cfg->blocks) {
auto visitor = new LivenessBBVisitor(this); // livenessCache unique_ptr will delete it.
for (BST_stmt* stmt : b->body) {
for (BST_stmt* stmt : *b) {
stmt->accept(visitor);
}
liveness_cache.insert(std::make_pair(b, std::unique_ptr<LivenessBBVisitor>(visitor)));
......@@ -257,8 +257,8 @@ public:
void DefinednessBBAnalyzer::processBB(Map& starting, CFGBlock* block) const {
DefinednessVisitor visitor(code_constants, starting);
for (int i = 0; i < block->body.size(); i++) {
block->body[i]->accept(&visitor);
for (BST_stmt* stmt : *block) {
stmt->accept(&visitor);
}
if (VERBOSITY("analysis") >= 3) {
......
......@@ -101,8 +101,8 @@ private:
speculation(speculation) {}
void run() {
for (int i = 0; i < block->body.size(); i++) {
block->body[i]->accept_stmt(this);
for (BST_stmt* stmt : *block) {
stmt->accept_stmt(this);
}
}
......@@ -526,8 +526,6 @@ private:
getType(node->vreg_locals);
}
void visit_invoke(BST_Invoke* node) override { node->stmt->accept_stmt(this); }
void visit_jump(BST_Jump* node) override {}
void visit_print(BST_Print* node) override {
......
......@@ -74,6 +74,8 @@ public:
static Box* executeInner(ASTInterpreter& interpreter, CFGBlock* start_block, BST_stmt* start_at);
private:
Value executeStmt(BST_stmt* node);
Value createFunction(BST_FunctionDef* node, BoxedCode* node_code);
Value doBinOp(BST_stmt* node, Value left, Value right, int op, BinExpType exp_type);
void doStore(int vreg, STOLEN(Value) value);
......@@ -95,7 +97,6 @@ private:
Value visit_importfrom(BST_ImportFrom* node);
Value visit_importname(BST_ImportName* node);
Value visit_importstar(BST_ImportStar* node);
Value visit_invoke(BST_Invoke* node);
Value visit_jump(BST_Jump* node);
Value visit_landingpad(BST_Landingpad* node);
Value visit_list(BST_List* node);
......@@ -362,7 +363,7 @@ Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
} catch (ExcInfo e) {
--num_inside;
BST_stmt* stmt = getCurrentStatement();
if (stmt->type != BST_TYPE::Invoke)
if (!stmt->is_invoke())
throw e;
assert(getPythonFrameInfo(0) == getFrameInfo());
......@@ -370,7 +371,7 @@ Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
++getCode()->cxx_exception_count[stmt];
caughtCxxException(&e);
next_block = ((BST_Invoke*)stmt)->exc_dest;
next_block = stmt->get_exc_block();
last_exception = e;
}
return nullptr;
......@@ -384,7 +385,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
assert((start_block == NULL) == (start_at == NULL));
if (start_block == NULL) {
start_block = interpreter.source_info->cfg->getStartingBlock();
start_at = start_block->body[0];
start_at = start_block->body();
}
// Important that this happens after RegisterHelper:
......@@ -395,7 +396,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
if (!from_start) {
interpreter.current_block = start_block;
bool started = false;
for (auto s : start_block->body) {
for (auto s : *start_block) {
if (!started) {
if (s != start_at)
continue;
......@@ -404,7 +405,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
interpreter.setCurrentStatement(s);
Py_XDECREF(v.o);
v = interpreter.visit_stmt(s);
v = interpreter.executeStmt(s);
}
} else {
interpreter.next_block = start_block;
......@@ -427,7 +428,7 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
// check if we returned from the baseline JIT because we should do a OSR.
if (unlikely(rtn == (Box*)ASTInterpreterJitInterface::osr_dummy_value)) {
BST_Jump* cur_stmt = (BST_Jump*)interpreter.getCurrentStatement();
RELEASE_ASSERT(cur_stmt->type == BST_TYPE::Jump, "");
RELEASE_ASSERT(cur_stmt->type() == BST_TYPE::Jump, "");
// WARNING: do not put a try catch + rethrow block around this code here.
// it will confuse our unwinder!
rtn = interpreter.doOSR(cur_stmt);
......@@ -449,14 +450,14 @@ Box* ASTInterpreter::executeInner(ASTInterpreter& interpreter, CFGBlock* start_b
interpreter.startJITing(interpreter.current_block);
}
for (BST_stmt* s : interpreter.current_block->body) {
for (BST_stmt* s : *interpreter.current_block) {
interpreter.setCurrentStatement(s);
if (interpreter.jit)
interpreter.jit->emitSetCurrentInst(s);
if (v.o) {
Py_DECREF(v.o);
}
v = interpreter.visit_stmt(s);
v = interpreter.executeStmt(s);
}
}
return v.o;
......@@ -759,11 +760,14 @@ Box* ASTInterpreter::doOSR(BST_Jump* node) {
}
}
Value ASTInterpreter::visit_invoke(BST_Invoke* node) {
Value ASTInterpreter::executeStmt(BST_stmt* node) {
if (!node->is_invoke())
return visit_stmt(node);
Value v;
try {
v = visit_stmt(node->stmt);
next_block = node->normal_dest;
v = visit_stmt(node);
next_block = node->get_normal_block();
if (jit) {
jit->emitJump(next_block);
......@@ -778,7 +782,7 @@ Value ASTInterpreter::visit_invoke(BST_Invoke* node) {
++getCode()->cxx_exception_count[node];
caughtCxxException(&e);
next_block = node->exc_dest;
next_block = node->get_exc_block();
last_exception = e;
}
......@@ -909,7 +913,7 @@ Value ASTInterpreter::visit_stmt(BST_stmt* node) {
// to be careful to wrap pendingCallsCheckHelper, and it can signal that it was careful
// by returning from the function instead of breaking.
switch (node->type) {
switch (node->type()) {
case BST_TYPE::Assert:
visit_assert((BST_Assert*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
......@@ -977,9 +981,6 @@ Value ASTInterpreter::visit_stmt(BST_stmt* node) {
break;
case BST_TYPE::Jump:
return visit_jump((BST_Jump*)node);
case BST_TYPE::Invoke:
visit_invoke((BST_Invoke*)node);
break;
case BST_TYPE::SetExcInfo:
visit_setexcinfo((BST_SetExcInfo*)node);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
......@@ -996,7 +997,7 @@ Value ASTInterpreter::visit_stmt(BST_stmt* node) {
// Handle all cases which are derived from BST_stmt_with_dest
default: {
Value v;
switch (node->type) {
switch (node->type()) {
case BST_TYPE::CopyVReg:
v = visit_copyvreg((BST_CopyVReg*)node);
break;
......@@ -1084,7 +1085,7 @@ Value ASTInterpreter::visit_stmt(BST_stmt* node) {
v = visit_makeslice((BST_MakeSlice*)node);
break;
default:
RELEASE_ASSERT(0, "not implemented %d", node->type);
RELEASE_ASSERT(0, "not implemented %d", node->type());
};
doStore(((BST_stmt_with_dest*)node)->vreg_dst, v);
ASTInterpreterJitInterface::pendingCallsCheckHelper();
......@@ -1425,14 +1426,14 @@ Value ASTInterpreter::visit_call(BST_Call* node) {
bool is_callattr = false;
bool callattr_clsonly = false;
int* vreg_elts = NULL;
if (node->type == BST_TYPE::CallAttr) {
if (node->type() == BST_TYPE::CallAttr) {
is_callattr = true;
callattr_clsonly = false;
auto* attr_ast = bst_cast<BST_CallAttr>(node);
func = getVReg(attr_ast->vreg_value);
attr = getCodeConstants().getInternedString(attr_ast->index_attr);
vreg_elts = bst_cast<BST_CallAttr>(node)->elts;
} else if (node->type == BST_TYPE::CallClsAttr) {
} else if (node->type() == BST_TYPE::CallClsAttr) {
is_callattr = true;
callattr_clsonly = true;
auto* attr_ast = bst_cast<BST_CallClsAttr>(node);
......@@ -2109,30 +2110,28 @@ extern "C" Box* astInterpretDeoptFromASM(BoxedCode* code, BST_stmt* enclosing_st
CFGBlock* start_block = NULL;
BST_stmt* starting_statement = NULL;
while (true) {
if (enclosing_stmt->type == BST_TYPE::Invoke) {
auto invoke = bst_cast<BST_Invoke>(enclosing_stmt);
start_block = invoke->normal_dest;
starting_statement = start_block->body[0];
enclosing_stmt = invoke->stmt;
} else if (enclosing_stmt->has_dest_vreg()) {
if (enclosing_stmt->is_invoke()) {
start_block = enclosing_stmt->get_normal_block();
starting_statement = start_block->body();
}
if (enclosing_stmt->has_dest_vreg()) {
int vreg_dst = ((BST_stmt_with_dest*)enclosing_stmt)->vreg_dst;
if (vreg_dst != VREG_UNDEFINED)
interpreter.addSymbol(vreg_dst, expr_val, true);
break;
} else {
RELEASE_ASSERT(0, "encountered an yet unimplemented opcode (got %d)", enclosing_stmt->type);
RELEASE_ASSERT(0, "encountered an yet unimplemented opcode (got %d)", enclosing_stmt->type());
}
}
if (start_block == NULL) {
// TODO innefficient
for (auto block : code->source->cfg->blocks) {
int n = block->body.size();
for (int i = 0; i < n; i++) {
if (block->body[i] == enclosing_stmt) {
ASSERT(i + 1 < n, "how could we deopt from a non-invoke terminator?");
for (auto it = block->begin(), it_end = block->end(); it != it_end; ++it) {
if (*it == enclosing_stmt) {
ASSERT(!(*it)->is_terminator(), "how could we deopt from a non-invoke terminator?");
start_block = block;
starting_statement = block->body[i + 1];
starting_statement = *(++it);
break;
}
}
......
......@@ -69,7 +69,7 @@ SourceInfo::SourceInfo(BoxedModule* m, ScopingResults scoping, FutureFlags futur
}
SourceInfo::~SourceInfo() {
// TODO: release memory..
delete cfg;
}
void FunctionAddressRegistry::registerFunction(const std::string& name, void* addr, int length,
......
......@@ -371,7 +371,7 @@ protected:
public:
static std::pair<SymbolTable*, bool /* created_new_sym_table */>
removeDestVRegsFromSymTable(const CodeConstants& code_constants, SymbolTable* sym_table, BST_Invoke* stmt) {
removeDestVRegsFromSymTable(const CodeConstants& code_constants, SymbolTable* sym_table, BST_stmt* stmt) {
SymTableDstVRegDeleter visitor(code_constants, sym_table);
stmt->accept(&visitor);
return std::make_pair(visitor.sym_table, visitor.created_new_sym_table);
......@@ -649,7 +649,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// Function-entry safepoint:
// TODO might be more efficient to do post-call safepoints?
generator->doSafePoint(block->body[0]);
generator->doSafePoint(block->body());
} else if (entry_descriptor && block == entry_descriptor->backedge->target) {
assert(block->predecessors.size() > 1);
assert(osr_entry_block);
......@@ -742,13 +742,13 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// are disallowed
auto pred = block->predecessors[0];
auto last_inst = pred->body.back();
auto last_inst = pred->getLastStmt();
SymbolTable* sym_table = ending_symbol_tables[pred];
bool created_new_sym_table = false;
if (last_inst->type == BST_TYPE::Invoke && bst_cast<BST_Invoke>(last_inst)->exc_dest == block)
if (last_inst->is_invoke() && last_inst->get_exc_block() == block)
std::tie(sym_table, created_new_sym_table) = SymTableDstVRegDeleter::removeDestVRegsFromSymTable(
irstate->getCodeConstants(), sym_table, bst_cast<BST_Invoke>(last_inst));
irstate->getCodeConstants(), sym_table, last_inst);
generator->copySymbolsFrom(sym_table);
for (auto&& p : *definedness_tables[pred]) {
......@@ -809,7 +809,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
if (predecessor->idx > block->idx) {
// Loop safepoint:
// TODO does it matter which side of the backedge these are on?
generator->doSafePoint(block->body[0]);
generator->doSafePoint(block->body());
break;
}
}
......@@ -824,9 +824,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
llvm_exit_blocks[block] = ending_st.ending_block;
if (ending_st.exception_state.size()) {
BST_stmt* last_stmt = block->body.back();
assert(last_stmt->type == BST_TYPE::Invoke);
CFGBlock* exc_block = bst_cast<BST_Invoke>(last_stmt)->exc_dest;
BST_stmt* last_stmt = block->getLastStmt();
assert(last_stmt->is_invoke());
CFGBlock* exc_block = last_stmt->get_exc_block();
assert(!incoming_exception_state.count(exc_block));
incoming_exception_state.insert(std::make_pair(exc_block, ending_st.exception_state));
......
......@@ -1098,14 +1098,14 @@ private:
InternedString attr;
CompilerVariable* func;
int* vreg_elts = NULL;
if (node->type == BST_TYPE::CallAttr) {
if (node->type() == BST_TYPE::CallAttr) {
is_callattr = true;
callattr_clsonly = false;
auto* attr_ast = bst_cast<BST_CallAttr>(node);
vreg_elts = bst_cast<BST_CallAttr>(node)->elts;
func = evalVReg(attr_ast->vreg_value);
attr = irstate->getCodeConstants().getInternedString(attr_ast->index_attr);
} else if (node->type == BST_TYPE::CallClsAttr) {
} else if (node->type() == BST_TYPE::CallClsAttr) {
is_callattr = true;
callattr_clsonly = true;
auto* attr_ast = bst_cast<BST_CallClsAttr>(node);
......@@ -2406,7 +2406,7 @@ private:
llvm::DebugLoc::get(node->lineno, 0, irstate->getFuncDbgInfo()));
}
switch (node->type) {
switch (node->type()) {
case BST_TYPE::Assert:
doAssert(bst_cast<BST_Assert>(node), unw_info);
break;
......@@ -2455,20 +2455,6 @@ private:
assert(!unw_info.hasHandler());
doJump(bst_cast<BST_Jump>(node), unw_info);
break;
case BST_TYPE::Invoke: {
assert(!unw_info.hasHandler());
BST_Invoke* invoke = bst_cast<BST_Invoke>(node);
doStmt(invoke->stmt, UnwindInfo(irstate->getCode(), node, entry_blocks[invoke->exc_dest]));
assert(state == RUNNING || state == DEAD);
if (state == RUNNING) {
emitter.getBuilder()->CreateBr(entry_blocks[invoke->normal_dest]);
endBlock(FINISHED);
}
break;
}
case BST_TYPE::Raise:
doRaise(bst_cast<BST_Raise>(node), unw_info);
break;
......@@ -2485,7 +2471,7 @@ private:
// Handle all cases which are derived from BST_stmt_with_dest
default: {
CompilerVariable* rtn = NULL;
switch (node->type) {
switch (node->type()) {
case BST_TYPE::CopyVReg:
rtn = evalAssign(bst_cast<BST_CopyVReg>(node), unw_info);
break;
......@@ -2573,7 +2559,7 @@ private:
rtn = evalMakeSlice(bst_cast<BST_MakeSlice>(node), unw_info);
break;
default:
printf("Unhandled stmt type at " __FILE__ ":" STRINGIFY(__LINE__) ": %d\n", node->type);
printf("Unhandled stmt type at " __FILE__ ":" STRINGIFY(__LINE__) ": %d\n", node->type());
exit(1);
}
rtn = evalSliceExprPost((BST_stmt_with_dest*)node, unw_info, rtn);
......@@ -2951,18 +2937,25 @@ public:
}
printf("\n");
}
for (int i = 0; i < block->body.size(); i++) {
for (BST_stmt* stmt : *block) {
if (state == DEAD)
break;
assert(state != FINISHED);
#if ENABLE_SAMPLING_PROFILER
auto stmt = block->body[i];
if (stmt->type != BST_TYPE::Landigpad && stmt->lineno > 0)
doSafePoint(block->body[i]);
doSafePoint(stmt);
#endif
if (stmt->is_invoke()) {
doStmt(stmt, UnwindInfo(irstate->getCode(), stmt, entry_blocks[stmt->get_exc_block()]));
doStmt(block->body[i], UnwindInfo(irstate->getCode(), block->body[i], NULL));
assert(state == RUNNING || state == DEAD);
if (state == RUNNING) {
emitter.getBuilder()->CreateBr(entry_blocks[stmt->get_normal_block()]);
endBlock(FINISHED);
}
} else
doStmt(stmt, UnwindInfo(irstate->getCode(), stmt, NULL));
}
if (VERBOSITY("irgenerator") >= 2) { // print ending symbol table
printf(" %d fini:", block->idx);
......
......@@ -35,7 +35,6 @@ class MDNode;
namespace pyston {
class BST_Invoke;
class CFGBlock;
class GCBuilder;
struct PatchpointInfo;
......
......@@ -43,6 +43,25 @@ template <class T> static void visitVector(const std::vector<T*>& vec, BSTVisito
}
}
void BST_stmt::accept(BSTVisitor* v) {
switch (type()) {
#define DISPATCH_ACCEPT(x, y) \
case BST_TYPE::x: \
return bst_cast<BST_##x>(this)->accept(v);
FOREACH_TYPE(DISPATCH_ACCEPT)
};
}
void BST_stmt::accept_stmt(StmtVisitor* v) {
switch (type()) {
#define DISPATCH_ACCEPT_STMT(x, y) \
case BST_TYPE::x: \
return bst_cast<BST_##x>(this)->accept_stmt(v);
FOREACH_TYPE(DISPATCH_ACCEPT_STMT)
};
}
void BST_Assert::accept(BSTVisitor* v) {
bool skip = v->visit_assert(this);
if (skip)
......@@ -272,18 +291,6 @@ void BST_FunctionDef::accept_stmt(StmtVisitor* v) {
v->visit_functiondef(this);
}
void BST_Invoke::accept(BSTVisitor* v) {
bool skip = v->visit_invoke(this);
if (skip)
return;
this->stmt->accept(v);
}
void BST_Invoke::accept_stmt(StmtVisitor* v) {
return v->visit_invoke(this);
}
void BST_Landingpad::accept(BSTVisitor* v) {
bool skip = v->visit_landingpad(this);
if (skip)
......@@ -773,7 +780,15 @@ bool PrintVisitor::visit_vreg(int* vreg, bool is_dst) {
return true;
}
bool PrintVisitor::check_if_invoke(BST_stmt* node) {
if (node->is_invoke())
stream << "invoke " << node->get_normal_block()->idx << " " << node->get_exc_block()->idx << ": ";
return false;
}
bool PrintVisitor::visit_assert(BST_Assert* node) {
check_if_invoke(node);
stream << "assert 0";
if (node->vreg_msg != VREG_UNDEFINED) {
stream << ", ";
......@@ -783,6 +798,8 @@ bool PrintVisitor::visit_assert(BST_Assert* node) {
}
bool PrintVisitor::visit_copyvreg(BST_CopyVReg* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "nokill ";
visit_vreg(&node->vreg_src);
......@@ -790,6 +807,8 @@ bool PrintVisitor::visit_copyvreg(BST_CopyVReg* node) {
}
bool PrintVisitor::visit_augbinop(BST_AugBinOp* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_left);
stream << " =" << getOpSymbol(node->op_type) << " ";
......@@ -798,6 +817,8 @@ bool PrintVisitor::visit_augbinop(BST_AugBinOp* node) {
}
bool PrintVisitor::visit_binop(BST_BinOp* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_left);
stream << " " << getOpSymbol(node->op_type) << " ";
......@@ -806,6 +827,8 @@ bool PrintVisitor::visit_binop(BST_BinOp* node) {
}
bool PrintVisitor::visit_callfunc(BST_CallFunc* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_func);
stream << "(";
......@@ -834,6 +857,8 @@ bool PrintVisitor::visit_callfunc(BST_CallFunc* node) {
}
bool PrintVisitor::visit_callattr(BST_CallAttr* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_value);
stream << ".";
......@@ -864,6 +889,8 @@ bool PrintVisitor::visit_callattr(BST_CallAttr* node) {
}
bool PrintVisitor::visit_callclsattr(BST_CallClsAttr* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_value);
stream << ":";
......@@ -894,6 +921,8 @@ bool PrintVisitor::visit_callclsattr(BST_CallClsAttr* node) {
}
bool PrintVisitor::visit_compare(BST_Compare* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_left);
stream << " " << getOpSymbol(node->op) << " ";
......@@ -903,6 +932,8 @@ bool PrintVisitor::visit_compare(BST_Compare* node) {
}
bool PrintVisitor::visit_classdef(BST_ClassDef* node) {
check_if_invoke(node);
for (int i = 0, n = node->num_decorator; i < n; i++) {
stream << "@";
visit_vreg(&node->decorator[i]);
......@@ -930,6 +961,8 @@ bool PrintVisitor::visit_classdef(BST_ClassDef* node) {
}
bool PrintVisitor::visit_deletesub(BST_DeleteSub* node) {
check_if_invoke(node);
stream << "del ";
visit_vreg(&node->vreg_value);
stream << "[";
......@@ -938,6 +971,8 @@ bool PrintVisitor::visit_deletesub(BST_DeleteSub* node) {
return true;
}
bool PrintVisitor::visit_deletesubslice(BST_DeleteSubSlice* node) {
check_if_invoke(node);
stream << "del ";
visit_vreg(&node->vreg_value);
stream << "[";
......@@ -951,6 +986,8 @@ bool PrintVisitor::visit_deletesubslice(BST_DeleteSubSlice* node) {
return true;
}
bool PrintVisitor::visit_deleteattr(BST_DeleteAttr* node) {
check_if_invoke(node);
stream << "del ";
visit_vreg(&node->vreg_value);
stream << '.';
......@@ -958,6 +995,8 @@ bool PrintVisitor::visit_deleteattr(BST_DeleteAttr* node) {
return true;
}
bool PrintVisitor::visit_deletename(BST_DeleteName* node) {
check_if_invoke(node);
stream << "del ";
if (node->lookup_type == ScopeInfo::VarScopeType::FAST || node->lookup_type == ScopeInfo::VarScopeType::CLOSURE) {
visit_vreg(&node->vreg);
......@@ -968,12 +1007,16 @@ bool PrintVisitor::visit_deletename(BST_DeleteName* node) {
}
bool PrintVisitor::visit_dict(BST_Dict* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "{}";
return true;
}
bool PrintVisitor::visit_exec(BST_Exec* node) {
check_if_invoke(node);
stream << "exec ";
visit_vreg(&node->vreg_body);
......@@ -991,6 +1034,8 @@ bool PrintVisitor::visit_exec(BST_Exec* node) {
}
bool PrintVisitor::visit_functiondef(BST_FunctionDef* node) {
check_if_invoke(node);
for (int i = 0; i < node->num_decorator; ++i) {
stream << "@";
visit_vreg(&node->elts[i]);
......@@ -1030,23 +1075,23 @@ bool PrintVisitor::visit_functiondef(BST_FunctionDef* node) {
return true;
}
bool PrintVisitor::visit_invoke(BST_Invoke* node) {
stream << "invoke " << node->normal_dest->idx << " " << node->exc_dest->idx << ": ";
node->stmt->accept(this);
return true;
}
bool PrintVisitor::visit_landingpad(BST_Landingpad* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":LANDINGPAD()";
return true;
}
bool PrintVisitor::visit_locals(BST_Locals* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":LOCALS()";
return true;
}
bool PrintVisitor::visit_getiter(BST_GetIter* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":GET_ITER(";
visit_vreg(&node->vreg_value);
......@@ -1054,6 +1099,8 @@ bool PrintVisitor::visit_getiter(BST_GetIter* node) {
return true;
}
bool PrintVisitor::visit_importfrom(BST_ImportFrom* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":IMPORT_FROM(";
visit_vreg(&node->vreg_module);
......@@ -1063,6 +1110,8 @@ bool PrintVisitor::visit_importfrom(BST_ImportFrom* node) {
return true;
}
bool PrintVisitor::visit_importname(BST_ImportName* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":IMPORT_NAME(";
visit_vreg(&node->vreg_from);
......@@ -1072,6 +1121,8 @@ bool PrintVisitor::visit_importname(BST_ImportName* node) {
return true;
}
bool PrintVisitor::visit_importstar(BST_ImportStar* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":IMPORT_STAR(";
visit_vreg(&node->vreg_name);
......@@ -1079,6 +1130,8 @@ bool PrintVisitor::visit_importstar(BST_ImportStar* node) {
return true;
}
bool PrintVisitor::visit_nonzero(BST_Nonzero* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":NONZERO(";
visit_vreg(&node->vreg_value);
......@@ -1086,6 +1139,8 @@ bool PrintVisitor::visit_nonzero(BST_Nonzero* node) {
return true;
}
bool PrintVisitor::visit_checkexcmatch(BST_CheckExcMatch* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":CHECK_EXC_MATCH(";
visit_vreg(&node->vreg_value);
......@@ -1095,6 +1150,8 @@ bool PrintVisitor::visit_checkexcmatch(BST_CheckExcMatch* node) {
return true;
}
bool PrintVisitor::visit_setexcinfo(BST_SetExcInfo* node) {
check_if_invoke(node);
stream << ":SET_EXC_INFO(";
visit_vreg(&node->vreg_value);
stream << ", ";
......@@ -1105,10 +1162,14 @@ bool PrintVisitor::visit_setexcinfo(BST_SetExcInfo* node) {
return true;
}
bool PrintVisitor::visit_uncacheexcinfo(BST_UncacheExcInfo* node) {
check_if_invoke(node);
stream << ":UNCACHE_EXC_INFO()";
return true;
}
bool PrintVisitor::visit_hasnext(BST_HasNext* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << ":HAS_NEXT(";
visit_vreg(&node->vreg_value);
......@@ -1116,6 +1177,8 @@ bool PrintVisitor::visit_hasnext(BST_HasNext* node) {
return true;
}
bool PrintVisitor::visit_printexpr(BST_PrintExpr* node) {
check_if_invoke(node);
stream << ":PRINT_EXPR(";
visit_vreg(&node->vreg_value);
stream << ")";
......@@ -1123,6 +1186,8 @@ bool PrintVisitor::visit_printexpr(BST_PrintExpr* node) {
}
bool PrintVisitor::visit_list(BST_List* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "[";
for (int i = 0, n = node->num_elts; i < n; ++i) {
......@@ -1135,6 +1200,8 @@ bool PrintVisitor::visit_list(BST_List* node) {
}
bool PrintVisitor::visit_print(BST_Print* node) {
check_if_invoke(node);
stream << "print ";
if (node->vreg_dest != VREG_UNDEFINED) {
stream << ">>";
......@@ -1149,6 +1216,8 @@ bool PrintVisitor::visit_print(BST_Print* node) {
}
bool PrintVisitor::visit_raise(BST_Raise* node) {
check_if_invoke(node);
stream << "raise";
if (node->vreg_arg0 != VREG_UNDEFINED) {
stream << " ";
......@@ -1166,6 +1235,8 @@ bool PrintVisitor::visit_raise(BST_Raise* node) {
}
bool PrintVisitor::visit_repr(BST_Repr* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "`";
visit_vreg(&node->vreg_value);
......@@ -1174,6 +1245,8 @@ bool PrintVisitor::visit_repr(BST_Repr* node) {
}
bool PrintVisitor::visit_return(BST_Return* node) {
check_if_invoke(node);
stream << "return ";
if (node->vreg_value != VREG_UNDEFINED)
visit_vreg(&node->vreg_value);
......@@ -1181,6 +1254,8 @@ bool PrintVisitor::visit_return(BST_Return* node) {
}
bool PrintVisitor::visit_set(BST_Set* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
// An empty set literal is not writeable in Python (it's a dictionary),
// but we sometimes generate it (ex in set comprehension lowering).
......@@ -1204,6 +1279,8 @@ bool PrintVisitor::visit_set(BST_Set* node) {
}
bool PrintVisitor::visit_makeslice(BST_MakeSlice* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "<slice>(";
if (node->vreg_lower != VREG_UNDEFINED)
......@@ -1221,6 +1298,8 @@ bool PrintVisitor::visit_makeslice(BST_MakeSlice* node) {
}
bool PrintVisitor::visit_loadname(BST_LoadName* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
if (node->lookup_type == ScopeInfo::VarScopeType::FAST || node->lookup_type == ScopeInfo::VarScopeType::CLOSURE) {
visit_vreg(&node->vreg);
......@@ -1231,6 +1310,8 @@ bool PrintVisitor::visit_loadname(BST_LoadName* node) {
}
bool PrintVisitor::visit_loadattr(BST_LoadAttr* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_value);
stream << (node->clsonly ? ':' : '.') << code_constants.getInternedString(node->index_attr).s();
......@@ -1238,6 +1319,8 @@ bool PrintVisitor::visit_loadattr(BST_LoadAttr* node) {
}
bool PrintVisitor::visit_loadsub(BST_LoadSub* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_value);
stream << "[";
......@@ -1247,6 +1330,8 @@ bool PrintVisitor::visit_loadsub(BST_LoadSub* node) {
}
bool PrintVisitor::visit_loadsubslice(BST_LoadSubSlice* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
visit_vreg(&node->vreg_value);
stream << "[";
......@@ -1261,6 +1346,8 @@ bool PrintVisitor::visit_loadsubslice(BST_LoadSubSlice* node) {
}
bool PrintVisitor::visit_storename(BST_StoreName* node) {
check_if_invoke(node);
if (node->lookup_type == ScopeInfo::VarScopeType::FAST || node->lookup_type == ScopeInfo::VarScopeType::CLOSURE) {
visit_vreg(&node->vreg);
stream << " ";
......@@ -1272,6 +1359,8 @@ bool PrintVisitor::visit_storename(BST_StoreName* node) {
}
bool PrintVisitor::visit_storeattr(BST_StoreAttr* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_target);
stream << "." << code_constants.getInternedString(node->index_attr).s() << " = ";
visit_vreg(&node->vreg_value);
......@@ -1279,6 +1368,8 @@ bool PrintVisitor::visit_storeattr(BST_StoreAttr* node) {
}
bool PrintVisitor::visit_storesub(BST_StoreSub* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_target);
stream << "[";
visit_vreg(&node->vreg_slice);
......@@ -1288,6 +1379,8 @@ bool PrintVisitor::visit_storesub(BST_StoreSub* node) {
}
bool PrintVisitor::visit_storesubslice(BST_StoreSubSlice* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_target);
stream << "[";
if (node->vreg_lower != VREG_UNDEFINED)
......@@ -1302,6 +1395,8 @@ bool PrintVisitor::visit_storesubslice(BST_StoreSubSlice* node) {
}
bool PrintVisitor::visit_tuple(BST_Tuple* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "(";
int n = node->num_elts;
......@@ -1317,6 +1412,8 @@ bool PrintVisitor::visit_tuple(BST_Tuple* node) {
}
bool PrintVisitor::visit_unaryop(BST_UnaryOp* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
switch (node->op_type) {
case AST_TYPE::Invert:
......@@ -1342,6 +1439,8 @@ bool PrintVisitor::visit_unaryop(BST_UnaryOp* node) {
}
bool PrintVisitor::visit_unpackintoarray(BST_UnpackIntoArray* node) {
check_if_invoke(node);
stream << "(";
for (int i = 0; i < node->num_elts; ++i) {
visit_vreg(&node->vreg_dst[i]);
......@@ -1355,6 +1454,8 @@ bool PrintVisitor::visit_unpackintoarray(BST_UnpackIntoArray* node) {
}
bool PrintVisitor::visit_yield(BST_Yield* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "yield ";
if (node->vreg_value != VREG_UNDEFINED)
......@@ -1363,6 +1464,8 @@ bool PrintVisitor::visit_yield(BST_Yield* node) {
}
bool PrintVisitor::visit_branch(BST_Branch* node) {
check_if_invoke(node);
stream << "if ";
visit_vreg(&node->vreg_test);
stream << " goto " << node->iftrue->idx << " else goto " << node->iffalse->idx;
......@@ -1370,17 +1473,23 @@ bool PrintVisitor::visit_branch(BST_Branch* node) {
}
bool PrintVisitor::visit_jump(BST_Jump* node) {
check_if_invoke(node);
stream << "goto " << node->target->idx;
return true;
}
bool PrintVisitor::visit_makefunction(BST_MakeFunction* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "make_";
return false;
}
bool PrintVisitor::visit_makeclass(BST_MakeClass* node) {
check_if_invoke(node);
visit_vreg(&node->vreg_dst, true);
stream << "make_";
return false;
......
......@@ -58,35 +58,34 @@ namespace BST_TYPE {
X(ImportFrom, 21) \
X(ImportName, 22) \
X(ImportStar, 23) \
X(Invoke, 24) \
X(Jump, 25) \
X(Landingpad, 26) \
X(List, 27) \
X(LoadAttr, 28) \
X(LoadName, 29) \
X(LoadSub, 30) \
X(LoadSubSlice, 31) \
X(Locals, 32) \
X(MakeClass, 33) \
X(MakeFunction, 34) \
X(MakeSlice, 35) \
X(Nonzero, 36) \
X(Print, 37) \
X(PrintExpr, 38) \
X(Raise, 39) \
X(Repr, 40) \
X(Return, 41) \
X(Set, 42) \
X(SetExcInfo, 43) \
X(StoreAttr, 44) \
X(StoreName, 45) \
X(StoreSub, 46) \
X(StoreSubSlice, 47) \
X(Tuple, 48) \
X(UnaryOp, 49) \
X(UncacheExcInfo, 50) \
X(UnpackIntoArray, 51) \
X(Yield, 52)
X(Jump, 24) \
X(Landingpad, 25) \
X(List, 26) \
X(LoadAttr, 27) \
X(LoadName, 28) \
X(LoadSub, 29) \
X(LoadSubSlice, 30) \
X(Locals, 31) \
X(MakeClass, 32) \
X(MakeFunction, 33) \
X(MakeSlice, 34) \
X(Nonzero, 35) \
X(Print, 36) \
X(PrintExpr, 37) \
X(Raise, 38) \
X(Repr, 39) \
X(Return, 40) \
X(Set, 41) \
X(SetExcInfo, 42) \
X(StoreAttr, 43) \
X(StoreName, 44) \
X(StoreSub, 45) \
X(StoreSubSlice, 46) \
X(Tuple, 47) \
X(UnaryOp, 48) \
X(UncacheExcInfo, 49) \
X(UnpackIntoArray, 50) \
X(Yield, 51)
#define GENERATE_ENUM(ENUM, N) ENUM = N,
#define GENERATE_STRING(STRING, N) m[N] = #STRING;
......@@ -99,7 +98,6 @@ static const char* stringify(int n) {
return m[n];
}
#undef FOREACH_TYPE
#undef GENERATE_ENUM
#undef GENERATE_STRING
};
......@@ -128,17 +126,78 @@ static constexpr int VREG_UNDEFINED = std::numeric_limits<int>::min();
// in order to make it easier for a human to understand we print the actual value of the constant between | characters.
#define PACKED __attribute__((packed)) __attribute__((__aligned__(1)))
class BSTAllocator {
public:
BSTAllocator() = default;
BSTAllocator(BSTAllocator&) = delete;
void* allocate(int num_bytes) {
mem.resize(mem.size() + num_bytes, 0);
return &mem[mem.size() - num_bytes];
}
template <typename T> T* allocate() { return (T*)allocate(sizeof(T)); }
void reserve(int num_bytes) { mem.reserve(num_bytes); }
int getOffset(void* ptr) const {
auto offset = (unsigned char*)ptr - mem.data();
// assert(offset >= 0);
return offset;
}
int getSize() const { return mem.size(); }
void optimizeSize() { mem.shrink_to_fit(); }
unsigned char* getData() { return mem.data(); }
bool isInside(void* ptr) const { return ptr >= mem.data() && ptr <= &mem.back(); }
private:
std::vector<unsigned char> mem;
};
class BST_stmt {
public:
virtual ~BST_stmt() {}
static constexpr unsigned char invoke_flag = 64;
// contains the opcode which can have the invoke bit set which signals that this stmt is inside a invoke and that a
// pointer to the normal CFGBlock and the exception block follow directly after the last field in the instruction.
unsigned char type_and_flags;
const BST_TYPE::BST_TYPE type;
uint32_t lineno;
virtual void accept(BSTVisitor* v) = 0;
virtual void accept_stmt(StmtVisitor* v) = 0;
virtual bool has_dest_vreg() const { return false; }
BST_TYPE::BST_TYPE type() const { return (BST_TYPE::BST_TYPE)(type_and_flags & (~invoke_flag)); }
bool is_invoke() const { return type_and_flags & invoke_flag; }
CFGBlock* get_normal_block() const {
assert(is_invoke());
return ((CFGBlock * const*)&((const unsigned char*)this)[size_in_bytes()])[-2];
}
CFGBlock* get_exc_block() const {
assert(is_invoke());
return ((CFGBlock * const*)&((const unsigned char*)this)[size_in_bytes()])[-1];
}
// if this instruction is inside a invoke it will return the size including the two CFGBlock* it contains
inline int size_in_bytes() const __attribute__((always_inline));
inline bool has_dest_vreg() const __attribute__((always_inline));
bool is_terminator() const __attribute__((always_inline)) {
if (is_invoke())
return true;
switch (type_and_flags) {
case BST_TYPE::Assert:
case BST_TYPE::Branch:
case BST_TYPE::Jump:
case BST_TYPE::Raise:
case BST_TYPE::Return:
return true;
default:
return false;
}
}
void accept(BSTVisitor* v);
void accept_stmt(StmtVisitor* v);
// #define DEBUG_LINE_NUMBERS 1
#ifdef DEBUG_LINE_NUMBERS
......@@ -150,10 +209,10 @@ private:
public:
BST_stmt(BST_TYPE::BST_TYPE type);
#else
BST_stmt(BST_TYPE::BST_TYPE type) : type(type), lineno(0) {}
BST_stmt(BST_TYPE::BST_TYPE type) : type_and_flags(type), lineno(0) {}
#endif
BST_stmt(BST_TYPE::BST_TYPE type, uint32_t lineno) : type(type), lineno(lineno) {}
};
BST_stmt(BST_TYPE::BST_TYPE type, uint32_t lineno) : type_and_flags(type), lineno(lineno) {}
} PACKED;
// base class of all nodes which have a single destination vreg
class BST_stmt_with_dest : public BST_stmt {
......@@ -161,28 +220,33 @@ public:
int vreg_dst = VREG_UNDEFINED;
BST_stmt_with_dest(BST_TYPE::BST_TYPE type) : BST_stmt(type) {}
BST_stmt_with_dest(BST_TYPE::BST_TYPE type, int lineno) : BST_stmt(type, lineno) {}
bool has_dest_vreg() const override { return true; }
};
} PACKED;
#define BSTNODE(opcode) \
virtual void accept(BSTVisitor* v); \
virtual void accept_stmt(StmtVisitor* v); \
void accept(BSTVisitor* v); \
void accept_stmt(StmtVisitor* v); \
static const BST_TYPE::BST_TYPE TYPE = BST_TYPE::opcode;
#define BSTFIXEDVREGS(opcode, base_class) \
BSTNODE(opcode) \
BST_##opcode() : base_class(BST_TYPE::opcode) {}
static BST_##opcode* create(BSTAllocator& alloc) { return new (alloc) BST_##opcode(); } \
BST_##opcode() : base_class(BST_TYPE::opcode) {} \
int size_in_bytes() const { return sizeof(*this); } \
static void* operator new(size_t s, BSTAllocator & alloc) { return alloc.allocate(s); } \
static void operator delete(void* ptr) { RELEASE_ASSERT(0, ""); }
#define BSTVARVREGS(opcode, base_class, num_elts, vreg_dst) \
public: \
BSTNODE(opcode) \
static BST_##opcode* create(int num_elts) { return new (num_elts) BST_##opcode(num_elts); } \
static void operator delete(void* ptr) { ::operator delete[](ptr); } \
static BST_##opcode* create(BSTAllocator& alloc, int num_elts) { \
return new (alloc, num_elts) BST_##opcode(num_elts); \
} \
static void operator delete(void* ptr) { RELEASE_ASSERT(0, ""); } \
int size_in_bytes() const { return offsetof(BST_##opcode, vreg_dst) + num_elts * sizeof(int); } \
\
private: \
static void* operator new(size_t, int num_elts) { \
return ::new char[offsetof(BST_##opcode, vreg_dst) + num_elts * sizeof(int)]; \
static void* operator new(size_t, BSTAllocator & alloc, int num_elts) { \
return alloc.allocate(offsetof(BST_##opcode, vreg_dst) + num_elts * sizeof(int)); \
} \
BST_##opcode(int num_elts) : base_class(BST_TYPE::opcode), num_elts(num_elts) { \
for (int i = 0; i < num_elts; ++i) { \
......@@ -193,14 +257,15 @@ private:
#define BSTVARVREGS2(opcode, base_class, num_elts, num_elts2, vreg_dst) \
public: \
BSTNODE(opcode) \
static BST_##opcode* create(int num_elts, int num_elts2) { \
return new (num_elts + num_elts2) BST_##opcode(num_elts, num_elts2); \
static BST_##opcode* create(BSTAllocator& alloc, int num_elts, int num_elts2) { \
return new (alloc, num_elts + num_elts2) BST_##opcode(num_elts, num_elts2); \
} \
static void operator delete(void* ptr) { ::operator delete[](ptr); } \
int size_in_bytes() const { return offsetof(BST_##opcode, vreg_dst) + (num_elts + num_elts2) * sizeof(int); } \
\
private: \
static void* operator new(size_t, int num_elts_total) { \
return ::new char[offsetof(BST_##opcode, vreg_dst) + num_elts_total * sizeof(int)]; \
static void* operator new(size_t, BSTAllocator & alloc, int num_elts_total) { \
return alloc.allocate(offsetof(BST_##opcode, vreg_dst) + num_elts_total * sizeof(int)); \
} \
BST_##opcode(int num_elts, int num_elts2) \
: base_class(BST_TYPE::opcode), num_elts(num_elts), num_elts2(num_elts2) { \
......@@ -212,14 +277,15 @@ private:
#define BSTVARVREGS2CALL(opcode, num_elts, num_elts2, vreg_dst) \
public: \
BSTNODE(opcode) \
static BST_##opcode* create(int num_elts, int num_elts2) { \
return new (num_elts + num_elts2) BST_##opcode(num_elts, num_elts2); \
static BST_##opcode* create(BSTAllocator& alloc, int num_elts, int num_elts2) { \
return new (alloc, num_elts + num_elts2) BST_##opcode(num_elts, num_elts2); \
} \
static void operator delete(void* ptr) { ::operator delete[](ptr); } \
static void operator delete(void* ptr) { RELEASE_ASSERT(0, ""); } \
int size_in_bytes() const { return offsetof(BST_##opcode, vreg_dst) + (num_elts + num_elts2) * sizeof(int); } \
\
private: \
static void* operator new(size_t, int num_elts_total) { \
return ::new char[offsetof(BST_##opcode, vreg_dst) + num_elts_total * sizeof(int)]; \
static void* operator new(size_t, BSTAllocator & alloc, int num_elts_total) { \
return alloc.allocate(offsetof(BST_##opcode, vreg_dst) + num_elts_total * sizeof(int)); \
} \
BST_##opcode(int num_elts, int num_elts2) : BST_Call(BST_TYPE::opcode, num_elts, num_elts2) { \
for (int i = 0; i < num_elts + num_elts2; ++i) { \
......@@ -232,7 +298,7 @@ public:
int vreg_msg = VREG_UNDEFINED;
BSTFIXEDVREGS(Assert, BST_stmt)
};
} PACKED;
class BST_UnpackIntoArray : public BST_stmt {
public:
......@@ -241,7 +307,7 @@ public:
int vreg_dst[1];
BSTVARVREGS(UnpackIntoArray, BST_stmt, num_elts, vreg_dst)
};
} PACKED;
// This is a special instruction which copies a vreg without destroying the source.
// All other instructions always kill the operands (except if they are a constant) so if one needs the operand to stay
......@@ -251,7 +317,7 @@ public:
int vreg_src = VREG_UNDEFINED; // this vreg will not get killed!
BSTFIXEDVREGS(CopyVReg, BST_stmt_with_dest)
};
} PACKED;
class BST_StoreName : public BST_stmt {
......@@ -268,7 +334,7 @@ public:
int closure_offset = -1;
BSTFIXEDVREGS(StoreName, BST_stmt)
};
} PACKED;
class BST_StoreAttr : public BST_stmt {
public:
......@@ -277,7 +343,7 @@ public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(StoreAttr, BST_stmt)
};
} PACKED;
class BST_StoreSub : public BST_stmt {
public:
......@@ -286,7 +352,7 @@ public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(StoreSub, BST_stmt)
};
} PACKED;
class BST_StoreSubSlice : public BST_stmt {
public:
......@@ -295,7 +361,7 @@ public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(StoreSubSlice, BST_stmt)
};
} PACKED;
class BST_LoadName : public BST_stmt_with_dest {
public:
......@@ -310,7 +376,7 @@ public:
int closure_offset = -1;
BSTFIXEDVREGS(LoadName, BST_stmt_with_dest)
};
} PACKED;
class BST_LoadAttr : public BST_stmt_with_dest {
public:
......@@ -319,7 +385,7 @@ public:
bool clsonly = false;
BSTFIXEDVREGS(LoadAttr, BST_stmt_with_dest)
};
} PACKED;
class BST_LoadSub : public BST_stmt_with_dest {
public:
......@@ -327,7 +393,7 @@ public:
int vreg_slice = VREG_UNDEFINED;
BSTFIXEDVREGS(LoadSub, BST_stmt_with_dest)
};
} PACKED;
class BST_LoadSubSlice : public BST_stmt_with_dest {
public:
......@@ -335,7 +401,7 @@ public:
int vreg_lower = VREG_UNDEFINED, vreg_upper = VREG_UNDEFINED;
BSTFIXEDVREGS(LoadSubSlice, BST_stmt_with_dest)
};
} PACKED;
class BST_AugBinOp : public BST_stmt_with_dest {
public:
......@@ -343,7 +409,7 @@ public:
int vreg_left = VREG_UNDEFINED, vreg_right = VREG_UNDEFINED;
BSTFIXEDVREGS(AugBinOp, BST_stmt_with_dest)
};
} PACKED;
class BST_BinOp : public BST_stmt_with_dest {
public:
......@@ -351,7 +417,7 @@ public:
int vreg_left = VREG_UNDEFINED, vreg_right = VREG_UNDEFINED;
BSTFIXEDVREGS(BinOp, BST_stmt_with_dest)
};
} PACKED;
class BST_Call : public BST_stmt_with_dest {
public:
......@@ -363,7 +429,7 @@ public:
BST_Call(BST_TYPE::BST_TYPE type, int num_args, int num_keywords)
: BST_stmt_with_dest(type), num_args(num_args), num_keywords(num_keywords) {}
};
} PACKED;
class BST_CallFunc : public BST_Call {
public:
......@@ -371,7 +437,7 @@ public:
int elts[1];
BSTVARVREGS2CALL(CallFunc, num_args, num_keywords, elts)
};
} PACKED;
class BST_CallAttr : public BST_Call {
public:
......@@ -380,7 +446,7 @@ public:
int elts[1];
BSTVARVREGS2CALL(CallAttr, num_args, num_keywords, elts)
};
} PACKED;
class BST_CallClsAttr : public BST_Call {
public:
......@@ -389,7 +455,7 @@ public:
int elts[1];
BSTVARVREGS2CALL(CallClsAttr, num_args, num_keywords, elts)
};
} PACKED;
class BST_Compare : public BST_stmt_with_dest {
......@@ -399,7 +465,7 @@ public:
int vreg_left = VREG_UNDEFINED;
BSTFIXEDVREGS(Compare, BST_stmt_with_dest)
};
} PACKED;
class BST_ClassDef : public BST_stmt {
public:
......@@ -408,13 +474,18 @@ public:
const int num_decorator;
int decorator[1];
static BST_ClassDef* create(int num_decorator) { return new (num_decorator) BST_ClassDef(num_decorator); }
static void* operator new(size_t, int num_decorator) {
return ::new unsigned char[offsetof(BST_ClassDef, decorator) + num_decorator * sizeof(int)];
}
BSTVARVREGS(ClassDef, BST_stmt, num_decorator, decorator)
};
} PACKED;
class BST_Dict : public BST_stmt_with_dest {
public:
BSTFIXEDVREGS(Dict, BST_stmt_with_dest)
};
} PACKED;
class BST_DeleteAttr : public BST_stmt {
public:
......@@ -422,7 +493,7 @@ public:
int index_attr = VREG_UNDEFINED;
BSTFIXEDVREGS(DeleteAttr, BST_stmt)
};
} PACKED;
class BST_DeleteName : public BST_stmt {
public:
......@@ -436,7 +507,7 @@ public:
int closure_offset = -1;
BSTFIXEDVREGS(DeleteName, BST_stmt)
};
} PACKED;
class BST_DeleteSub : public BST_stmt {
public:
......@@ -444,7 +515,7 @@ public:
int vreg_slice = VREG_UNDEFINED;
BSTFIXEDVREGS(DeleteSub, BST_stmt)
};
} PACKED;
class BST_DeleteSubSlice : public BST_stmt {
public:
......@@ -453,7 +524,7 @@ public:
int vreg_upper = VREG_UNDEFINED;
BSTFIXEDVREGS(DeleteSubSlice, BST_stmt)
};
} PACKED;
class BST_Exec : public BST_stmt {
public:
......@@ -462,7 +533,7 @@ public:
int vreg_locals = VREG_UNDEFINED;
BSTFIXEDVREGS(Exec, BST_stmt)
};
} PACKED;
class BST_FunctionDef : public BST_stmt {
public:
......@@ -473,8 +544,15 @@ public:
int elts[1]; // decorators followed by defaults
static BST_FunctionDef* create(int num_decorator, int num_defaults) {
return new (num_decorator + num_defaults) BST_FunctionDef(num_decorator, num_defaults);
}
static void* operator new(size_t, int num_elts) {
return ::new unsigned char[offsetof(BST_FunctionDef, elts) + num_elts * sizeof(int)];
}
BSTVARVREGS2(FunctionDef, BST_stmt, num_decorator, num_defaults, elts)
};
} PACKED;
class BST_List : public BST_stmt_with_dest {
public:
......@@ -482,14 +560,14 @@ public:
int elts[1];
BSTVARVREGS(List, BST_stmt_with_dest, num_elts, elts)
};
} PACKED;
class BST_Repr : public BST_stmt_with_dest {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(Repr, BST_stmt_with_dest)
};
} PACKED;
class BST_Print : public BST_stmt {
public:
......@@ -498,7 +576,7 @@ public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(Print, BST_stmt)
};
} PACKED;
class BST_Raise : public BST_stmt {
public:
......@@ -509,14 +587,14 @@ public:
int vreg_arg0 = VREG_UNDEFINED, vreg_arg1 = VREG_UNDEFINED, vreg_arg2 = VREG_UNDEFINED;
BSTFIXEDVREGS(Raise, BST_stmt)
};
} PACKED;
class BST_Return : public BST_stmt {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(Return, BST_stmt)
};
} PACKED;
class BST_Set : public BST_stmt_with_dest {
public:
......@@ -524,14 +602,14 @@ public:
int elts[1];
BSTVARVREGS(Set, BST_stmt_with_dest, num_elts, elts)
};
} PACKED;
class BST_MakeSlice : public BST_stmt_with_dest {
public:
int vreg_lower = VREG_UNDEFINED, vreg_upper = VREG_UNDEFINED, vreg_step = VREG_UNDEFINED;
BSTFIXEDVREGS(MakeSlice, BST_stmt_with_dest)
};
} PACKED;
class BST_Tuple : public BST_stmt_with_dest {
public:
......@@ -539,7 +617,7 @@ public:
int elts[1];
BSTVARVREGS(Tuple, BST_stmt_with_dest, num_elts, elts)
};
} PACKED;
class BST_UnaryOp : public BST_stmt_with_dest {
public:
......@@ -547,14 +625,14 @@ public:
AST_TYPE::AST_TYPE op_type;
BSTFIXEDVREGS(UnaryOp, BST_stmt_with_dest)
};
} PACKED;
class BST_Yield : public BST_stmt_with_dest {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(Yield, BST_stmt_with_dest)
};
} PACKED;
class BST_MakeFunction : public BST_stmt_with_dest {
public:
......@@ -562,9 +640,17 @@ public:
BST_MakeFunction(BST_FunctionDef* fd, int index_func_def)
: BST_stmt_with_dest(BST_TYPE::MakeFunction, fd->lineno), index_func_def(index_func_def) {}
int size_in_bytes() const { return sizeof(*this); }
static BST_MakeFunction* create(BSTAllocator& alloc, BST_FunctionDef* fd, int index_func_def) {
return new (alloc) BST_MakeFunction(fd, index_func_def);
}
static void* operator new(size_t s, BSTAllocator& alloc) { return alloc.allocate(s); }
static void operator delete(void* ptr) { RELEASE_ASSERT(0, ""); }
BSTNODE(MakeFunction)
};
} PACKED;
class BST_MakeClass : public BST_stmt_with_dest {
public:
......@@ -572,9 +658,17 @@ public:
BST_MakeClass(BST_ClassDef* cd, int index_class_def)
: BST_stmt_with_dest(BST_TYPE::MakeClass, cd->lineno), index_class_def(index_class_def) {}
int size_in_bytes() const { return sizeof(*this); }
static BST_MakeClass* create(BSTAllocator& alloc, BST_ClassDef* cd, int index_class_def) {
return new (alloc) BST_MakeClass(cd, index_class_def);
}
static void* operator new(size_t s, BSTAllocator& alloc) { return alloc.allocate(s); }
static void operator delete(void* ptr) { RELEASE_ASSERT(0, ""); }
BSTNODE(MakeClass)
};
} PACKED;
class CFGBlock;
......@@ -584,44 +678,32 @@ public:
CFGBlock* iftrue, *iffalse;
BSTFIXEDVREGS(Branch, BST_stmt)
};
} PACKED;
class BST_Jump : public BST_stmt {
public:
CFGBlock* target;
BSTFIXEDVREGS(Jump, BST_stmt)
};
class BST_Invoke : public BST_stmt {
public:
BST_stmt* stmt;
CFGBlock* normal_dest, *exc_dest;
BST_Invoke(BST_stmt* stmt) : BST_stmt(BST_TYPE::Invoke), stmt(stmt) {}
BSTNODE(Invoke)
};
} PACKED;
// grabs the info about the last raised exception
class BST_Landingpad : public BST_stmt_with_dest {
public:
BSTFIXEDVREGS(Landingpad, BST_stmt_with_dest)
};
} PACKED;
class BST_Locals : public BST_stmt_with_dest {
public:
BSTFIXEDVREGS(Locals, BST_stmt_with_dest)
};
} PACKED;
class BST_GetIter : public BST_stmt_with_dest {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(GetIter, BST_stmt_with_dest)
};
} PACKED;
class BST_ImportFrom : public BST_stmt_with_dest {
public:
......@@ -629,7 +711,7 @@ public:
int vreg_name = VREG_UNDEFINED;
BSTFIXEDVREGS(ImportFrom, BST_stmt_with_dest)
};
} PACKED;
class BST_ImportName : public BST_stmt_with_dest {
public:
......@@ -638,14 +720,14 @@ public:
int vreg_name = VREG_UNDEFINED;
BSTFIXEDVREGS(ImportName, BST_stmt_with_dest)
};
} PACKED;
class BST_ImportStar : public BST_stmt_with_dest {
public:
int vreg_name = VREG_UNDEFINED;
BSTFIXEDVREGS(ImportStar, BST_stmt_with_dest)
};
} PACKED;
// determines whether something is "true" for purposes of `if' and so forth
class BST_Nonzero : public BST_stmt_with_dest {
......@@ -653,7 +735,7 @@ public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(Nonzero, BST_stmt_with_dest)
};
} PACKED;
class BST_CheckExcMatch : public BST_stmt_with_dest {
public:
......@@ -661,7 +743,7 @@ public:
int vreg_cls = VREG_UNDEFINED;
BSTFIXEDVREGS(CheckExcMatch, BST_stmt_with_dest)
};
} PACKED;
class BST_SetExcInfo : public BST_stmt {
public:
......@@ -670,27 +752,57 @@ public:
int vreg_traceback = VREG_UNDEFINED;
BSTFIXEDVREGS(SetExcInfo, BST_stmt)
};
} PACKED;
class BST_UncacheExcInfo : public BST_stmt {
public:
BSTFIXEDVREGS(UncacheExcInfo, BST_stmt)
};
} PACKED;
class BST_HasNext : public BST_stmt_with_dest {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(HasNext, BST_stmt_with_dest)
};
} PACKED;
class BST_PrintExpr : public BST_stmt {
public:
int vreg_value = VREG_UNDEFINED;
BSTFIXEDVREGS(PrintExpr, BST_stmt)
};
} PACKED;
template <typename T> T* bst_cast(const BST_stmt* node) {
ASSERT(!node || node->type() == T::TYPE, "%d", node ? node->type() : 0);
return static_cast<T*>(node);
}
int BST_stmt::size_in_bytes() const {
int s = is_invoke() ? 2 * sizeof(CFGBlock*) : 0;
switch (type()) {
#define DISPATCH_SIZE(x, y) \
case BST_TYPE::x: \
return bst_cast<const BST_##x>(this)->size_in_bytes() + s;
FOREACH_TYPE(DISPATCH_SIZE)
};
assert(0);
__builtin_unreachable();
#undef DISPATCH_SIZE
}
bool BST_stmt::has_dest_vreg() const {
switch (type()) {
#define DISPATCH_HAS_DEST(x, y) \
case BST_TYPE::x: \
return std::is_base_of<BST_stmt_with_dest, BST_##x>();
FOREACH_TYPE(DISPATCH_HAS_DEST)
};
assert(0);
__builtin_unreachable();
#undef DISPATCH_HAS_DEST
}
// this is not a real bytecode it's only used to initalize arguments
class BST_Name {
......@@ -715,7 +827,7 @@ public:
};
template <typename T> T* bst_cast(BST_stmt* node) {
ASSERT(!node || node->type == T::TYPE, "%d", node ? node->type : 0);
ASSERT(!node || node->type() == T::TYPE, "%d", node ? node->type() : 0);
return static_cast<T*>(node);
}
......@@ -754,7 +866,6 @@ public:
virtual bool visit_importfrom(BST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_importname(BST_ImportName* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_importstar(BST_ImportStar* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_invoke(BST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_jump(BST_Jump* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_landingpad(BST_Landingpad* node) { RELEASE_ASSERT(0, ""); }
virtual bool visit_list(BST_List* node) { RELEASE_ASSERT(0, ""); }
......@@ -814,7 +925,6 @@ public:
virtual bool visit_importfrom(BST_ImportFrom* node) override { return false; }
virtual bool visit_importname(BST_ImportName* node) override { return false; }
virtual bool visit_importstar(BST_ImportStar* node) override { return false; }
virtual bool visit_invoke(BST_Invoke* node) override { return false; }
virtual bool visit_jump(BST_Jump* node) override { return false; }
virtual bool visit_landingpad(BST_Landingpad* node) override { return false; }
virtual bool visit_list(BST_List* node) override { return false; }
......@@ -877,7 +987,6 @@ public:
virtual void visit_importfrom(BST_ImportFrom* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_importname(BST_ImportName* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_importstar(BST_ImportStar* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_invoke(BST_Invoke* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_jump(BST_Jump* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_landingpad(BST_Landingpad* node) { RELEASE_ASSERT(0, ""); }
virtual void visit_list(BST_List* node) { RELEASE_ASSERT(0, ""); }
......@@ -923,6 +1032,9 @@ public:
virtual ~PrintVisitor() {}
void flush() { stream.flush(); }
// checks if the stmt is inside an invoke an if true prints the destination blocks
bool check_if_invoke(BST_stmt* node);
virtual bool visit_vreg(int* vreg, bool is_dst = false);
virtual bool visit_assert(BST_Assert* node);
......@@ -948,7 +1060,6 @@ public:
virtual bool visit_importfrom(BST_ImportFrom* node);
virtual bool visit_importname(BST_ImportName* node);
virtual bool visit_importstar(BST_ImportStar* node);
virtual bool visit_invoke(BST_Invoke* node);
virtual bool visit_jump(BST_Jump* node);
virtual bool visit_landingpad(BST_Landingpad* node);
virtual bool visit_list(BST_List* node);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -75,20 +75,68 @@ public:
// contains the address of the entry function
std::pair<CFGBlock*, Box*>(*entry_code)(void* interpeter, CFGBlock* block, Box** vregs);
llvm::SmallVector<BST_stmt*, 4> body;
llvm::SmallVector<CFGBlock*, 2> predecessors, successors;
int idx; // index in the CFG
const char* info;
int offset_of_first_stmt; // offset of this block into the bytecode array in bytes
typedef llvm::SmallVector<BST_stmt*, 4>::iterator iterator;
#ifndef NDEBUG
// only one block at a time is allowed to add instructions to the CFG
bool allowed_to_add_stuff = false;
#endif
CFGBlock(CFG* cfg, int idx) : cfg(cfg), code(NULL), entry_code(NULL), idx(idx), info(NULL) {}
CFGBlock(CFG* cfg, int idx, const char* info = NULL)
: cfg(cfg), code(NULL), entry_code(NULL), idx(idx), info(info), offset_of_first_stmt(-1) {}
BST_stmt* body() {
auto it = begin();
return it != end() ? *it : NULL;
}
int sizeInBytes() const {
int size = 0;
for (BST_stmt* stmt : *this) {
size += stmt->size_in_bytes();
}
return size;
}
BST_stmt* getLastStmt() const {
// TODO: this is inefficient
for (BST_stmt* stmt : *this) {
if (stmt->is_terminator())
return stmt;
}
return NULL;
}
bool isPlaced() const { return offset_of_first_stmt != -1; }
void connectTo(CFGBlock* successor, bool allow_backedge = false);
void unconnectFrom(CFGBlock* successor);
void push_back(BST_stmt* node) { body.push_back(node); }
void print(const CodeConstants& code_constants, llvm::raw_ostream& stream = llvm::outs());
class iterator {
private:
BST_stmt* stmt;
public:
iterator(BST_stmt* stmt) : stmt(stmt) {}
bool operator!=(const iterator& rhs) const { return stmt != rhs.stmt; }
bool operator==(const iterator& rhs) const { return stmt == rhs.stmt; }
iterator& operator++() __attribute__((always_inline)) {
if (likely(stmt)) {
if (unlikely(stmt->is_terminator()))
*this = CFGBlock::end();
else
stmt = (BST_stmt*)&((unsigned char*)stmt)[stmt->size_in_bytes()];
}
return *this;
}
BST_stmt* operator*() const { return stmt; }
};
inline iterator begin() const;
static iterator end() { return iterator(NULL); }
};
// the vregs are split into three parts.
......@@ -169,7 +217,7 @@ public:
bool hasVRegsAssigned() const { return num_vregs != -1; }
void assignVRegs(const CodeConstants& code_constants, CFG* cfg, const ParamNames& param_names,
llvm::DenseMap<int*, InternedString>& id_vreg);
llvm::DenseMap<class TrackingVRegPtr, InternedString>& id_vreg);
};
// Control Flow Graph
......@@ -180,22 +228,19 @@ private:
public:
std::vector<CFGBlock*> blocks;
BSTAllocator bytecode;
public:
CFG() : next_idx(0) {}
~CFG() {
for (auto&& block : blocks) {
delete block;
}
}
CFGBlock* getStartingBlock() { return blocks[0]; }
VRegInfo& getVRegInfo() { return vreg_info; }
CFGBlock* addBlock() {
int idx = next_idx;
next_idx++;
CFGBlock* block = new CFGBlock(this, idx);
blocks.push_back(block);
return block;
}
// Creates a block which must be placed later, using placeBlock().
// Must be placed on same CFG it was created on.
// You can also safely delete it without placing it.
......@@ -205,15 +250,43 @@ public:
}
void placeBlock(CFGBlock* block) {
assert(!block->isPlaced());
#ifndef NDEBUG
// check that there is no block with the same offset of first stmt
assert(!block->allowed_to_add_stuff);
std::unordered_map<int /* offset */, int> check_no_dup_blocks;
for (auto&& b : blocks) {
b->allowed_to_add_stuff = false;
++check_no_dup_blocks[b->offset_of_first_stmt];
}
++check_no_dup_blocks[bytecode.getSize()];
assert(check_no_dup_blocks[bytecode.getSize()] == 1);
for (auto&& e : check_no_dup_blocks) {
assert(e.second == 1);
}
#endif
assert(block->idx == -1);
block->idx = next_idx;
next_idx++;
blocks.push_back(block);
block->offset_of_first_stmt = bytecode.getSize();
#ifndef NDEBUG
block->allowed_to_add_stuff = true;
#endif
}
void print(const CodeConstants& code_constants, llvm::raw_ostream& stream = llvm::outs());
};
CFGBlock::iterator CFGBlock::begin() const {
if (offset_of_first_stmt >= cfg->bytecode.getSize())
return end();
return iterator((BST_stmt*)&cfg->bytecode.getData()[offset_of_first_stmt]);
}
class VRegSet {
private:
llvm::BitVector v;
......
......@@ -563,7 +563,7 @@ extern "C" int PyGen_NeedsFinalizing(PyGenObject* gen) noexcept {
return true;
// TODO: is this safe? probably not...
// return self->paused_frame_info->stmt->type == AST_TYPE::Invoke;
// return self->paused_frame_info->stmt->is_invoke();
#if 0
int i;
PyFrameObject* f = gen->gi_frame;
......
......@@ -27,8 +27,8 @@ protected:
static BoxedCode* getCodeObjectOfFirstMakeFunction(BoxedCode* module_code) {
BoxedCode* code = NULL;
for (BST_stmt* stmt : module_code->source->cfg->blocks[0]->body) {
if (stmt->type != BST_TYPE::MakeFunction)
for (BST_stmt* stmt : *module_code->source->cfg->getStartingBlock()) {
if (stmt->type() != BST_TYPE::MakeFunction)
continue;
code = module_code->code_constants.getFuncOrClass(bst_cast<BST_MakeFunction>(stmt)->index_func_def).second;
break;
......@@ -74,7 +74,7 @@ TEST_F(AnalysisTest, augassign) {
for (CFGBlock* block : cfg->blocks) {
//printf("%d\n", block->idx);
if (block->body.back()->type != BST_TYPE::Return)
if (block->getLastStmt()->type() != BST_TYPE::Return)
ASSERT_TRUE(liveness->isLiveAtEnd(vregs.getVReg(module->interned_strings->get("a")), block));
}
......@@ -116,10 +116,10 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) {
CFGBlock* loop_backedge = cfg->blocks[5];
ASSERT_EQ(6, loop_backedge->idx);
ASSERT_EQ(1, loop_backedge->body.size());
ASSERT_TRUE(loop_backedge->body()->is_terminator());
ASSERT_EQ(BST_TYPE::Jump, loop_backedge->body[0]->type);
BST_Jump* backedge = bst_cast<BST_Jump>(loop_backedge->body[0]);
ASSERT_EQ(BST_TYPE::Jump, loop_backedge->body()->type());
BST_Jump* backedge = bst_cast<BST_Jump>(loop_backedge->body());
ASSERT_LE(backedge->target->idx, loop_backedge->idx);
std::unique_ptr<PhiAnalysis> phis;
......
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