Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions range.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
static void
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
{
// Changing this condition has implications for JITs. If you do, please let maintainers know.
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
VALUE v;

Expand Down
15 changes: 15 additions & 0 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,21 @@ def test = /#{1}#{2}#{3}/
}, insns: [:toregexp]
end

def test_new_range_non_leaf
assert_compiles '(0/1)..1', %q{
def jit_entry(v) = make_range_then_exit(v)

def make_range_then_exit(v)
range = (v..1)
super rescue range # TODO(alan): replace super with side-exit intrinsic
end

jit_entry(0) # profile
jit_entry(0) # compile
jit_entry(0/1r) # run without stub
}, call_threshold: 2
end

private

# Assert that every method call in `test_script` can be compiled by ZJIT
Expand Down
6 changes: 4 additions & 2 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::Const { val: Const::Value(val) } => gen_const(*val),
Insn::NewArray { elements, state } => gen_new_array(asm, opnds!(elements), &function.frame_state(*state)),
Insn::NewHash { elements, state } => gen_new_hash(jit, asm, elements, &function.frame_state(*state)),
Insn::NewRange { low, high, flag, state } => gen_new_range(asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::NewRange { low, high, flag, state } => gen_new_range(jit, asm, opnd!(low), opnd!(high), *flag, &function.frame_state(*state)),
Insn::ArrayDup { val, state } => gen_array_dup(asm, opnd!(val), &function.frame_state(*state)),
Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)),
// concatstrings shouldn't have 0 strings
Expand Down Expand Up @@ -1040,13 +1040,15 @@ fn gen_new_hash(

/// Compile a new range instruction
fn gen_new_range(
jit: &JITState,
asm: &mut Assembler,
low: lir::Opnd,
high: lir::Opnd,
flag: RangeType,
state: &FrameState,
) -> lir::Opnd {
gen_prepare_call_with_gc(asm, state);
// Sometimes calls `low.<=>(high)`
gen_prepare_non_leaf_call(jit, asm, state);

// Call rb_range_new(low, high, flag)
asm_ccall!(asm, rb_range_new, low, high, (flag as i64).into())
Expand Down
27 changes: 26 additions & 1 deletion zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,6 @@ impl Insn {
// NewHash's operands may be hashed and compared for equality, which could have
// side-effects.
Insn::NewHash { elements, .. } => elements.len() > 0,
Insn::NewRange { .. } => false,
Insn::ArrayDup { .. } => false,
Insn::HashDup { .. } => false,
Insn::Test { .. } => false,
Expand All @@ -660,6 +659,9 @@ impl Insn {
Insn::GetLocal { .. } => false,
Insn::IsNil { .. } => false,
Insn::CCall { elidable, .. } => !elidable,
// TODO: NewRange is effects free if we can prove the two ends to be Fixnum,
// but we don't have type information here in `impl Insn`. See rb_range_new().
Insn::NewRange { .. } => true,
_ => true,
}
}
Expand Down Expand Up @@ -6198,6 +6200,29 @@ mod opt_tests {
"#]]);
}

#[test]
fn test_do_not_eliminate_new_range_non_fixnum() {
eval("
def test()
_ = (-'a'..'b')
0
end
test; test
");
assert_optimized_method_hir("test", expect![[r#"
fn test@<compiled>:3:
bb0(v0:BasicObject):
v1:NilClass = Const Value(nil)
v4:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
PatchPoint BOPRedefined(STRING_REDEFINED_OP_FLAG, BOP_UMINUS)
v6:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
v8:StringExact = StringCopy v6
v10:RangeExact = NewRange v4 NewRangeInclusive v8
v11:Fixnum[0] = Const Value(0)
Return v11
"#]]);
}

#[test]
fn test_eliminate_new_array_with_elements() {
eval("
Expand Down
Loading