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

ruby-changes:73165

From: Kevin <ko1@a...>
Date: Tue, 30 Aug 2022 00:57:44 +0900 (JST)
Subject: [ruby-changes:73165] 8864691bde (master): Better label refs (https://github.com/Shopify/ruby/pull/310)

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

From 8864691bde2560ef440c4a8dac16b2c661faa228 Mon Sep 17 00:00:00 2001
From: Kevin Newton <kddnewton@g...>
Date: Mon, 11 Jul 2022 17:51:58 -0400
Subject: Better label refs (https://github.com/Shopify/ruby/pull/310)

Previously we were using a `Box<dyn FnOnce>` to support patching the
code when jumping to labels. We needed to do this because some of the
closures that were being used to patch needed to capture local variables
(on both X86 and ARM it was the type of condition for the conditional
jumps).

To get around that, we can instead use const generics since the
condition codes are always known at compile-time. This means that the
closures go from polymorphic to monomorphic, which means they can be
represented as an `fn` instead of a `Box<dyn FnOnce>`, which means they
can fall back to a plain function pointer. This simplifies the storage
of the `LabelRef` structs and should hopefully be a better default
going forward.
---
 yjit/src/asm/arm64/arg/condition.rs    | 34 +++++++++---------
 yjit/src/asm/arm64/inst/branch_cond.rs |  4 +--
 yjit/src/asm/arm64/mod.rs              |  2 +-
 yjit/src/asm/mod.rs                    |  6 ++--
 yjit/src/asm/x86_64/mod.rs             | 66 +++++++++++++++++-----------------
 yjit/src/backend/arm64/mod.rs          | 20 +++++------
 6 files changed, 67 insertions(+), 65 deletions(-)

diff --git a/yjit/src/asm/arm64/arg/condition.rs b/yjit/src/asm/arm64/arg/condition.rs
index db269726d7..e791e4b078 100644
--- a/yjit/src/asm/arm64/arg/condition.rs
+++ b/yjit/src/asm/arm64/arg/condition.rs
@@ -1,20 +1,22 @@ https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/arg/condition.rs#L1
 /// Various instructions in A64 can have condition codes attached. This enum
 /// includes all of the various kinds of conditions along with their respective
 /// encodings.
-pub enum Condition {
-    EQ = 0b0000, // equal to
-    NE = 0b0001, // not equal to
-    CS = 0b0010, // carry set (alias for HS)
-    CC = 0b0011, // carry clear (alias for LO)
-    MI = 0b0100, // minus, negative
-    PL = 0b0101, // positive or zero
-    VS = 0b0110, // signed overflow
-    VC = 0b0111, // no signed overflow
-    HI = 0b1000, // greater than (unsigned)
-    LS = 0b1001, // less than or equal to (unsigned)
-    GE = 0b1010, // greater than or equal to (signed)
-    LT = 0b1011, // less than (signed)
-    GT = 0b1100, // greater than (signed)
-    LE = 0b1101, // less than or equal to (signed)
-    AL = 0b1110, // always
+pub struct Condition;
+
+impl Condition {
+    pub const EQ: u8 = 0b0000; // equal to
+    pub const NE: u8 = 0b0001; // not equal to
+    pub const CS: u8 = 0b0010; // carry set (alias for HS)
+    pub const CC: u8 = 0b0011; // carry clear (alias for LO)
+    pub const MI: u8 = 0b0100; // minus, negative
+    pub const PL: u8 = 0b0101; // positive or zero
+    pub const VS: u8 = 0b0110; // signed overflow
+    pub const VC: u8 = 0b0111; // no signed overflow
+    pub const HI: u8 = 0b1000; // greater than (unsigned)
+    pub const LS: u8 = 0b1001; // less than or equal to (unsigned)
+    pub const GE: u8 = 0b1010; // greater than or equal to (signed)
+    pub const LT: u8 = 0b1011; // less than (signed)
+    pub const GT: u8 = 0b1100; // greater than (signed)
+    pub const LE: u8 = 0b1101; // less than or equal to (signed)
+    pub const AL: u8 = 0b1110; // always
 }
diff --git a/yjit/src/asm/arm64/inst/branch_cond.rs b/yjit/src/asm/arm64/inst/branch_cond.rs
index 21fdda5d3f..33cc9c3649 100644
--- a/yjit/src/asm/arm64/inst/branch_cond.rs
+++ b/yjit/src/asm/arm64/inst/branch_cond.rs
@@ -11,7 +11,7 @@ use super::super::arg::Condition; https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/branch_cond.rs#L11
 ///
 pub struct BranchCond {
     /// The kind of condition to check before branching.
-    cond: Condition,
+    cond: u8,
 
     /// The instruction offset from this instruction to branch to.
     imm19: i32
@@ -20,7 +20,7 @@ pub struct BranchCond { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/inst/branch_cond.rs#L20
 impl BranchCond {
     /// B.cond
     /// https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/B-cond--Branch-conditionally-
-    pub fn bcond(cond: Condition, byte_offset: i32) -> Self {
+    pub fn bcond(cond: u8, byte_offset: i32) -> Self {
         Self { cond, imm19: byte_offset >> 2 }
     }
 }
diff --git a/yjit/src/asm/arm64/mod.rs b/yjit/src/asm/arm64/mod.rs
index 2dc5aa9388..3b5f1ff022 100644
--- a/yjit/src/asm/arm64/mod.rs
+++ b/yjit/src/asm/arm64/mod.rs
@@ -167,7 +167,7 @@ pub const fn bcond_offset_fits_bits(offset: i64) -> bool { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/arm64/mod.rs#L167
 }
 
 /// B.cond - branch to target if condition is true
-pub fn bcond(cb: &mut CodeBlock, cond: Condition, byte_offset: A64Opnd) {
+pub fn bcond(cb: &mut CodeBlock, cond: u8, byte_offset: A64Opnd) {
     let bytes: [u8; 4] = match byte_offset {
         A64Opnd::Imm(imm) => {
             assert!(bcond_offset_fits_bits(imm), "The immediate operand must be 21 bits or less and be aligned to a 2-bit boundary.");
diff --git a/yjit/src/asm/mod.rs b/yjit/src/asm/mod.rs
index 126c9a8548..2fc75083e4 100644
--- a/yjit/src/asm/mod.rs
+++ b/yjit/src/asm/mod.rs
@@ -30,7 +30,7 @@ struct LabelRef { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L30
     num_bytes: usize,
 
     /// The object that knows how to encode the branch instruction.
-    encode: Box<dyn FnOnce(&mut CodeBlock, i64, i64)>
+    encode: fn(&mut CodeBlock, i64, i64)
 }
 
 /// Block of memory into which instructions can be assembled
@@ -227,11 +227,11 @@ impl CodeBlock { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/mod.rs#L227
     }
 
     // Add a label reference at the current write position
-    pub fn label_ref<E: 'static>(&mut self, label_idx: usize, num_bytes: usize, encode: E) where E: FnOnce(&mut CodeBlock, i64, i64) {
+    pub fn label_ref(&mut self, label_idx: usize, num_bytes: usize, encode: fn(&mut CodeBlock, i64, i64)) {
         assert!(label_idx < self.label_addrs.len());
 
         // Keep track of the reference
-        self.label_refs.push(LabelRef { pos: self.write_pos, label_idx, num_bytes, encode: Box::new(encode) });
+        self.label_refs.push(LabelRef { pos: self.write_pos, label_idx, num_bytes, encode });
 
         // Move past however many bytes the instruction takes up
         self.write_pos += num_bytes;
diff --git a/yjit/src/asm/x86_64/mod.rs b/yjit/src/asm/x86_64/mod.rs
index a2a3b47f82..d23279f277 100644
--- a/yjit/src/asm/x86_64/mod.rs
+++ b/yjit/src/asm/x86_64/mod.rs
@@ -799,45 +799,45 @@ pub fn int3(cb: &mut CodeBlock) { https://github.com/ruby/ruby/blob/trunk/yjit/src/asm/x86_64/mod.rs#L799
 
 // Encode a conditional relative jump to a label
 // Note: this always encodes a 32-bit offset
-fn write_jcc(cb: &mut CodeBlock, op: u8, label_idx: usize) {
-    cb.label_ref(label_idx, 6, move |cb, src_addr, dst_addr| {
+fn write_jcc<const OP: u8>(cb: &mut CodeBlock, label_idx: usize) {
+    cb.label_ref(label_idx, 6, |cb, src_addr, dst_addr| {
         cb.write_byte(0x0F);
-        cb.write_byte(op);
+        cb.write_byte(OP);
         cb.write_int((dst_addr - src_addr) as u64, 32);
     });
 }
 
 /// jcc - relative jumps to a label
-pub fn ja_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x87, label_idx); }
-pub fn jae_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); }
-pub fn jb_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); }
-pub fn jbe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x86, label_idx); }
-pub fn jc_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); }
-pub fn je_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x84, label_idx); }
-pub fn jg_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8F, label_idx); }
-pub fn jge_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8D, label_idx); }
-pub fn jl_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8C, label_idx); }
-pub fn jle_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8E, label_idx); }
-pub fn jna_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x86, label_idx); }
-pub fn jnae_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x82, label_idx); }
-pub fn jnb_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); }
-pub fn jnbe_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x87, label_idx); }
-pub fn jnc_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x83, label_idx); }
-pub fn jne_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x85, label_idx); }
-pub fn jng_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8E, label_idx); }
-pub fn jnge_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8C, label_idx); }
-pub fn jnl_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8D, label_idx); }
-pub fn jnle_label(cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8F, label_idx); }
-pub fn jno_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x81, label_idx); }
-pub fn jnp_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8b, label_idx); }
-pub fn jns_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x89, label_idx); }
-pub fn jnz_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x85, label_idx); }
-pub fn jo_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x80, label_idx); }
-pub fn jp_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8A, label_idx); }
-pub fn jpe_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8A, label_idx); }
-pub fn jpo_label (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x8B, label_idx); }
-pub fn js_label  (cb: &mut CodeBlock, label_idx: usize) { write_jcc(cb, 0x88, label_idx); }
-pub fn jz_label  (cb: &mut  (... truncated)

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

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