Skip to content

Commit 6acf75b

Browse files
committed
ZJIT: Parse branchnil into HIR
1 parent 39de0e1 commit 6acf75b

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

zjit/src/hir.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ pub enum Insn {
347347
/// Check if the value is truthy and "return" a C boolean. In reality, we will likely fuse this
348348
/// with IfTrue/IfFalse in the backend to generate jcc.
349349
Test { val: InsnId },
350+
/// Return C `true` if `val` is `Qnil`, else `false`.
351+
IsNil { val: InsnId },
350352
Defined { op_type: usize, obj: VALUE, pushval: VALUE, v: InsnId },
351353
GetConstantPath { ic: *const iseq_inline_constant_cache },
352354

@@ -506,6 +508,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
506508
Insn::HashDup { val, .. } => { write!(f, "HashDup {val}") }
507509
Insn::StringCopy { val } => { write!(f, "StringCopy {val}") }
508510
Insn::Test { val } => { write!(f, "Test {val}") }
511+
Insn::IsNil { val } => { write!(f, "IsNil {val}") }
509512
Insn::Jump(target) => { write!(f, "Jump {target}") }
510513
Insn::IfTrue { val, target } => { write!(f, "IfTrue {val}, {target}") }
511514
Insn::IfFalse { val, target } => { write!(f, "IfFalse {val}, {target}") }
@@ -860,6 +863,7 @@ impl Function {
860863
StringCopy { val } => StringCopy { val: find!(*val) },
861864
StringIntern { val } => StringIntern { val: find!(*val) },
862865
Test { val } => Test { val: find!(*val) },
866+
&IsNil { val } => IsNil { val: find!(val) },
863867
Jump(target) => Jump(find_branch_edge!(target)),
864868
IfTrue { val, target } => IfTrue { val: find!(*val), target: find_branch_edge!(target) },
865869
IfFalse { val, target } => IfFalse { val: find!(*val), target: find_branch_edge!(target) },
@@ -963,6 +967,9 @@ impl Function {
963967
Insn::Test { val } if self.type_of(*val).is_known_falsy() => Type::from_cbool(false),
964968
Insn::Test { val } if self.type_of(*val).is_known_truthy() => Type::from_cbool(true),
965969
Insn::Test { .. } => types::CBool,
970+
Insn::IsNil { val } if self.is_a(*val, types::NilClassExact) => Type::from_cbool(true),
971+
Insn::IsNil { val } if !self.type_of(*val).could_be(types::NilClassExact) => Type::from_cbool(false),
972+
Insn::IsNil { .. } => types::CBool,
966973
Insn::StringCopy { .. } => types::StringExact,
967974
Insn::StringIntern { .. } => types::StringExact,
968975
Insn::NewArray { .. } => types::ArrayExact,
@@ -1454,7 +1461,8 @@ impl Function {
14541461
| Insn::StringIntern { val }
14551462
| Insn::Return { val }
14561463
| Insn::Defined { v: val, .. }
1457-
| Insn::Test { val } =>
1464+
| Insn::Test { val }
1465+
| Insn::IsNil { val } =>
14581466
worklist.push_back(val),
14591467
Insn::GuardType { val, state, .. }
14601468
| Insn::GuardBitEquals { val, state, .. }
@@ -2084,6 +2092,19 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
20842092
});
20852093
queue.push_back((state.clone(), target, target_idx));
20862094
}
2095+
YARVINSN_branchnil => {
2096+
let offset = get_arg(pc, 0).as_i64();
2097+
let val = state.stack_pop()?;
2098+
let test_id = fun.push_insn(block, Insn::IsNil { val });
2099+
// TODO(max): Check interrupts
2100+
let target_idx = insn_idx_at_offset(insn_idx, offset);
2101+
let target = insn_idx_to_block[&target_idx];
2102+
let _branch_id = fun.push_insn(block, Insn::IfTrue {
2103+
val: test_id,
2104+
target: BranchEdge { target, args: state.as_args() }
2105+
});
2106+
queue.push_back((state.clone(), target, target_idx));
2107+
}
20872108
YARVINSN_opt_new => {
20882109
let offset = get_arg(pc, 1).as_i64();
20892110
// TODO(max): Check interrupts
@@ -3508,6 +3529,25 @@ mod tests {
35083529
Return v4
35093530
"#]]);
35103531
}
3532+
3533+
#[test]
3534+
fn test_branchnil() {
3535+
eval("
3536+
def test(x)
3537+
x&.itself
3538+
end
3539+
");
3540+
assert_method_hir("test", expect![[r#"
3541+
fn test:
3542+
bb0(v0:BasicObject):
3543+
v2:CBool = IsNil v0
3544+
IfTrue v2, bb1(v0, v0)
3545+
v5:BasicObject = SendWithoutBlock v0, :itself
3546+
Jump bb1(v0, v5)
3547+
bb1(v7:BasicObject, v8:BasicObject):
3548+
Return v8
3549+
"#]]);
3550+
}
35113551
}
35123552

35133553
#[cfg(test)]

0 commit comments

Comments
 (0)