@@ -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,23 @@ mod tests {
35083529 Return v4
35093530 "# ] ] ) ;
35103531 }
3532+
3533+ #[ test]
3534+ fn test_branchnil ( ) {
3535+ eval ( "
3536+ def test(x) = x&.itself
3537+ " ) ;
3538+ assert_method_hir ( "test" , expect ! [ [ r#"
3539+ fn test:
3540+ bb0(v0:BasicObject):
3541+ v2:CBool = IsNil v0
3542+ IfTrue v2, bb1(v0, v0)
3543+ v5:BasicObject = SendWithoutBlock v0, :itself
3544+ Jump bb1(v0, v5)
3545+ bb1(v7:BasicObject, v8:BasicObject):
3546+ Return v8
3547+ "# ] ] ) ;
3548+ }
35113549}
35123550
35133551#[ cfg( test) ]
0 commit comments