From 15461c1e4b49d28633e4771d59bbfb05fa9b5ed3 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Thu, 12 Oct 2017 12:49:10 -0700 Subject: [PATCH] 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. --- cranelift/docs/metaref.rst | 3 +- lib/cretonne/meta/base/types.py | 15 +++++++- lib/cretonne/meta/cdsl/types.py | 16 +++++++++ lib/cretonne/meta/cdsl/typevar.py | 60 ++++++++++++++++++++++++------- lib/cretonne/meta/gen_types.py | 2 ++ lib/cretonne/src/ir/types.rs | 34 +++++++++++++----- lib/reader/src/lexer.rs | 14 ++++++-- misc/vim/syntax/cton.vim | 2 +- 8 files changed, 119 insertions(+), 27 deletions(-) diff --git a/cranelift/docs/metaref.rst b/cranelift/docs/metaref.rst index 209fa230d6..6f23647b0a 100644 --- a/cranelift/docs/metaref.rst +++ b/cranelift/docs/metaref.rst @@ -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: diff --git a/lib/cretonne/meta/base/types.py b/lib/cretonne/meta/base/types.py index 7111626009..b60ca3719f 100644 --- a/lib/cretonne/meta/base/types.py +++ b/lib/cretonne/meta/base/types.py @@ -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. + """) diff --git a/lib/cretonne/meta/cdsl/types.py b/lib/cretonne/meta/cdsl/types.py index 505c0a1b2b..3f2593fb78 100644 --- a/lib/cretonne/meta/cdsl/types.py +++ b/lib/cretonne/meta/cdsl/types.py @@ -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.""" diff --git a/lib/cretonne/meta/cdsl/typevar.py b/lib/cretonne/meta/cdsl/typevar.py index 0186ede5da..f818719a4d 100644 --- a/lib/cretonne/meta/cdsl/typevar.py +++ b/lib/cretonne/meta/cdsl/typevar.py @@ -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" diff --git a/lib/cretonne/meta/gen_types.py b/lib/cretonne/meta/gen_types.py index 42ccc1bfe7..c5e36758ba 100644 --- a/lib/cretonne/meta/gen_types.py +++ b/lib/cretonne/meta/gen_types.py @@ -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. diff --git a/lib/cretonne/src/ir/types.rs b/lib/cretonne/src/ir/types.rs index 7efeb55558..1a20f9e511 100644 --- a/lib/cretonne/src/ir/types.rs +++ b/lib/cretonne/src/ir/types.rs @@ -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"); diff --git a/lib/reader/src/lexer.rs b/lib/reader/src/lexer.rs index 357880ef4a..10cd9737af 100644 --- a/lib/reader/src/lexer.rs +++ b/lib/reader/src/lexer.rs @@ -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); } diff --git a/misc/vim/syntax/cton.vim b/misc/vim/syntax/cton.vim index 56602e8ded..6ccacae7fc 100644 --- a/misc/vim/syntax/cton.vim +++ b/misc/vim/syntax/cton.vim @@ -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 /\/ syn match ctonName /%\w\+\>/