Skip to content

Commit 1ca0660

Browse files
authored
ZJIT: Add Type::has_value method (ruby#15867)
Resolves TODO added in ruby#15863 (See ruby#15863 (comment)) Adds a method `Type::has_value` for comparing value specialized types with a `Const`.
1 parent b8566fa commit 1ca0660

File tree

2 files changed

+100
-8
lines changed

2 files changed

+100
-8
lines changed

zjit/src/hir.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3812,14 +3812,11 @@ impl Function {
38123812
}
38133813
}
38143814
Insn::GuardBitEquals { val, expected, .. } => {
3815-
match self.find(val) {
3816-
// TODO: Refactor this into a more general method like
3817-
// has_value(Const) that can check on the value specialization
3818-
// of the Type instead
3819-
Insn::Const { val: const_val } if const_val == expected => {
3820-
continue;
3821-
}
3822-
_ => insn_id
3815+
let recv_type = self.type_of(val);
3816+
if recv_type.has_value(expected) {
3817+
continue;
3818+
} else {
3819+
insn_id
38233820
}
38243821
}
38253822
Insn::AnyToString { str, .. } if self.is_a(str, types::String) => {

zjit/src/hir_type/mod.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,25 @@ impl Type {
335335
self.is_subtype(types::NilClass) || self.is_subtype(types::FalseClass)
336336
}
337337

338+
pub fn has_value(&self, val: Const) -> bool {
339+
match (self.spec, val) {
340+
(Specialization::Object(v1), Const::Value(v2)) => v1 == v2,
341+
(Specialization::Int(v1), Const::CBool(v2)) if self.is_subtype(types::CBool) => v1 == (v2 as u64),
342+
(Specialization::Int(v1), Const::CInt8(v2)) if self.is_subtype(types::CInt8) => v1 == (v2 as u64),
343+
(Specialization::Int(v1), Const::CInt16(v2)) if self.is_subtype(types::CInt16) => v1 == (v2 as u64),
344+
(Specialization::Int(v1), Const::CInt32(v2)) if self.is_subtype(types::CInt32) => v1 == (v2 as u64),
345+
(Specialization::Int(v1), Const::CInt64(v2)) if self.is_subtype(types::CInt64) => v1 == (v2 as u64),
346+
(Specialization::Int(v1), Const::CUInt8(v2)) if self.is_subtype(types::CUInt8) => v1 == (v2 as u64),
347+
(Specialization::Int(v1), Const::CUInt16(v2)) if self.is_subtype(types::CUInt16) => v1 == (v2 as u64),
348+
(Specialization::Int(v1), Const::CUInt32(v2)) if self.is_subtype(types::CUInt32) => v1 == (v2 as u64),
349+
(Specialization::Int(v1), Const::CShape(v2)) if self.is_subtype(types::CShape) => v1 == (v2.0 as u64),
350+
(Specialization::Int(v1), Const::CUInt64(v2)) if self.is_subtype(types::CUInt64) => v1 == v2,
351+
(Specialization::Int(v1), Const::CPtr(v2)) if self.is_subtype(types::CPtr) => v1 == (v2 as u64),
352+
(Specialization::Double(v1), Const::CDouble(v2)) => v1.to_bits() == v2.to_bits(),
353+
_ => false,
354+
}
355+
}
356+
338357
/// Return the object specialization, if any.
339358
pub fn ruby_object(&self) -> Option<VALUE> {
340359
match self.spec {
@@ -958,4 +977,80 @@ mod tests {
958977
assert_bit_equal(d_instance.union(c_instance), Type { bits: bits::ObjectSubclass, spec: Specialization::Type(c_class)});
959978
});
960979
}
980+
981+
#[test]
982+
fn has_value() {
983+
// With known values
984+
crate::cruby::with_rubyvm(|| {
985+
let a = rust_str_to_sym("a");
986+
let b = rust_str_to_sym("b");
987+
let ty = Type::from_value(a);
988+
assert!(ty.has_value(Const::Value(a)));
989+
assert!(!ty.has_value(Const::Value(b)));
990+
});
991+
992+
let true_ty = Type::from_cbool(true);
993+
assert!(true_ty.has_value(Const::CBool(true)));
994+
assert!(!true_ty.has_value(Const::CBool(false)));
995+
996+
let int8_ty = Type::from_cint(types::CInt8, 42);
997+
assert!(int8_ty.has_value(Const::CInt8(42)));
998+
assert!(!int8_ty.has_value(Const::CInt8(-1)));
999+
let neg_int8_ty = Type::from_cint(types::CInt8, -1);
1000+
assert!(neg_int8_ty.has_value(Const::CInt8(-1)));
1001+
1002+
let int16_ty = Type::from_cint(types::CInt16, 1000);
1003+
assert!(int16_ty.has_value(Const::CInt16(1000)));
1004+
assert!(!int16_ty.has_value(Const::CInt16(2000)));
1005+
1006+
let int32_ty = Type::from_cint(types::CInt32, 100000);
1007+
assert!(int32_ty.has_value(Const::CInt32(100000)));
1008+
assert!(!int32_ty.has_value(Const::CInt32(-100000)));
1009+
1010+
let int64_ty = Type::from_cint(types::CInt64, i64::MAX);
1011+
assert!(int64_ty.has_value(Const::CInt64(i64::MAX)));
1012+
assert!(!int64_ty.has_value(Const::CInt64(0)));
1013+
1014+
let uint8_ty = Type::from_cint(types::CUInt8, u8::MAX as i64);
1015+
assert!(uint8_ty.has_value(Const::CUInt8(u8::MAX)));
1016+
assert!(!uint8_ty.has_value(Const::CUInt8(0)));
1017+
1018+
let uint16_ty = Type::from_cint(types::CUInt16, u16::MAX as i64);
1019+
assert!(uint16_ty.has_value(Const::CUInt16(u16::MAX)));
1020+
assert!(!uint16_ty.has_value(Const::CUInt16(1)));
1021+
1022+
let uint32_ty = Type::from_cint(types::CUInt32, u32::MAX as i64);
1023+
assert!(uint32_ty.has_value(Const::CUInt32(u32::MAX)));
1024+
assert!(!uint32_ty.has_value(Const::CUInt32(42)));
1025+
1026+
let uint64_ty = Type::from_cint(types::CUInt64, i64::MAX);
1027+
assert!(uint64_ty.has_value(Const::CUInt64(i64::MAX as u64)));
1028+
assert!(!uint64_ty.has_value(Const::CUInt64(123)));
1029+
1030+
let shape_ty = Type::from_cint(types::CShape, 0x1234);
1031+
assert!(shape_ty.has_value(Const::CShape(crate::cruby::ShapeId(0x1234))));
1032+
assert!(!shape_ty.has_value(Const::CShape(crate::cruby::ShapeId(0x5678))));
1033+
1034+
let ptr = 0x1000 as *const u8;
1035+
let ptr_ty = Type::from_cptr(ptr);
1036+
assert!(ptr_ty.has_value(Const::CPtr(ptr)));
1037+
assert!(!ptr_ty.has_value(Const::CPtr(0x2000 as *const u8)));
1038+
1039+
let double_ty = Type::from_double(std::f64::consts::PI);
1040+
assert!(double_ty.has_value(Const::CDouble(std::f64::consts::PI)));
1041+
assert!(!double_ty.has_value(Const::CDouble(3.123)));
1042+
1043+
let nan_ty = Type::from_double(f64::NAN);
1044+
assert!(nan_ty.has_value(Const::CDouble(f64::NAN)));
1045+
1046+
// Mismatched types
1047+
assert!(!int8_ty.has_value(Const::CInt16(42)));
1048+
assert!(!int16_ty.has_value(Const::CInt32(1000)));
1049+
assert!(!uint8_ty.has_value(Const::CInt8(-1i8)));
1050+
1051+
// Wrong specialization (unknown value)
1052+
assert!(!types::CInt8.has_value(Const::CInt8(42)));
1053+
assert!(!types::CBool.has_value(Const::CBool(true)));
1054+
assert!(!types::CShape.has_value(Const::CShape(crate::cruby::ShapeId(0x1234))));
1055+
}
9611056
}

0 commit comments

Comments
 (0)