ruby-changes:68661
From: Maxime <ko1@a...>
Date: Thu, 21 Oct 2021 08:12:04 +0900 (JST)
Subject: [ruby-changes:68661] 20f5b7426e (master): Start implementing BBV primitives
https://git.ruby-lang.org/ruby.git/commit/?id=20f5b7426e From 20f5b7426e839c90819f223c1a30992fd8d4023c Mon Sep 17 00:00:00 2001 From: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@s...> Date: Thu, 10 Dec 2020 16:59:13 -0500 Subject: Start implementing BBV primitives --- ujit_codegen.c | 13 +++++++------ ujit_codegen.h | 2 +- ujit_core.c | 60 ++++++++++++++++++++++++++++++++++++++++++---------------- ujit_core.h | 14 ++++++++++++++ ujit_iface.c | 4 ++-- 5 files changed, 68 insertions(+), 25 deletions(-) diff --git a/ujit_codegen.c b/ujit_codegen.c index c51f7b1944..4897e38cde 100644 --- a/ujit_codegen.c +++ b/ujit_codegen.c @@ -34,6 +34,9 @@ static void https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L34 ujit_gen_entry(codeblock_t* cb) { cb_write_pre_call_bytes(cb); + + // Load the current SP from the CFP into REG_SP + mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp)); } /** @@ -98,7 +101,7 @@ Compile a sequence of bytecode instructions starting at `insn_idx`. https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L101 Returns `NULL` if compilation fails. */ uint8_t * -ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx) +ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry) { assert (cb != NULL); unsigned first_insn_idx = insn_idx; @@ -147,12 +150,10 @@ ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx) https://github.com/ruby/ruby/blob/trunk/ujit_codegen.c#L150 break; } - // Write the pre call bytes before the first instruction - if (num_instrs == 0) { + // If requested, write the interpreter entry + // prologue before the first instruction + if (gen_entry && num_instrs == 0) { ujit_gen_entry(cb); - - // Load the current SP from the CFP into REG_SP - mov(cb, REG_SP, member_opnd(REG_CFP, rb_control_frame_t, sp)); } // Call the code generation function diff --git a/ujit_codegen.h b/ujit_codegen.h index 7c03420097..5216dbb1be 100644 --- a/ujit_codegen.h +++ b/ujit_codegen.h @@ -3,7 +3,7 @@ https://github.com/ruby/ruby/blob/trunk/ujit_codegen.h#L3 #include "stddef.h" -uint8_t * ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx); +uint8_t *ujit_compile_block(const rb_iseq_t *iseq, unsigned int insn_idx, bool gen_entry); void ujit_init_codegen(void); diff --git a/ujit_core.c b/ujit_core.c index 261a33315f..c981ef0e30 100644 --- a/ujit_core.c +++ b/ujit_core.c @@ -2,35 +2,56 @@ https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L2 #include "ujit_asm.h" #include "ujit_iface.h" #include "ujit_core.h" - - - +#include "ujit_codegen.h" // Table of block versions indexed by (iseq, index) tuples st_table * version_tbl; -/* -struct st_hash_type { - int (*compare)(st_data_t, st_data_t); // st_compare_func* - st_index_t (*hash)(st_data_t); // st_hash_func* -}; +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)blockid->idx); -static const struct st_hash_type st_hashtype_num = { - st_numcmp, - st_numhash, + // Use XOR to combine the hashes + return hash0 ^ hash1; +} + +static const struct st_hash_type hashtype_blockid = { + blockid_cmp, + blockid_hash, }; -strcasehash(st_data_t arg) +// Retrieve a basic block version for an (iseq, idx) tuple +// TODO: we need to add a versioning context here +uint8_t* get_block_version(const rb_iseq_t *iseq, unsigned int idx /*, ctx_t* ctx */) { - register const char *string = (const char *)arg; - ... -} + blockid_t blockid = { iseq, idx }; -*/ + // If there exists a version for this block id + st_data_t st_version; + if (rb_st_lookup(version_tbl, (st_data_t)&blockid, &st_version)) { + return (uint8_t*)st_version; + } + uint8_t* code_ptr = ujit_compile_block(iseq, idx, false); + st_insert(version_tbl, (st_data_t)&blockid, (st_data_t)code_ptr); + return code_ptr; +} +// +// Method to generate stubs for branches +// TODO: get_branch_stub() or get_branch() function +// // Get the current instruction opcode from the context object int @@ -96,3 +117,10 @@ ctx_stack_opnd(ctx_t* ctx, int32_t idx) https://github.com/ruby/ruby/blob/trunk/ujit_core.c#L117 return opnd; } + +void +ujit_init_core(void) +{ + // Initialize the version hash table + version_tbl = st_init_table(&hashtype_blockid); +} diff --git a/ujit_core.h b/ujit_core.h index 320be8fa01..f42ff84ace 100644 --- a/ujit_core.h +++ b/ujit_core.h @@ -20,6 +20,17 @@ https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L20 // Maximum number of versions per block #define MAX_VERSIONS 5 +// Tuple of (iseq, idx) used to idenfity basic blocks +typedef struct BlockId +{ + // Instruction sequence + const rb_iseq_t *iseq; + + // Instruction index + const unsigned int idx; + +} blockid_t; + // Code generation context typedef struct ctx_struct { @@ -48,6 +59,7 @@ typedef struct ctx_struct https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L59 } ctx_t; +// Context object methods int ctx_get_opcode(ctx_t *ctx); VALUE ctx_get_arg(ctx_t* ctx, size_t arg_idx); x86opnd_t ctx_sp_opnd(ctx_t* ctx, int32_t offset_bytes); @@ -55,4 +67,6 @@ x86opnd_t ctx_stack_push(ctx_t* ctx, size_t n); https://github.com/ruby/ruby/blob/trunk/ujit_core.h#L67 x86opnd_t ctx_stack_pop(ctx_t* ctx, size_t n); x86opnd_t ctx_stack_opnd(ctx_t* ctx, int32_t idx); +void ujit_init_core(void); + #endif // #ifndef UJIT_CORE_H diff --git a/ujit_iface.c b/ujit_iface.c index ac541b7cdc..e30e3afa3b 100644 --- a/ujit_iface.c +++ b/ujit_iface.c @@ -233,7 +233,7 @@ rb_ujit_compile_iseq(const rb_iseq_t *iseq) https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L233 VALUE *encoded = (VALUE *)iseq->body->iseq_encoded; // Compile a block version starting at the first instruction - uint8_t* native_code_ptr = ujit_compile_block(iseq, 0); + uint8_t* native_code_ptr = ujit_compile_block(iseq, 0, true); if (native_code_ptr) { encoded[0] = (VALUE)native_code_ptr; @@ -253,7 +253,7 @@ rb_ujit_init(void) https://github.com/ruby/ruby/blob/trunk/ujit_iface.c#L253 rb_ujit_enabled = true; - // Initialize ujit codegen + ujit_init_core(); ujit_init_codegen(); // Initialize the GC hooks -- cgit v1.2.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/