Commit 482d2e86 authored by Marius Wachtler's avatar Marius Wachtler

BST: convert all nodes to directly operate at vregs instead of names

**basic design:**
This PR changes our BST nodes to directly operate on vregs instead of pointers to other nodes and names (except a few exceptions: `BST_Invoke`, `BST_MakeFunction` and `BST_MakeClass` which still needs to get converted).
Most nodes got a destination vreg and one or more source vregs. Currently all of them are 32bit long but I plan to store them more compact very soon. Some nodes support a variable size of operands (e.g. the tuple node) but the size can't change after creating the node. I removed several unneeded opcodes and split a lot of nodes into separate opcodes (it may make sense to split them even further in the future).
Generally all instructions except `CopyVReg` kill the source operand vregs except if the source is a ref to a constant. If one needs the preserve the source vreg on needs to create a new temporary using the `CopyVReg` opcode.

There is a special vreg number: `VREG_UNDEFINED = std::numeric_limits<int>::min()`.
- when it's set as an operand vreg: it means that this is a not-set optional argument. (e.g. for a slice which only has `lower` set, `upper` would be `VREG_UNDEFINED`)
- if it's the destination it's means the result value should get immediately killed (e.g. `invoke 15 16: %undef = %11(%14)` this is a call whose result gets ignored)

all other negative vreg numbers are indices into a constant table (after adding 1 and making them positive).
(e.g. `(4, 2, 'lala')` generates:  `%undef = (%-1|4|, %-2|2|, %-3|'lala'|)` this creates a tuple whose elements are the constant idx -1, -2 and -3. In order to make it easier for a human to understand we print the actual value of the constant between | characters)
- constants can be all str and numeric types and 'None'.
- every constant will only get stored once in the table

this reduces the total memory usage by about 20% currently but I'm very sure with the future changes it will be significantly lower.

**near future:**
- change the jump and branch instruction to reference `CFGBlocks` by index.
- store all `InternedString` inside a table and use indices into the the table to access them.
- remove the 'BoxedCode*' member
- devirtualize the classes
= with this changes the bytecode can get freely copied around (only need to update the CFGBlock table) which allows us to attach the directly next to each other.

- I plan to use one bit of the the opcode to mark the instruction as only requiring 8bit vreg operands (which should handle the majority of cases with 128 temps and 127 constants + 1undef vreg value)
- another bit will get used to specify if this instruction is inside an `invoke`. if this bit is set there are 2 one 1 or 4 bytes long block indices directly behind the instruction.

- serialize the bytecode to disk. (maybe serialize the constants using pickle)

**thing which need to get improved**
- currently the constant table get's attached to the `BoxedModule` maybe there is a better location, I also needed to pass the `BoxedModule` into some functions e.g. BST printing because otherwise we could not pretty-print the constants
- `BST_Name` is not an opcode it's just used to initialize the arguments when a function get's called and stores where and how the arguments need to get stored.
- more consistent opcode names and rename `TmpValue` to something better
- we currently don't print the `InternedString` name - we only print the vreg number

