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

ruby-changes:68601

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:10:26 +0900 (JST)
Subject: [ruby-changes:68601] 77cfdb24d4 (master): Implemented delayed stack pointer adjustment optimization

https://git.ruby-lang.org/ruby.git/commit/?id=77cfdb24d4

From 77cfdb24d4d7445a6e8f4a110d4e2159360f3c2b Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Thu, 17 Sep 2020 13:40:50 -0400
Subject: Implemented delayed stack pointer adjustment optimization

---
 ujit_compile.c | 105 ++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 67 insertions(+), 38 deletions(-)

diff --git a/ujit_compile.c b/ujit_compile.c
index 14ed3ee997..2b4b1ad03e 100644
--- a/ujit_compile.c
+++ b/ujit_compile.c
@@ -17,7 +17,8 @@ typedef struct ctx_struct https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L17
     // Current PC
     VALUE* pc;
 
-    // TODO: virtual stack pointer handling
+    // Difference between the current stack pointer and actual stack top
+    int32_t stack_diff;
 
 } ctx_t;
 
@@ -81,6 +82,32 @@ VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L82
     return *(ctx->pc + arg_idx + 1);
 }
 
+/*
+Make space on the stack for N values
+Return a pointer to the new stack top
+*/
+x86opnd_t ctx_stack_push(ctx_t* ctx, size_t n)
+{
+    ctx->stack_diff += n;
+
+    // SP points just above the topmost value
+    int32_t offset = (ctx->stack_diff - 1) * 8;
+    return mem_opnd(64, RSI, offset);
+}
+
+/*
+Pop N values off the stack
+Return a pointer to the stack top before the pop operation
+*/
+x86opnd_t ctx_stack_pop(ctx_t* ctx, size_t n)
+{
+    ctx->stack_diff -= n;
+
+    // SP points just above the topmost value
+    int32_t offset = (ctx->stack_diff - 1) * 8;
+    return mem_opnd(64, RSI, offset);
+}
+
 /*
 Generate a chunk of machine code for one individual bytecode instruction
 Eventually, this will handle multiple instructions in a sequence
@@ -88,6 +115,8 @@ Eventually, this will handle multiple instructions in a sequence https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L115
 MicroJIT code gets a pointer to the cfp as the first argument in RDI
 See rb_ujit_empty_func(rb_control_frame_t *cfp) in iseq.c
 
+Throughout the generated code, we store the current stack pointer in RSI
+
 System V ABI reference:
 https://wiki.osdev.org/System_V_ABI#x86-64
 */
@@ -117,6 +146,8 @@ ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_uji https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L146
 
     // Create codegen context
     ctx_t ctx;
+    ctx.pc = NULL;
+    ctx.stack_diff = 0;
 
     // For each instruction to compile
     size_t num_instrs;
@@ -130,9 +161,7 @@ ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_uji https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L161
 
         // Lookup the codegen function for this instruction
         st_data_t st_gen_fn;
-        int found = rb_st_lookup(gen_fns, opcode, &st_gen_fn);
-
-        if (!found)
+        if (!rb_st_lookup(gen_fns, opcode, &st_gen_fn))
         {
             break;
         }
@@ -141,6 +170,9 @@ ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_uji https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L170
         if (num_instrs == 0)
         {
             ujit_instr_entry(cb);
+
+            // Load the current SP from the CFP into RSI
+            mov(cb, RSI, mem_opnd(64, RDI, 8));
         }
 
         // Call the code generation function
@@ -160,6 +192,15 @@ ujit_compile_insn(rb_iseq_t *iseq, unsigned int insn_idx, unsigned int* next_uji https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L192
         return NULL;
     }
 
+    // Write the adjusted SP back into the CFP
+    if (ctx.stack_diff != 0)
+    {
+        // The stack pointer points one above the actual stack top
+        x86opnd_t stack_pointer = ctx_stack_push(&ctx, 1);
+        lea(cb, RSI, stack_pointer);
+        mov(cb, mem_opnd(64, RDI, 8), RSI);
+    }
+
     // Directly return the next PC, which is a constant
     mov(cb, RAX, const_ptr_opnd(ctx.pc));
 
@@ -178,50 +219,42 @@ void gen_nop(codeblock_t* cb, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L219
 void gen_pop(codeblock_t* cb, ctx_t* ctx)
 {
     // Decrement SP
-    sub(cb, mem_opnd(64, RDI, 8), imm_opnd(8));
+    ctx_stack_pop(ctx, 1);
 }
 
-void gen_putobject_int2fix(codeblock_t* cb, ctx_t* ctx)
+void gen_putnil(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);
+    x86opnd_t stack_top = ctx_stack_push(ctx, 1);
+    mov(cb, stack_top, imm_opnd(Qnil));
 }
 
-void gen_putnil(codeblock_t* cb, ctx_t* ctx)
+void gen_putobject(codeblock_t* cb, ctx_t* ctx)
 {
-    // Load current SP into RAX
-    mov(cb, RAX, mem_opnd(64, RDI, 8));
+    // Get the argument
+    VALUE object = ctx_get_arg(ctx, 0);
+    x86opnd_t ptr_imm = const_ptr_opnd((void*)object);
 
     // Write constant at SP
-    mov(cb, mem_opnd(64, RAX, 0), imm_opnd(Qnil));
+    x86opnd_t stack_top = ctx_stack_push(ctx, 1);
+    mov(cb, RAX, ptr_imm);
+    mov(cb, stack_top, RAX);
+}
 
-    // Load incremented SP into RCX
-    lea(cb, RCX, mem_opnd(64, RAX, 8));
+void gen_putobject_int2fix(codeblock_t* cb, ctx_t* ctx)
+{
+    int opcode = ctx_get_opcode(ctx);
+    int cst_val = (opcode == BIN(putobject_INT2FIX_0_))? 0:1;
 
-    // Write back incremented SP
-    mov(cb, mem_opnd(64, RDI, 8), RCX);
+    // Write constant at SP
+    x86opnd_t stack_top = ctx_stack_push(ctx, 1);
+    mov(cb, stack_top, imm_opnd(INT2FIX(cst_val)));
 }
 
 // TODO: implement putself
 
-// TODO: implement putobject
-
 void gen_getlocal_wc0(codeblock_t* cb, ctx_t* ctx)
 {
-    // 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));
 
@@ -233,13 +266,8 @@ void gen_getlocal_wc0(codeblock_t* cb, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L266
     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);
+    x86opnd_t stack_top = ctx_stack_push(ctx, 1);
+    mov(cb, stack_top, RCX);
 }
 
 static void ujit_init()
@@ -255,6 +283,7 @@ static void ujit_init() https://github.com/ruby/ruby/blob/trunk/ujit_compile.c#L283
     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(putnil), (st_data_t)&gen_putnil);
+    st_insert(gen_fns, (st_data_t)BIN(putobject), (st_data_t)&gen_putobject);
     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/

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