Commit 5c70bb30 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #870 from undingen/trampoline

Small improvements to reduce the size of rewrites
parents 15098268 4f745cab
......@@ -300,6 +300,17 @@ void Assembler::movslq(Indirect src, Register dest) {
mov_generic(src, dest, MovType::SLQ);
}
void Assembler::clear_reg(Register reg) {
int reg_idx = reg.regnum;
// we don't need to generate a REX_W because 32bit instructions will clear the upper 32bits.
if (reg_idx >= 8) {
emitRex(REX_R | REX_B);
reg_idx -= 8;
}
emitByte(0x31);
emitModRM(0b11, reg_idx, reg_idx);
}
void Assembler::mov_generic(Indirect src, Register dest, MovType type) {
int rex;
switch (type) {
......
......@@ -144,6 +144,8 @@ public:
void movswq(Indirect scr, Register dest);
void movslq(Indirect scr, Register dest);
void clear_reg(Register reg); // = xor reg, reg
void mov_generic(Indirect src, Register dest, MovType type);
void push(Register reg);
......
......@@ -206,6 +206,11 @@ assembler::Register Rewriter::ConstLoader::findConst(uint64_t val, bool& found_v
void Rewriter::ConstLoader::loadConstIntoReg(uint64_t val, assembler::Register dst_reg) {
assert(rewriter->phase_emitting);
if (val == 0) {
rewriter->assembler->clear_reg(dst_reg);
return;
}
if (tryRegRegMove(val, dst_reg))
return;
......@@ -215,22 +220,6 @@ void Rewriter::ConstLoader::loadConstIntoReg(uint64_t val, assembler::Register d
moveImmediate(val, dst_reg);
}
assembler::Register Rewriter::ConstLoader::loadConst(uint64_t val, Location otherThan) {
assert(rewriter->phase_emitting);
bool found_value = false;
assembler::Register /*reg = findConst(val, found_value);
if (found_value)
return reg;*/
reg = rewriter->allocReg(Location::any(), otherThan);
if (tryLea(val, reg))
return reg;
moveImmediate(val, reg);
return reg;
}
void Rewriter::restoreArgs() {
ASSERT(!done_guarding, "this will probably work but why are we calling this at this time");
......@@ -284,6 +273,23 @@ void RewriterVar::addGuard(uint64_t val) {
rewriter->addAction([=]() { rewriter->_addGuard(this, val_var); }, { this, val_var }, ActionType::GUARD);
}
void Rewriter::_slowpathJump(bool condition_eq) {
// If a jump offset is larger then 0x80 the instruction encoding requires 6bytes instead of 2bytes.
// This adds up quickly, thats why we will try to find another jump to the slowpath with the same condition with a
// smaller offset and jump to it / use it as a trampoline.
// The benchmark show that this increases the performance slightly even though it introduces additional jumps.
int& last_jmp_offset = condition_eq ? offset_eq_jmp_slowpath : offset_ne_jmp_slowpath;
auto condition = condition_eq ? assembler::COND_EQUAL : assembler::COND_NOT_EQUAL;
assert(assembler->bytesWritten() + assembler->bytesLeft() == rewrite->getSlotSize());
if (last_jmp_offset != -1 && assembler->bytesLeft() >= 0x80 && assembler->bytesWritten() - last_jmp_offset < 0x80) {
assembler->jmp_cond(assembler::JumpDestination::fromStart(last_jmp_offset), condition);
} else {
last_jmp_offset = assembler->bytesWritten();
assembler->jmp_cond(assembler::JumpDestination::fromStart(rewrite->getSlotSize()), condition);
}
}
void Rewriter::_addGuard(RewriterVar* var, RewriterVar* val_constant) {
assembler->comment("_addGuard");
......@@ -300,7 +306,7 @@ void Rewriter::_addGuard(RewriterVar* var, RewriterVar* val_constant) {
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
assembler->jne(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
_slowpathJump(false /*= not equal jmp */);
var->bumpUse();
val_constant->bumpUse();
......@@ -331,7 +337,7 @@ void Rewriter::_addGuardNotEq(RewriterVar* var, RewriterVar* val_constant) {
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
assembler->je(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
_slowpathJump(true /*= equal jmp */);
var->bumpUse();
val_constant->bumpUse();
......@@ -381,10 +387,7 @@ void Rewriter::_addAttrGuard(RewriterVar* var, int offset, RewriterVar* val_cons
restoreArgs(); // can only do movs, doesn't affect flags, so it's safe
assertArgsInPlace();
if (negate)
assembler->je(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
else
assembler->jne(assembler::JumpDestination::fromStart(rewrite->getSlotSize()));
_slowpathJump(negate);
var->bumpUse();
val_constant->bumpUse();
......@@ -894,6 +897,9 @@ void Rewriter::_setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> ar
assembler::Immediate imm = var->tryGetAsImmediate(&is_immediate);
if (is_immediate) {
if (imm.val == 0)
assembler->clear_reg(r);
else
assembler->mov(imm, r);
addLocationToVar(var, l);
} else {
......@@ -1813,8 +1819,10 @@ Rewriter::Rewriter(std::unique_ptr<ICSlotRewrite> rewrite, int num_args, const L
failed(false),
added_changing_action(false),
marked_inside_ic(false),
done_guarding(false),
last_guard_action(-1),
done_guarding(false) {
offset_eq_jmp_slowpath(-1),
offset_ne_jmp_slowpath(-1) {
initPhaseCollecting();
finished = false;
......
......@@ -379,9 +379,6 @@ protected:
// Loads the constant into the specified register
void loadConstIntoReg(uint64_t val, assembler::Register reg);
// Loads the constant into any register or if already in a register just return it
assembler::Register loadConst(uint64_t val, Location otherThan = Location::any());
llvm::SmallVector<std::pair<uint64_t, RewriterVar*>, 16> consts;
};
......@@ -444,14 +441,16 @@ protected:
bool added_changing_action;
bool marked_inside_ic;
int last_guard_action;
bool done_guarding;
bool isDoneGuarding() {
assertPhaseEmitting();
return done_guarding;
}
int last_guard_action;
int offset_eq_jmp_slowpath;
int offset_ne_jmp_slowpath;
// Move the original IC args back into their original registers:
void restoreArgs();
// Assert that our original args are correctly placed in case we need to
......@@ -482,6 +481,7 @@ protected:
bool finishAssembly(int continue_offset) override;
void _slowpathJump(bool condition_eq);
void _trap();
void _loadConst(RewriterVar* result, int64_t val);
void _setupCall(bool has_side_effects, llvm::ArrayRef<RewriterVar*> args, llvm::ArrayRef<RewriterVar*> args_xmm);
......
......@@ -810,7 +810,7 @@ void JitFragmentWriter::_emitOSRPoint(RewriterVar* result, RewriterVar* node_var
assembler->test(result_reg, result_reg);
{
assembler::ForwardJump je(*assembler, assembler::COND_EQUAL);
assembler->mov(assembler::Immediate(0ul), assembler::RAX); // TODO: use xor
assembler->clear_reg(assembler::RAX);
assembler->add(assembler::Immediate(JitCodeBlock::sp_adjustment), assembler::RSP);
assembler->pop(assembler::R12);
assembler->pop(assembler::R14);
......@@ -904,7 +904,7 @@ void JitFragmentWriter::_emitRecordType(RewriterVar* type_recorder_var, Rewriter
void JitFragmentWriter::_emitReturn(RewriterVar* return_val) {
return_val->getInReg(assembler::RDX, true);
assembler->mov(assembler::Immediate(0ul), assembler::RAX); // TODO: use xor
assembler->clear_reg(assembler::RAX);
assembler->add(assembler::Immediate(JitCodeBlock::sp_adjustment), assembler::RSP);
assembler->pop(assembler::R12);
assembler->pop(assembler::R14);
......
......@@ -117,7 +117,7 @@ class JitFragmentWriter;
// second_JitFragment:
// ...
// ; this shows how a AST_Return looks like
// mov $0,%rax ; rax contains the next block to interpret.
// xor %eax,%eax ; rax contains the next block to interpret.
// in this case 0 which means we are finished
// movabs $0x1270014108,%rdx ; rdx must contain the Box* value to return
// add $0x118,%rsp ; restore stack pointer
......
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