ruby-changes:68677
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:18 +0900 (JST)
Subject: [ruby-changes:68677] 16ddb422eb (master): Complete refactoring to codegen functions
https://git.ruby-lang.org/ruby.git/commit/?id=16ddb422eb From 16ddb422eb83cc8223a8e93297aef4d6ab273238 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Wed, 16 Sep 2020 10:33:34 -0400 Subject: Complete refactoring to codegen functions --- ujit_compile.c | 176 ++++++++++++++++++++++++++------------------------------- 1 file changed, 81 insertions(+), 95 deletions(-) diff --git a/ujit_compile.c b/ujit_compile.c index 62a98481ba..2a99a85e45 100644 --- a/ujit_compile.c +++ b/ujit_compile.c @@ -14,6 +14,9 @@ https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L14 // Code generation context typedef struct ctx_struct { + // Current PC + VALUE* pc; + // TODO: virtual stack pointer handling } ctx_t; @@ -65,11 +68,26 @@ addr2insn_bookkeeping(void *code_ptr, int insn) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L68 } } -// Generate a chunk of machine code for one individual bytecode instruction -// Eventually, this will handle multiple instructions in a sequence -// -// MicroJIT code gets a pointer to the cfp as the first argument in RSI -// See rb_ujit_empty_func(rb_control_frame_t *cfp) in iseq.c +// Get the current instruction opcode from the context object +int ctx_get_opcode(ctx_t* ctx) +{ + return (int)(*ctx->pc); +} + +// Get an instruction argument from the context object +VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx) +{ + assert (arg_idx + 1 < insn_len(ctx_get_opcode(ctx))); + return *(ctx->pc + arg_idx + 1); +} + +/* +Generate a chunk of machine code for one individual bytecode instruction +Eventually, this will handle multiple instructions in a sequence + +MicroJIT code gets a pointer to the cfp as the first argument in RSI +See rb_ujit_empty_func(rb_control_frame_t *cfp) in iseq.c +*/ uint8_t * ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) { @@ -84,9 +102,12 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L102 rb_bug("out of executable memory"); } + // Get a pointer to the current write position in the code block + uint8_t *code_ptr = &cb->mem_block[cb->write_pos]; + //printf("write pos: %ld\n", cb->write_pos); + int insn = (int)iseq->body->iseq_encoded[insn_idx]; int len = insn_len(insn); - //const char* name = insn_name(insn); //printf("%s\n", name); @@ -99,22 +120,20 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L120 codegen_fn gen_fn = (codegen_fn)st_gen_fn; - // Compute the address of the next instruction - void *next_pc = &iseq->body->iseq_encoded[insn_idx + len]; - - // Get a pointer to the current write position in the code block - uint8_t *code_ptr = &cb->mem_block[cb->write_pos]; - //printf("write pos: %ld\n", cb->write_pos); - // Write the pre call bytes ujit_instr_entry(cb); - // TODO: create codegen context + // Create codegen context + ctx_t ctx; + + // Set the current PC + ctx.pc = &iseq->body->iseq_encoded[insn_idx]; // Call the code generation function - gen_fn(cb, NULL); + gen_fn(cb, &ctx); // Directly return the next PC, which is a constant + void *next_pc = &iseq->body->iseq_encoded[insn_idx + len]; mov(cb, RAX, const_ptr_opnd(next_pc)); // Write the post call bytes @@ -123,102 +142,66 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L142 addr2insn_bookkeeping(code_ptr, insn); return code_ptr; +} +void gen_nop(codeblock_t* cb, ctx_t* ctx) +{ +} +void gen_pop(codeblock_t* cb, ctx_t* ctx) +{ + // Decrement SP + sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8)); +} +void gen_putobject_int2fix(codeblock_t* cb, ctx_t* ctx) +{ + // Load current SP into RAX + mov(cb, RAX, mem_opnd(64, RDI, 8)); + // Write constant at SP + int opcode = ctx_get_opcode(ctx); + int cst_val = (opcode == BIN(putobject_INT2FIX_0_))? 0:1; + mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst_val))); + // Load incremented SP into RCX + lea(cb, RCX, mem_opnd(64, RAX, 8)); + // Write back incremented SP + mov(cb, mem_opnd(64, RDI, 8), RCX); +} - /* - if (insn == BIN(putobject_INT2FIX_0_) || insn == BIN(putobject_INT2FIX_1_)) - { - // Load current SP into RAX - mov(cb, RAX, mem_opnd(64, RDI, 8)); - - // Write constant at SP - int cst_val = (insn == BIN(putobject_INT2FIX_0_))? 0:1; - mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst_val))); - - // Load incremented SP into RCX - lea(cb, RCX, mem_opnd(64, RAX, 8)); - - // Write back incremented SP - mov(cb, mem_opnd(64, RDI, 8), RCX); - - // Directly return the next PC, which is a constant - mov(cb, RAX, const_ptr_opnd(next_pc)); - - // Write the post call bytes - ujit_instr_exit(cb); - - addr2insn_bookkeeping(code_ptr, insn); - - return code_ptr; - } - */ - - // TODO: implement putself - /* - if (insn == BIN(putself)) - { - } - */ - - // TODO: implement putobject - /* - if (insn == BIN(putobject)) - { - } - */ - - /* - if (insn == BIN(getlocal_WC_0)) - { - //printf("compiling getlocal_WC_0\n"); - - // Load current SP from CFP - mov(cb, RAX, mem_opnd(64, RDI, 8)); - - // Load block pointer from CFP - mov(cb, RDX, mem_opnd(64, RDI, 32)); - - // TODO: we may want a macro or helper function to get insn operands - // Compute the offset from BP to the local - int32_t opnd0 = (int)iseq->body->iseq_encoded[insn_idx+1]; - const int32_t offs = -8 * opnd0; +// TODO: putnil +// could we reuse code from putobject_int2fix here? - // Load the local from the block - mov(cb, RCX, mem_opnd(64, RDX, offs)); +// TODO: implement putself - // Write the local at SP - mov(cb, mem_opnd(64, RAX, 0), RCX); +// TODO: implement putobject - // Compute address of incremented SP - lea(cb, RCX, mem_opnd(64, RAX, 8)); +void gen_getlocal_wc0(codeblock_t* cb, ctx_t* ctx) +{ + // Load current SP from CFP + mov(cb, RAX, mem_opnd(64, RDI, 8)); - // Write back incremented SP - mov(cb, mem_opnd(64, RDI, 8), RCX); + // Load block pointer from CFP + mov(cb, RDX, mem_opnd(64, RDI, 32)); - // Directly return the next PC, which is a constant - mov(cb, RAX, const_ptr_opnd(next_pc)); + // TODO: we may want a macro or helper function to get insn operands + // Compute the offset from BP to the local + int32_t local_idx = (int32_t)ctx_get_arg(ctx, 0); + const int32_t offs = -8 * local_idx; - // Write the post call bytes - ujit_instr_exit(cb); + // Load the local from the block + mov(cb, RCX, mem_opnd(64, RDX, offs)); - addr2insn_bookkeeping(code_ptr, insn); - } - */ -} + // Write the local at SP + mov(cb, mem_opnd(64, RAX, 0), RCX); -void gen_nop(codeblock_t* cb, ctx_t* ctx) -{ -} + // Compute address of incremented SP + lea(cb, RCX, mem_opnd(64, RAX, 8)); -void gen_pop(codeblock_t* cb, ctx_t* ctx) -{ - // Decrement SP - sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8)); + // Write back incremented SP + mov(cb, mem_opnd(64, RDI, 8), RCX); } static void ujit_init() @@ -233,4 +216,7 @@ static void ujit_init() https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L216 // Map YARV opcodes to the corresponding codegen functions st_insert(gen_fns, (st_data_t)BIN(nop), (st_data_t)&gen_nop); st_insert(gen_fns, (st_data_t)BIN(pop), (st_data_t)&gen_pop); + st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_0_), (st_data_t)&gen_putobject_int2fix); + st_insert(gen_fns, (st_data_t)BIN(putobject_INT2FIX_1_), (st_data_t)&gen_putobject_int2fix); + st_insert(gen_fns, (st_data_t)BIN(getlocal_WC_0), (st_data_t)&gen_getlocal_wc0); } -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/