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:
Jakob Stoklund Olesen
2017-10-12 12:49:10 -07:00
parent dbaa919ca9
commit 15461c1e4b
8 changed files with 119 additions and 27 deletions

View File

@@ -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:

View File

@@ -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.
""")

View File

@@ -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."""

View File

@@ -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"

View File

@@ -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.

View File

@@ -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");

View File

@@ -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);
}

View File

@@ -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\+\>/