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

ruby-changes:69131

From: Kevin <ko1@a...>
Date: Thu, 21 Oct 2021 08:20:57 +0900 (JST)
Subject: [ruby-changes:69131] bfde30c326 (master): Implement expandarray

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

From bfde30c326788c614ea72c76b9ae22cfb5eef950 Mon Sep 17 00:00:00 2001
From: Kevin Deisz <kevin.deisz@g...>
Date: Wed, 7 Jul 2021 14:45:48 -0400
Subject: Implement expandarray

---
 yjit.rb        |   1 +
 yjit_codegen.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 yjit_iface.h   |   5 +++
 3 files changed, 122 insertions(+)

diff --git a/yjit.rb b/yjit.rb
index cf5cac5f2f..20668663a3 100644
--- a/yjit.rb
+++ b/yjit.rb
@@ -151,6 +151,7 @@ module YJIT https://github.com/ruby/ruby/blob/trunk/yjit.rb#L151
       print_counters(stats, prefix: 'getivar_', prompt: 'getinstancevariable exit reasons:')
       print_counters(stats, prefix: 'setivar_', prompt: 'setinstancevariable exit reasons:')
       print_counters(stats, prefix: 'oaref_', prompt: 'opt_aref exit reasons: ')
+      print_counters(stats, prefix: 'expandarray_', prompt: 'expandarray exit reasons: ')
 
       total_exits = total_exit_count(stats)
 
diff --git a/yjit_codegen.c b/yjit_codegen.c
index b9226cf738..4147853f20 100644
--- a/yjit_codegen.c
+++ b/yjit_codegen.c
@@ -720,6 +720,118 @@ gen_splatarray(jitstate_t* jit, ctx_t* ctx) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L720
     return YJIT_KEEP_COMPILING;
 }
 
