@@ -334,6 +334,7 @@ pub enum Insn {
334334 NewArray { elements : Vec < InsnId > , state : InsnId } ,
335335 /// NewHash contains a vec of (key, value) pairs
336336 NewHash { elements : Vec < ( InsnId , InsnId ) > , state : InsnId } ,
337+ NewRange { low : InsnId , high : InsnId , flag : u32 , state : InsnId } ,
337338 ArraySet { array : InsnId , idx : usize , val : InsnId } ,
338339 ArrayDup { val : InsnId , state : InsnId } ,
339340 ArrayMax { elements : Vec < InsnId > , state : InsnId } ,
@@ -443,6 +444,7 @@ impl Insn {
443444 Insn :: StringCopy { .. } => false ,
444445 Insn :: NewArray { .. } => false ,
445446 Insn :: NewHash { .. } => false ,
447+ Insn :: NewRange { .. } => false ,
446448 Insn :: ArrayDup { .. } => false ,
447449 Insn :: HashDup { .. } => false ,
448450 Insn :: Test { .. } => false ,
@@ -494,6 +496,14 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
494496 }
495497 Ok ( ( ) )
496498 }
499+ Insn :: NewRange { low, high, flag, .. } => {
500+ let flag_str = match * flag {
501+ 0 => "..." ,
502+ 1 => ".." ,
503+ _ => & format ! ( "flag({})" , flag) ,
504+ } ;
505+ write ! ( f, "NewRange {low} {flag_str} {high}" )
506+ }
497507 Insn :: ArrayMax { elements, .. } => {
498508 write ! ( f, "ArrayMax" ) ?;
499509 let mut prefix = " " ;
@@ -916,6 +926,7 @@ impl Function {
916926 }
917927 NewHash { elements : found_elements, state : find ! ( state) }
918928 }
929+ & NewRange { low, high, flag, state } => NewRange { low : find ! ( low) , high : find ! ( high) , flag, state } ,
919930 ArrayMax { elements, state } => ArrayMax { elements : find_vec ! ( * elements) , state : find ! ( * state) } ,
920931 & GetIvar { self_val, id, state } => GetIvar { self_val : find ! ( self_val) , id, state } ,
921932 & SetIvar { self_val, id, val, state } => SetIvar { self_val : find ! ( self_val) , id, val, state } ,
@@ -976,6 +987,7 @@ impl Function {
976987 Insn :: ArrayDup { .. } => types:: ArrayExact ,
977988 Insn :: NewHash { .. } => types:: HashExact ,
978989 Insn :: HashDup { .. } => types:: HashExact ,
990+ Insn :: NewRange { .. } => types:: RangeExact ,
979991 Insn :: CCall { return_type, .. } => * return_type,
980992 Insn :: GuardType { val, guard_type, .. } => self . type_of ( * val) . intersection ( * guard_type) ,
981993 Insn :: GuardBitEquals { val, expected, .. } => self . type_of ( * val) . intersection ( Type :: from_value ( * expected) ) ,
@@ -1490,6 +1502,11 @@ impl Function {
14901502 }
14911503 worklist. push_back ( state) ;
14921504 }
1505+ Insn :: NewRange { low, high, state, .. } => {
1506+ worklist. push_back ( low) ;
1507+ worklist. push_back ( high) ;
1508+ worklist. push_back ( state) ;
1509+ }
14931510 Insn :: StringCopy { val }
14941511 | Insn :: StringIntern { val }
14951512 | Insn :: Return { val }
@@ -2316,6 +2333,14 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
23162333 let val = state. stack_pop ( ) ?;
23172334 fun. push_insn ( block, Insn :: SetIvar { self_val, id, val, state : exit_id } ) ;
23182335 }
2336+ YARVINSN_newrange => {
2337+ let flag = get_arg ( pc, 0 ) . as_u32 ( ) ;
2338+ let high = state. stack_pop ( ) ?;
2339+ let low = state. stack_pop ( ) ?;
2340+ let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
2341+ let insn_id = fun. push_insn ( block, Insn :: NewRange { low, high, flag, state : exit_id } ) ;
2342+ state. stack_push ( insn_id) ;
2343+ }
23192344 _ => {
23202345 // Unknown opcode; side-exit into the interpreter
23212346 let exit_id = fun. push_insn ( block, Insn :: Snapshot { state : exit_state } ) ;
@@ -2709,6 +2734,41 @@ mod tests {
27092734 "# ] ] ) ;
27102735 }
27112736
2737+ #[ test]
2738+ fn test_new_range ( ) {
2739+ eval ( "def test = (1..2)" ) ;
2740+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2741+ fn test:
2742+ bb0():
2743+ v1:Fixnum[1] = Const Value(1)
2744+ v2:Fixnum[2] = Const Value(2)
2745+ v4:RangeExact = NewRange v1 .. v2
2746+ Return v4
2747+ "# ] ] ) ;
2748+ }
2749+
2750+ #[ test]
2751+ fn test_new_range_with_element ( ) {
2752+ eval ( "def test(a) = (a..2)" ) ;
2753+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2754+ fn test:
2755+ bb0(v0:BasicObject):
2756+ v3:BasicObject = NewRange v0, 2, 0
2757+ Return v3
2758+ "# ] ] ) ;
2759+ }
2760+
2761+ #[ test]
2762+ fn test_new_range_with_elements ( ) {
2763+ eval ( "def test(a, b) = (a..b)" ) ;
2764+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2765+ fn test:
2766+ bb0(v0:BasicObject, v1:BasicObject):
2767+ v4:BasicObject = NewRange v0, v1, 0
2768+ Return v4
2769+ "# ] ] ) ;
2770+ }
2771+
27122772 #[ test]
27132773 fn test_array_dup ( ) {
27142774 eval ( "def test = [1, 2, 3]" ) ;
@@ -4233,6 +4293,23 @@ mod opt_tests {
42334293 "# ] ] ) ;
42344294 }
42354295
4296+ #[ test]
4297+ fn test_eliminate_new_range ( ) {
4298+ eval ( "
4299+ def test()
4300+ c = (1..2)
4301+ 5
4302+ end
4303+ test; test
4304+ " ) ;
4305+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
4306+ fn test:
4307+ bb0():
4308+ v3:Fixnum[5] = Const Value(5)
4309+ Return v3
4310+ "# ] ] ) ;
4311+ }
4312+
42364313 #[ test]
42374314 fn test_eliminate_new_array_with_elements ( ) {
42384315 eval ( "
0 commit comments