mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Avoid generating redundant interpreter exit code after branches
This commit is contained in:
parent
97cffcf79a
commit
1744c15578
3 changed files with 87 additions and 56 deletions
|
@ -173,6 +173,9 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_
|
||||||
// Get a pointer to the current write position in the code block
|
// Get a pointer to the current write position in the code block
|
||||||
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
|
uint8_t *code_ptr = cb_get_ptr(cb, cb->write_pos);
|
||||||
|
|
||||||
|
// Last operation that was successfully compiled
|
||||||
|
opdesc_t* p_last_op = NULL;
|
||||||
|
|
||||||
// Initialize JIT state object
|
// Initialize JIT state object
|
||||||
jitstate_t jit = { 0 };
|
jitstate_t jit = { 0 };
|
||||||
jit.iseq = iseq;
|
jit.iseq = iseq;
|
||||||
|
@ -187,42 +190,40 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_
|
||||||
// Get the current opcode
|
// Get the current opcode
|
||||||
int opcode = jit_get_opcode(&jit);
|
int opcode = jit_get_opcode(&jit);
|
||||||
|
|
||||||
//fprintf(stderr, "compiling %s\n", insn_name(opcode));
|
|
||||||
|
|
||||||
// Lookup the codegen function for this instruction
|
// Lookup the codegen function for this instruction
|
||||||
st_data_t st_gen_fn;
|
st_data_t st_op_desc;
|
||||||
if (!rb_st_lookup(gen_fns, opcode, &st_gen_fn)) {
|
if (!rb_st_lookup(gen_fns, opcode, &st_op_desc)) {
|
||||||
//print_int(cb, imm_opnd(num_instrs));
|
|
||||||
//print_str(cb, insn_name(opcode));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fprintf(stderr, "compiling %s\n", insn_name(opcode));
|
||||||
//print_str(cb, insn_name(opcode));
|
//print_str(cb, insn_name(opcode));
|
||||||
|
|
||||||
// Call the code generation function
|
// Call the code generation function
|
||||||
codegen_fn gen_fn = (codegen_fn)st_gen_fn;
|
opdesc_t* p_desc = (opdesc_t*)st_op_desc;
|
||||||
if (!gen_fn(&jit, ctx)) {
|
bool success = p_desc->gen_fn(&jit, ctx);
|
||||||
|
|
||||||
|
// If we can't compile this instruction
|
||||||
|
if (!success) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next instruction
|
// Move to the next instruction
|
||||||
|
p_last_op = p_desc;
|
||||||
insn_idx += insn_len(opcode);
|
insn_idx += insn_len(opcode);
|
||||||
(*num_instrs)++;
|
(*num_instrs)++;
|
||||||
|
|
||||||
// Ensure we only have one send per region. Our code invalidation mechanism can't
|
// If this instruction terminates this block
|
||||||
// invalidate running code and one send could invalidate the other if we had
|
if (p_desc->is_branch) {
|
||||||
// multiple in the same region.
|
|
||||||
if (opcode == BIN(opt_send_without_block)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//print_str(cb, "exiting to interpreter\n");
|
// If the last instruction compiled did not properly terminate the block
|
||||||
|
|
||||||
// FIXME: we only need to generate an exit if an instruction fails to compile
|
|
||||||
//
|
|
||||||
// Generate code to exit to the interpreter
|
// Generate code to exit to the interpreter
|
||||||
ujit_gen_exit(&jit, ctx, cb, &encoded[insn_idx]);
|
if (!p_last_op || !p_last_op->is_branch) {
|
||||||
|
ujit_gen_exit(&jit, ctx, cb, &encoded[insn_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
if (UJIT_DUMP_MODE >= 2) {
|
if (UJIT_DUMP_MODE >= 2) {
|
||||||
// Dump list of compiled instrutions
|
// Dump list of compiled instrutions
|
||||||
|
@ -976,6 +977,21 @@ gen_branchunless(jitstate_t* jit, ctx_t* ctx)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ujit_reg_op(int opcode, codegen_fn gen_fn, bool is_branch)
|
||||||
|
{
|
||||||
|
// Check that the op wasn't previously registered
|
||||||
|
st_data_t st_desc;
|
||||||
|
if (rb_st_lookup(gen_fns, opcode, &st_desc)) {
|
||||||
|
rb_bug("op already registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
opdesc_t* p_desc = (opdesc_t*)malloc(sizeof(opdesc_t));
|
||||||
|
p_desc->gen_fn = gen_fn;
|
||||||
|
p_desc->is_branch = is_branch;
|
||||||
|
|
||||||
|
st_insert(gen_fns, (st_data_t)opcode, (st_data_t)p_desc);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ujit_init_codegen(void)
|
ujit_init_codegen(void)
|
||||||
{
|
{
|
||||||
|
@ -991,21 +1007,21 @@ ujit_init_codegen(void)
|
||||||
gen_fns = rb_st_init_numtable();
|
gen_fns = rb_st_init_numtable();
|
||||||
|
|
||||||
// Map YARV opcodes to the corresponding codegen functions
|
// Map YARV opcodes to the corresponding codegen functions
|
||||||
st_insert(gen_fns, (st_data_t)BIN(dup), (st_data_t)&gen_dup);
|
ujit_reg_op(BIN(dup), gen_dup, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(nop), (st_data_t)&gen_nop);
|
ujit_reg_op(BIN(nop), gen_nop, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(pop), (st_data_t)&gen_pop);
|
ujit_reg_op(BIN(pop), gen_pop, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(putnil), (st_data_t)&gen_putnil);
|
ujit_reg_op(BIN(putnil), gen_putnil, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(putobject), (st_data_t)&gen_putobject);
|
ujit_reg_op(BIN(putobject), gen_putobject, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_0_), (st_data_t)&gen_putobject_int2fix);
|
ujit_reg_op(BIN(putobject_INT2FIX_0_), gen_putobject_int2fix, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_1_), (st_data_t)&gen_putobject_int2fix);
|
ujit_reg_op(BIN(putobject_INT2FIX_1_), gen_putobject_int2fix, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(putself), (st_data_t)&gen_putself);
|
ujit_reg_op(BIN(putself), gen_putself, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(getlocal_WC_0), (st_data_t)&gen_getlocal_wc0);
|
ujit_reg_op(BIN(getlocal_WC_0), gen_getlocal_wc0, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(setlocal_WC_0), (st_data_t)&gen_setlocal_wc0);
|
ujit_reg_op(BIN(setlocal_WC_0), gen_setlocal_wc0, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(getinstancevariable), (st_data_t)&gen_getinstancevariable);
|
ujit_reg_op(BIN(getinstancevariable), gen_getinstancevariable, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(setinstancevariable), (st_data_t)&gen_setinstancevariable);
|
ujit_reg_op(BIN(setinstancevariable), gen_setinstancevariable, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(opt_lt), (st_data_t)&gen_opt_lt);
|
ujit_reg_op(BIN(opt_lt), gen_opt_lt, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(opt_minus), (st_data_t)&gen_opt_minus);
|
ujit_reg_op(BIN(opt_minus), gen_opt_minus, false);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(opt_plus), (st_data_t)&gen_opt_plus);
|
ujit_reg_op(BIN(opt_plus), gen_opt_plus, false);
|
||||||
//st_insert(gen_fns, (st_data_t)BIN(opt_send_without_block), (st_data_t)&gen_opt_send_without_block);
|
//ujit_reg_op(BIN(opt_send_without_block), gen_opt_send_without_block);
|
||||||
st_insert(gen_fns, (st_data_t)BIN(branchunless), (st_data_t)&gen_branchunless);
|
ujit_reg_op(BIN(branchunless), gen_branchunless, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,18 @@ typedef struct JITState
|
||||||
// Code generation function signature
|
// Code generation function signature
|
||||||
typedef bool (*codegen_fn)(jitstate_t* jit, ctx_t* ctx);
|
typedef bool (*codegen_fn)(jitstate_t* jit, ctx_t* ctx);
|
||||||
|
|
||||||
|
// Meta-information associated with a given opcode
|
||||||
|
typedef struct OpDesc
|
||||||
|
{
|
||||||
|
// Code generation function
|
||||||
|
codegen_fn gen_fn;
|
||||||
|
|
||||||
|
// Indicates that this is a branch instruction
|
||||||
|
// which terminates a block
|
||||||
|
bool is_branch;
|
||||||
|
|
||||||
|
} opdesc_t;
|
||||||
|
|
||||||
uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx);
|
uint8_t* ujit_compile_entry(const rb_iseq_t *iseq, uint32_t insn_idx);
|
||||||
|
|
||||||
uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs);
|
uint8_t *ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs);
|
||||||
|
|
47
ujit_core.c
47
ujit_core.c
|
@ -69,28 +69,6 @@ ctx_stack_opnd(ctx_t* ctx, int32_t idx)
|
||||||
return opnd;
|
return opnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockid_cmp(st_data_t arg0, st_data_t arg1)
|
|
||||||
{
|
|
||||||
const blockid_t *block0 = (const blockid_t*)arg0;
|
|
||||||
const blockid_t *block1 = (const blockid_t*)arg1;
|
|
||||||
return block0->iseq == block1->iseq && block0->idx == block1->idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
st_index_t blockid_hash(st_data_t arg)
|
|
||||||
{
|
|
||||||
const blockid_t *blockid = (const blockid_t*)arg;
|
|
||||||
st_index_t hash0 = st_numhash((st_data_t)blockid->iseq);
|
|
||||||
st_index_t hash1 = st_numhash((st_data_t)(uint64_t)blockid->idx);
|
|
||||||
|
|
||||||
// Use XOR to combine the hashes
|
|
||||||
return hash0 ^ hash1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct st_hash_type hashtype_blockid = {
|
|
||||||
blockid_cmp,
|
|
||||||
blockid_hash,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Retrieve a basic block version for an (iseq, idx) tuple
|
// Retrieve a basic block version for an (iseq, idx) tuple
|
||||||
uint8_t* find_block_version(blockid_t block)
|
uint8_t* find_block_version(blockid_t block)
|
||||||
{
|
{
|
||||||
|
@ -113,10 +91,13 @@ uint8_t* branch_stub_hit(uint32_t branch_idx, uint32_t target_idx)
|
||||||
blockid_t target = branch->targets[target_idx];
|
blockid_t target = branch->targets[target_idx];
|
||||||
|
|
||||||
//fprintf(stderr, "\nstub hit, branch idx: %d, target idx: %d\n", branch_idx, target_idx);
|
//fprintf(stderr, "\nstub hit, branch idx: %d, target idx: %d\n", branch_idx, target_idx);
|
||||||
|
//fprintf(stderr, "cb->write_pos=%ld\n", cb->write_pos);
|
||||||
|
//fprintf(stderr, "branch->end_pos=%d\n", branch->end_pos);
|
||||||
|
|
||||||
// If either of the target blocks will be placed next
|
// If either of the target blocks will be placed next
|
||||||
if (cb->write_pos == branch->end_pos)
|
if (cb->write_pos == branch->end_pos)
|
||||||
{
|
{
|
||||||
|
//fprintf(stderr, "target idx %d will be placed next\n", target_idx);
|
||||||
branch->shape = (uint8_t)target_idx;
|
branch->shape = (uint8_t)target_idx;
|
||||||
|
|
||||||
// Rewrite the branch with the new, potentially more compact shape
|
// Rewrite the branch with the new, potentially more compact shape
|
||||||
|
@ -222,6 +203,28 @@ void gen_branch(ctx_t* ctx, blockid_t target0, blockid_t target1, branchgen_fn g
|
||||||
num_branches++;
|
num_branches++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int blockid_cmp(st_data_t arg0, st_data_t arg1)
|
||||||
|
{
|
||||||
|
const blockid_t *block0 = (const blockid_t*)arg0;
|
||||||
|
const blockid_t *block1 = (const blockid_t*)arg1;
|
||||||
|
return block0->iseq == block1->iseq && block0->idx == block1->idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
st_index_t blockid_hash(st_data_t arg)
|
||||||
|
{
|
||||||
|
const blockid_t *blockid = (const blockid_t*)arg;
|
||||||
|
st_index_t hash0 = st_numhash((st_data_t)blockid->iseq);
|
||||||
|
st_index_t hash1 = st_numhash((st_data_t)(uint64_t)blockid->idx);
|
||||||
|
|
||||||
|
// Use XOR to combine the hashes
|
||||||
|
return hash0 ^ hash1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct st_hash_type hashtype_blockid = {
|
||||||
|
blockid_cmp,
|
||||||
|
blockid_hash,
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ujit_init_core(void)
|
ujit_init_core(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue