Rename Top to Any and Bottom to Empty
Top/Bottom can be unintuitive or ambiguous.
This commit is contained in:
parent
bbbf40de3f
commit
c5a93df555
Notes:
git
2025-04-18 13:48:22 +00:00
@ -43,13 +43,13 @@ end
|
||||
|
||||
# ===== Start generating the type DAG =====
|
||||
|
||||
# Start at Top. All types are subtypes of Top.
|
||||
top = Type.new "Top"
|
||||
# Start at Any. All types are subtypes of Any.
|
||||
any = Type.new "Any"
|
||||
# Build the Ruby object universe.
|
||||
object = top.subtype "Object"
|
||||
object = any.subtype "Object"
|
||||
object.subtype "ObjectExact"
|
||||
$object_user = object.subtype "ObjectUser"
|
||||
$user = top.subtype "User"
|
||||
$user = any.subtype "User"
|
||||
$builtin_exact = object.subtype "BuiltinExact"
|
||||
|
||||
# Define a new type that can be subclassed (most of them).
|
||||
@ -86,7 +86,7 @@ base_type "TrueClass"
|
||||
base_type "FalseClass"
|
||||
|
||||
# Build the primitive object universe.
|
||||
primitive = top.subtype "Primitive"
|
||||
primitive = any.subtype "Primitive"
|
||||
primitive.subtype "CBool"
|
||||
primitive.subtype "CPtr"
|
||||
primitive.subtype "CDouble"
|
||||
@ -101,9 +101,9 @@ unsigned = primitive_int.subtype "CUnsigned"
|
||||
|
||||
# Assign individual bits to type leaves and union bit patterns to nodes with subtypes
|
||||
num_bits = 0
|
||||
bits = {"Bottom" => ["0u64"]}
|
||||
numeric_bits = {"Bottom" => 0}
|
||||
Set[top, *top.all_subtypes].sort_by(&:name).each {|type|
|
||||
bits = {"Empty" => ["0u64"]}
|
||||
numeric_bits = {"Empty" => 0}
|
||||
Set[any, *any.all_subtypes].sort_by(&:name).each {|type|
|
||||
subtypes = type.subtypes
|
||||
if subtypes.empty?
|
||||
# Assign bits for leaves
|
||||
@ -115,7 +115,7 @@ Set[top, *top.all_subtypes].sort_by(&:name).each {|type|
|
||||
bits[type.name] = subtypes.map(&:name).sort
|
||||
end
|
||||
}
|
||||
[*top.all_subtypes, top].each {|type|
|
||||
[*any.all_subtypes, any].each {|type|
|
||||
subtypes = type.subtypes
|
||||
unless subtypes.empty?
|
||||
numeric_bits[type.name] = subtypes.map {|ty| numeric_bits[ty.name]}.reduce(&:|)
|
||||
|
12
zjit/src/hir_type.inc.rs
generated
12
zjit/src/hir_type.inc.rs
generated
@ -1,10 +1,10 @@
|
||||
// This file is @generated by src/gen_hir_type.rb.
|
||||
mod bits {
|
||||
pub const Any: u64 = Object | Primitive | User;
|
||||
pub const Array: u64 = ArrayExact | ArrayUser;
|
||||
pub const ArrayExact: u64 = 1u64 << 0;
|
||||
pub const ArrayUser: u64 = 1u64 << 1;
|
||||
pub const Bignum: u64 = 1u64 << 2;
|
||||
pub const Bottom: u64 = 0u64;
|
||||
pub const BuiltinExact: u64 = ArrayExact | FalseClassExact | FloatExact | HashExact | IntegerExact | NilClassExact | StringExact | SymbolExact | TrueClassExact;
|
||||
pub const CBool: u64 = 1u64 << 3;
|
||||
pub const CDouble: u64 = 1u64 << 4;
|
||||
@ -22,6 +22,7 @@ mod bits {
|
||||
pub const CUInt8: u64 = 1u64 << 14;
|
||||
pub const CUnsigned: u64 = CUInt16 | CUInt32 | CUInt64 | CUInt8;
|
||||
pub const DynamicSymbol: u64 = 1u64 << 15;
|
||||
pub const Empty: u64 = 0u64;
|
||||
pub const FalseClass: u64 = FalseClassExact | FalseClassUser;
|
||||
pub const FalseClassExact: u64 = 1u64 << 16;
|
||||
pub const FalseClassUser: u64 = 1u64 << 17;
|
||||
@ -51,13 +52,12 @@ mod bits {
|
||||
pub const Symbol: u64 = SymbolExact | SymbolUser;
|
||||
pub const SymbolExact: u64 = DynamicSymbol | StaticSymbol;
|
||||
pub const SymbolUser: u64 = 1u64 << 31;
|
||||
pub const Top: u64 = Object | Primitive | User;
|
||||
pub const TrueClass: u64 = TrueClassExact | TrueClassUser;
|
||||
pub const TrueClassExact: u64 = 1u64 << 32;
|
||||
pub const TrueClassUser: u64 = 1u64 << 33;
|
||||
pub const User: u64 = ArrayUser | FalseClassUser | FloatUser | HashUser | IntegerUser | NilClassUser | StringUser | SymbolUser | TrueClassUser;
|
||||
pub const AllBitPatterns: [(&'static str, u64); 56] = [
|
||||
("Top", Top),
|
||||
("Any", Any),
|
||||
("Object", Object),
|
||||
("ObjectUser", ObjectUser),
|
||||
("TrueClass", TrueClass),
|
||||
@ -112,17 +112,17 @@ mod bits {
|
||||
("Array", Array),
|
||||
("ArrayUser", ArrayUser),
|
||||
("ArrayExact", ArrayExact),
|
||||
("Bottom", Bottom),
|
||||
("Empty", Empty),
|
||||
];
|
||||
pub const NumTypeBits: u64 = 34;
|
||||
}
|
||||
pub mod types {
|
||||
use super::*;
|
||||
pub const Any: Type = Type::from_bits(bits::Any);
|
||||
pub const Array: Type = Type::from_bits(bits::Array);
|
||||
pub const ArrayExact: Type = Type::from_bits(bits::ArrayExact);
|
||||
pub const ArrayUser: Type = Type::from_bits(bits::ArrayUser);
|
||||
pub const Bignum: Type = Type::from_bits(bits::Bignum);
|
||||
pub const Bottom: Type = Type::from_bits(bits::Bottom);
|
||||
pub const BuiltinExact: Type = Type::from_bits(bits::BuiltinExact);
|
||||
pub const CBool: Type = Type::from_bits(bits::CBool);
|
||||
pub const CDouble: Type = Type::from_bits(bits::CDouble);
|
||||
@ -140,6 +140,7 @@ pub mod types {
|
||||
pub const CUInt8: Type = Type::from_bits(bits::CUInt8);
|
||||
pub const CUnsigned: Type = Type::from_bits(bits::CUnsigned);
|
||||
pub const DynamicSymbol: Type = Type::from_bits(bits::DynamicSymbol);
|
||||
pub const Empty: Type = Type::from_bits(bits::Empty);
|
||||
pub const FalseClass: Type = Type::from_bits(bits::FalseClass);
|
||||
pub const FalseClassExact: Type = Type::from_bits(bits::FalseClassExact);
|
||||
pub const FalseClassUser: Type = Type::from_bits(bits::FalseClassUser);
|
||||
@ -169,7 +170,6 @@ pub mod types {
|
||||
pub const Symbol: Type = Type::from_bits(bits::Symbol);
|
||||
pub const SymbolExact: Type = Type::from_bits(bits::SymbolExact);
|
||||
pub const SymbolUser: Type = Type::from_bits(bits::SymbolUser);
|
||||
pub const Top: Type = Type::from_bits(bits::Top);
|
||||
pub const TrueClass: Type = Type::from_bits(bits::TrueClass);
|
||||
pub const TrueClassExact: Type = Type::from_bits(bits::TrueClassExact);
|
||||
pub const TrueClassUser: Type = Type::from_bits(bits::TrueClassUser);
|
||||
|
@ -17,7 +17,7 @@ use crate::cruby::ClassRelationship;
|
||||
/// Type internals.
|
||||
pub enum Specialization {
|
||||
/// We know nothing about the specialization of this Type.
|
||||
Top,
|
||||
Any,
|
||||
/// We know that this Type is an instance of the given Ruby class in the VALUE or any of its subclasses.
|
||||
Type(VALUE),
|
||||
/// We know that this Type is an instance of exactly the Ruby class in the VALUE.
|
||||
@ -29,9 +29,9 @@ pub enum Specialization {
|
||||
Int(u64),
|
||||
/// We know that this Type is exactly the given primitive/C double.
|
||||
Double(f64),
|
||||
/// We know that the Type is [`types::Bottom`] and therefore the instruction that produces this
|
||||
/// We know that the Type is [`types::Empty`] and therefore the instruction that produces this
|
||||
/// value never returns.
|
||||
Bottom,
|
||||
Empty,
|
||||
}
|
||||
|
||||
// NOTE: Type very intentionally does not support Eq or PartialEq; we almost never want to check
|
||||
@ -47,8 +47,8 @@ pub enum Specialization {
|
||||
pub struct Type {
|
||||
/// A bitset representing type information about the object. Specific bits are assigned for
|
||||
/// leaf types (for example, static symbols) and union-ing bitsets together represents
|
||||
/// union-ing sets of types. These sets form a lattice (with Top as "could be anything" and
|
||||
/// Bottom as "can be nothing").
|
||||
/// union-ing sets of types. These sets form a lattice (with Any as "could be anything" and
|
||||
/// Empty as "can be nothing").
|
||||
///
|
||||
/// Capable of also representing primitive types (bool, i32, etc).
|
||||
///
|
||||
@ -76,7 +76,7 @@ fn get_class_name(class: Option<VALUE>) -> String {
|
||||
|
||||
fn write_spec(f: &mut std::fmt::Formatter, ty: Type) -> std::fmt::Result {
|
||||
match ty.spec {
|
||||
Specialization::Top | Specialization::Bottom => { Ok(()) },
|
||||
Specialization::Any | Specialization::Empty => { Ok(()) },
|
||||
Specialization::Object(val) => write!(f, "[{val}]"),
|
||||
Specialization::Type(val) => write!(f, "[class:{}]", get_class_name(Some(val))),
|
||||
Specialization::TypeExact(val) => write!(f, "[class_exact:{}]", get_class_name(Some(val))),
|
||||
@ -175,10 +175,10 @@ impl Type {
|
||||
const fn from_bits(bits: u64) -> Type {
|
||||
Type {
|
||||
bits,
|
||||
spec: if bits == bits::Bottom {
|
||||
Specialization::Bottom
|
||||
spec: if bits == bits::Empty {
|
||||
Specialization::Empty
|
||||
} else {
|
||||
Specialization::Top
|
||||
Specialization::Any
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -187,7 +187,7 @@ impl Type {
|
||||
/// `specialization` represents. For example, `Type::from_cint(types::CBool, 1)` or
|
||||
/// `Type::from_cint(types::CUInt16, 12)`.
|
||||
pub fn from_cint(ty: Type, val: i64) -> Type {
|
||||
assert_eq!(ty.spec, Specialization::Top);
|
||||
assert_eq!(ty.spec, Specialization::Any);
|
||||
assert!((ty.is_subtype(types::CUnsigned) || ty.is_subtype(types::CSigned)) &&
|
||||
ty.bits != types::CUnsigned.bits && ty.bits != types::CSigned.bits,
|
||||
"ty must be a specific int size");
|
||||
@ -302,10 +302,10 @@ impl Type {
|
||||
/// You probably want [`Type::is_subtype`] instead.
|
||||
fn spec_is_subtype_of(&self, other: Type) -> bool {
|
||||
match (self.spec, other.spec) {
|
||||
// Bottom is a subtype of everything; Top is a supertype of everything
|
||||
(Specialization::Bottom, _) | (_, Specialization::Top) => true,
|
||||
// Other is not Top from the previous case, so Top is definitely not a subtype
|
||||
(Specialization::Top, _) | (_, Specialization::Bottom) => false,
|
||||
// Empty is a subtype of everything; Any is a supertype of everything
|
||||
(Specialization::Empty, _) | (_, Specialization::Any) => true,
|
||||
// Other is not Any from the previous case, so Any is definitely not a subtype
|
||||
(Specialization::Any, _) | (_, Specialization::Empty) => false,
|
||||
// Int and double specialization requires exact equality
|
||||
(Specialization::Int(_), _) | (_, Specialization::Int(_)) |
|
||||
(Specialization::Double(_), _) | (_, Specialization::Double(_)) =>
|
||||
@ -348,27 +348,27 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bottom_is_subtype_of_everything() {
|
||||
fn empty_is_subtype_of_everything() {
|
||||
// Spot check a few cases
|
||||
assert_subtype(types::Bottom, types::NilClassExact);
|
||||
assert_subtype(types::Bottom, types::Array);
|
||||
assert_subtype(types::Bottom, types::Object);
|
||||
assert_subtype(types::Bottom, types::CUInt16);
|
||||
assert_subtype(types::Bottom, Type::from_cint(types::CInt32, 10));
|
||||
assert_subtype(types::Bottom, types::Top);
|
||||
assert_subtype(types::Bottom, types::Bottom);
|
||||
assert_subtype(types::Empty, types::NilClassExact);
|
||||
assert_subtype(types::Empty, types::Array);
|
||||
assert_subtype(types::Empty, types::Object);
|
||||
assert_subtype(types::Empty, types::CUInt16);
|
||||
assert_subtype(types::Empty, Type::from_cint(types::CInt32, 10));
|
||||
assert_subtype(types::Empty, types::Any);
|
||||
assert_subtype(types::Empty, types::Empty);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn everything_is_a_subtype_of_top() {
|
||||
fn everything_is_a_subtype_of_any() {
|
||||
// Spot check a few cases
|
||||
assert_subtype(types::NilClassExact, types::Top);
|
||||
assert_subtype(types::Array, types::Top);
|
||||
assert_subtype(types::Object, types::Top);
|
||||
assert_subtype(types::CUInt16, types::Top);
|
||||
assert_subtype(Type::from_cint(types::CInt32, 10), types::Top);
|
||||
assert_subtype(types::Bottom, types::Top);
|
||||
assert_subtype(types::Top, types::Top);
|
||||
assert_subtype(types::NilClassExact, types::Any);
|
||||
assert_subtype(types::Array, types::Any);
|
||||
assert_subtype(types::Object, types::Any);
|
||||
assert_subtype(types::CUInt16, types::Any);
|
||||
assert_subtype(Type::from_cint(types::CInt32, 10), types::Any);
|
||||
assert_subtype(types::Empty, types::Any);
|
||||
assert_subtype(types::Any, types::Any);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -499,7 +499,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn union_bits_unions_bits() {
|
||||
assert_bit_equal(types::Fixnum.union(types::StaticSymbol), Type { bits: bits::Fixnum | bits::StaticSymbol, spec: Specialization::Top });
|
||||
assert_bit_equal(types::Fixnum.union(types::StaticSymbol), Type { bits: bits::Fixnum | bits::StaticSymbol, spec: Specialization::Any });
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -517,8 +517,8 @@ mod tests {
|
||||
crate::cruby::with_rubyvm(|| {
|
||||
let specialized = Type::from_value(unsafe { rb_ary_new_capa(0) });
|
||||
let unspecialized = types::StringExact;
|
||||
assert_bit_equal(specialized.union(unspecialized), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Top });
|
||||
assert_bit_equal(unspecialized.union(specialized), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Top });
|
||||
assert_bit_equal(specialized.union(unspecialized), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Any });
|
||||
assert_bit_equal(unspecialized.union(specialized), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Any });
|
||||
});
|
||||
}
|
||||
|
||||
@ -571,7 +571,7 @@ mod tests {
|
||||
crate::cruby::with_rubyvm(|| {
|
||||
let string = Type::from_value(rust_str_to_ruby("hello"));
|
||||
let array = Type::from_value(unsafe { rb_ary_new_capa(0) });
|
||||
assert_bit_equal(string.union(array), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Top });
|
||||
assert_bit_equal(string.union(array), Type { bits: bits::ArrayExact | bits::StringExact, spec: Specialization::Any });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
use core::ffi::c_void;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{cruby::*, hir_type::{types::{Bottom, Fixnum}, Type}};
|
||||
use crate::{cruby::*, hir_type::{types::{Empty, Fixnum}, Type}};
|
||||
|
||||
/// Ephemeral state for profiling runtime information
|
||||
struct Profiler {
|
||||
@ -67,7 +67,7 @@ fn profile_operands(profiler: &mut Profiler, n: usize) {
|
||||
let mut types = if let Some(types) = payload.opnd_types.get(&profiler.insn_idx) {
|
||||
types.clone()
|
||||
} else {
|
||||
vec![Bottom; n]
|
||||
vec![Empty; n]
|
||||
};
|
||||
|
||||
for i in 0..n {
|
||||
|
Loading…
x
Reference in New Issue
Block a user