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.
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
51
meta/gen_types.py
Normal file
51
meta/gen_types.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user