diff options
| author | Chris HasiĆski <krzysztof.hasinski@gmail.com> | 2026-04-12 13:56:45 +0200 |
|---|---|---|
| committer | Takashi Kokubun <takashikkbn@gmail.com> | 2026-04-14 14:04:52 -0700 |
| commit | edb95b13a3789617095f9c4f1d4b8e9bcee23344 (patch) | |
| tree | 437e9dc4458d82bd69ec7dd79bf5c87608e48536 | |
| parent | 54527e24c8f08dd69bc07d7e3b6425ab101e7709 (diff) | |
ZJIT: Add HIR tests and benchmarks for numeric predicate annotations
Add snapshot tests verifying correct HIR generation for each annotated
method:
- Float cfuncs (nan?, finite?, infinite?) emit CCall with BoolExact
or Fixnum|NilClass return type
- Integer builtins (zero?, even?, odd?) emit InvokeBuiltin with
BoolExact return type
- Float builtins (zero?, positive?, negative?) emit InvokeBuiltin
with BoolExact return type
Add benchmark yml files for Float and Integer predicates to the
benchmark/ directory.
| -rw-r--r-- | benchmark/float_predicate.yml | 12 | ||||
| -rw-r--r-- | benchmark/integer_predicate.yml | 9 | ||||
| -rw-r--r-- | zjit/src/hir/opt_tests.rs | 224 |
3 files changed, 245 insertions, 0 deletions
diff --git a/benchmark/float_predicate.yml b/benchmark/float_predicate.yml new file mode 100644 index 0000000000..b946937666 --- /dev/null +++ b/benchmark/float_predicate.yml @@ -0,0 +1,12 @@ +prelude: | + floats = [1.0, -1.0, 0.0, Float::NAN, Float::INFINITY, -Float::INFINITY] + +benchmark: + float_nan?: floats.each { |f| f.nan? } + float_finite?: floats.each { |f| f.finite? } + float_infinite?: floats.each { |f| f.infinite? } + float_zero?: floats.each { |f| f.zero? } + float_positive?: floats.each { |f| f.positive? } + float_negative?: floats.each { |f| f.negative? } + +loop_count: 1000000 diff --git a/benchmark/integer_predicate.yml b/benchmark/integer_predicate.yml new file mode 100644 index 0000000000..7c05ff2587 --- /dev/null +++ b/benchmark/integer_predicate.yml @@ -0,0 +1,9 @@ +prelude: | + nums = (0..9).to_a + +benchmark: + integer_zero?: nums.each { |n| n.zero? } + integer_even?: nums.each { |n| n.even? } + integer_odd?: nums.each { |n| n.odd? } + +loop_count: 1000000 diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index 0bc1b6cd0d..b14df62461 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -15647,4 +15647,228 @@ mod hir_opt_tests { Jump bb6(v81, v114) "); } + + #[test] + fn test_float_nan_p_annotation() { + eval(r#" + def test(x) = x.nan? + test(1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, nan?@0x1010, cme:0x1018) + v23:Flonum = GuardType v10, Flonum + v24:BoolExact = CCall v23, :Float#nan?@0x1040 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_float_finite_p_annotation() { + eval(r#" + def test(x) = x.finite? + test(1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, finite?@0x1010, cme:0x1018) + v23:Flonum = GuardType v10, Flonum + v24:BoolExact = CCall v23, :Float#finite?@0x1040 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_float_infinite_p_annotation() { + eval(r#" + def test(x) = x.infinite? + test(1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, infinite?@0x1010, cme:0x1018) + v23:Flonum = GuardType v10, Flonum + v24:NilClass|Fixnum = CCall v23, :Float#infinite?@0x1040 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_integer_even_p_annotation() { + eval(r#" + def test(x) = x.even? + test(2) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Integer@0x1008, even?@0x1010, cme:0x1018) + v22:Fixnum = GuardType v10, Fixnum + v24:BoolExact = InvokeBuiltin leaf <inline_expr>, v22 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_integer_odd_p_annotation() { + eval(r#" + def test(x) = x.odd? + test(3) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Integer@0x1008, odd?@0x1010, cme:0x1018) + v22:Fixnum = GuardType v10, Fixnum + v24:BoolExact = InvokeBuiltin leaf <inline_expr>, v22 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_float_zero_p_annotation() { + eval(r#" + def test(x) = x.zero? + test(1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, zero?@0x1010, cme:0x1018) + v22:Flonum = GuardType v10, Flonum + v24:BoolExact = InvokeBuiltin leaf <inline_expr>, v22 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_float_positive_p_annotation() { + eval(r#" + def test(x) = x.positive? + test(1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, positive?@0x1010, cme:0x1018) + v22:Flonum = GuardType v10, Flonum + v24:BoolExact = InvokeBuiltin leaf <inline_expr>, v22 + CheckInterrupts + Return v24 + "); + } + + #[test] + fn test_float_negative_p_annotation() { + eval(r#" + def test(x) = x.negative? + test(-1.0) + "#); + assert_snapshot!(hir_string("test"), @" + fn test@<compiled>:2: + bb1(): + EntryPoint interpreter + v1:BasicObject = LoadSelf + v2:CPtr = LoadSP + v3:BasicObject = LoadField v2, :x@0x1000 + Jump bb3(v1, v3) + bb2(): + EntryPoint JIT(0) + v6:BasicObject = LoadArg :self@0 + v7:BasicObject = LoadArg :x@1 + Jump bb3(v6, v7) + bb3(v9:BasicObject, v10:BasicObject): + PatchPoint MethodRedefined(Float@0x1008, negative?@0x1010, cme:0x1018) + v22:Flonum = GuardType v10, Flonum + v24:BoolExact = InvokeBuiltin leaf <inline_expr>, v22 + CheckInterrupts + Return v24 + "); + } } |
