Add two new value types: iflags and fflags.
These two value types represent the state of CPU flags after an integer comparison and a floating point comparison respectively. Instructions using these types TBD.
This commit is contained in:
@@ -166,7 +166,7 @@ Concrete value types are represented as instances of :class:`ValueType`. There
|
||||
are subclasses to represent scalar and vector types.
|
||||
|
||||
.. autoclass:: ValueType
|
||||
.. inheritance-diagram:: ValueType LaneType VectorType SpecialType IntType FloatType BoolType
|
||||
.. inheritance-diagram:: ValueType LaneType VectorType IntType FloatType BoolType SpecialType FlagsType
|
||||
:parts: 1
|
||||
.. autoclass:: LaneType
|
||||
:members:
|
||||
@@ -175,6 +175,7 @@ are subclasses to represent scalar and vector types.
|
||||
.. autoclass:: IntType
|
||||
.. autoclass:: FloatType
|
||||
.. autoclass:: BoolType
|
||||
.. autoclass:: FlagsType
|
||||
|
||||
.. automodule:: base.types
|
||||
:members:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The base.types module predefines all the Cretonne scalar types.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.types import IntType, FloatType, BoolType
|
||||
from cdsl.types import IntType, FloatType, BoolType, FlagsType
|
||||
|
||||
#: Boolean.
|
||||
b1 = BoolType(1) #: 1-bit bool. Type is abstract (can't be stored in mem)
|
||||
@@ -31,3 +31,16 @@ f64 = FloatType(
|
||||
*binary64* interchange format. This corresponds to the :c:type:`double`
|
||||
type in most C implementations.
|
||||
""")
|
||||
#: CPU flags from an integer comparison.
|
||||
iflags = FlagsType(
|
||||
'iflags', """
|
||||
CPU flags representing the result of an integer comparison. These flags
|
||||
can be tested with an `intcc` condition code.
|
||||
""")
|
||||
|
||||
#: CPU flags from a floating point comparison.
|
||||
fflags = FlagsType(
|
||||
'fflags', """
|
||||
CPU flags representing the result of a floating point comparison. These
|
||||
flags can be tested with a `floatcc` condition code.
|
||||
""")
|
||||
|
||||
@@ -287,6 +287,22 @@ class BoolType(LaneType):
|
||||
return self.bits
|
||||
|
||||
|
||||
class FlagsType(SpecialType):
|
||||
"""
|
||||
A type representing CPU flags.
|
||||
|
||||
Flags can't be stored in memory.
|
||||
"""
|
||||
|
||||
def __init__(self, name, doc):
|
||||
# type: (str, str) -> None
|
||||
super(FlagsType, self).__init__(name, 0, doc)
|
||||
|
||||
def __repr__(self):
|
||||
# type: () -> str
|
||||
return 'FlagsType({})'.format(self.name)
|
||||
|
||||
|
||||
class BVType(ValueType):
|
||||
"""A flat bitvector type. Used for semantics description only."""
|
||||
|
||||
|
||||
@@ -163,6 +163,9 @@ class TypeSet(object):
|
||||
>>> TypeSet(lanes=True, ints=True)
|
||||
TypeSet(lanes={1, 2, 4, 8, 16, 32, 64, 128, 256}, ints={8, 16, 32, 64})
|
||||
|
||||
Finally, a type set can contain special types (derived from `SpecialType`)
|
||||
which can't appear as lane types.
|
||||
|
||||
:param lanes: `(min, max)` inclusive range of permitted vector lane counts.
|
||||
:param ints: `(min, max)` inclusive range of permitted scalar integer
|
||||
widths.
|
||||
@@ -172,11 +175,19 @@ class TypeSet(object):
|
||||
widths.
|
||||
:param bitvecs : `(min, max)` inclusive range of permitted bitvector
|
||||
widths.
|
||||
:param specials: Sequence of speical types to appear in the set.
|
||||
"""
|
||||
|
||||
def __init__(self, lanes=None, ints=None, floats=None, bools=None,
|
||||
bitvecs=None):
|
||||
# type: (BoolInterval, BoolInterval, BoolInterval, BoolInterval, BoolInterval) -> None # noqa
|
||||
def __init__(
|
||||
self,
|
||||
lanes=None, # type: BoolInterval
|
||||
ints=None, # type: BoolInterval
|
||||
floats=None, # type: BoolInterval
|
||||
bools=None, # type: BoolInterval
|
||||
bitvecs=None, # type: BoolInterval
|
||||
specials=None # type: Iterable[types.SpecialType]
|
||||
):
|
||||
# type: (...) -> None
|
||||
self.lanes = interval_to_set(decode_interval(lanes, (1, MAX_LANES), 1))
|
||||
self.ints = interval_to_set(decode_interval(ints, (8, MAX_BITS)))
|
||||
self.floats = interval_to_set(decode_interval(floats, (32, 64)))
|
||||
@@ -184,6 +195,7 @@ class TypeSet(object):
|
||||
self.bools = set(filter(legal_bool, self.bools))
|
||||
self.bitvecs = interval_to_set(decode_interval(bitvecs,
|
||||
(1, MAX_BITVEC)))
|
||||
self.specials = set(specials) if specials else set()
|
||||
|
||||
def copy(self):
|
||||
# type: (TypeSet) -> TypeSet
|
||||
@@ -194,13 +206,14 @@ class TypeSet(object):
|
||||
return deepcopy(self)
|
||||
|
||||
def typeset_key(self):
|
||||
# type: () -> Tuple[Tuple, Tuple, Tuple, Tuple, Tuple]
|
||||
# type: () -> Tuple[Tuple, Tuple, Tuple, Tuple, Tuple, Tuple]
|
||||
"""Key tuple used for hashing and equality."""
|
||||
return (tuple(sorted(list(self.lanes))),
|
||||
tuple(sorted(list(self.ints))),
|
||||
tuple(sorted(list(self.floats))),
|
||||
tuple(sorted(list(self.bools))),
|
||||
tuple(sorted(list(self.bitvecs))))
|
||||
tuple(sorted(list(self.bitvecs))),
|
||||
tuple(sorted(list(self.specials))))
|
||||
|
||||
def __hash__(self):
|
||||
# type: () -> int
|
||||
@@ -231,6 +244,8 @@ class TypeSet(object):
|
||||
s += ', bools={}'.format(pp_set(self.bools))
|
||||
if len(self.bitvecs) > 0:
|
||||
s += ', bitvecs={}'.format(pp_set(self.bitvecs))
|
||||
if len(self.specials) > 0:
|
||||
s += ', specials=[{}]'.format(pp_set(self.specials))
|
||||
return s + ')'
|
||||
|
||||
def emit_fields(self, fmt):
|
||||
@@ -273,6 +288,7 @@ class TypeSet(object):
|
||||
self.floats.intersection_update(other.floats)
|
||||
self.bools.intersection_update(other.bools)
|
||||
self.bitvecs.intersection_update(other.bitvecs)
|
||||
self.specials.intersection_update(other.specials)
|
||||
|
||||
return self
|
||||
|
||||
@@ -481,8 +497,9 @@ class TypeSet(object):
|
||||
"""
|
||||
Return the number of concrete types represented by this typeset
|
||||
"""
|
||||
return len(self.lanes) * (len(self.ints) + len(self.floats) +
|
||||
len(self.bools) + len(self.bitvecs))
|
||||
return (len(self.lanes) * (len(self.ints) + len(self.floats) +
|
||||
len(self.bools) + len(self.bitvecs)) +
|
||||
len(self.specials))
|
||||
|
||||
def concrete_types(self):
|
||||
# type: () -> Iterable[types.ValueType]
|
||||
@@ -504,6 +521,9 @@ class TypeSet(object):
|
||||
assert nlanes == 1
|
||||
yield types.BVType.with_bits(bits)
|
||||
|
||||
for spec in self.specials:
|
||||
yield spec
|
||||
|
||||
def get_singleton(self):
|
||||
# type: () -> types.ValueType
|
||||
"""
|
||||
@@ -545,11 +565,20 @@ class TypeVar(object):
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, name, doc,
|
||||
ints=False, floats=False, bools=False,
|
||||
scalars=True, simd=False, bitvecs=False,
|
||||
base=None, derived_func=None):
|
||||
# type: (str, str, BoolInterval, BoolInterval, BoolInterval, bool, BoolInterval, BoolInterval, TypeVar, str) -> None # noqa
|
||||
self,
|
||||
name, # type: str
|
||||
doc, # type: str
|
||||
ints=False, # type: BoolInterval
|
||||
floats=False, # type: BoolInterval
|
||||
bools=False, # type: BoolInterval
|
||||
scalars=True, # type: bool
|
||||
simd=False, # type: BoolInterval
|
||||
bitvecs=False, # type: BoolInterval
|
||||
base=None, # type: TypeVar
|
||||
derived_func=None, # type: str
|
||||
specials=None # type: Iterable[types.SpecialType]
|
||||
):
|
||||
# type: (...) -> None
|
||||
self.name = name
|
||||
self.__doc__ = doc
|
||||
self.is_derived = isinstance(base, TypeVar)
|
||||
@@ -567,7 +596,8 @@ class TypeVar(object):
|
||||
ints=ints,
|
||||
floats=floats,
|
||||
bools=bools,
|
||||
bitvecs=bitvecs)
|
||||
bitvecs=bitvecs,
|
||||
specials=specials)
|
||||
|
||||
@staticmethod
|
||||
def singleton(typ):
|
||||
@@ -580,6 +610,8 @@ class TypeVar(object):
|
||||
elif isinstance(typ, types.LaneType):
|
||||
scalar = typ
|
||||
lanes = (1, 1)
|
||||
elif isinstance(typ, types.SpecialType):
|
||||
return TypeVar(typ.name, typ.__doc__, specials=[typ])
|
||||
else:
|
||||
assert isinstance(typ, types.BVType)
|
||||
scalar = typ
|
||||
@@ -681,6 +713,8 @@ class TypeVar(object):
|
||||
# Safety checks to avoid over/underflows.
|
||||
ts = base.get_typeset()
|
||||
|
||||
assert len(ts.specials) == 0, "Can't derive from special types"
|
||||
|
||||
if derived_func == TypeVar.HALFWIDTH:
|
||||
if len(ts.ints) > 0:
|
||||
assert min(ts.ints) > 8, "Can't halve all integer types"
|
||||
|
||||
@@ -45,6 +45,8 @@ def emit_vectors(bits, fmt):
|
||||
|
||||
def emit_types(fmt):
|
||||
# type: (srcgen.Formatter) -> None
|
||||
for spec in ValueType.all_special_types:
|
||||
emit_type(spec, fmt)
|
||||
for ty in ValueType.all_lane_types:
|
||||
emit_type(ty, fmt)
|
||||
# Emit vector definitions for common SIMD sizes.
|
||||
|
||||
@@ -272,9 +272,7 @@ impl Type {
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
if self.is_void() {
|
||||
write!(f, "void")
|
||||
} else if self.is_bool() {
|
||||
if self.is_bool() {
|
||||
write!(f, "b{}", self.lane_bits())
|
||||
} else if self.is_int() {
|
||||
write!(f, "i{}", self.lane_bits())
|
||||
@@ -283,16 +281,19 @@ impl Display for Type {
|
||||
} else if self.is_vector() {
|
||||
write!(f, "{}x{}", self.lane_type(), self.lane_count())
|
||||
} else {
|
||||
panic!("Invalid Type(0x{:x})", self.0)
|
||||
f.write_str(match *self {
|
||||
VOID => "void",
|
||||
IFLAGS => "iflags",
|
||||
FFLAGS => "fflags",
|
||||
_ => panic!("Invalid Type(0x{:x})", self.0),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Type {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
if self.is_void() {
|
||||
write!(f, "types::VOID")
|
||||
} else if self.is_bool() {
|
||||
if self.is_bool() {
|
||||
write!(f, "types::B{}", self.lane_bits())
|
||||
} else if self.is_int() {
|
||||
write!(f, "types::I{}", self.lane_bits())
|
||||
@@ -301,7 +302,12 @@ impl Debug for Type {
|
||||
} else if self.is_vector() {
|
||||
write!(f, "{:?}X{}", self.lane_type(), self.lane_count())
|
||||
} else {
|
||||
write!(f, "Type(0x{:x})", self.0)
|
||||
match *self {
|
||||
VOID => write!(f, "types::VOID"),
|
||||
IFLAGS => write!(f, "types::IFLAGS"),
|
||||
FFLAGS => write!(f, "types::FFLAGS"),
|
||||
_ => write!(f, "Type(0x{:x})", self.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -320,6 +326,10 @@ mod tests {
|
||||
fn basic_scalars() {
|
||||
assert_eq!(VOID, VOID.lane_type());
|
||||
assert_eq!(0, VOID.bits());
|
||||
assert_eq!(IFLAGS, IFLAGS.lane_type());
|
||||
assert_eq!(0, IFLAGS.bits());
|
||||
assert_eq!(FFLAGS, FFLAGS.lane_type());
|
||||
assert_eq!(0, FFLAGS.bits());
|
||||
assert_eq!(B1, B1.lane_type());
|
||||
assert_eq!(B8, B8.lane_type());
|
||||
assert_eq!(B16, B16.lane_type());
|
||||
@@ -333,6 +343,8 @@ mod tests {
|
||||
assert_eq!(F64, F64.lane_type());
|
||||
|
||||
assert_eq!(VOID.lane_bits(), 0);
|
||||
assert_eq!(IFLAGS.lane_bits(), 0);
|
||||
assert_eq!(FFLAGS.lane_bits(), 0);
|
||||
assert_eq!(B1.lane_bits(), 1);
|
||||
assert_eq!(B8.lane_bits(), 8);
|
||||
assert_eq!(B16.lane_bits(), 16);
|
||||
@@ -349,6 +361,8 @@ mod tests {
|
||||
#[test]
|
||||
fn typevar_functions() {
|
||||
assert_eq!(VOID.half_width(), None);
|
||||
assert_eq!(IFLAGS.half_width(), None);
|
||||
assert_eq!(FFLAGS.half_width(), None);
|
||||
assert_eq!(B1.half_width(), None);
|
||||
assert_eq!(B8.half_width(), None);
|
||||
assert_eq!(B16.half_width(), Some(B8));
|
||||
@@ -363,6 +377,8 @@ mod tests {
|
||||
assert_eq!(F64.half_width(), Some(F32));
|
||||
|
||||
assert_eq!(VOID.double_width(), None);
|
||||
assert_eq!(IFLAGS.double_width(), None);
|
||||
assert_eq!(FFLAGS.double_width(), None);
|
||||
assert_eq!(B1.double_width(), None);
|
||||
assert_eq!(B8.double_width(), Some(B16));
|
||||
assert_eq!(B16.double_width(), Some(B32));
|
||||
@@ -397,6 +413,8 @@ mod tests {
|
||||
#[test]
|
||||
fn format_scalars() {
|
||||
assert_eq!(VOID.to_string(), "void");
|
||||
assert_eq!(IFLAGS.to_string(), "iflags");
|
||||
assert_eq!(FFLAGS.to_string(), "fflags");
|
||||
assert_eq!(B1.to_string(), "b1");
|
||||
assert_eq!(B8.to_string(), "b8");
|
||||
assert_eq!(B16.to_string(), "b16");
|
||||
|
||||
@@ -303,7 +303,11 @@ impl<'a> Lexer<'a> {
|
||||
Self::value_type(text, prefix, number)
|
||||
})
|
||||
})
|
||||
.unwrap_or(Token::Identifier(text)),
|
||||
.unwrap_or_else(|| match text {
|
||||
"iflags" => Token::Type(types::IFLAGS),
|
||||
"fflags" => Token::Type(types::FFLAGS),
|
||||
_ => Token::Identifier(text),
|
||||
}),
|
||||
loc,
|
||||
)
|
||||
}
|
||||
@@ -554,7 +558,8 @@ mod tests {
|
||||
fn lex_identifiers() {
|
||||
let mut lex = Lexer::new(
|
||||
"v0 v00 vx01 ebb1234567890 ebb5234567890 v1x vx1 vxvx4 \
|
||||
function0 function b1 i32x4 f32x5",
|
||||
function0 function b1 i32x4 f32x5 \
|
||||
iflags fflags iflagss",
|
||||
);
|
||||
assert_eq!(
|
||||
lex.next(),
|
||||
@@ -573,8 +578,11 @@ mod tests {
|
||||
assert_eq!(lex.next(), token(Token::Identifier("function0"), 1));
|
||||
assert_eq!(lex.next(), token(Token::Identifier("function"), 1));
|
||||
assert_eq!(lex.next(), token(Token::Type(types::B1), 1));
|
||||
assert_eq!(lex.next(), token(Token::Type(types::I32.by(4).unwrap()), 1));
|
||||
assert_eq!(lex.next(), token(Token::Type(types::I32X4), 1));
|
||||
assert_eq!(lex.next(), token(Token::Identifier("f32x5"), 1));
|
||||
assert_eq!(lex.next(), token(Token::Type(types::IFLAGS), 1));
|
||||
assert_eq!(lex.next(), token(Token::Type(types::FFLAGS), 1));
|
||||
assert_eq!(lex.next(), token(Token::Identifier("iflagss"), 1));
|
||||
assert_eq!(lex.next(), None);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ syn keyword ctonHeader test isa set
|
||||
syn keyword ctonDecl function jump_table incoming_arg outgoing_arg spill_slot local emergency_slot
|
||||
syn keyword ctonFilecheck check sameln nextln unordered not regex contained
|
||||
|
||||
syn match ctonType /\<[bif]\d\+\(x\d\+\)\?\>/
|
||||
syn match ctonType /\<\([bif]\d\+\(x\d\+\)\?\)\|[if]flags\>/
|
||||
syn match ctonEntity /\<\(v\|ss\|jt\|fn\|sig\)\d\+\>/
|
||||
syn match ctonLabel /\<ebb\d+\>/
|
||||
syn match ctonName /%\w\+\>/
|
||||
|
||||
Reference in New Issue
Block a user