summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris HasiƄski <krzysztof.hasinski@gmail.com>2026-04-12 13:56:45 +0200
committerTakashi Kokubun <takashikkbn@gmail.com>2026-04-14 14:04:52 -0700
commitedb95b13a3789617095f9c4f1d4b8e9bcee23344 (patch)
tree437e9dc4458d82bd69ec7dd79bf5c87608e48536
parent54527e24c8f08dd69bc07d7e3b6425ab101e7709 (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.yml12
-rw-r--r--benchmark/integer_predicate.yml9
-rw-r--r--zjit/src/hir/opt_tests.rs224
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
+ ");
+ }
}