ruby-changes:68571
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:09:43 +0900 (JST)
Subject: [ruby-changes:68571] 2811792f91 (master): Compiling getlocal_WC_0
https://git.ruby-lang.org/ruby.git/commit/?id=2811792f91 From 2811792f91d9651a40d1e41de8c85a9b347e6377 Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Tue, 15 Sep 2020 15:12:31 -0400 Subject: Compiling getlocal_WC_0 --- ujit_asm.c | 25 +++++++++++++++++++-- ujit_asm.h | 8 +++++-- ujit_asm_tests.c | 1 + ujit_compile.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 90 insertions(+), 10 deletions(-) diff --git a/ujit_asm.c b/ujit_asm.c index 75c2dc8dc8..c7221091ca 100644 --- a/ujit_asm.c +++ b/ujit_asm.c @@ -11,6 +11,9 @@ https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L11 // Dummy none/null operand const x86opnd_t NO_OPND = { OPND_NONE, 0, .imm = 0 }; +// Instruction pointer +const x86opnd_t RIP = { OPND_REG, 64, .reg = { REG_IP, 5 }}; + // 64-bit GP registers const x86opnd_t RAX = { OPND_REG, 64, .reg = { REG_GP, 0 }}; const x86opnd_t RCX = { OPND_REG, 64, .reg = { REG_GP, 1 }}; @@ -77,10 +80,12 @@ size_t unsig_imm_size(uint64_t imm) https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L80 x86opnd_t mem_opnd(size_t num_bits, x86opnd_t base_reg, int32_t disp) { + bool is_iprel = base_reg.reg.reg_type == REG_IP; + x86opnd_t opnd = { OPND_MEM, num_bits, - .mem = { base_reg.reg.reg_no, 0, 0, false, false, disp } + .mem = { base_reg.reg.reg_no, 0, 0, false, is_iprel, disp } }; return opnd; @@ -542,7 +547,7 @@ void cb_write_rm( https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L547 cb_write_byte(cb, sib_byte); } - // Add the displacement size + // Add the displacement if (rm_opnd.type == OPND_MEM) { size_t dsize = disp_size(rm_opnd); @@ -1285,6 +1290,15 @@ void pop(codeblock_t* cb, x86opnd_t reg) https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L1290 cb_write_opcode(cb, 0x58, reg); } +/// popfq - Pop the flags register (64-bit) +void popfq(codeblock_t* cb) +{ + //cb.writeASM("popfq"); + + // REX.W + 0x9D + cb_write_bytes(cb, 2, 0x48, 0x9D); +} + /// push - Push a register on the stack void push(codeblock_t* cb, x86opnd_t reg) { @@ -1298,6 +1312,13 @@ void push(codeblock_t* cb, x86opnd_t reg) https://github.com/ruby/ruby/blob/trunk/ujit_asm.c#L1312 cb_write_opcode(cb, 0x50, reg); } +/// pushfq - Push the flags register (64-bit) +void pushfq(codeblock_t* cb) +{ + //cb.writeASM("pushfq"); + cb_write_byte(cb, 0x9C); +} + /// ret - Return from call, popping only the return address void ret(codeblock_t* cb) { diff --git a/ujit_asm.h b/ujit_asm.h index 502b7c665f..f47e5a2059 100644 --- a/ujit_asm.h +++ b/ujit_asm.h @@ -62,8 +62,7 @@ enum OpndType https://github.com/ruby/ruby/blob/trunk/ujit_asm.h#L62 OPND_NONE, OPND_REG, OPND_IMM, - OPND_MEM, - //OPND_IPREL + OPND_MEM }; enum RegType @@ -135,6 +134,9 @@ typedef struct X86Opnd https://github.com/ruby/ruby/blob/trunk/ujit_asm.h#L134 // Dummy none/null operand const x86opnd_t NO_OPND; +// Instruction pointer +const x86opnd_t RIP; + // 64-bit GP registers const x86opnd_t RAX; const x86opnd_t RCX; @@ -270,7 +272,9 @@ void nop(codeblock_t* cb, size_t length); https://github.com/ruby/ruby/blob/trunk/ujit_asm.h#L272 void not(codeblock_t* cb, x86opnd_t opnd); void or(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); void pop(codeblock_t* cb, x86opnd_t reg); +void popfq(codeblock_t* cb); void push(codeblock_t* cb, x86opnd_t reg); +void pushfq(codeblock_t* cb); void ret(codeblock_t* cb); void sal(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); void sar(codeblock_t* cb, x86opnd_t opnd0, x86opnd_t opnd1); diff --git a/ujit_asm_tests.c b/ujit_asm_tests.c index a0e3e07e15..650762ff46 100644 --- a/ujit_asm_tests.c +++ b/ujit_asm_tests.c @@ -169,6 +169,7 @@ void run_tests() https://github.com/ruby/ruby/blob/trunk/ujit_asm_tests.c#L169 // lea //cb_set_pos(cb, 0); lea(cb, EBX, mem_opnd(32, RSP, 4)); check_bytes(cb, "8D5C2404"); cb_set_pos(cb, 0); lea(cb, RDX, mem_opnd(64, RCX, 8)); check_bytes(cb, "488D5108"); + //cb_set_pos(cb, 0); lea(cb, RAX, mem_opnd(8, RIP, 5)); check_bytes(cb, "488D042505000000"); // mov cb_set_pos(cb, 0); mov(cb, EAX, imm_opnd(7)); check_bytes(cb, "B807000000"); diff --git a/ujit_compile.c b/ujit_compile.c index 88eb2d657e..37cff26ba1 100644 --- a/ujit_compile.c +++ b/ujit_compile.c @@ -51,8 +51,11 @@ addr2insn_bookkeeping(void *code_ptr, int insn) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L51 } } -// Generate a chunk of machinecode for one individual bytecode instruction +// 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) { @@ -69,14 +72,15 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L72 int insn = (int)iseq->body->iseq_encoded[insn_idx]; int len = insn_len(insn); + //const char* name = insn_name(insn); //printf("%s\n", name); // Compute the address of the next instruction - void* next_pc = &iseq->body->iseq_encoded[insn_idx + len]; + 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]; + uint8_t *code_ptr = &cb->mem_block[cb->write_pos]; //printf("write pos: %ld\n", cb->write_pos); // Write the pre call bytes @@ -90,7 +94,7 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L94 if (insn == BIN(nop)) { //add(cb, RSI, imm_opnd(8)); // increment PC - //mov(cb, mem_opnd(64, RDI, 0), RSI); // write new PC to EC object, not necessary for nop bytecode? + //mov(cb, mem_opnd(64, RDI, 0), RSI); // write new PC to CFP object, not necessary for nop bytecode? //mov(cb, RAX, RSI); // return new PC // Directly return the next PC, which is a constant @@ -126,8 +130,8 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L130 mov(cb, RAX, mem_opnd(64, RDI, 8)); // Write constant at SP - int cst = (insn == BIN(putobject_INT2FIX_0_))? 0:1; - mov(cb, mem_opnd(64, RAX, 0), imm_opnd(INT2FIX(cst))); + 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)); @@ -146,6 +150,56 @@ ujit_compile_insn(rb_iseq_t *iseq, size_t insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L150 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; + + // Load the local from the block + mov(cb, RCX, mem_opnd(64, RDX, offs)); + + // Write the local at SP + mov(cb, mem_opnd(64, RAX, 0), RCX); + + // Compute address of incremented SP + 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 0; } -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/