Skip to content

Commit 23000c7

Browse files
authored
ZJIT: Parse opt_newarray_send into HIR (ruby#13242)
1 parent 186022d commit 23000c7

File tree

1 file changed

+80
-4
lines changed

1 file changed

+80
-4
lines changed

zjit/src/hir.rs

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
141141
write!(f, "BOPRedefined(")?;
142142
match klass {
143143
INTEGER_REDEFINED_OP_FLAG => write!(f, "INTEGER_REDEFINED_OP_FLAG")?,
144+
ARRAY_REDEFINED_OP_FLAG => write!(f, "ARRAY_REDEFINED_OP_FLAG")?,
144145
_ => write!(f, "{klass}")?,
145146
}
146147
write!(f, ", ")?;
@@ -156,6 +157,7 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
156157
BOP_LE => write!(f, "BOP_LE")?,
157158
BOP_GT => write!(f, "BOP_GT")?,
158159
BOP_GE => write!(f, "BOP_GE")?,
160+
BOP_MAX => write!(f, "BOP_MAX")?,
159161
_ => write!(f, "{bop}")?,
160162
}
161163
write!(f, ")")
@@ -310,6 +312,7 @@ pub enum Insn {
310312
NewArray { elements: Vec<InsnId>, state: InsnId },
311313
ArraySet { array: InsnId, idx: usize, val: InsnId },
312314
ArrayDup { val: InsnId, state: InsnId },
315+
ArrayMax { elements: Vec<InsnId>, state: InsnId },
313316

314317
// Check if the value is truthy and "return" a C boolean. In reality, we will likely fuse this
315318
// with IfTrue/IfFalse in the backend to generate jcc.
@@ -441,6 +444,15 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
441444
}
442445
Ok(())
443446
}
447+
Insn::ArrayMax { elements, .. } => {
448+
write!(f, "ArrayMax")?;
449+
let mut prefix = " ";
450+
for element in elements {
451+
write!(f, "{prefix}{element}")?;
452+
prefix = ", ";
453+
}
454+
Ok(())
455+
}
444456
Insn::ArraySet { array, idx, val } => { write!(f, "ArraySet {array}, {idx}, {val}") }
445457
Insn::ArrayDup { val, .. } => { write!(f, "ArrayDup {val}") }
446458
Insn::StringCopy { val } => { write!(f, "StringCopy {val}") }
@@ -744,20 +756,27 @@ impl Function {
744756
}
745757
};
746758
}
759+
macro_rules! find_vec {
760+
( $x:expr ) => {
761+
{
762+
$x.iter().map(|arg| find!(*arg)).collect()
763+
}
764+
};
765+
}
747766
macro_rules! find_branch_edge {
748767
( $edge:ident ) => {
749768
{
750769
BranchEdge {
751770
target: $edge.target,
752-
args: $edge.args.iter().map(|x| find!(*x)).collect(),
771+
args: find_vec!($edge.args),
753772
}
754773
}
755774
};
756775
}
757776
let insn_id = self.union_find.borrow_mut().find(insn_id);
758777
use Insn::*;
759778
match &self.insns[insn_id.0] {
760-
result@(PutSelf | Const {..} | Param {..} | NewArray {..} | GetConstantPath {..}
779+
result@(PutSelf | Const {..} | Param {..} | GetConstantPath {..}
761780
| PatchPoint {..}) => result.clone(),
762781
Snapshot { state: FrameState { iseq, insn_idx, pc, stack, locals } } =>
763782
Snapshot {
@@ -816,6 +835,8 @@ impl Function {
816835
ArrayDup { val , state } => ArrayDup { val: find!(*val), state: *state },
817836
CCall { cfun, args, name, return_type } => CCall { cfun: *cfun, args: args.iter().map(|arg| find!(*arg)).collect(), name: *name, return_type: *return_type },
818837
Defined { .. } => todo!("find(Defined)"),
838+
NewArray { elements, state } => NewArray { elements: find_vec!(*elements), state: find!(*state) },
839+
ArrayMax { elements, state } => ArrayMax { elements: find_vec!(*elements), state: find!(*state) },
819840
}
820841
}
821842

@@ -882,6 +903,7 @@ impl Function {
882903
Insn::PutSelf => types::BasicObject,
883904
Insn::Defined { .. } => types::BasicObject,
884905
Insn::GetConstantPath { .. } => types::BasicObject,
906+
Insn::ArrayMax { .. } => types::BasicObject,
885907
}
886908
}
887909

@@ -1309,9 +1331,13 @@ impl Function {
13091331
necessary[insn_id.0] = true;
13101332
match self.find(insn_id) {
13111333
Insn::PutSelf | Insn::Const { .. } | Insn::Param { .. }
1312-
| Insn::NewArray { .. } | Insn::PatchPoint(..)
1313-
| Insn::GetConstantPath { .. } =>
1334+
| Insn::PatchPoint(..) | Insn::GetConstantPath { .. } =>
13141335
{}
1336+
Insn::ArrayMax { elements, state }
1337+
| Insn::NewArray { elements, state } => {
1338+
worklist.extend(elements);
1339+
worklist.push_back(state);
1340+
}
13151341
Insn::StringCopy { val }
13161342
| Insn::StringIntern { val }
13171343
| Insn::Return { val }
@@ -1636,6 +1662,7 @@ pub enum CallType {
16361662
pub enum ParseError {
16371663
StackUnderflow(FrameState),
16381664
UnknownOpcode(String),
1665+
UnknownNewArraySend(String),
16391666
UnhandledCallType(CallType),
16401667
}
16411668

@@ -1755,6 +1782,26 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
17551782
elements.reverse();
17561783
state.stack_push(fun.push_insn(block, Insn::NewArray { elements, state: exit_id }));
17571784
}
1785+
YARVINSN_opt_newarray_send => {
1786+
let count = get_arg(pc, 0).as_usize();
1787+
let method = get_arg(pc, 1).as_u32();
1788+
let mut elements = vec![];
1789+
for _ in 0..count {
1790+
elements.push(state.stack_pop()?);
1791+
}
1792+
elements.reverse();
1793+
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
1794+
let (bop, insn) = match method {
1795+
VM_OPT_NEWARRAY_SEND_MAX => (BOP_MAX, Insn::ArrayMax { elements, state: exit_id }),
1796+
VM_OPT_NEWARRAY_SEND_MIN => return Err(ParseError::UnknownNewArraySend("min".into())),
1797+
VM_OPT_NEWARRAY_SEND_HASH => return Err(ParseError::UnknownNewArraySend("hash".into())),
1798+
VM_OPT_NEWARRAY_SEND_PACK => return Err(ParseError::UnknownNewArraySend("pack".into())),
1799+
VM_OPT_NEWARRAY_SEND_PACK_BUFFER => return Err(ParseError::UnknownNewArraySend("pack_buffer".into())),
1800+
_ => return Err(ParseError::UnknownNewArraySend(format!("{method}"))),
1801+
};
1802+
fun.push_insn(block, Insn::PatchPoint(Invariant::BOPRedefined { klass: ARRAY_REDEFINED_OP_FLAG, bop }));
1803+
state.stack_push(fun.push_insn(block, insn));
1804+
}
17581805
YARVINSN_duparray => {
17591806
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
17601807
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
@@ -2831,6 +2878,35 @@ mod tests {
28312878
Return v10
28322879
"#]]);
28332880
}
2881+
2882+
#[test]
2883+
fn test_opt_newarray_send_max_no_elements() {
2884+
eval("
2885+
def test = [].max
2886+
");
2887+
// TODO(max): Rewrite to nil
2888+
assert_method_hir("test", expect![[r#"
2889+
fn test:
2890+
bb0():
2891+
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX)
2892+
v3:BasicObject = ArrayMax
2893+
Return v3
2894+
"#]]);
2895+
}
2896+
2897+
#[test]
2898+
fn test_opt_newarray_send_max() {
2899+
eval("
2900+
def test(a,b) = [a,b].max
2901+
");
2902+
assert_method_hir("test", expect![[r#"
2903+
fn test:
2904+
bb0(v0:BasicObject, v1:BasicObject):
2905+
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX)
2906+
v5:BasicObject = ArrayMax v0, v1
2907+
Return v5
2908+
"#]]);
2909+
}
28342910
}
28352911

28362912
#[cfg(test)]

0 commit comments

Comments
 (0)