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

ruby-changes:68705

From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:30 +0900 (JST)
Subject: [ruby-changes:68705] 1744c15578 (master): Avoid generating redundant interpreter exit code after branches

https://git.ruby-lang.org/ruby.git/commit/?id=1744c15578

From 1744c15578cf1955dfdaf5bc02db13a05a8d6970 Mon Sep 17 00:00:00 2001
From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...>
Date: Thu, 7 Jan 2021 17:09:25 -0500
Subject: Avoid generating redundant interpreter exit code after branches

---
 ujit_codegen.c | 84 ++++++++++++++++++++++++++++++++++------------------------
 ujit_codegen.h | 12 +++++++++
 ujit_core.c    | 47 +++++++++++++++++---------------
 3 files changed, 87 insertions(+), 56 deletions(-)

diff --git a/ujit_codegen.c b/ujit_codegen.c
index a75ac9d9e7..a5c75a2140 100644
--- a/ujit_codegen.c
+++ b/ujit_codegen.c
@@ -173,6 +173,9 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L173
     // Get a pointer to the current write position in the code block
     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
     jitstate_t jit = { 0 };
     jit.iseq = iseq;
@@ -187,42 +190,40 @@ ujit_compile_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L190
         // Get the current opcode
         int opcode = jit_get_opcode(&jit);
 
-        //fprintf(stderr, "compiling %s\n", insn_name(opcode));
-
         // Lookup the codegen function for this instruction
-        st_data_t st_gen_fn;
-        if (!rb_st_lookup(gen_fns, opcode, &st_gen_fn)) {
-            //print_int(cb, imm_opnd(num_instrs));
-            //print_str(cb, insn_name(opcode));
+        st_data_t st_op_desc;
+        if (!rb_st_lookup(gen_fns, opcode, &st_op_desc)) {
             break;
         }
 
+        //fprintf(stderr, "compiling %s\n", insn_name(opcode));
         //print_str(cb, insn_name(opcode));
 
         // Call the code generation function
-        codegen_fn gen_fn = (codegen_fn)st_gen_fn;
-        if (!gen_fn(&jit, ctx)) {
+        opdesc_t* p_desc = (opdesc_t*)st_op_desc;
+        bool success = p_desc->gen_fn(&jit, ctx);
+
+        // If we can't compile this instruction
+        if (!success) {
             break;
         }
 
     	// Move to the next instruction
+        p_last_op = p_desc;
         insn_idx += insn_len(opcode);
         (*num_instrs)++;
 
-        // Ensure we only have one send per region. Our code invalidation mechanism can't
-        // invalidate running code and one send could invalidate the other if we had
-        // multiple in the same region.
-        if (opcode == BIN(opt_send_without_block)) {
+        // If this instruction terminates this block
+        if (p_desc->is_branch) {
             break;
         }
     }
 
-    //print_str(cb, "exiting to interpreter\n");
-
-    // FIXME: we only need to generate an exit if an instruction fails to compile
-    //
+    // If the last instruction compiled did not properly terminate the block
     // 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) {
         // Dump list of compiled instrutions
@@ -976,6 +977,21 @@ gen_branchunless(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L977
     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
 ujit_init_codegen(void)
 {
@@ -991,21 +1007,21 @@ ujit_init_codegen(void) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L1007
     gen_fns = rb_st_init_numtable();
 
     // Map YARV opcodes to the corresponding codegen functions
-    st_insert(gen_fns, (st_data_t)BIN(dup), (st_data_t)&gen_dup);
-    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(putself), (st_data_t)&gen_putself);
-    st_insert(gen_fns, (st_data_t)BIN(getlocal_WC_0), (st_data_t)&gen_getlocal_wc0);
-    st_insert(gen_fns, (st_data_t)BIN(setlocal_WC_0), (st_data_t)&gen_setlocal_wc0);
-    st_insert(gen_fns, (st_data_t)BIN(getinstancevariable), (st_data_t)&gen_getinstancevariable);
-    st_insert(gen_fns, (st_data_t)BIN(setinstancevariable), (st_data_t)&gen_setinstancevariable);
-    st_insert(gen_fns, (st_data_t)BIN(opt_lt), (st_data_t)&gen_opt_lt);
-    st_insert(gen_fns, (st_data_t)BIN(opt_minus), (st_data_t)&gen_opt_minus);
-    st_insert(gen_fns, (st_data_t)BIN(opt_plus), (st_data_t)&gen_opt_plus);
-    //st_insert(gen_fns, (st_data_t)BIN(opt_send_without_block), (st_data_t)&gen_opt_send_without_block);
-    st_insert(gen_fns, (st_data_t)BIN(branchunless), (st_data_t)&gen_branchunless);
+    ujit_reg_op(BIN(dup), gen_dup, false);
+    ujit_reg_op(BIN(nop), gen_nop, false);
+    ujit_reg_op(BIN(pop), gen_pop, false);
+    ujit_reg_op(BIN(putnil), gen_putnil, false);
+    ujit_reg_op(BIN(putobject), gen_putobject, false);
+    ujit_reg_op(BIN(putobject_INT2FIX_0_), gen_putobject_int2fix, false);
+    ujit_reg_op(BIN(putobject_INT2FIX_1_), gen_putobject_int2fix, false);
+    ujit_reg_op(BIN(putself), gen_putself, false);
+    ujit_reg_op(BIN(getlocal_WC_0), gen_getlocal_wc0, false);
+    ujit_reg_op(BIN(setlocal_WC_0), gen_setlocal_wc0, false);
+    ujit_reg_op(BIN(getinstancevariable), gen_getinstancevariable, false);
+    ujit_reg_op(BIN(setinstancevariable), gen_setinstancevariable, false);
+    ujit_reg_op(BIN(opt_lt), gen_opt_lt, false);
+    ujit_reg_op(BIN(opt_minus), gen_opt_minus, false);
+    ujit_reg_op(BIN(opt_plus), gen_opt_plus, false);
+    //ujit_reg_op(BIN(opt_send_without_block), gen_opt_send_without_block);
+    ujit_reg_op(BIN(branchunless), gen_branchunless, true);
 }
diff --git a/ujit_codegen.h b/ujit_codegen.h
index 7abeaadfc0..0a845571eb 100644
--- a/ujit_codegen.h
+++ b/ujit_codegen.h
@@ -28,6 +28,18 @@ typedef struct JITState https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L28
 // Code generation function signature
 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_block(const rb_iseq_t *iseq, uint32_t insn_idx, ctx_t* ctx, uint32_t* num_instrs);
diff --git a/ujit_core.c b/ujit_core.c
index af0b8c86a5..aead85a649 100644
--- a/ujit_core.c
+++ b/ujit_core.c
@@ -69,28 +69,6 @@ ctx_stack_opnd(ctx_t* ctx, int32_t idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L69
     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
 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) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L91
     blockid_t target = branch->targets[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 (cb->write_pos == branch->end_pos)
     {
+        //fprintf(stderr, "target idx %d will be placed next\n", target_idx);
         branch->shape = (uint8_t)target_idx;
 
         // 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 https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L203
     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
 ujit_init_core(void)
 {
-- 
cgit v1.2.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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