**additional changed made which are hidden in the large diff** 👎
- removed unused code initializing the items of `BST_Dict` (we use/used separate  assignments to add the items)
- lower `ExtSlice` inside the CFG phase to a tuple of slices
- separated opcode for load subscript when it needs to be a slice and when it's only lower and upper (=`__getslice__`) before this got handled in the interpreter/jit
- generate a constant `None` load inside the CFG when `None` gets loaded by name
parent 4e10a4f0
...@@ -55,7 +55,7 @@ private: ...@@ -55,7 +55,7 @@ private:
VRegMap<Status> statuses; VRegMap<Status> statuses;
LivenessAnalysis* analysis; LivenessAnalysis* analysis;
void _doLoad(int vreg, BST_Name* node) { void _doLoad(int vreg) {
Status& status = statuses[vreg]; Status& status = statuses[vreg];
status.addUsage(Status::USED); status.addUsage(Status::USED);
} }
...@@ -70,50 +70,28 @@ private: ...@@ -70,50 +70,28 @@ private:
public: public:
LivenessBBVisitor(LivenessAnalysis* analysis) LivenessBBVisitor(LivenessAnalysis* analysis)
: statuses(analysis->cfg->getVRegInfo().getTotalNumOfVRegs()), analysis(analysis) {} : NoopBSTVisitor(true /* skip child CFG nodes */),
statuses(analysis->cfg->getVRegInfo().getTotalNumOfVRegs()),
analysis(analysis) {}
bool firstIsUse(int vreg) const { return getStatusFirst(vreg) == Status::USED; } bool firstIsUse(int vreg) const { return getStatusFirst(vreg) == Status::USED; }
bool firstIsDef(int vreg) const { return getStatusFirst(vreg) == Status::DEFINED; } bool firstIsDef(int vreg) const { return getStatusFirst(vreg) == Status::DEFINED; }
bool isKilledAt(BST_Name* node, bool is_live_at_end) { return node->is_kill; } bool visit_vreg(int* vreg, bool is_dst) override {
if (*vreg >= 0) {
bool visit_classdef(BST_ClassDef* node) { if (is_dst)
for (auto e : node->bases) _doStore(*vreg);
e->accept(this); else
for (auto e : node->decorator_list) _doLoad(*vreg);
e->accept(this); }
return true;
}
bool visit_functiondef(BST_FunctionDef* node) {
for (auto* d : node->decorator_list)
d->accept(this);
for (auto* d : node->args->defaults)
d->accept(this);
return true; return true;
} }
bool visit_name(BST_Name* node) { bool visit_deletename(BST_DeleteName* node) override {
if (node->vreg == -1) if (node->vreg < 0 || node->vreg >= analysis->cfg->getVRegInfo().getNumOfUserVisibleVRegs())
return true; return true;
_doLoad(node->vreg);
if (node->ctx_type == AST_TYPE::Load) _doStore(node->vreg);
_doLoad(node->vreg, node);
else if (node->ctx_type == AST_TYPE::Del) {
// Hack: we don't have a bytecode for temporary-kills:
if (node->vreg >= analysis->cfg->getVRegInfo().getNumOfUserVisibleVRegs())
return true;
_doLoad(node->vreg, node);
_doStore(node->vreg);
} else if (node->ctx_type == AST_TYPE::Store || node->ctx_type == AST_TYPE::Param)
_doStore(node->vreg);
else {
ASSERT(0, "%d", node->ctx_type);
abort();
}
return true; return true;
} }
}; };
...@@ -136,13 +114,6 @@ LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg), result_cache(cfg->getVR ...@@ -136,13 +114,6 @@ LivenessAnalysis::LivenessAnalysis(CFG* cfg) : cfg(cfg), result_cache(cfg->getVR
LivenessAnalysis::~LivenessAnalysis() { LivenessAnalysis::~LivenessAnalysis() {
} }
bool LivenessAnalysis::isKill(BST_Name* node, CFGBlock* parent_block) {
if (node->id.s()[0] != '#')
return false;
return liveness_cache[parent_block]->isKilledAt(node, isLiveAtEnd(node->vreg, parent_block));
}
bool LivenessAnalysis::isLiveAtEnd(int vreg, CFGBlock* block) { bool LivenessAnalysis::isLiveAtEnd(int vreg, CFGBlock* block) {
// Is a user-visible name, always live: // Is a user-visible name, always live:
if (vreg < block->cfg->getVRegInfo().getNumOfUserVisibleVRegs()) if (vreg < block->cfg->getVRegInfo().getNumOfUserVisibleVRegs())
...@@ -228,102 +199,55 @@ public: ...@@ -228,102 +199,55 @@ public:
virtual void processBB(Map& starting, CFGBlock* block) const; virtual void processBB(Map& starting, CFGBlock* block) const;
}; };
class DefinednessVisitor : public BSTVisitor { class DefinednessVisitor : public NoopBSTVisitor {
private: private:
typedef DefinednessBBAnalyzer::Map Map; typedef DefinednessBBAnalyzer::Map Map;
Map& state; Map& state;
void _doSet(int vreg) { void _doSet(int vreg) {
if (vreg == VREG_UNDEFINED)
return;
assert(vreg >= 0 && vreg < state.numVregs()); assert(vreg >= 0 && vreg < state.numVregs());
state[vreg] = DefinednessAnalysis::Defined; state[vreg] = DefinednessAnalysis::Defined;
} }
void _doSet(BST* t) {
switch (t->type) {
case BST_TYPE::Attribute:
// doesn't affect definedness (yet?)
break;
case BST_TYPE::Name: {
auto name = bst_cast<BST_Name>(t);
if (name->lookup_type == ScopeInfo::VarScopeType::FAST
|| name->lookup_type == ScopeInfo::VarScopeType::CLOSURE) {
assert(name->vreg != -1);
_doSet(name->vreg);
} else if (name->lookup_type == ScopeInfo::VarScopeType::GLOBAL
|| name->lookup_type == ScopeInfo::VarScopeType::NAME) {
assert(name->vreg == -1);
// skip
} else {
RELEASE_ASSERT(0, "%d", static_cast<int>(name->lookup_type));
}
break;
}
case BST_TYPE::Subscript:
break;
case BST_TYPE::Tuple: {
BST_Tuple* tt = bst_cast<BST_Tuple>(t);
for (int i = 0; i < tt->elts.size(); i++) {
_doSet(tt->elts[i]);
}
break;
}
default:
ASSERT(0, "Unknown type for DefinednessVisitor: %d", t->type);
}
}
public: public:
DefinednessVisitor(Map& state) : state(state) {} DefinednessVisitor(Map& state) : NoopBSTVisitor(true /* skip child CFG nodes */), state(state) {}
bool visit_vreg(int* vreg, bool is_dest) override {
virtual bool visit_assert(BST_Assert* node) { return true; } if (*vreg < 0)
virtual bool visit_branch(BST_Branch* node) { return true; } return false;
virtual bool visit_expr(BST_Expr* node) { return true; }
virtual bool visit_invoke(BST_Invoke* node) { return false; } if (is_dest)
virtual bool visit_jump(BST_Jump* node) { return true; } state[*vreg] = DefinednessAnalysis::Defined;
virtual bool visit_print(BST_Print* node) { return true; } else
virtual bool visit_raise(BST_Raise* node) { return true; } state[*vreg] = DefinednessAnalysis::Undefined;
virtual bool visit_return(BST_Return* node) { return true; } return false;
virtual bool visit_delete(BST_Delete* node) {
auto t = node->target;
if (t->type == BST_TYPE::Name) {
BST_Name* name = bst_cast<BST_Name>(t);
if (name->lookup_type != ScopeInfo::VarScopeType::GLOBAL
&& name->lookup_type != ScopeInfo::VarScopeType::NAME) {
assert(name->vreg != -1);
state[name->vreg] = DefinednessAnalysis::Undefined;
} else
assert(name->vreg == -1);
} else {
// The CFG pass should reduce all deletes to the "basic" deletes on names/attributes/subscripts.
// If not, probably the best way to do this would be to just do a full BST traversal
// and look for BST_Name's with a ctx of Del
assert(t->type == BST_TYPE::Attribute || t->type == BST_TYPE::Subscript);
}
return true;
} }
virtual bool visit_classdef(BST_ClassDef* node) { bool visit_deletename(BST_DeleteName* node) override {
assert(0 && "I think this isn't needed"); if (node->lookup_type != ScopeInfo::VarScopeType::GLOBAL
//_doSet(node->name); && node->lookup_type != ScopeInfo::VarScopeType::NAME) {
assert(node->vreg >= 0);
state[node->vreg] = DefinednessAnalysis::Undefined;
} else
assert(node->vreg == VREG_UNDEFINED);
return true; return true;
} }
virtual bool visit_functiondef(BST_FunctionDef* node) { bool visit_copyvreg(BST_CopyVReg* node) override {
assert(0 && "I think this isn't needed"); // don't visit the vreg it will never get killed
//_doSet(node->name); // visit_vreg(&node->vreg_src, false);
_doSet(node->vreg_dst);
return true; return true;
} }
virtual bool visit_assign(BST_Assign* node) { bool visit_loadname(BST_LoadName* node) override {
_doSet(node->target); // don't visit the vreg it will never get killed
// visit_vreg(&node->vreg, false);
_doSet(node->vreg_dst);
return true; return true;
} }
virtual bool visit_arguments(BST_arguments* node) { RELEASE_ASSERT(0, "this shouldn't get hit"); }
virtual bool visit_exec(BST_Exec* node) { return true; }
friend class DefinednessBBAnalyzer; friend class DefinednessBBAnalyzer;
}; };
...@@ -460,11 +384,13 @@ const VRegSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) { ...@@ -460,11 +384,13 @@ const VRegSet& PhiAnalysis::getAllRequiredFor(CFGBlock* block) {
} }
bool PhiAnalysis::isRequired(int vreg, CFGBlock* block) { bool PhiAnalysis::isRequired(int vreg, CFGBlock* block) {
assert(vreg >= 0);
assert(required_phis.count(block)); assert(required_phis.count(block));
return required_phis.find(block)->second[vreg]; return required_phis.find(block)->second[vreg];
} }
bool PhiAnalysis::isRequiredAfter(int vreg, CFGBlock* block) { bool PhiAnalysis::isRequiredAfter(int vreg, CFGBlock* block) {
assert(vreg >= 0);
// If there are multiple successors, then none of them are allowed // If there are multiple successors, then none of them are allowed
// to require any phi nodes // to require any phi nodes
if (block->successors.size() != 1) if (block->successors.size() != 1)
...@@ -475,6 +401,7 @@ bool PhiAnalysis::isRequiredAfter(int vreg, CFGBlock* block) { ...@@ -475,6 +401,7 @@ bool PhiAnalysis::isRequiredAfter(int vreg, CFGBlock* block) {
} }
bool PhiAnalysis::isPotentiallyUndefinedAfter(int vreg, CFGBlock* block) { bool PhiAnalysis::isPotentiallyUndefinedAfter(int vreg, CFGBlock* block) {
assert(vreg >= 0);
for (auto b : block->successors) { for (auto b : block->successors) {
if (isPotentiallyUndefinedAt(vreg, b)) if (isPotentiallyUndefinedAt(vreg, b))
return true; return true;
...@@ -483,6 +410,7 @@ bool PhiAnalysis::isPotentiallyUndefinedAfter(int vreg, CFGBlock* block) { ...@@ -483,6 +410,7 @@ bool PhiAnalysis::isPotentiallyUndefinedAfter(int vreg, CFGBlock* block) {
} }
bool PhiAnalysis::isPotentiallyUndefinedAt(int vreg, CFGBlock* block) { bool PhiAnalysis::isPotentiallyUndefinedAt(int vreg, CFGBlock* block) {
assert(vreg >= 0);
assert(definedness.defined_at_beginning.count(block)); assert(definedness.defined_at_beginning.count(block));
return definedness.defined_at_beginning.find(block)->second[vreg] != DefinednessAnalysis::Defined; return definedness.defined_at_beginning.find(block)->second[vreg] != DefinednessAnalysis::Defined;
} }
......
...@@ -26,9 +26,7 @@ ...@@ -26,9 +26,7 @@
namespace pyston { namespace pyston {
class BST_arguments;
class BST_Jump; class BST_Jump;
class BST_Name;
class CFG; class CFG;
class CFGBlock; class CFGBlock;
class LivenessBBVisitor; class LivenessBBVisitor;
...@@ -47,9 +45,6 @@ public: ...@@ -47,9 +45,6 @@ public:
LivenessAnalysis(CFG* cfg); LivenessAnalysis(CFG* cfg);
~LivenessAnalysis(); ~LivenessAnalysis();
// we don't keep track of node->parent_block relationships, so you have to pass both:
bool isKill(BST_Name* node, CFGBlock* parent_block);
bool isLiveAtEnd(int vreg, CFGBlock* block); bool isLiveAtEnd(int vreg, CFGBlock* block);
}; };
......
...@@ -36,16 +36,11 @@ ScopingResults::ScopingResults(ScopeInfo* scope_info, bool globals_from_module) ...@@ -36,16 +36,11 @@ ScopingResults::ScopingResults(ScopeInfo* scope_info, bool globals_from_module)
deref_info = scope_info->getAllDerefVarsAndInfo(); deref_info = scope_info->getAllDerefVarsAndInfo();
} }
DerefInfo ScopingResults::getDerefInfo(BST_Name* node) const { DerefInfo ScopingResults::getDerefInfo(BST_LoadName* node) const {
assert(node->lookup_type == ScopeInfo::VarScopeType::DEREF); assert(node->lookup_type == ScopeInfo::VarScopeType::DEREF);
assert(node->deref_info.offset != INT_MAX); assert(node->deref_info.offset != INT_MAX);
return node->deref_info; return node->deref_info;
} }
size_t ScopingResults::getClosureOffset(BST_Name* node) const {
assert(node->lookup_type == ScopeInfo::VarScopeType::CLOSURE);
assert(node->closure_offset != -1);
return node->closure_offset;
}
class YieldVisitor : public NoopASTVisitor { class YieldVisitor : public NoopASTVisitor {
public: public:
......
This diff is collapsed.
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
namespace pyston { namespace pyston {
class CFGBlock; class CFGBlock;
class ConstantVRegInfo;
class BoxedClass; class BoxedClass;
class BST_expr; class BST_stmt_with_dest;
class BST_slice;
class OSREntryDescriptor; class OSREntryDescriptor;
class TypeAnalysis { class TypeAnalysis {
...@@ -40,15 +40,14 @@ public: ...@@ -40,15 +40,14 @@ public:
virtual ConcreteCompilerType* getTypeAtBlockStart(int vreg, CFGBlock* block) = 0; virtual ConcreteCompilerType* getTypeAtBlockStart(int vreg, CFGBlock* block) = 0;
virtual ConcreteCompilerType* getTypeAtBlockEnd(int vreg, CFGBlock* block) = 0; virtual ConcreteCompilerType* getTypeAtBlockEnd(int vreg, CFGBlock* block) = 0;
virtual BoxedClass* speculatedExprClass(BST_expr*) = 0; virtual BoxedClass* speculatedExprClass(BST_stmt_with_dest*) = 0;
virtual BoxedClass* speculatedExprClass(BST_slice*) = 0;
}; };
TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& param_names, TypeAnalysis* doTypeAnalysis(CFG* cfg, const ParamNames& param_names,
const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel effort, const std::vector<ConcreteCompilerType*>& arg_types, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation); TypeAnalysis::SpeculationLevel speculation, const ConstantVRegInfo& constant_vregs);
TypeAnalysis* doTypeAnalysis(const OSREntryDescriptor* entry_descriptor, EffortLevel effort, TypeAnalysis* doTypeAnalysis(const OSREntryDescriptor* entry_descriptor, EffortLevel effort,
TypeAnalysis::SpeculationLevel speculation); TypeAnalysis::SpeculationLevel speculation, const ConstantVRegInfo& constant_vregs);
} }
#endif #endif
...@@ -341,7 +341,7 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) { ...@@ -341,7 +341,7 @@ ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) {
} }
static llvm::DenseMap<void*, ICInfo*> ics_by_return_addr; static llvm::DenseMap<void*, ICInfo*> ics_by_return_addr;
static llvm::DenseMap<BST*, ICInfo*> ics_by_ast_node; static llvm::DenseMap<BST_stmt*, ICInfo*> ics_by_ast_node;
ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int size, ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int size,
llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs, assembler::GenericRegister return_register, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs, assembler::GenericRegister return_register,
...@@ -485,13 +485,13 @@ bool ICInfo::isMegamorphic() { ...@@ -485,13 +485,13 @@ bool ICInfo::isMegamorphic() {
return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD; return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD;
} }
ICInfo* ICInfo::getICInfoForNode(BST* node) { ICInfo* ICInfo::getICInfoForNode(BST_stmt* node) {
auto&& it = ics_by_ast_node.find(node); auto&& it = ics_by_ast_node.find(node);
if (it != ics_by_ast_node.end()) if (it != ics_by_ast_node.end())
return it->second; return it->second;
return NULL; return NULL;
} }
void ICInfo::associateNodeWithICInfo(BST* node, std::unique_ptr<TypeRecorder> type_recorder) { void ICInfo::associateNodeWithICInfo(BST_stmt* node, std::unique_ptr<TypeRecorder> type_recorder) {
assert(!this->node); assert(!this->node);
this->node = node; this->node = node;
this->type_recorder = std::move(type_recorder); this->type_recorder = std::move(type_recorder);
......
...@@ -105,7 +105,7 @@ private: ...@@ -105,7 +105,7 @@ private:
std::vector<Location> ic_global_decref_locations; std::vector<Location> ic_global_decref_locations;
// associated BST node for this IC // associated BST node for this IC
BST* node; BST_stmt* node;
// for ICSlotRewrite: // for ICSlotRewrite:
ICSlotInfo* pickEntryForRewrite(const char* debug_name); ICSlotInfo* pickEntryForRewrite(const char* debug_name);
...@@ -145,8 +145,8 @@ public: ...@@ -145,8 +145,8 @@ public:
friend class ICSlotRewrite; friend class ICSlotRewrite;
static ICInfo* getICInfoForNode(BST* node); static ICInfo* getICInfoForNode(BST_stmt* node);
void associateNodeWithICInfo(BST* node, std::unique_ptr<TypeRecorder> type_recorder); void associateNodeWithICInfo(BST_stmt* node, std::unique_ptr<TypeRecorder> type_recorder);
void appendDecrefInfosTo(std::vector<DecrefInfo>& dest_decref_infos); void appendDecrefInfosTo(std::vector<DecrefInfo>& dest_decref_infos);
}; };
......
This diff is collapsed.
...@@ -23,7 +23,6 @@ namespace gc { ...@@ -23,7 +23,6 @@ namespace gc {
class GCVisitor; class GCVisitor;
} }
class BST_expr;
class BST_stmt; class BST_stmt;
class BST_Jump; class BST_Jump;
class Box; class Box;
...@@ -46,11 +45,11 @@ struct ASTInterpreterJitInterface { ...@@ -46,11 +45,11 @@ struct ASTInterpreterJitInterface {
static int getGlobalsOffset(); static int getGlobalsOffset();
static void delNameHelper(void* _interpreter, InternedString name); static void delNameHelper(void* _interpreter, InternedString name);
static Box* derefHelper(void* interp, BST_Name* node); static Box* derefHelper(void* interp, BST_LoadName* node);
static Box* landingpadHelper(void* interp); static Box* landingpadHelper(void* interp);
static void pendingCallsCheckHelper(); static void pendingCallsCheckHelper();
static void setExcInfoHelper(void* interp, STOLEN(Box*) type, STOLEN(Box*) value, STOLEN(Box*) traceback); static void setExcInfoHelper(void* interp, STOLEN(Box*) type, STOLEN(Box*) value, STOLEN(Box*) traceback);
static void setLocalClosureHelper(void* interp, BST_Name* name, Box* v); static void setLocalClosureHelper(void* interp, int vreg, int closure_offset, Box* v);
static void uncacheExcInfoHelper(void* interp); static void uncacheExcInfoHelper(void* interp);
static void raise0Helper(void* interp) __attribute__((noreturn)); static void raise0Helper(void* interp) __attribute__((noreturn));
static Box* yieldHelper(void* interp, STOLEN(Box*) value); static Box* yieldHelper(void* interp, STOLEN(Box*) value);
...@@ -79,7 +78,7 @@ Box* astInterpretFunction(BoxedCode* f, Box* closure, Box* generator, Box* globa ...@@ -79,7 +78,7 @@ Box* astInterpretFunction(BoxedCode* f, Box* closure, Box* generator, Box* globa
Box** args); Box** args);
Box* astInterpretFunctionEval(BoxedCode* cf, Box* globals, Box* boxedLocals); Box* astInterpretFunctionEval(BoxedCode* cf, Box* globals, Box* boxedLocals);
// this function is implemented in the src/codegen/ast_interpreter_exec.S assembler file // this function is implemented in the src/codegen/ast_interpreter_exec.S assembler file
extern "C" Box* astInterpretDeopt(BoxedCode* cf, BST_expr* after_expr, BST_stmt* enclosing_stmt, Box* expr_val, extern "C" Box* astInterpretDeopt(BoxedCode* cf, BST_stmt* enclosing_stmt, Box* expr_val,
STOLEN(FrameStackState) frame_state); STOLEN(FrameStackState) frame_state);
struct FrameInfo; struct FrameInfo;
......
...@@ -43,7 +43,7 @@ executeInnerAndSetupFrame: ...@@ -43,7 +43,7 @@ executeInnerAndSetupFrame:
// Our unwinder must be able to detect deopt frames and by writting this wrapper in assembler we can be sure to correctly // Our unwinder must be able to detect deopt frames and by writting this wrapper in assembler we can be sure to correctly
// detect the frame independent of compiler optimizations because this function will always appear in the call stack. // detect the frame independent of compiler optimizations because this function will always appear in the call stack.
// //
// Box* astInterpretDeopt(FunctionMetadata* cf, AST_expr* after_expr, AST_stmt* enclosing_stmt, Box* expr_val, // Box* astInterpretDeopt(FunctionMetadata* cf, AST_stmt* enclosing_stmt, Box* expr_val,
// FrameStackState frame_state); // FrameStackState frame_state);
.text .text
.globl astInterpretDeopt .globl astInterpretDeopt
......
This diff is collapsed.
...@@ -231,7 +231,7 @@ private: ...@@ -231,7 +231,7 @@ private:
JitCodeBlock& code_block; JitCodeBlock& code_block;
RewriterVar* interp; RewriterVar* interp;
RewriterVar* vregs_array; RewriterVar* vregs_array;
llvm::DenseMap<InternedString, RewriterVar*> local_syms; llvm::DenseMap<int /*vreg*/, RewriterVar*> local_syms;
// keeps track which non block local vregs are known to have a non NULL value // keeps track which non block local vregs are known to have a non NULL value
llvm::DenseSet<int> known_non_null_vregs; llvm::DenseSet<int> known_non_null_vregs;
...@@ -249,7 +249,7 @@ private: ...@@ -249,7 +249,7 @@ private:
uint8_t* end_addr; uint8_t* end_addr;
std::unique_ptr<ICSetupInfo> ic; std::unique_ptr<ICSetupInfo> ic;
StackInfo stack_info; StackInfo stack_info;
BST* node; BST_stmt* node;
std::vector<Location> decref_infos; std::vector<Location> decref_infos;
std::unique_ptr<TypeRecorder> type_recorder; std::unique_ptr<TypeRecorder> type_recorder;
}; };
...@@ -266,39 +266,41 @@ public: ...@@ -266,39 +266,41 @@ public:
RewriterVar* imm(uint64_t val); RewriterVar* imm(uint64_t val);
RewriterVar* imm(void* val); RewriterVar* imm(void* val);
RewriterVar* emitAugbinop(BST_expr* node, RewriterVar* lhs, RewriterVar* rhs, int op_type); RewriterVar* emitAugbinop(BST_stmt* node, RewriterVar* lhs, RewriterVar* rhs, int op_type);
RewriterVar* emitApplySlice(RewriterVar* target, RewriterVar* lower, RewriterVar* upper); RewriterVar* emitApplySlice(RewriterVar* target, RewriterVar* lower, RewriterVar* upper);
RewriterVar* emitBinop(BST_expr* node, RewriterVar* lhs, RewriterVar* rhs, int op_type); RewriterVar* emitBinop(BST_stmt* node, RewriterVar* lhs, RewriterVar* rhs, int op_type);
RewriterVar* emitCallattr(BST_expr* node, RewriterVar* obj, BoxedString* attr, CallattrFlags flags, RewriterVar* emitCallattr(BST_stmt* node, RewriterVar* obj, BoxedString* attr, CallattrFlags flags,
const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names); const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names);
RewriterVar* emitCompare(BST_expr* node, RewriterVar* lhs, RewriterVar* rhs, int op_type); RewriterVar* emitCompare(BST_stmt* node, RewriterVar* lhs, RewriterVar* rhs, int op_type);
RewriterVar* emitCreateDict(); RewriterVar* emitCreateDict();
void emitDictSet(RewriterVar* dict, RewriterVar* k, RewriterVar* v); void emitDictSet(RewriterVar* dict, RewriterVar* k, RewriterVar* v);
RewriterVar* emitCreateList(const llvm::ArrayRef<STOLEN(RewriterVar*)> values); RewriterVar* emitCreateList(const llvm::ArrayRef<STOLEN(RewriterVar*)> values);
RewriterVar* emitCreateSet(const llvm::ArrayRef<RewriterVar*> values); RewriterVar* emitCreateSet(const llvm::ArrayRef<RewriterVar*> values);
RewriterVar* emitCreateSlice(RewriterVar* start, RewriterVar* stop, RewriterVar* step); RewriterVar* emitCreateSlice(RewriterVar* start, RewriterVar* stop, RewriterVar* step);
RewriterVar* emitCreateTuple(const llvm::ArrayRef<RewriterVar*> values); RewriterVar* emitCreateTuple(const llvm::ArrayRef<RewriterVar*> values);
RewriterVar* emitDeref(BST_Name* name); RewriterVar* emitDeref(BST_LoadName* name);
RewriterVar* emitExceptionMatches(RewriterVar* v, RewriterVar* cls); RewriterVar* emitExceptionMatches(RewriterVar* v, RewriterVar* cls);
RewriterVar* emitGetAttr(RewriterVar* obj, BoxedString* s, BST_expr* node); RewriterVar* emitGetAttr(BST_stmt* node, RewriterVar* obj, BoxedString* s);
RewriterVar* emitGetBlockLocal(BST_Name* name); RewriterVar* emitGetBlockLocal(InternedString name, int vreg);
void emitKillTemporary(BST_Name* name); RewriterVar* emitGetBlockLocalMustExist(int vreg);
void emitKillTemporary(int vreg);
RewriterVar* emitGetBoxedLocal(BoxedString* s); RewriterVar* emitGetBoxedLocal(BoxedString* s);
RewriterVar* emitGetBoxedLocals(); RewriterVar* emitGetBoxedLocals();
RewriterVar* emitGetClsAttr(RewriterVar* obj, BoxedString* s); RewriterVar* emitGetClsAttr(RewriterVar* obj, BoxedString* s);
RewriterVar* emitGetGlobal(BoxedString* s); RewriterVar* emitGetGlobal(BoxedString* s);
RewriterVar* emitGetItem(BST_expr* node, RewriterVar* value, RewriterVar* slice); RewriterVar* emitGetItem(BST_stmt* node, RewriterVar* value, RewriterVar* slice);
RewriterVar* emitGetLocal(BST_Name* name); RewriterVar* emitGetLocal(InternedString name, int vreg);
RewriterVar* emitGetLocalMustExist(int vreg);
RewriterVar* emitGetPystonIter(RewriterVar* v); RewriterVar* emitGetPystonIter(RewriterVar* v);
RewriterVar* emitHasnext(RewriterVar* v); RewriterVar* emitHasnext(RewriterVar* v);
RewriterVar* emitImportFrom(RewriterVar* module, BoxedString* name); RewriterVar* emitImportFrom(RewriterVar* module, RewriterVar* name);
RewriterVar* emitImportName(int level, RewriterVar* from_imports, llvm::StringRef module_name); RewriterVar* emitImportName(int level, RewriterVar* from_imports, RewriterVar* module_name);
RewriterVar* emitImportStar(RewriterVar* module); RewriterVar* emitImportStar(RewriterVar* module);
RewriterVar* emitLandingpad(); RewriterVar* emitLandingpad();
RewriterVar* emitNonzero(RewriterVar* v); RewriterVar* emitNonzero(RewriterVar* v);
RewriterVar* emitNotNonzero(RewriterVar* v); RewriterVar* emitNotNonzero(RewriterVar* v);
RewriterVar* emitRepr(RewriterVar* v); RewriterVar* emitRepr(RewriterVar* v);
RewriterVar* emitRuntimeCall(BST_expr* node, RewriterVar* obj, ArgPassSpec argspec, RewriterVar* emitRuntimeCall(BST_stmt* node, RewriterVar* obj, ArgPassSpec argspec,
const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names); const llvm::ArrayRef<RewriterVar*> args, std::vector<BoxedString*>* keyword_names);
RewriterVar* emitUnaryop(RewriterVar* v, int op_type); RewriterVar* emitUnaryop(RewriterVar* v, int op_type);
std::vector<RewriterVar*> emitUnpackIntoArray(RewriterVar* v, uint64_t num); std::vector<RewriterVar*> emitUnpackIntoArray(RewriterVar* v, uint64_t num);
...@@ -317,14 +319,15 @@ public: ...@@ -317,14 +319,15 @@ public:
void emitRaise0(); void emitRaise0();
void emitRaise3(RewriterVar* arg0, RewriterVar* arg1, RewriterVar* arg2); void emitRaise3(RewriterVar* arg0, RewriterVar* arg1, RewriterVar* arg2);
void emitReturn(RewriterVar* v); void emitReturn(RewriterVar* v);
void emitSetAttr(BST_expr* node, RewriterVar* obj, BoxedString* s, STOLEN(RewriterVar*) attr); void emitSetAttr(BST_stmt* node, RewriterVar* obj, BoxedString* s, STOLEN(RewriterVar*) attr);
void emitSetBlockLocal(BST_Name* name, STOLEN(RewriterVar*) v); void emitSetBlockLocal(int vreg, STOLEN(RewriterVar*) v);
void emitSetCurrentInst(BST_stmt* node); void emitSetCurrentInst(BST_stmt* node);
void emitSetExcInfo(RewriterVar* type, RewriterVar* value, RewriterVar* traceback); void emitSetExcInfo(RewriterVar* type, RewriterVar* value, RewriterVar* traceback);
void emitSetGlobal(BoxedString* s, STOLEN(RewriterVar*) v, bool are_globals_from_module); void emitSetGlobal(BoxedString* s, STOLEN(RewriterVar*) v, bool are_globals_from_module);
void emitSetItemName(BoxedString* s, RewriterVar* v); void emitSetItemName(BoxedString* s, RewriterVar* v);
void emitSetItem(RewriterVar* target, RewriterVar* slice, RewriterVar* value); void emitSetItem(RewriterVar* target, RewriterVar* slice, RewriterVar* value);
void emitSetLocal(BST_Name* name, bool set_closure, STOLEN(RewriterVar*) v); void emitSetLocal(int vreg, STOLEN(RewriterVar*) v);
void emitSetLocalClosure(BST_StoreName* name, STOLEN(RewriterVar*) v);
// emitSideExit steals a full ref from v, not just a vref // emitSideExit steals a full ref from v, not just a vref
void emitSideExit(STOLEN(RewriterVar*) v, Box* cmp_value, CFGBlock* next_block); void emitSideExit(STOLEN(RewriterVar*) v, Box* cmp_value, CFGBlock* next_block);
void emitUncacheExcInfo(); void emitUncacheExcInfo();
...@@ -351,7 +354,7 @@ private: ...@@ -351,7 +354,7 @@ private:
const llvm::ArrayRef<RewriterVar*> additional_uses); const llvm::ArrayRef<RewriterVar*> additional_uses);
std::pair<RewriterVar*, RewriterAction*> emitPPCall(void* func_addr, llvm::ArrayRef<RewriterVar*> args, std::pair<RewriterVar*, RewriterAction*> emitPPCall(void* func_addr, llvm::ArrayRef<RewriterVar*> args,
unsigned short pp_size, bool should_record_type = false, unsigned short pp_size, bool should_record_type = false,
BST* bst_node = NULL, BST_stmt* bst_node = NULL,
llvm::ArrayRef<RewriterVar*> additional_uses = {}); llvm::ArrayRef<RewriterVar*> additional_uses = {});
static void assertNameDefinedHelper(const char* id); static void assertNameDefinedHelper(const char* id);
...@@ -371,7 +374,7 @@ private: ...@@ -371,7 +374,7 @@ private:
void _emitJump(CFGBlock* b, RewriterVar* block_next, ExitInfo& exit_info); void _emitJump(CFGBlock* b, RewriterVar* block_next, ExitInfo& exit_info);
void _emitOSRPoint(); void _emitOSRPoint();
void _emitPPCall(RewriterVar* result, void* func_addr, llvm::ArrayRef<RewriterVar*> args, unsigned short pp_size, void _emitPPCall(RewriterVar* result, void* func_addr, llvm::ArrayRef<RewriterVar*> args, unsigned short pp_size,
BST* bst_node, llvm::ArrayRef<RewriterVar*> vars_to_bump); BST_stmt* bst_node, llvm::ArrayRef<RewriterVar*> vars_to_bump);
void _emitRecordType(RewriterVar* obj_cls_var); void _emitRecordType(RewriterVar* obj_cls_var);
void _emitReturn(RewriterVar* v); void _emitReturn(RewriterVar* v);
void _emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val_constant, CFGBlock* next_block, void _emitSideExit(STOLEN(RewriterVar*) var, RewriterVar* val_constant, CFGBlock* next_block,
......
...@@ -73,7 +73,7 @@ struct GlobalState { ...@@ -73,7 +73,7 @@ struct GlobalState {
llvm::Type* llvm_value_type, *llvm_value_type_ptr, *llvm_value_type_ptr_ptr; llvm::Type* llvm_value_type, *llvm_value_type_ptr, *llvm_value_type_ptr_ptr;
llvm::Type* llvm_class_type, *llvm_class_type_ptr; llvm::Type* llvm_class_type, *llvm_class_type_ptr;
llvm::Type* llvm_opaque_type; llvm::Type* llvm_opaque_type;
llvm::Type* llvm_boxedstring_type_ptr, *llvm_dict_type_ptr, *llvm_bststmt_type_ptr, *llvm_bstexpr_type_ptr; llvm::Type* llvm_boxedstring_type_ptr, *llvm_dict_type_ptr, *llvm_bststmt_type_ptr;
llvm::Type* llvm_frame_info_type; llvm::Type* llvm_frame_info_type;
llvm::Type* llvm_code_type_ptr, *llvm_closure_type_ptr, *llvm_generator_type_ptr; llvm::Type* llvm_code_type_ptr, *llvm_closure_type_ptr, *llvm_generator_type_ptr;
llvm::Type* llvm_module_type_ptr, *llvm_bool_type_ptr; llvm::Type* llvm_module_type_ptr, *llvm_bool_type_ptr;
......
...@@ -2762,6 +2762,15 @@ public: ...@@ -2762,6 +2762,15 @@ public:
return new ConcreteCompilerVariable(SLICE, rtn); return new ConcreteCompilerVariable(SLICE, rtn);
} }
CompilerVariable* dup(VAR* v, DupCache& cache) override {
// TODO copied from UnknownType
auto& rtn = cache[v];
if (rtn == NULL) {
rtn = new VAR(this, v->getValue());
}
return rtn;
}
} _UNBOXED_SLICE; } _UNBOXED_SLICE;
CompilerType* UNBOXED_SLICE = &_UNBOXED_SLICE; CompilerType* UNBOXED_SLICE = &_UNBOXED_SLICE;
......
...@@ -337,6 +337,38 @@ llvm::Value* handlePotentiallyUndefined(ConcreteCompilerVariable* is_defined_var ...@@ -337,6 +337,38 @@ llvm::Value* handlePotentiallyUndefined(ConcreteCompilerVariable* is_defined_var
return phi; return phi;
} }
// This is used to filter out any names set by an invoke statement at the end of the previous block, if we're in the
// unwind path.
class SymTableDstVRegDeleter : NoopBSTVisitor {
private:
SymbolTable* sym_table;
bool created_new_sym_table;
SymTableDstVRegDeleter(SymbolTable* sym_table)
: NoopBSTVisitor(true /* skip child CFG nodes */), sym_table(sym_table), created_new_sym_table(false) {}
protected:
bool visit_vreg(int* vreg, bool is_dst = false) override {
if (!is_dst || *vreg == VREG_UNDEFINED || !(*sym_table)[*vreg])
return false;
if (!created_new_sym_table) {
sym_table = new SymbolTable(*sym_table);
created_new_sym_table = true;
}
(*sym_table)[*vreg] = NULL;
return false;
}
public:
static std::pair<SymbolTable*, bool /* created_new_sym_table */> removeDestVRegsFromSymTable(SymbolTable* sym_table,
BST_Invoke* stmt) {
SymTableDstVRegDeleter visitor(sym_table);
stmt->accept(&visitor);
return std::make_pair(visitor.sym_table, visitor.created_new_sym_table);
}
};
static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDescriptor* entry_descriptor, static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDescriptor* entry_descriptor,
const BlockSet& blocks) { const BlockSet& blocks) {
SourceInfo* source = irstate->getSourceInfo(); SourceInfo* source = irstate->getSourceInfo();
...@@ -551,7 +583,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -551,7 +583,7 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
if (block == cfg->getStartingBlock()) { if (block == cfg->getStartingBlock()) {
assert(entry_descriptor == NULL); assert(entry_descriptor == NULL);
if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast_type != BST_TYPE::Module) { if (ENABLE_REOPT && effort < EffortLevel::MAXIMAL && source->ast_type != AST_TYPE::Module) {
llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create( llvm::BasicBlock* preentry_bb = llvm::BasicBlock::Create(
g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[cfg->getStartingBlock()]); g.context, "pre_entry", irstate->getLLVMFunction(), llvm_entry_blocks[cfg->getStartingBlock()]);
llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction()); llvm::BasicBlock* reopt_bb = llvm::BasicBlock::Create(g.context, "reopt", irstate->getLLVMFunction());
...@@ -695,16 +727,6 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -695,16 +727,6 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
// analysis frameworks can't (yet) support the idea of a block flowing differently to its different // analysis frameworks can't (yet) support the idea of a block flowing differently to its different
// successors. // successors.
// //
// There are four kinds of BST statements which can set a name:
// - Assign
// - ClassDef
// - FunctionDef
// - Import, ImportFrom
//
// However, all of these get translated away into Assigns, so we only need to worry about those. Also,
// as an invariant, all assigns that can fail assign to a temporary rather than a python name. This
// ensures that we interoperate properly with definedness analysis.
//
// We only need to do this in the case that we have exactly one predecessor, because: // We only need to do this in the case that we have exactly one predecessor, because:
// - a block ending in an invoke will have multiple successors // - a block ending in an invoke will have multiple successors
// - critical edges (block with multiple successors -> block with multiple predecessors) // - critical edges (block with multiple successors -> block with multiple predecessors)
...@@ -715,38 +737,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc ...@@ -715,38 +737,9 @@ static void emitBBs(IRGenState* irstate, TypeAnalysis* types, const OSREntryDesc
SymbolTable* sym_table = ending_symbol_tables[pred]; SymbolTable* sym_table = ending_symbol_tables[pred];
bool created_new_sym_table = false; 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->type == BST_TYPE::Invoke && bst_cast<BST_Invoke>(last_inst)->exc_dest == block)
BST_stmt* stmt = bst_cast<BST_Invoke>(last_inst)->stmt; std::tie(sym_table, created_new_sym_table) = SymTableDstVRegDeleter::removeDestVRegsFromSymTable(
sym_table, bst_cast<BST_Invoke>(last_inst));
// The CFG pass translates away these statements, so we should never encounter them.
// If we did, we'd need to remove a name here.
assert(stmt->type != BST_TYPE::ClassDef);
assert(stmt->type != BST_TYPE::FunctionDef);
assert(stmt->type != BST_TYPE::Import);
assert(stmt->type != BST_TYPE::ImportFrom);
if (stmt->type == BST_TYPE::Assign) {
auto asgn = bst_cast<BST_Assign>(stmt);
if (asgn->target->type == BST_TYPE::Name) {
auto asname = bst_cast<BST_Name>(asgn->target);
assert(asname->lookup_type != ScopeInfo::VarScopeType::UNKNOWN);
InternedString name = asname->id;
int vreg = bst_cast<BST_Name>(asgn->target)->vreg;
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(asname->lookup_type != ScopeInfo::VarScopeType::GLOBAL);
// TODO: inefficient
sym_table = new SymbolTable(*sym_table);
ASSERT((*sym_table)[vreg] != NULL, "%d %s\n", block->idx, name.c_str());
(*sym_table)[vreg] = NULL;
created_new_sym_table = true;
}
}
}
generator->copySymbolsFrom(sym_table); generator->copySymbolsFrom(sym_table);
for (auto&& p : *definedness_tables[pred]) { for (auto&& p : *definedness_tables[pred]) {
...@@ -1034,7 +1027,7 @@ std::pair<CompiledFunction*, llvm::Function*> doCompile(BoxedCode* code, SourceI ...@@ -1034,7 +1027,7 @@ std::pair<CompiledFunction*, llvm::Function*> doCompile(BoxedCode* code, SourceI
assert((entry_descriptor != NULL) + (spec != NULL) == 1); assert((entry_descriptor != NULL) + (spec != NULL) == 1);
if (VERBOSITY("irgen") >= 2) if (VERBOSITY("irgen") >= 2)
source->cfg->print(); source->cfg->print(code->constant_vregs);
assert(g.cur_module == NULL); assert(g.cur_module == NULL);
...@@ -1108,9 +1101,10 @@ std::pair<CompiledFunction*, llvm::Function*> doCompile(BoxedCode* code, SourceI ...@@ -1108,9 +1101,10 @@ std::pair<CompiledFunction*, llvm::Function*> doCompile(BoxedCode* code, SourceI
speculation_level = TypeAnalysis::SOME; speculation_level = TypeAnalysis::SOME;
TypeAnalysis* types; TypeAnalysis* types;
if (entry_descriptor) if (entry_descriptor)
types = doTypeAnalysis(entry_descriptor, effort, speculation_level); types = doTypeAnalysis(entry_descriptor, effort, speculation_level, code->constant_vregs);
else else
types = doTypeAnalysis(source->cfg, *param_names, spec->arg_types, effort, speculation_level); types = doTypeAnalysis(source->cfg, *param_names, spec->arg_types, effort, speculation_level,
code->constant_vregs);
_t2.split(); _t2.split();
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
namespace pyston { namespace pyston {
class BST_expr;
class BST_stmt; class BST_stmt;
class CFGBlock; class CFGBlock;
class GCBuilder; class GCBuilder;
...@@ -119,7 +118,7 @@ public: ...@@ -119,7 +118,7 @@ public:
// virtual void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val, // virtual void checkAndPropagateCapiException(const UnwindInfo& unw_info, llvm::Value* returned_val,
// llvm::Value* exc_val, bool double_check = false) = 0; // llvm::Value* exc_val, bool double_check = false) = 0;
virtual llvm::Value* createDeopt(BST_stmt* current_stmt, BST_expr* node, llvm::Value* node_value) = 0; virtual llvm::Value* createDeopt(BST_stmt* current_stmt, llvm::Value* node_value) = 0;
virtual BORROWED(Box*) getIntConstant(int64_t n) = 0; virtual BORROWED(Box*) getIntConstant(int64_t n) = 0;
virtual BORROWED(Box*) getFloatConstant(double d) = 0; virtual BORROWED(Box*) getFloatConstant(double d) = 0;
......
This diff is collapsed.
...@@ -203,8 +203,6 @@ class BST_Call; ...@@ -203,8 +203,6 @@ class BST_Call;
IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL); IREmitter* createIREmitter(IRGenState* irstate, llvm::BasicBlock*& curblock, IRGenerator* irgenerator = NULL);
IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks, IRGenerator* createIRGenerator(IRGenState* irstate, std::unordered_map<CFGBlock*, llvm::BasicBlock*>& entry_blocks,
CFGBlock* myblock, TypeAnalysis* types); CFGBlock* myblock, TypeAnalysis* types);
std::vector<BoxedString*>* getKeywordNameStorage(BST_Call* node);
} }
#endif #endif
...@@ -151,10 +151,6 @@ void initGlobalFuncs(GlobalState& g) { ...@@ -151,10 +151,6 @@ void initGlobalFuncs(GlobalState& g) {
assert(g.llvm_bststmt_type_ptr); assert(g.llvm_bststmt_type_ptr);
g.llvm_bststmt_type_ptr = g.llvm_bststmt_type_ptr->getPointerTo(); g.llvm_bststmt_type_ptr = g.llvm_bststmt_type_ptr->getPointerTo();
g.llvm_bstexpr_type_ptr = g.stdlib_module->getTypeByName("class.pyston::BST_expr");
assert(g.llvm_bstexpr_type_ptr);
g.llvm_bstexpr_type_ptr = g.llvm_bstexpr_type_ptr->getPointerTo();
// The LLVM vector type for the arguments that we pass to runtimeCall and related functions. // The LLVM vector type for the arguments that we pass to runtimeCall and related functions.
// It will be a pointer to a type named something like class.std::vector or // It will be a pointer to a type named something like class.std::vector or
// class.std::vector.##. We can figure out exactly what it is by looking at the last // class.std::vector.##. We can figure out exactly what it is by looking at the last
......
...@@ -42,7 +42,7 @@ Box* recordType(TypeRecorder* self, Box* obj) { ...@@ -42,7 +42,7 @@ Box* recordType(TypeRecorder* self, Box* obj) {
return obj; return obj;
} }
BoxedClass* predictClassFor(BST* node) { BoxedClass* predictClassFor(BST_stmt* node) {
ICInfo* ic = ICInfo::getICInfoForNode(node); ICInfo* ic = ICInfo::getICInfoForNode(node);
if (!ic || !ic->getTypeRecorder()) if (!ic || !ic->getTypeRecorder())
return NULL; return NULL;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
namespace pyston { namespace pyston {
class BST; class BST_stmt;
class Box; class Box;
class BoxedClass; class BoxedClass;
...@@ -44,7 +44,7 @@ public: ...@@ -44,7 +44,7 @@ public:
friend Box* recordType(TypeRecorder*, Box*); friend Box* recordType(TypeRecorder*, Box*);
}; };
BoxedClass* predictClassFor(BST* node); BoxedClass* predictClassFor(BST_stmt* node);
} }
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -88,8 +88,7 @@ public: ...@@ -88,8 +88,7 @@ public:
void unconnectFrom(CFGBlock* successor); void unconnectFrom(CFGBlock* successor);
void push_back(BST_stmt* node) { body.push_back(node); } void push_back(BST_stmt* node) { body.push_back(node); }
void print(llvm::raw_ostream& stream = llvm::outs()); void print(const ConstantVRegInfo& constant_vregs, llvm::raw_ostream& stream = llvm::outs());
void _print() { print(); }
}; };
// the vregs are split into three parts. // the vregs are split into three parts.
...@@ -110,8 +109,8 @@ class VRegInfo { ...@@ -110,8 +109,8 @@ class VRegInfo {
private: private:
#ifndef NDEBUG #ifndef NDEBUG
// this maps use too much memory, we only use them in the debug build for asserts // this maps use too much memory, we only use them in the debug build for asserts
llvm::DenseMap<InternedString, DefaultedInt<-1>> sym_vreg_map_user_visible; llvm::DenseMap<InternedString, DefaultedInt<VREG_UNDEFINED>> sym_vreg_map_user_visible;
llvm::DenseMap<InternedString, DefaultedInt<-1>> sym_vreg_map; llvm::DenseMap<InternedString, DefaultedInt<VREG_UNDEFINED>> sym_vreg_map;
#endif #endif
// Reverse map, from vreg->symbol name. // Reverse map, from vreg->symbol name.
...@@ -126,8 +125,8 @@ public: ...@@ -126,8 +125,8 @@ public:
#ifndef NDEBUG #ifndef NDEBUG
// map of all assigned names. if the name is block local the vreg number is not unique because this vregs get reused // map of all assigned names. if the name is block local the vreg number is not unique because this vregs get reused
// between blocks. // between blocks.
const llvm::DenseMap<InternedString, DefaultedInt<-1>>& getSymVRegMap() const { return sym_vreg_map; } const llvm::DenseMap<InternedString, DefaultedInt<VREG_UNDEFINED>>& getSymVRegMap() const { return sym_vreg_map; }
const llvm::DenseMap<InternedString, DefaultedInt<-1>>& getUserVisibleSymVRegMap() const { const llvm::DenseMap<InternedString, DefaultedInt<VREG_UNDEFINED>>& getUserVisibleSymVRegMap() const {
return sym_vreg_map_user_visible; return sym_vreg_map_user_visible;
} }
...@@ -169,7 +168,7 @@ public: ...@@ -169,7 +168,7 @@ public:
int getNumOfCrossBlockVRegs() const { return num_vregs_cross_block; } int getNumOfCrossBlockVRegs() const { return num_vregs_cross_block; }
bool hasVRegsAssigned() const { return num_vregs != -1; } bool hasVRegsAssigned() const { return num_vregs != -1; }
void assignVRegs(CFG* cfg, const ParamNames& param_names); void assignVRegs(CFG* cfg, const ParamNames& param_names, llvm::DenseMap<int*, InternedString>& id_vreg);
}; };
// Control Flow Graph // Control Flow Graph
...@@ -211,7 +210,7 @@ public: ...@@ -211,7 +210,7 @@ public:
blocks.push_back(block); blocks.push_back(block);
} }
void print(llvm::raw_ostream& stream = llvm::outs()); void print(const ConstantVRegInfo& constant_vregs, llvm::raw_ostream& stream = llvm::outs());
}; };
class VRegSet { class VRegSet {
...@@ -332,7 +331,7 @@ public: ...@@ -332,7 +331,7 @@ public:
BoxedCode* computeAllCFGs(AST* ast, bool globals_from_module, FutureFlags future_flags, BoxedString* fn, BoxedCode* computeAllCFGs(AST* ast, bool globals_from_module, FutureFlags future_flags, BoxedString* fn,
BoxedModule* bm); BoxedModule* bm);
void printCFG(CFG* cfg); void printCFG(CFG* cfg, const ConstantVRegInfo& constant_vregs);
} }
#endif #endif
...@@ -154,11 +154,11 @@ struct ICSlotInfo; ...@@ -154,11 +154,11 @@ struct ICSlotInfo;
class CFG; class CFG;
class AST; class AST;
class BST;
class BST_FunctionDef; class BST_FunctionDef;
class AST_arguments; class AST_arguments;
class BST_expr;
class BST_Name; class BST_Name;
class BST_LoadName;
class BST_StoreName;
class BST_stmt; class BST_stmt;
class PhiAnalysis; class PhiAnalysis;
...@@ -478,8 +478,7 @@ public: ...@@ -478,8 +478,7 @@ public:
return closure_size; return closure_size;
} }
const std::vector<std::pair<InternedString, DerefInfo>>& getAllDerefVarsAndInfo() const { return deref_info; } const std::vector<std::pair<InternedString, DerefInfo>>& getAllDerefVarsAndInfo() const { return deref_info; }
DerefInfo getDerefInfo(BST_Name*) const; DerefInfo getDerefInfo(BST_LoadName*) const;
size_t getClosureOffset(BST_Name*) const;
ScopingResults(ScopeInfo* scope_info, bool globals_from_module); ScopingResults(ScopeInfo* scope_info, bool globals_from_module);
}; };
......
...@@ -113,9 +113,10 @@ void BoxedCode::dealloc(Box* b) noexcept { ...@@ -113,9 +113,10 @@ void BoxedCode::dealloc(Box* b) noexcept {
} }
BoxedCode::BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, int firstlineno, BoxedCode::BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, int firstlineno,
std::unique_ptr<SourceInfo> source, ParamNames param_names, BoxedString* filename, std::unique_ptr<SourceInfo> source, ConstantVRegInfo constant_vregs, ParamNames param_names,
BoxedString* name, Box* doc) BoxedString* filename, BoxedString* name, Box* doc)
: source(std::move(source)), : source(std::move(source)),
constant_vregs(std::move(constant_vregs)),
filename(incref(filename)), filename(incref(filename)),
name(incref(name)), name(incref(name)),
firstlineno(firstlineno), firstlineno(firstlineno),
......
...@@ -133,8 +133,10 @@ extern "C" PyObject* PyImport_ExecCodeModuleEx(const char* name, PyObject* co, c ...@@ -133,8 +133,10 @@ extern "C" PyObject* PyImport_ExecCodeModuleEx(const char* name, PyObject* co, c
} }
} }
extern "C" Box* import(int level, Box* from_imports, llvm::StringRef module_name) { extern "C" Box* import(int level, Box* from_imports, Box* _module_name) {
Box* rtn = PyImport_ImportModuleLevel(module_name.str().c_str(), getGlobalsDict(), NULL, from_imports, level); assert(_module_name->cls == str_cls);
BoxedString* module_name = (BoxedString*)_module_name;
Box* rtn = PyImport_ImportModuleLevel(module_name->c_str(), getGlobalsDict(), NULL, from_imports, level);
if (!rtn) if (!rtn)
throwCAPIException(); throwCAPIException();
return rtn; return rtn;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
namespace pyston { namespace pyston {
extern "C" PyObject* PyImport_GetImporter(PyObject* path) noexcept; extern "C" PyObject* PyImport_GetImporter(PyObject* path) noexcept;
extern "C" Box* import(int level, Box* from_imports, llvm::StringRef module_name); extern "C" Box* import(int level, Box* from_imports, Box* module_name);
BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path); BoxedModule* importCExtension(BoxedString* full_name, const std::string& last_name, const std::string& path);
#ifdef Py_REF_DEBUG #ifdef Py_REF_DEBUG
......
...@@ -136,7 +136,7 @@ extern "C" void xdecrefAndRethrow(void* cxa_ptr, int num, ...) { ...@@ -136,7 +136,7 @@ extern "C" void xdecrefAndRethrow(void* cxa_ptr, int num, ...) {
rawReraise(e.type, e.value, e.traceback); rawReraise(e.type, e.value, e.traceback);
} }
extern "C" Box* deopt(BST_expr* expr, Box* value) { extern "C" Box* deopt(Box* value) {
ASSERT(ENABLE_FRAME_INTROSPECTION, "deopt will not work with frame introspection turned off"); ASSERT(ENABLE_FRAME_INTROSPECTION, "deopt will not work with frame introspection turned off");
STAT_TIMER(t0, "us_timer_deopt", 10); STAT_TIMER(t0, "us_timer_deopt", 10);
...@@ -156,7 +156,7 @@ extern "C" Box* deopt(BST_expr* expr, Box* value) { ...@@ -156,7 +156,7 @@ extern "C" Box* deopt(BST_expr* expr, Box* value) {
deopt_state.frame_state.frame_info->exc.value = NULL; deopt_state.frame_state.frame_info->exc.value = NULL;
} }
return astInterpretDeopt(deopt_state.cf->code_obj, expr, deopt_state.current_stmt, value, deopt_state.frame_state); return astInterpretDeopt(deopt_state.cf->code_obj, deopt_state.current_stmt, value, deopt_state.frame_state);
} }
extern "C" void printHelper(Box* w, Box* v, bool nl) { extern "C" void printHelper(Box* w, Box* v, bool nl) {
...@@ -7442,9 +7442,12 @@ extern "C" void setGlobal(Box* globals, BoxedString* name, STOLEN(Box*) value) { ...@@ -7442,9 +7442,12 @@ extern "C" void setGlobal(Box* globals, BoxedString* name, STOLEN(Box*) value) {
} }
} }
extern "C" Box* importFrom(Box* _m, BoxedString* name) { extern "C" Box* importFrom(Box* _m, Box* _name) {
STAT_TIMER(t0, "us_timer_importFrom", 10); STAT_TIMER(t0, "us_timer_importFrom", 10);
assert(_name->cls == str_cls);
BoxedString* name = (BoxedString*)_name;
Box* r = getattrInternal<CXX>(_m, name); Box* r = getattrInternal<CXX>(_m, name);
if (r) if (r)
return r; return r;
......
...@@ -45,7 +45,7 @@ void _printStacktrace(); ...@@ -45,7 +45,7 @@ void _printStacktrace();
// to see if they are getting called from jitted code. If we inline them into a function that // to see if they are getting called from jitted code. If we inline them into a function that
// got called from jitted code, they might incorrectly think that they are a rewritable entrypoint. // got called from jitted code, they might incorrectly think that they are a rewritable entrypoint.
extern "C" Box* deopt(BST_expr* expr, Box* value) __attribute__((noinline)); extern "C" Box* deopt(Box* value) __attribute__((noinline));
// helper function for raising from the runtime: // helper function for raising from the runtime:
void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__)) void raiseExcHelper(BoxedClass*, const char* fmt, ...) __attribute__((__noreturn__))
...@@ -94,7 +94,7 @@ extern "C" void assignSlice(PyObject* u, PyObject* v, PyObject* w, PyObject* x); ...@@ -94,7 +94,7 @@ extern "C" void assignSlice(PyObject* u, PyObject* v, PyObject* w, PyObject* x);
extern "C" Box* getclsattr(Box* obj, BoxedString* attr) __attribute__((noinline)); extern "C" Box* getclsattr(Box* obj, BoxedString* attr) __attribute__((noinline));
extern "C" Box* getclsattrMaybeNonstring(Box* obj, Box* attr) __attribute__((noinline)); extern "C" Box* getclsattrMaybeNonstring(Box* obj, Box* attr) __attribute__((noinline));
extern "C" Box* unaryop(Box* operand, int op_type) __attribute__((noinline)); extern "C" Box* unaryop(Box* operand, int op_type) __attribute__((noinline));
extern "C" Box* importFrom(Box* obj, BoxedString* attr) __attribute__((noinline)); extern "C" Box* importFrom(Box* obj, Box* attr) __attribute__((noinline));
extern "C" Box* importStar(Box* from_module, Box* to_globals) __attribute__((noinline)); extern "C" Box* importStar(Box* from_module, Box* to_globals) __attribute__((noinline));
extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size, Box** out_keep_alive); extern "C" Box** unpackIntoArray(Box* obj, int64_t expected_size, Box** out_keep_alive);
extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg); extern "C" void assertNameDefined(bool b, const char* name, BoxedClass* exc_cls, bool local_var_msg);
......
...@@ -1068,6 +1068,23 @@ public: ...@@ -1068,6 +1068,23 @@ public:
}; };
static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), ""); static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), "");
class ConstantVRegInfo {
private:
std::vector<Box*> constants;
public:
ConstantVRegInfo(){};
Box* getConstant(int vreg) const { return constants[-(vreg + 1)]; }
// returns the vreg num for the constant (which is a negative number)
int addConstant(Box* o) {
constants.push_back(o);
return -constants.size();
}
};
// BoxedCode corresponds to metadata about a function definition. If the same 'def foo():' block gets // BoxedCode corresponds to metadata about a function definition. If the same 'def foo():' block gets
// executed multiple times, there will only be a single BoxedCode, even though multiple function objects // executed multiple times, there will only be a single BoxedCode, even though multiple function objects
// will get created from it. // will get created from it.
...@@ -1076,7 +1093,8 @@ static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), ""); ...@@ -1076,7 +1093,8 @@ static_assert(sizeof(BoxedDict) == sizeof(PyDictObject), "");
// BoxedCode objects also keep track of any machine code that we have available for this function. // BoxedCode objects also keep track of any machine code that we have available for this function.
class BoxedCode : public Box { class BoxedCode : public Box {
public: public:
std::unique_ptr<SourceInfo> source; // source can be NULL for functions defined in the C/C++ runtime std::unique_ptr<SourceInfo> source; // source can be NULL for functions defined in the C/C++ runtime
const ConstantVRegInfo BORROWED(constant_vregs); // keeps track of all constants inside the bytecode
BoxedString* filename = nullptr; BoxedString* filename = nullptr;
BoxedString* name = nullptr; BoxedString* name = nullptr;
...@@ -1103,6 +1121,7 @@ public: ...@@ -1103,6 +1121,7 @@ public:
std::vector<std::unique_ptr<JitCodeBlock>> code_blocks; std::vector<std::unique_ptr<JitCodeBlock>> code_blocks;
ICInvalidator dependent_interp_callsites; ICInvalidator dependent_interp_callsites;
// Functions can provide an "internal" version, which will get called instead // Functions can provide an "internal" version, which will get called instead
// of the normal dispatch through the functionlist. // of the normal dispatch through the functionlist.
// This can be used to implement functions which know how to rewrite themselves, // This can be used to implement functions which know how to rewrite themselves,
...@@ -1113,7 +1132,8 @@ public: ...@@ -1113,7 +1132,8 @@ public:
// Constructor for Python code objects: // Constructor for Python code objects:
BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, int firstlineno, std::unique_ptr<SourceInfo> source, BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, int firstlineno, std::unique_ptr<SourceInfo> source,
ParamNames param_names, BoxedString* filename, BoxedString* name, Box* doc); ConstantVRegInfo constant_vregs, ParamNames param_names, BoxedString* filename, BoxedString* name,
Box* doc);
// Constructor for code objects created by the runtime: // Constructor for code objects created by the runtime:
BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, const char* name, const char* doc = "", BoxedCode(int num_args, bool takes_varargs, bool takes_kwargs, const char* name, const char* doc = "",
......
...@@ -254,7 +254,7 @@ extern "C" void dumpEx(void* p, int levels) { ...@@ -254,7 +254,7 @@ extern "C" void dumpEx(void* p, int levels) {
printf("Defined at %s:%d\n", code->filename->c_str(), code->firstlineno); printf("Defined at %s:%d\n", code->filename->c_str(), code->firstlineno);
if (code->source->cfg && levels > 0) { if (code->source->cfg && levels > 0) {
code->source->cfg->print(); code->source->cfg->print(code->constant_vregs);
} }
} else { } else {
printf("A builtin function\n"); printf("A builtin function\n");
......
...@@ -37,7 +37,8 @@ TEST_F(AnalysisTest, augassign) { ...@@ -37,7 +37,8 @@ TEST_F(AnalysisTest, augassign) {
FutureFlags future_flags = getFutureFlags(module->body, fn.c_str()); FutureFlags future_flags = getFutureFlags(module->body, fn.c_str());
auto scoping = std::make_shared<ScopingAnalysis>(module, true); auto scoping = std::make_shared<ScopingAnalysis>(module, true);
auto module_code = computeAllCFGs(module, true, future_flags, boxString(fn), NULL); BoxedModule* main_module = createModule(autoDecref(boxString("__main__")), "<string>");
auto module_code = computeAllCFGs(module, true, future_flags, boxString(fn), main_module);
assert(module->body[0]->type == AST_TYPE::FunctionDef); assert(module->body[0]->type == AST_TYPE::FunctionDef);
AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]); AST_FunctionDef* func = static_cast<AST_FunctionDef*>(module->body[0]);
...@@ -51,8 +52,14 @@ TEST_F(AnalysisTest, augassign) { ...@@ -51,8 +52,14 @@ TEST_F(AnalysisTest, augassign) {
ParamNames param_names(args, *module->interned_strings.get()); ParamNames param_names(args, *module->interned_strings.get());
// Hack to get at the cfg: // Hack to get at the cfg:
auto node = module_code->source->cfg->blocks[0]->body[0]; CFG* cfg = NULL;
CFG* cfg = bst_cast<BST_MakeFunction>(bst_cast<BST_Assign>(node)->value)->function_def->code->source->cfg; for (BST_stmt* stmt : module_code->source->cfg->blocks[0]->body) {
if (stmt->type != BST_TYPE::MakeFunction)
continue;
cfg = bst_cast<BST_MakeFunction>(stmt)->function_def->code->source->cfg;
break;
}
assert(cfg);
std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg); std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
auto&& vregs = cfg->getVRegInfo(); auto&& vregs = cfg->getVRegInfo();
...@@ -85,11 +92,18 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) { ...@@ -85,11 +92,18 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) {
FutureFlags future_flags = getFutureFlags(module->body, fn.c_str()); FutureFlags future_flags = getFutureFlags(module->body, fn.c_str());
auto module_code = computeAllCFGs(module, true, future_flags, boxString(fn), NULL); BoxedModule* main_module = createModule(autoDecref(boxString("__main__")), "<string>");
auto module_code = computeAllCFGs(module, true, future_flags, boxString(fn), main_module);
// Hack to get at the cfg: // Hack to get at the cfg:
auto node = module_code->source->cfg->blocks[0]->body[0]; BoxedCode* code = NULL;
auto code = bst_cast<BST_MakeFunction>(bst_cast<BST_Assign>(node)->value)->function_def->code; for (BST_stmt* stmt : module_code->source->cfg->blocks[0]->body) {
if (stmt->type != BST_TYPE::MakeFunction)
continue;
code = bst_cast<BST_MakeFunction>(stmt)->function_def->code;
break;
}
assert(code);
CFG* cfg = code->source->cfg; CFG* cfg = code->source->cfg;
std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg); std::unique_ptr<LivenessAnalysis> liveness = computeLivenessInfo(cfg);
...@@ -99,7 +113,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) { ...@@ -99,7 +113,7 @@ void doOsrTest(bool is_osr, bool i_maybe_undefined) {
InternedString i_str = module->interned_strings->get("i"); InternedString i_str = module->interned_strings->get("i");
InternedString idi_str = module->interned_strings->get("!is_defined_i"); InternedString idi_str = module->interned_strings->get("!is_defined_i");
InternedString iter_str = module->interned_strings->get("#iter_3"); InternedString iter_str = module->interned_strings->get("#iter_4");
CFGBlock* loop_backedge = cfg->blocks[5]; CFGBlock* loop_backedge = cfg->blocks[5];
ASSERT_EQ(6, loop_backedge->idx); ASSERT_EQ(6, loop_backedge->idx);
......
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