Skip to content

ZJIT: Pass self through basic block params #13529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 5, 2025

Conversation

k0kubun
Copy link
Member

@k0kubun k0kubun commented Jun 5, 2025

This PR moves the storage of self from cfp->self to the first basic block argument to use a register.

Currently, ZJIT basic blocks are not allowed to refer to an argument of another basic block because the register allocator uses a fixed register for each basic block argument index, which would cause a conflict for such a reuse. I left a TODO comment in as_args() to fix it when we make the register allocator more flexible.

@k0kubun k0kubun force-pushed the zjit-self-param branch 2 times, most recently from c41b83b to 84d0f24 Compare June 5, 2025 17:31
Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
@k0kubun k0kubun force-pushed the zjit-self-param branch from 84d0f24 to 257d1cd Compare June 5, 2025 17:48
@k0kubun k0kubun marked this pull request as ready for review June 5, 2025 17:52
@matzbot matzbot requested a review from a team June 5, 2025 18:53
Copy link
Contributor

@tekknolagi tekknolagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are some lingering indexing and typing issues but otherwise looks ok to me

zjit/src/hir.rs Outdated
let val = function.push_insn(function.entry_block, Insn::Test { val: param });
function.infer_types();
assert_bit_equal(function.type_of(val), types::CBool);
assert_bit_equal(function.type_of(val), Type::from_cbool(false));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this change? We shouldn't know that it's false

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still weird to me :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, we need to do

            function.param_types.push(types::BasicObject); // self

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(in the test)

Copy link
Member Author

@k0kubun k0kubun Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing out the fix. Yeah I was looking into this and it had Empty and is_known_falsy() returned true (?). Pushed the fix at 5a543a6.

I wish we had less (ideally, no) synthetic tests like this. It seems to test something unreal and requires non-trivial effort for debugging it. The more integrated, the easier to maintain.

Copy link
Contributor

@tekknolagi tekknolagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something is still up with the indexing; see my comments about the modified tests

@tekknolagi
Copy link
Contributor

I can't push a commit but I think you want something like

commit d4d83a0d74b8ffe406ae9e5acd38b2a53f6829be (HEAD -> zjit-self-param)
Author: Max Bernstein <max@bernsteinbear.com>
Date:   Thu Jun 5 16:44:55 2025 -0400

    Only push self param for non-entry blocks

diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 1d26c99964..2711c7561b 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -1989,6 +1989,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
     // item between commas in the source increase the parameter count by one,
     // regardless of parameter kind.
     let mut entry_state = FrameState::new(iseq);
+    fun.push_insn(fun.entry_block, Insn::Param { idx: SELF_PARAM_IDX });
     fun.param_types.push(types::BasicObject); // self
     for local_idx in 0..num_locals(iseq) {
         if local_idx < unsafe { get_iseq_body_param_size(iseq) }.as_usize() {
@@ -2012,11 +2013,14 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
     while let Some((incoming_state, block, mut insn_idx)) = queue.pop_front() {
         if visited.contains(&block) { continue; }
         visited.insert(block);
-        let self_param = fun.push_insn(block, Insn::Param { idx: SELF_PARAM_IDX });
-        let mut state = if insn_idx == 0 { incoming_state.clone() } else {
+        let (self_param, mut state) = if insn_idx == 0 {
+            (fun.blocks[fun.entry_block.0].params[0], incoming_state.clone())
+        } else {
+            assert_eq!(fun.blocks[block.0].params.len(), 0);
+            let self_param = fun.push_insn(block, Insn::Param { idx: SELF_PARAM_IDX });
             let mut result = FrameState::new(iseq);
             let mut idx = 1;
-            for _ in 0..incoming_state.locals.len() {
+            for _ in incoming_state.locals {
                 result.locals.push(fun.push_insn(block, Insn::Param { idx }));
                 idx += 1;
             }
@@ -2024,7 +2028,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
                 result.stack.push(fun.push_insn(block, Insn::Param { idx }));
                 idx += 1;
             }
-            result
+            (self_param, result)
         };
         // Start the block off with a Snapshot so that if we need to insert a new Guard later on
         // and we don't have a Snapshot handy, we can just iterate backward (at the earliest, to

Co-authored-by: Max Bernstein <tekknolagi@gmail.com>
Copy link
Contributor

@tekknolagi tekknolagi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm except for the weird type thing :/

zjit/src/hir.rs Outdated
let val = function.push_insn(function.entry_block, Insn::Test { val: param });
function.infer_types();
assert_bit_equal(function.type_of(val), types::CBool);
assert_bit_equal(function.type_of(val), Type::from_cbool(false));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still weird to me :/

@k0kubun k0kubun merged commit 1a99113 into ruby:master Jun 5, 2025
66 of 80 checks passed
@k0kubun k0kubun deleted the zjit-self-param branch June 5, 2025 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants