Parse topn, opt_length, opt_size into HIR
authorMax Bernstein <[email protected]>
Fri, 2 May 2025 21:11:52 +0000 (2 17:11 -0400)
committerAlan Wu <[email protected]>
Tue, 6 May 2025 15:11:44 +0000 (7 00:11 +0900)
zjit/src/hir.rs

index da56738..72cd855 100644 (file)
@@ -1573,6 +1573,12 @@ impl FrameState {
         self.stack[idx] = opnd;
     }
 
+    /// Get a stack operand at idx
+    fn stack_topn(&mut self, idx: usize) -> Result<InsnId, ParseError> {
+        let idx = self.stack.len() - idx - 1;
+        self.stack.get(idx).ok_or_else(|| ParseError::StackUnderflow(self.clone())).copied()
+    }
+
     fn setlocal(&mut self, ep_offset: u32, opnd: InsnId) {
         let idx = ep_offset_to_local_idx(self.iseq, ep_offset);
         self.locals[idx] = opnd;
@@ -1896,6 +1902,11 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
                     let top = state.stack_top()?;
                     state.stack_setn(n, top);
                 }
+                YARVINSN_topn => {
+                    let n = get_arg(pc, 0).as_usize();
+                    let top = state.stack_topn(n)?;
+                    state.stack_push(top);
+                }
                 YARVINSN_adjuststack => {
                     let mut n = get_arg(pc, 0).as_usize();
                     while n > 0 {
@@ -1946,6 +1957,8 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
                 YARVINSN_opt_ge |
                 YARVINSN_opt_ltlt |
                 YARVINSN_opt_aset |
+                YARVINSN_opt_length |
+                YARVINSN_opt_size |
                 YARVINSN_opt_send_without_block => {
                     let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
                     let call_info = unsafe { rb_get_call_data_ci(cd) };
@@ -2907,6 +2920,34 @@ mod tests {
               Return v5
         "#]]);
     }
+
+    #[test]
+    fn test_opt_length() {
+        eval("
+            def test(a,b) = [a,b].length
+        ");
+        assert_method_hir("test",  expect![[r#"
+            fn test:
+            bb0(v0:BasicObject, v1:BasicObject):
+              v4:ArrayExact = NewArray v0, v1
+              v6:BasicObject = SendWithoutBlock v4, :length
+              Return v6
+        "#]]);
+    }
+
+    #[test]
+    fn test_opt_size() {
+        eval("
+            def test(a,b) = [a,b].size
+        ");
+        assert_method_hir("test",  expect![[r#"
+            fn test:
+            bb0(v0:BasicObject, v1:BasicObject):
+              v4:ArrayExact = NewArray v0, v1
+              v6:BasicObject = SendWithoutBlock v4, :size
+              Return v6
+        "#]]);
+    }
 }
 
 #[cfg(test)]
@@ -3850,4 +3891,32 @@ mod opt_tests {
               Return v12
         "#]]);
     }
+
+    #[test]
+    fn test_opt_length() {
+        eval("
+            def test(a,b) = [a,b].length
+        ");
+        assert_optimized_method_hir("test",  expect![[r#"
+            fn test:
+            bb0(v0:BasicObject, v1:BasicObject):
+              v4:ArrayExact = NewArray v0, v1
+              v6:BasicObject = SendWithoutBlock v4, :length
+              Return v6
+        "#]]);
+    }
+
+    #[test]
+    fn test_opt_size() {
+        eval("
+            def test(a,b) = [a,b].size
+        ");
+        assert_optimized_method_hir("test",  expect![[r#"
+            fn test:
+            bb0(v0:BasicObject, v1:BasicObject):
+              v4:ArrayExact = NewArray v0, v1
+              v6:BasicObject = SendWithoutBlock v4, :size
+              Return v6
+        "#]]);
+    }
 }