@@ -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,52 @@ mod tests {
27092734 "# ] ] ) ;
27102735 }
27112736
2737+ #[ test]
2738+ fn test_new_range_with_one_element ( ) {
2739+ eval ( "def test(a) = (a..10)" ) ;
2740+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2741+ fn test:
2742+ bb0(v0:BasicObject):
2743+ v2:Fixnum[10] = Const Value(10)
2744+ v4:RangeExact = NewRange v0 .. v2
2745+ Return v4
2746+ "# ] ] ) ;
2747+ }
2748+
2749+ #[ test]
2750+ fn test_new_range_with_two_elements ( ) {
2751+ eval ( "def test(a, b) = (a..b)" ) ;
2752+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2753+ fn test:
2754+ bb0(v0:BasicObject, v1:BasicObject):
2755+ v4:RangeExact = NewRange v0 .. v1
2756+ Return v4
2757+ "# ] ] ) ;
2758+ }
2759+
2760+ #[ test]
2761+ fn test_new_range_exclude_with_one_element ( ) {
2762+ eval ( "def test(a) = (a...10)" ) ;
2763+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2764+ fn test:
2765+ bb0(v0:BasicObject):
2766+ v2:Fixnum[10] = Const Value(10)
2767+ v4:RangeExact = NewRange v0 ... v2
2768+ Return v4
2769+ "# ] ] ) ;
2770+ }
2771+
2772+ #[ test]
2773+ fn test_new_range_exclude_with_two_elements ( ) {
2774+ eval ( "def test(a, b) = (a...b)" ) ;
2775+ assert_method_hir_with_opcode ( "test" , YARVINSN_newrange , expect ! [ [ r#"
2776+ fn test:
2777+ bb0(v0:BasicObject, v1:BasicObject):
2778+ v4:RangeExact = NewRange v0 ... v1
2779+ Return v4
2780+ "# ] ] ) ;
2781+ }
2782+
27122783 #[ test]
27132784 fn test_array_dup ( ) {
27142785 eval ( "def test = [1, 2, 3]" ) ;
@@ -4233,6 +4304,23 @@ mod opt_tests {
42334304 "# ] ] ) ;
42344305 }
42354306
4307+ #[ test]
4308+ fn test_eliminate_new_range ( ) {
4309+ eval ( "
4310+ def test()
4311+ c = (1..2)
4312+ 5
4313+ end
4314+ test; test
4315+ " ) ;
4316+ assert_optimized_method_hir ( "test" , expect ! [ [ r#"
4317+ fn test:
4318+ bb0():
4319+ v3:Fixnum[5] = Const Value(5)
4320+ Return v3
4321+ "# ] ] ) ;
4322+ }
4323+
42364324 #[ test]
42374325 fn test_eliminate_new_array_with_elements ( ) {
42384326 eval ( "
0 commit comments