Skip to content

Commit 490a6d8

Browse files
aidenfoxiveyk0kubun
authored andcommitted
Add codegen for NewArray instruction (Shopify/zjit#110)
* Show failing test * Add second test case * Add empty NewArray setup * Update opt_tests and fix NewArray instantiation * Add code generation for NewArray * Add NewArray ordering test
1 parent 1b95e9c commit 490a6d8

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

test/ruby/test_zjit.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,31 @@ def test(a, b) = a >= b
187187
}, call_threshold: 2
188188
end
189189

190+
def test_new_array_empty
191+
assert_compiles '[]', %q{
192+
def test = []
193+
test
194+
}
195+
end
196+
197+
def test_new_array_nonempty
198+
assert_compiles '[5]', %q{
199+
def a = 5
200+
def test = [a]
201+
test
202+
}
203+
end
204+
205+
def test_new_array_order
206+
assert_compiles '[3, 2, 1]', %q{
207+
def a = 3
208+
def b = 2
209+
def c = 1
210+
def test = [a, b, c]
211+
test
212+
}
213+
end
214+
190215
def test_array_dup
191216
assert_compiles '[1, 2, 3]', %q{
192217
def test = [1,2,3]

zjit/src/codegen.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
243243
let out_opnd = match insn {
244244
Insn::PutSelf => gen_putself(),
245245
Insn::Const { val: Const::Value(val) } => gen_const(*val),
246+
Insn::NewArray { elements, state } => gen_new_array(jit, asm, elements, &function.frame_state(*state)),
246247
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
247248
Insn::Param { idx } => unreachable!("block.insns should not have Insn::Param({idx})"),
248249
Insn::Snapshot { .. } => return Some(()), // we don't need to do anything for this instruction at the moment
@@ -509,6 +510,37 @@ fn gen_array_dup(
509510
)
510511
}
511512

513+
/// Compile a new array instruction
514+
fn gen_new_array(
515+
jit: &mut JITState,
516+
asm: &mut Assembler,
517+
elements: &Vec<InsnId>,
518+
state: &FrameState,
519+
) -> lir::Opnd {
520+
asm_comment!(asm, "call rb_ary_new");
521+
522+
// Save PC
523+
gen_save_pc(asm, state);
524+
525+
let length: ::std::os::raw::c_long = elements.len().try_into().expect("Unable to fit length of elements into c_long");
526+
527+
let new_array = asm.ccall(
528+
rb_ary_new_capa as *const u8,
529+
vec![lir::Opnd::Imm(length)],
530+
);
531+
532+
for i in 0..elements.len() {
533+
let insn_id = elements.get(i as usize).expect("Element should exist at index");
534+
let val = jit.get_opnd(*insn_id).unwrap();
535+
asm.ccall(
536+
rb_ary_push as *const u8,
537+
vec![new_array, val]
538+
);
539+
}
540+
541+
new_array
542+
}
543+
512544
/// Compile code that exits from JIT code with a return value
513545
fn gen_return(asm: &mut Assembler, val: lir::Opnd) -> Option<()> {
514546
// Pop the current frame (ec->cfp++)

zjit/src/hir.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ pub enum Insn {
298298
StringCopy { val: InsnId },
299299
StringIntern { val: InsnId },
300300

301-
NewArray { elements: Vec<InsnId> },
301+
NewArray { elements: Vec<InsnId>, state: InsnId },
302302
ArraySet { array: InsnId, idx: usize, val: InsnId },
303303
ArrayDup { val: InsnId, state: InsnId },
304304

@@ -423,7 +423,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
423423
match &self.inner {
424424
Insn::Const { val } => { write!(f, "Const {}", val.print(self.ptr_map)) }
425425
Insn::Param { idx } => { write!(f, "Param {idx}") }
426-
Insn::NewArray { elements } => {
426+
Insn::NewArray { elements, .. } => {
427427
write!(f, "NewArray")?;
428428
let mut prefix = " ";
429429
for element in elements {
@@ -1633,12 +1633,13 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
16331633
}
16341634
YARVINSN_newarray => {
16351635
let count = get_arg(pc, 0).as_usize();
1636+
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
16361637
let mut elements = vec![];
16371638
for _ in 0..count {
16381639
elements.push(state.stack_pop()?);
16391640
}
16401641
elements.reverse();
1641-
state.stack_push(fun.push_insn(block, Insn::NewArray { elements }));
1642+
state.stack_push(fun.push_insn(block, Insn::NewArray { elements, state: exit_id }));
16421643
}
16431644
YARVINSN_duparray => {
16441645
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
@@ -2046,15 +2047,16 @@ mod infer_tests {
20462047
#[test]
20472048
fn newarray() {
20482049
let mut function = Function::new(std::ptr::null());
2049-
let val = function.push_insn(function.entry_block, Insn::NewArray { elements: vec![] });
2050+
// Fake FrameState index of 0usize
2051+
let val = function.push_insn(function.entry_block, Insn::NewArray { elements: vec![], state: InsnId(0usize) });
20502052
assert_bit_equal(function.infer_type(val), types::ArrayExact);
20512053
}
20522054

20532055
#[test]
20542056
fn arraydup() {
20552057
let mut function = Function::new(std::ptr::null());
2056-
let arr = function.push_insn(function.entry_block, Insn::NewArray { elements: vec![] });
20572058
// Fake FrameState index of 0usize
2059+
let arr = function.push_insn(function.entry_block, Insn::NewArray { elements: vec![], state: InsnId(0usize) });
20582060
let val = function.push_insn(function.entry_block, Insn::ArrayDup { val: arr, state: InsnId(0usize) });
20592061
assert_bit_equal(function.infer_type(val), types::ArrayExact);
20602062
}
@@ -2168,8 +2170,8 @@ mod tests {
21682170
assert_method_hir("test", expect![[r#"
21692171
fn test:
21702172
bb0():
2171-
v1:ArrayExact = NewArray
2172-
Return v1
2173+
v2:ArrayExact = NewArray
2174+
Return v2
21732175
"#]]);
21742176
}
21752177

@@ -2179,8 +2181,8 @@ mod tests {
21792181
assert_method_hir("test", expect![[r#"
21802182
fn test:
21812183
bb0(v0:BasicObject):
2182-
v2:ArrayExact = NewArray v0
2183-
Return v2
2184+
v3:ArrayExact = NewArray v0
2185+
Return v3
21842186
"#]]);
21852187
}
21862188

@@ -2190,8 +2192,8 @@ mod tests {
21902192
assert_method_hir("test", expect![[r#"
21912193
fn test:
21922194
bb0(v0:BasicObject, v1:BasicObject):
2193-
v3:ArrayExact = NewArray v0, v1
2194-
Return v3
2195+
v4:ArrayExact = NewArray v0, v1
2196+
Return v4
21952197
"#]]);
21962198
}
21972199

@@ -2989,8 +2991,8 @@ mod opt_tests {
29892991
assert_optimized_method_hir("test", expect![[r#"
29902992
fn test:
29912993
bb0():
2992-
v3:Fixnum[5] = Const Value(5)
2993-
Return v3
2994+
v4:Fixnum[5] = Const Value(5)
2995+
Return v4
29942996
"#]]);
29952997
}
29962998

@@ -3006,8 +3008,8 @@ mod opt_tests {
30063008
assert_optimized_method_hir("test", expect![[r#"
30073009
fn test:
30083010
bb0(v0:BasicObject):
3009-
v4:Fixnum[5] = Const Value(5)
3010-
Return v4
3011+
v5:Fixnum[5] = Const Value(5)
3012+
Return v5
30113013
"#]]);
30123014
}
30133015

0 commit comments

Comments
 (0)