From 747dd508dfb97dbb48fbcaca28e19f4038c58914 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Fri, 26 Aug 2016 12:43:38 -0700 Subject: [PATCH] Generate type numbers at meta-time. We need to generate hash tables keyed by types, so the Python scripts need to know the index used to represent types in Rust code. To enforce this, add a new gen_types.py script which generates constant definitions for the ir/types module. Also generate constants for common SIMD vector sizes. --- meta/build.py | 2 ++ meta/cretonne/__init__.py | 19 +++++++++++--- meta/gen_types.py | 51 +++++++++++++++++++++++++++++++++++++ src/libcretonne/ir/types.rs | 44 +++++++++----------------------- 4 files changed, 80 insertions(+), 36 deletions(-) create mode 100644 meta/gen_types.py diff --git a/meta/build.py b/meta/build.py index 3ccbd49c0f..730d1c9b3f 100644 --- a/meta/build.py +++ b/meta/build.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import argparse import isa +import gen_types import gen_instr import gen_settings import gen_build_deps @@ -18,6 +19,7 @@ out_dir = args.out_dir isas = isa.all_isas() +gen_types.generate(out_dir) gen_instr.generate(isas, out_dir) gen_settings.generate(isas, out_dir) gen_encoding.generate(isas, out_dir) diff --git a/meta/cretonne/__init__.py b/meta/cretonne/__init__.py index bc20bcbcf3..324dc76b4b 100644 --- a/meta/cretonne/__init__.py +++ b/meta/cretonne/__init__.py @@ -6,6 +6,7 @@ instructions. """ from __future__ import absolute_import import re +import math import importlib from collections import namedtuple from .predicates import And @@ -279,9 +280,12 @@ class ValueType(object): or one of its subclasses. """ - # map name -> ValueType. + # Map name -> ValueType. _registry = dict() + # List of all the scalar types. + all_scalars = list() + def __init__(self, name, membytes, doc): self.name = name self.membytes = membytes @@ -321,6 +325,10 @@ class ScalarType(ValueType): def __init__(self, name, membytes, doc): super(ScalarType, self).__init__(name, membytes, doc) self._vectors = dict() + # Assign numbers starting from 1. (0 is VOID). + ValueType.all_scalars.append(self) + self.number = len(ValueType.all_scalars) + assert self.number < 16, 'Too many scalar types' def __repr__(self): return 'ScalarType({})'.format(self.name) @@ -356,10 +364,11 @@ class VectorType(ValueType): name='{}x{}'.format(base.name, lanes), membytes=lanes*base.membytes, doc=""" - A SIMD vector with {} lanes containing a {} each. + A SIMD vector with {} lanes containing a `{}` each. """.format(lanes, base.name)) self.base = base self.lanes = lanes + self.number = 16*int(math.log(lanes, 2)) + base.number def __repr__(self): return ('VectorType(base={}, lanes={})' @@ -386,8 +395,10 @@ class FloatType(ScalarType): def __init__(self, bits, doc): assert bits > 0, 'FloatType must have positive number of bits' - super(FloatType, self).__init__(name='f{:d}'.format(bits), - membytes=bits // 8, doc=doc) + super(FloatType, self).__init__( + name='f{:d}'.format(bits), + membytes=bits // 8, + doc=doc) self.bits = bits def __repr__(self): diff --git a/meta/gen_types.py b/meta/gen_types.py new file mode 100644 index 0000000000..51607a61f9 --- /dev/null +++ b/meta/gen_types.py @@ -0,0 +1,51 @@ +""" +Generate sources with type info. + +This generates a `types.rs` file which is included in +`libcretonne/ir/types/rs`. The file provides constant definitions for the most +commonly used types, including all of the scalar types. + +This ensures that Python and Rust use the same type numbering. +""" +from __future__ import absolute_import +import srcgen +from cretonne import ValueType + + +def emit_type(ty, fmt): + """ + Emit a constant definition of a single value type. + """ + name = ty.name.upper() + fmt.doc_comment(ty.__doc__) + fmt.line( + 'pub const {}: Type = Type({:#x});' + .format(name, ty.number)) + + +def emit_vectors(bits, fmt): + """ + Emit definition for all vector types with `bits` total size. + """ + size = bits // 8 + for ty in ValueType.all_scalars: + mb = ty.membytes + if mb == 0 or mb >= size: + continue + emit_type(ty.by(size // mb), fmt) + + +def emit_types(fmt): + for ty in ValueType.all_scalars: + emit_type(ty, fmt) + # Emit vector definitions for common SIMD sizes. + emit_vectors(64, fmt) + emit_vectors(128, fmt) + emit_vectors(256, fmt) + emit_vectors(512, fmt) + + +def generate(out_dir): + fmt = srcgen.Formatter() + emit_types(fmt) + fmt.update_file('types.rs', out_dir) diff --git a/src/libcretonne/ir/types.rs b/src/libcretonne/ir/types.rs index 1bc0d0a0b4..12dfc8c6ec 100644 --- a/src/libcretonne/ir/types.rs +++ b/src/libcretonne/ir/types.rs @@ -31,38 +31,9 @@ pub struct Type(u8); /// a SIMD vector. pub const VOID: Type = Type(0); -/// Integer type with 8 bits. -pub const I8: Type = Type(1); - -/// Integer type with 16 bits. -pub const I16: Type = Type(2); - -/// Integer type with 32 bits. -pub const I32: Type = Type(3); - -/// Integer type with 64 bits. -pub const I64: Type = Type(4); - -/// IEEE single precision floating point type. -pub const F32: Type = Type(5); - -/// IEEE double precision floating point type. -pub const F64: Type = Type(6); - -/// Boolean type. Can't be loaded or stored, but can be used to form SIMD vectors. -pub const B1: Type = Type(7); - -/// Boolean type using 8 bits to represent true/false. -pub const B8: Type = Type(8); - -/// Boolean type using 16 bits to represent true/false. -pub const B16: Type = Type(9); - -/// Boolean type using 32 bits to represent true/false. -pub const B32: Type = Type(10); - -/// Boolean type using 64 bits to represent true/false. -pub const B64: Type = Type(11); +// Include code generated by `meta/gen_types.py`. This file contains constant definitions for all +// the scalar types as well as common vector types for 64, 128, 256, and 512-bit SID vectors. +include!(concat!(env!("OUT_DIR"), "/types.rs")); impl Type { /// Get the lane type of this SIMD vector type. @@ -183,6 +154,11 @@ impl Type { Some(Type(self.0 - 0x10)) } } + + /// Index of this type, for use with hash tables etc. + pub fn index(self) -> usize { + self.0 as usize + } } impl Display for Type { @@ -362,6 +338,10 @@ mod tests { assert_eq!(B1.by(2).unwrap().half_vector().unwrap().to_string(), "b1"); assert_eq!(I32.half_vector(), None); assert_eq!(VOID.half_vector(), None); + + // Check that the generated constants match the computed vector types. + assert_eq!(I32.by(4), Some(I32X4)); + assert_eq!(F64.by(8), Some(F64X8)); } #[test]