Commit 236a402e authored by Marius Wachtler's avatar Marius Wachtler Committed by GitHub

Merge pull request #1391 from undingen/bst_inplace

transform BST to gapless bytecode inplace
parents 4e58ed33 581cebc5
......@@ -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);
}
}
......@@ -481,9 +481,7 @@ private:
}
}
void visit_makeclass(BST_MakeClass* mkclass) override {
auto* node = bst_cast<BST_ClassDef>(getCodeConstants().getFuncOrClass(mkclass->index_class_def).first);
void visit_makeclass(BST_MakeClass* node) override {
for (int i = 0; i < node->num_decorator; ++i) {
getType(node->decorator[i]);
}
......@@ -492,7 +490,7 @@ private:
// TODO should we speculate that classdefs will generally return a class?
// return typeFromClass(type_cls);
_doSet(mkclass->vreg_dst, UNKNOWN);
_doSet(node->vreg_dst, UNKNOWN);
}
void visit_deletesub(BST_DeleteSub* node) override { getType(node->vreg_value); }
......@@ -507,9 +505,7 @@ private:
assert(node->vreg == VREG_UNDEFINED);
}
void visit_makefunction(BST_MakeFunction* mkfn) override {
auto* node = bst_cast<BST_FunctionDef>(getCodeConstants().getFuncOrClass(mkfn->index_func_def).first);
void visit_makefunction(BST_MakeFunction* node) override {
for (int i = 0; i < node->num_defaults + node->num_decorator; ++i) {
getType(node->elts[i]);
}
......@@ -517,7 +513,7 @@ private:
CompilerType* t = UNKNOWN;
if (node->num_decorator == 0)
t = typeFromClass(function_cls);
_doSet(mkfn->vreg_dst, t);
_doSet(node->vreg_dst, t);
}
void visit_exec(BST_Exec* node) override {
......@@ -526,8 +522,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 {
......
This diff is collapsed.
......@@ -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,
......
......@@ -359,10 +359,19 @@ protected:
(*sym_table)[*vreg] = NULL;
return false;
}
bool visit_storename(BST_StoreName* node) override {
InternedString name = getCodeConstants().getInternedString(node->index_id);
assert(name.c_str()[0] == '#'); // it must be a temporary
// You might think I need to check whether `name' is being assigned globally or locally,
// since a global assign doesn't affect the symbol table. However, the CFG pass only
// generates invoke-assigns to temporary variables. Just to be sure, we assert:
assert(node->lookup_type != ScopeInfo::VarScopeType::GLOBAL);
return false;
}
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);
......@@ -640,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);
......@@ -733,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]) {
......@@ -800,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;
}
}
......@@ -815,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);
......@@ -1488,10 +1488,7 @@ private:
return new ConcreteCompilerVariable(UNKNOWN, rtn);
}
CompilerVariable* evalMakeClass(BST_MakeClass* mkclass, const UnwindInfo& unw_info) {
auto class_entry = irstate->getCodeConstants().getFuncOrClass(mkclass->index_class_def);
BST_ClassDef* node = bst_cast<BST_ClassDef>(class_entry.first);
CompilerVariable* evalMakeClass(BST_MakeClass* node, const UnwindInfo& unw_info) {
CompilerVariable* _bases_tuple = evalVReg(node->vreg_bases_tuple);
ConcreteCompilerVariable* bases_tuple = _bases_tuple->makeConverted(emitter, _bases_tuple->getBoxType());
......@@ -1500,8 +1497,9 @@ private:
decorators.push_back(evalVReg(node->decorator[i]));
}
BoxedCode* code = class_entry.second;
BoxedCode* code = (BoxedCode*)irstate->getCodeConstants().getConstant(node->vreg_code_obj);
assert(code);
assert(code->cls == code_cls);
const ScopingResults& scope_info = code->source->scoping;
// TODO duplication with _createFunction:
......@@ -1544,7 +1542,7 @@ private:
return cls;
}
CompilerVariable* _createFunction(BST_FunctionDef* node, BoxedCode* code, const UnwindInfo& unw_info) {
CompilerVariable* _createFunction(BST_MakeFunction* node, BoxedCode* code, const UnwindInfo& unw_info) {
assert(code);
std::vector<ConcreteCompilerVariable*> defaults;
......@@ -1572,16 +1570,17 @@ private:
return func;
}
CompilerVariable* evalMakeFunction(BST_MakeFunction* mkfn, const UnwindInfo& unw_info) {
auto func_entry = irstate->getCodeConstants().getFuncOrClass(mkfn->index_func_def);
BST_FunctionDef* node = bst_cast<BST_FunctionDef>(func_entry.first);
CompilerVariable* evalMakeFunction(BST_MakeFunction* node, const UnwindInfo& unw_info) {
BoxedCode* code = (BoxedCode*)irstate->getCodeConstants().getConstant(node->vreg_code_obj);
assert(code);
assert(code->cls == code_cls);
std::vector<CompilerVariable*> decorators;
for (int i = 0; i < node->num_decorator; ++i) {
decorators.push_back(evalVReg(node->elts[i]));
}
CompilerVariable* func = _createFunction(node, func_entry.second, unw_info);
CompilerVariable* func = _createFunction(node, code, unw_info);
for (int i = decorators.size() - 1; i >= 0; i--) {
func = decorators[i]->call(emitter, getOpInfoForNode(node, unw_info), ArgPassSpec(1), { func }, NULL);
......@@ -2406,7 +2405,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 +2454,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 +2470,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 +2558,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 +2936,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;
......
This diff is collapsed.
This diff is collapsed.
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;
......
......@@ -30,6 +30,7 @@
#include "codegen/ast_interpreter.h"
#include "codegen/entry.h"
#include "codegen/unwinding.h"
#include "core/bst.h"
#include "core/options.h"
#include "core/stats.h"
#include "core/types.h"
......@@ -4052,10 +4053,6 @@ BORROWED(BoxedFloat*) CodeConstants::getFloatConstant(double d) const {
void CodeConstants::dealloc() const {
decrefArray(owned_refs.data(), owned_refs.size());
owned_refs.clear();
for (auto&& e : funcs_and_classes) {
Py_DECREF(e.second);
}
funcs_and_classes.clear();
}
#ifndef Py_REF_DEBUG
......
......@@ -1079,8 +1079,6 @@ private:
// all objects we need to decref when the code object dies
mutable std::vector<Box*> owned_refs;
mutable std::vector<std::pair<BST_stmt*, BoxedCode*>> funcs_and_classes;
// Note: DenseMap doesn't work here since we don't prevent the tombstone/empty
// keys from reaching it.
mutable std::unordered_map<int64_t, BoxedInt*> int_constants;
......@@ -1113,17 +1111,8 @@ public:
BORROWED(BoxedInt*) getIntConstant(int64_t n) const;
BORROWED(BoxedFloat*) getFloatConstant(double d) const;
std::pair<BST_stmt*, BORROWED(BoxedCode*)> getFuncOrClass(int constant) const {
return funcs_and_classes[constant];
}
int addInternedString(InternedString s) { return createVRegEntryForConstant(s.getBox()); }
int addFuncOrClass(BST_stmt* stmt, STOLEN(BoxedCode*) code) {
funcs_and_classes.emplace_back(stmt, code);
return funcs_and_classes.size() - 1;
}
int addKeywordNames(llvm::ArrayRef<BoxedString*> name) {
keyword_names.emplace_back(new std::vector<BoxedString*>(name.begin(), name.end()));
return keyword_names.size() - 1;
......
......@@ -27,13 +27,14 @@ 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;
code = (BoxedCode*)module_code->code_constants.getConstant(bst_cast<BST_MakeFunction>(stmt)->vreg_code_obj);
assert(code);
assert(code->cls == code_cls);
break;
}
assert(code);
return code;
}
......@@ -74,7 +75,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 +117,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