Skip to content

Commit 8a21483

Browse files
committed
WIP
1 parent 5cfbdf8 commit 8a21483

5 files changed

Lines changed: 110 additions & 13 deletions

File tree

zjit/src/cruby_bindings.inc.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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,41 @@ mod tests {
27092734
"#]]);
27102735
}
27112736

2737+
#[test]
2738+
fn test_new_range() {
2739+
eval("def test = (1..2)");
2740+
assert_method_hir_with_opcode("test", YARVINSN_newrange, expect![[r#"
2741+
fn test:
2742+
bb0():
2743+
v1:Fixnum[1] = Const Value(1)
2744+
v2:Fixnum[2] = Const Value(2)
2745+
v4:RangeExact = NewRange v1 .. v2
2746+
Return v4
2747+
"#]]);
2748+
}
2749+
2750+
#[test]
2751+
fn test_new_range_with_element() {
2752+
eval("def test(a) = (a..2)");
2753+
assert_method_hir_with_opcode("test", YARVINSN_newrange, expect![[r#"
2754+
fn test:
2755+
bb0(v0:BasicObject):
2756+
v3:BasicObject = NewRange v0, 2, 0
2757+
Return v3
2758+
"#]]);
2759+
}
2760+
2761+
#[test]
2762+
fn test_new_range_with_elements() {
2763+
eval("def test(a, b) = (a..b)");
2764+
assert_method_hir_with_opcode("test", YARVINSN_newrange, expect![[r#"
2765+
fn test:
2766+
bb0(v0:BasicObject, v1:BasicObject):
2767+
v4:BasicObject = NewRange v0, v1, 0
2768+
Return v4
2769+
"#]]);
2770+
}
2771+
27122772
#[test]
27132773
fn test_array_dup() {
27142774
eval("def test = [1, 2, 3]");
@@ -4233,6 +4293,23 @@ mod opt_tests {
42334293
"#]]);
42344294
}
42354295

4296+
#[test]
4297+
fn test_eliminate_new_range() {
4298+
eval("
4299+
def test()
4300+
c = (1..2)
4301+
5
4302+
end
4303+
test; test
4304+
");
4305+
assert_optimized_method_hir("test", expect![[r#"
4306+
fn test:
4307+
bb0():
4308+
v3:Fixnum[5] = Const Value(5)
4309+
Return v3
4310+
"#]]);
4311+
}
4312+
42364313
#[test]
42374314
fn test_eliminate_new_array_with_elements() {
42384315
eval("

zjit/src/hir_type/gen_hir_type.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def base_type name
7171
base_type "String"
7272
base_type "Array"
7373
base_type "Hash"
74+
base_type "Range"
7475

7576
(integer, integer_exact) = base_type "Integer"
7677
# CRuby partitions Integer into immediate and non-immediate variants.

zjit/src/hir_type/hir_type.inc.rs

Lines changed: 21 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

zjit/src/hir_type/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(non_upper_case_globals)]
22
use crate::cruby::{Qfalse, Qnil, Qtrue, VALUE, RUBY_T_ARRAY, RUBY_T_STRING, RUBY_T_HASH};
3-
use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cObject, rb_cTrueClass, rb_cFalseClass, rb_cNilClass};
3+
use crate::cruby::{rb_cInteger, rb_cFloat, rb_cArray, rb_cHash, rb_cString, rb_cSymbol, rb_cObject, rb_cTrueClass, rb_cFalseClass, rb_cNilClass, rb_cRange};
44
use crate::cruby::ClassRelationship;
55
use crate::cruby::get_class_name;
66
use crate::hir::PtrPrintMap;
@@ -137,6 +137,10 @@ fn is_hash_exact(val: VALUE) -> bool {
137137
val.class_of() == unsafe { rb_cHash } || (val.class_of() == VALUE(0) && val.builtin_type() == RUBY_T_HASH)
138138
}
139139

140+
fn is_range_exact(val: VALUE) -> bool {
141+
val.class_of() == unsafe { rb_cRange } || (val.class_of() == VALUE(0) && val.builtin_type() == RUBY_T_RANGE)
142+
}
143+
140144
impl Type {
141145
/// Create a `Type` from the given integer.
142146
pub const fn fixnum(val: i64) -> Type {
@@ -183,6 +187,9 @@ impl Type {
183187
else if is_hash_exact(val) {
184188
Type { bits: bits::HashExact, spec: Specialization::Object(val) }
185189
}
190+
else if is_range_exact(val) {
191+
Type { bits: bits::RangeExact, spec: Specialization::Object(val) }
192+
}
186193
else if is_string_exact(val) {
187194
Type { bits: bits::StringExact, spec: Specialization::Object(val) }
188195
}
@@ -277,6 +284,7 @@ impl Type {
277284
if class == unsafe { rb_cInteger } { return true; }
278285
if class == unsafe { rb_cNilClass } { return true; }
279286
if class == unsafe { rb_cObject } { return true; }
287+
if class == unsafe { rb_cRange } { return true; }
280288
if class == unsafe { rb_cString } { return true; }
281289
if class == unsafe { rb_cSymbol } { return true; }
282290
if class == unsafe { rb_cTrueClass } { return true; }
@@ -383,6 +391,7 @@ impl Type {
383391
if self.is_subtype(types::IntegerExact) { return Some(unsafe { rb_cInteger }); }
384392
if self.is_subtype(types::NilClassExact) { return Some(unsafe { rb_cNilClass }); }
385393
if self.is_subtype(types::ObjectExact) { return Some(unsafe { rb_cObject }); }
394+
if self.is_subtype(types::RangeExact) { return Some(unsafe { rb_cRange }); }
386395
if self.is_subtype(types::StringExact) { return Some(unsafe { rb_cString }); }
387396
if self.is_subtype(types::SymbolExact) { return Some(unsafe { rb_cSymbol }); }
388397
if self.is_subtype(types::TrueClassExact) { return Some(unsafe { rb_cTrueClass }); }

0 commit comments

Comments
 (0)