[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]