+static void
+guard_object_is_heap(codeblock_t *cb, ctx_t *ctx, uint8_t *side_exit, x86opnd_t object_opnd)
+{
+    ADD_COMMENT(cb, "guard object is heap");
+
+    // Test that the object is not an immediate
+    test(cb, object_opnd, imm_opnd(RUBY_IMMEDIATE_MASK));
+    jnz_ptr(cb, side_exit);
+
+    // Test that the object is not false or nil
+    cmp(cb, object_opnd, imm_opnd(Qnil));
+    RUBY_ASSERT(Qfalse < Qnil);
+    jbe_ptr(cb, side_exit);
+}
+
+static inline void
+guard_object_is_array(codeblock_t *cb, x86opnd_t object_opnd, x86opnd_t flags_opnd, ctx_t *ctx, uint8_t *side_exit)
+{
+    guard_object_is_heap(cb, ctx, side_exit, object_opnd);
+    ADD_COMMENT(cb, "guard object is array");
+
+    // Pull out the type mask
+    mov(cb, flags_opnd, member_opnd(object_opnd, struct RBasic, flags));
+    and(cb, flags_opnd, imm_opnd(RUBY_T_MASK));
+
+    // Compare the result with T_ARRAY
+    cmp(cb, flags_opnd, imm_opnd(T_ARRAY));
+    jne_ptr(cb, side_exit);
+}
+
+// push enough nils onto the stack to fill out an array
+static codegen_status_t
+gen_expandarray(jitstate_t* jit, ctx_t* ctx)
+{
+    int flag = (int) jit_get_arg(jit, 1);
+
+    // If this instruction has the splat flag, then bail out.
+    if (flag & 0x01) {
+        GEN_COUNTER_INC(cb, expandarray_splat);
+        return YJIT_CANT_COMPILE;
+    }
+
+    // If this instruction has the postarg flag, then bail out.
+    if (flag & 0x02) {
+        GEN_COUNTER_INC(cb, expandarray_postarg);
+        return YJIT_CANT_COMPILE;
+    }
+
+    // num is the number of requested values. If there aren't enough in the
+    // array then we're going to push on nils.
+    rb_num_t num = (rb_num_t) jit_get_arg(jit, 0);
+
+    // If we don't actually want any values, then just return.
+    if (num == 0) {
+        return YJIT_KEEP_COMPILING;
+    }
+
+    uint8_t *side_exit = yjit_side_exit(jit, ctx);
+
+    // Move the array from the stack into REG0 and check that it's an array.
+    mov(cb, REG0, ctx_stack_pop(ctx, 1));
+    guard_object_is_array(cb, REG0, REG1, ctx, COUNTED_EXIT(side_exit, expandarray_not_array));
+
+    uint32_t embedded_length_label = cb_new_label(cb, "ea_embedded");
+    uint32_t push_values_label = cb_new_label(cb, "ea_push_vals");
+
+    // Pull out the embed flag to check if it's an embedded array.
+    mov(cb, REG1, member_opnd(REG0, struct RBasic, flags));
+    and(cb, REG1, imm_opnd(RARRAY_EMBED_FLAG));
+    jmp_label(cb, embedded_length_label);
+
+    // Pull out the length of the heap array and write it to REG1.
+    mov(cb, REG1, member_opnd(REG0, struct RArray, as.heap.len));
+    jmp_label(cb, push_values_label);
+
+    // Pull out the length of the embedded array and write it to REG1.
+    cb_write_label(cb, embedded_length_label);
+    mov(cb, REG1, member_opnd(REG0, struct RBasic, flags));
+    and(cb, REG1, imm_opnd(RARRAY_EMBED_LEN_MASK));
+    shr(cb, REG1, imm_opnd(RARRAY_EMBED_LEN_SHIFT));
+
+    // Only handle the case where the number of values in the array is greater
+    // than or equal to the number of values requested.
+    cb_write_label(cb, push_values_label);
+    cmp(cb, REG1, imm_opnd(num));
+    jl_ptr(cb, COUNTED_EXIT(side_exit, expandarray_not_equal_len));
+
+    // Once more, compare if it is an embedded array to use for cmovs.
+    mov(cb, REG1, member_opnd(REG0, struct RBasic, flags));
+    test(cb, REG1, imm_opnd(RARRAY_EMBED_FLAG));
+
+    // If the last comparison was not 0, then we have an embedded array, so
+    // we're going to get the values from the embedded array.
+    // (struct RArray *)(obj)->as.ary
+    lea(cb, REG1, member_opnd(REG0, struct RArray, as.ary));
+
+    // If the last comparison was 0, then we don't have an embedded array,
+    // so we're going to get the values off the heap.
+    // (struct RArray *)(obj)->as.heap.ptr
+    cmovz(cb, REG1, member_opnd(REG0, struct RArray, as.heap.ptr));
+
+    // Loop backward through the array and push each element onto the stack.
+    for (int32_t i = (int32_t) num - 1; i >= 0; i--) {
+        x86opnd_t top = ctx_stack_push(ctx, TYPE_UNKNOWN);
+        mov(cb, REG0, mem_opnd(64, REG1, i * SIZEOF_VALUE));
+        mov(cb, top, REG0);
+    }
+
+    cb_link_labels(cb);
+    return YJIT_KEEP_COMPILING;
+}
+
 // new hash initialized from top N values
 static codegen_status_t
 gen_newhash(jitstate_t* jit, ctx_t* ctx)
@@ -3499,7 +3611,11 @@ yjit_init_codegen(void) https://github.com/ruby/ruby/blob/trunk/yjit_codegen.c#L3611
     yjit_reg_op(BIN(adjuststack), gen_adjuststack);
     yjit_reg_op(BIN(newarray), gen_newarray);
     yjit_reg_op(BIN(duparray), gen_duparray);
+<<<<<<< HEAD
     yjit_reg_op(BIN(splatarray), gen_splatarray);
+=======
+    yjit_reg_op(BIN(expandarray), gen_expandarray);
+>>>>>>> dc01eb5c5e (Implement expandarray)
     yjit_reg_op(BIN(newhash), gen_newhash);
     yjit_reg_op(BIN(concatstrings), gen_concatstrings);
     yjit_reg_op(BIN(putnil), gen_putnil);
diff --git a/yjit_iface.h b/yjit_iface.h
index cdeef11765..6afedb47fe 100644
--- a/yjit_iface.h
+++ b/yjit_iface.h
@@ -71,6 +71,11 @@ YJIT_DECLARE_COUNTERS( https://github.com/ruby/ruby/blob/trunk/yjit_iface.h#L71
     vm_insns_count,
     compiled_iseq_count,
 
+    expandarray_splat,
+    expandarray_postarg,
+    expandarray_not_array,
+    expandarray_not_equal_len,
+
     // Member with known name for iterating over counters
     last_member
 )
-- 
cgit v1.2.1


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

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