Commit 5c0d56b3 authored by Marius Wachtler's avatar Marius Wachtler

bjit: args in the entry block are non null + pass info on to successor block

when possible
parent f0e39c1b
...@@ -128,7 +128,8 @@ private: ...@@ -128,7 +128,8 @@ private:
Value visit_langPrimitive(AST_LangPrimitive* node); Value visit_langPrimitive(AST_LangPrimitive* node);
// for doc on 'exit_offset' have a look at JitFragmentWriter::num_bytes_exit and num_bytes_overlapping // for doc on 'exit_offset' have a look at JitFragmentWriter::num_bytes_exit and num_bytes_overlapping
void startJITing(CFGBlock* block, int exit_offset = 0); void startJITing(CFGBlock* block, int exit_offset = 0,
llvm::DenseSet<int> known_non_null_vregs = llvm::DenseSet<int>());
void abortJITing(); void abortJITing();
void finishJITing(CFGBlock* continue_block = NULL); void finishJITing(CFGBlock* continue_block = NULL);
Box* execJITedBlock(CFGBlock* b); Box* execJITedBlock(CFGBlock* b);
...@@ -293,7 +294,7 @@ void ASTInterpreter::initArguments(BoxedClosure* _closure, BoxedGenerator* _gene ...@@ -293,7 +294,7 @@ void ASTInterpreter::initArguments(BoxedClosure* _closure, BoxedGenerator* _gene
assert(i == param_names.totalParameters()); assert(i == param_names.totalParameters());
} }
void ASTInterpreter::startJITing(CFGBlock* block, int exit_offset) { void ASTInterpreter::startJITing(CFGBlock* block, int exit_offset, llvm::DenseSet<int> known_non_null_vregs) {
assert(ENABLE_BASELINEJIT); assert(ENABLE_BASELINEJIT);
assert(!jit); assert(!jit);
...@@ -308,7 +309,18 @@ void ASTInterpreter::startJITing(CFGBlock* block, int exit_offset) { ...@@ -308,7 +309,18 @@ void ASTInterpreter::startJITing(CFGBlock* block, int exit_offset) {
exit_offset = 0; exit_offset = 0;
} }
jit = code_block->newFragment(block, exit_offset); // small optimization: we know that the passed arguments in the entry block are non zero
if (block == block->cfg->getStartingBlock() && block->predecessors.empty()) {
auto param_names = getMD()->param_names;
for (auto&& arg : param_names.arg_names) {
known_non_null_vregs.insert(arg->vreg);
}
if (param_names.vararg_name)
known_non_null_vregs.insert(param_names.vararg_name->vreg);
if (param_names.kwarg_name)
known_non_null_vregs.insert(param_names.kwarg_name->vreg);
}
jit = code_block->newFragment(block, exit_offset, std::move(known_non_null_vregs));
} }
void ASTInterpreter::abortJITing() { void ASTInterpreter::abortJITing() {
...@@ -323,10 +335,20 @@ void ASTInterpreter::abortJITing() { ...@@ -323,10 +335,20 @@ void ASTInterpreter::abortJITing() {
void ASTInterpreter::finishJITing(CFGBlock* continue_block) { void ASTInterpreter::finishJITing(CFGBlock* continue_block) {
if (!jit) if (!jit)
return; return;
int exit_offset = jit->finishCompilation();
int exit_offset = 0;
llvm::DenseSet<int> known_non_null;
std::tie(exit_offset, known_non_null) = jit->finishCompilation();
jit.reset(); jit.reset();
if (continue_block && !continue_block->code) if (continue_block && !continue_block->code) {
startJITing(continue_block, exit_offset); // check if we can reuse the known non null vreg set
if (continue_block->predecessors.size() == 1)
assert(current_block == continue_block->predecessors[0]);
else
known_non_null.clear();
startJITing(continue_block, exit_offset, std::move(known_non_null));
}
} }
Box* ASTInterpreter::execJITedBlock(CFGBlock* b) { Box* ASTInterpreter::execJITedBlock(CFGBlock* b) {
......
...@@ -123,7 +123,8 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name) ...@@ -123,7 +123,8 @@ JitCodeBlock::JitCodeBlock(llvm::StringRef name)
g.func_addr_registry.registerFunction(unique_name, code, code_size, NULL); g.func_addr_registry.registerFunction(unique_name, code, code_size, NULL);
} }
std::unique_ptr<JitFragmentWriter> JitCodeBlock::newFragment(CFGBlock* block, int patch_jump_offset) { std::unique_ptr<JitFragmentWriter> JitCodeBlock::newFragment(CFGBlock* block, int patch_jump_offset,
llvm::DenseSet<int> known_non_null_vregs) {
if (is_currently_writing || blocks_aborted.count(block)) if (is_currently_writing || blocks_aborted.count(block))
return std::unique_ptr<JitFragmentWriter>(); return std::unique_ptr<JitFragmentWriter>();
...@@ -142,8 +143,9 @@ std::unique_ptr<JitFragmentWriter> JitCodeBlock::newFragment(CFGBlock* block, in ...@@ -142,8 +143,9 @@ std::unique_ptr<JitFragmentWriter> JitCodeBlock::newFragment(CFGBlock* block, in
std::vector<Location>(), bjit_allocatable_regs)); std::vector<Location>(), bjit_allocatable_regs));
std::unique_ptr<ICSlotRewrite> rewrite = ic_info->startRewrite(""); std::unique_ptr<ICSlotRewrite> rewrite = ic_info->startRewrite("");
return std::unique_ptr<JitFragmentWriter>(new JitFragmentWriter( return std::unique_ptr<JitFragmentWriter>(
block, std::move(ic_info), std::move(rewrite), fragment_offset, patch_jump_offset, a.getStartAddr(), *this)); new JitFragmentWriter(block, std::move(ic_info), std::move(rewrite), fragment_offset, patch_jump_offset,
a.getStartAddr(), *this, std::move(known_non_null_vregs)));
} }
void JitCodeBlock::fragmentAbort(bool not_enough_space) { void JitCodeBlock::fragmentAbort(bool not_enough_space) {
...@@ -164,7 +166,8 @@ void JitCodeBlock::fragmentFinished(int bytes_written, int num_bytes_overlapping ...@@ -164,7 +166,8 @@ void JitCodeBlock::fragmentFinished(int bytes_written, int num_bytes_overlapping
JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic_info, JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic_info,
std::unique_ptr<ICSlotRewrite> rewrite, int code_offset, int num_bytes_overlapping, std::unique_ptr<ICSlotRewrite> rewrite, int code_offset, int num_bytes_overlapping,
void* entry_code, JitCodeBlock& code_block) void* entry_code, JitCodeBlock& code_block,
llvm::DenseSet<int> known_non_null_vregs)
: Rewriter(std::move(rewrite), 0, {}, /* needs_invalidation_support = */ false), : Rewriter(std::move(rewrite), 0, {}, /* needs_invalidation_support = */ false),
block(block), block(block),
code_offset(code_offset), code_offset(code_offset),
...@@ -173,6 +176,7 @@ JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic ...@@ -173,6 +176,7 @@ JitFragmentWriter::JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic
entry_code(entry_code), entry_code(entry_code),
code_block(code_block), code_block(code_block),
interp(0), interp(0),
known_non_null_vregs(std::move(known_non_null_vregs)),
ic_info(std::move(ic_info)) { ic_info(std::move(ic_info)) {
added_changing_action = true; added_changing_action = true;
...@@ -766,14 +770,14 @@ void JitFragmentWriter::abortCompilation() { ...@@ -766,14 +770,14 @@ void JitFragmentWriter::abortCompilation() {
abort(); abort();
} }
int JitFragmentWriter::finishCompilation() { std::pair<int, llvm::DenseSet<int>> JitFragmentWriter::finishCompilation() {
RELEASE_ASSERT(!assembler->hasFailed(), ""); RELEASE_ASSERT(!assembler->hasFailed(), "");
commit(); commit();
if (failed) { if (failed) {
blocks_aborted.insert(block); blocks_aborted.insert(block);
code_block.fragmentAbort(false); code_block.fragmentAbort(false);
return 0; return std::make_pair(0, llvm::DenseSet<int>());
} }
if (assembler->hasFailed()) { if (assembler->hasFailed()) {
...@@ -792,7 +796,7 @@ int JitFragmentWriter::finishCompilation() { ...@@ -792,7 +796,7 @@ int JitFragmentWriter::finishCompilation() {
// block for the next attempt. // block for the next attempt.
code_block.fragmentAbort(true /* not_enough_space */); code_block.fragmentAbort(true /* not_enough_space */);
} }
return 0; return std::make_pair(0, llvm::DenseSet<int>());
} }
block->code = (void*)((uint64_t)entry_code + code_offset); block->code = (void*)((uint64_t)entry_code + code_offset);
...@@ -865,7 +869,7 @@ int JitFragmentWriter::finishCompilation() { ...@@ -865,7 +869,7 @@ int JitFragmentWriter::finishCompilation() {
registerGCTrackedICInfo(ic_info.release()); registerGCTrackedICInfo(ic_info.release());
#endif #endif
return exit_info.num_bytes; return std::make_pair(exit_info.num_bytes, std::move(known_non_null_vregs));
} }
bool JitFragmentWriter::finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) { bool JitFragmentWriter::finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) {
......
...@@ -181,7 +181,8 @@ private: ...@@ -181,7 +181,8 @@ private:
public: public:
JitCodeBlock(llvm::StringRef name); JitCodeBlock(llvm::StringRef name);
std::unique_ptr<JitFragmentWriter> newFragment(CFGBlock* block, int patch_jump_offset = 0); std::unique_ptr<JitFragmentWriter> newFragment(CFGBlock* block, int patch_jump_offset,
llvm::DenseSet<int> known_non_null_vregs);
bool shouldCreateNewBlock() const { return asm_failed || a.bytesLeft() < 128; } bool shouldCreateNewBlock() const { return asm_failed || a.bytesLeft() < 128; }
void fragmentAbort(bool not_enough_space); void fragmentAbort(bool not_enough_space);
void fragmentFinished(int bytes_witten, int num_bytes_overlapping, void* next_fragment_start, ICInfo& ic_info); void fragmentFinished(int bytes_witten, int num_bytes_overlapping, void* next_fragment_start, ICInfo& ic_info);
...@@ -216,7 +217,6 @@ private: ...@@ -216,7 +217,6 @@ private:
RewriterVar* vregs_array; RewriterVar* vregs_array;
llvm::DenseMap<InternedString, RewriterVar*> local_syms; llvm::DenseMap<InternedString, 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
// TODO: in the future we could reuse this information between different basic blocks
llvm::DenseSet<int> known_non_null_vregs; llvm::DenseSet<int> known_non_null_vregs;
std::unique_ptr<ICInfo> ic_info; std::unique_ptr<ICInfo> ic_info;
llvm::SmallPtrSet<RewriterVar*, 4> var_is_a_python_bool; llvm::SmallPtrSet<RewriterVar*, 4> var_is_a_python_bool;
...@@ -241,7 +241,8 @@ private: ...@@ -241,7 +241,8 @@ private:
public: public:
JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic_info, std::unique_ptr<ICSlotRewrite> rewrite, JitFragmentWriter(CFGBlock* block, std::unique_ptr<ICInfo> ic_info, std::unique_ptr<ICSlotRewrite> rewrite,
int code_offset, int num_bytes_overlapping, void* entry_code, JitCodeBlock& code_block); int code_offset, int num_bytes_overlapping, void* entry_code, JitCodeBlock& code_block,
llvm::DenseSet<int> known_non_null_vregs);
RewriterVar* getInterp(); RewriterVar* getInterp();
RewriterVar* imm(uint64_t val); RewriterVar* imm(uint64_t val);
...@@ -311,7 +312,8 @@ public: ...@@ -311,7 +312,8 @@ public:
void emitUncacheExcInfo(); void emitUncacheExcInfo();
void abortCompilation(); void abortCompilation();
int finishCompilation(); // returns pair of the number of bytes for the overwriteable jump and known non null vregs at end of current block
std::pair<int, llvm::DenseSet<int>> finishCompilation();
bool finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) override; bool finishAssembly(int continue_offset, bool& should_fill_with_nops, bool& variable_size_slots) override;
......
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