Add insturction semantics. Add semantics for vsplit,vconcat,iadd. Add initial tests

This commit is contained in:
Dimo
2017-07-20 18:21:55 -07:00
committed by Jakob Stoklund Olesen
parent a12fa86e60
commit a5fe64440f
11 changed files with 797 additions and 6 deletions

View File

@@ -12,11 +12,12 @@ try:
from .ast import Expr, Apply, Var # noqa
from .typevar import TypeVar # noqa
from .ti import TypeConstraint # noqa
from .xform import XForm
# List of operands for ins/outs:
OpList = Union[Sequence[Operand], Operand]
ConstrList = Union[Sequence[TypeConstraint], TypeConstraint]
MaybeBoundInst = Union['Instruction', 'BoundInstruction']
VarTyping = Dict[Var, TypeVar]
InstructionSemantics = List[XForm]
except ImportError:
pass
@@ -119,6 +120,7 @@ class Instruction(object):
self.outs = self._to_operand_tuple(outs)
self.constraints = self._to_constraint_tuple(constraints)
self.format = InstructionFormat.lookup(self.ins, self.outs)
self.semantics = None # type: InstructionSemantics
# Opcode number, assigned by gen_instr.py.
self.number = None # type: int
@@ -334,6 +336,17 @@ class Instruction(object):
from .ast import Apply # noqa
return Apply(self, args)
def set_semantics(self, sem):
# type: (Union[XForm, InstructionSemantics]) -> None
"""Set our semantics."""
from semantics import verify_semantics
if not isinstance(sem, list):
sem = [sem]
verify_semantics(self, sem)
self.semantics = sem
class BoundInstruction(object):
"""

View File

@@ -54,8 +54,8 @@ class TypeConstraint(object):
"""
Return true iff all typevars in the constraint are singletons.
"""
tvs = filter(lambda x: isinstance(x, TypeVar), self._args())
return [] == list(filter(lambda x: x.singleton_type() is None, tvs))
return [] == list(filter(lambda x: x.singleton_type() is None,
self.tvs()))
def __hash__(self):
# type: () -> int
@@ -69,6 +69,13 @@ class TypeConstraint(object):
"""
assert False, "Abstract"
def tvs(self):
# type: () -> Iterable[TypeVar]
"""
Return the typevars contained in this constraint.
"""
return filter(lambda x: isinstance(x, TypeVar), self._args())
def is_trivial(self):
# type: () -> bool
"""
@@ -218,6 +225,47 @@ class WiderOrEq(TypeConstraint):
return typ1.wider_or_equal(typ2)
class SameWidth(TypeConstraint):
"""
Constraint specifying that two types have the same width. E.g. i32x2 has
the same width as i64x1, i16x4, f32x2, f64, b1x64 etc.
"""
def __init__(self, tv1, tv2):
# type: (TypeVar, TypeVar) -> None
self.tv1 = tv1
self.tv2 = tv2
def _args(self):
# type: () -> Tuple[Any,...]
""" See TypeConstraint._args() """
return (self.tv1, self.tv2)
def is_trivial(self):
# type: () -> bool
""" See TypeConstraint.is_trivial() """
# Trivially true
if (self.tv1 == self.tv2):
return True
ts1 = self.tv1.get_typeset()
ts2 = self.tv2.get_typeset()
# Trivially False
if len(ts1.widths().intersection(ts2.widths())) == 0:
return True
return self.is_concrete()
def eval(self):
# type: () -> bool
""" See TypeConstraint.eval() """
assert self.is_concrete()
typ1 = self.tv1.singleton_type()
typ2 = self.tv2.singleton_type()
return (typ1.width() == typ2.width())
class TypeEnv(object):
"""
Class encapsulating the neccessary book keeping for type inference.
@@ -537,6 +585,10 @@ class TypeEnv(object):
elif isinstance(constr, WiderOrEq):
assert constr.tv1 in nodes and constr.tv2 in nodes
edges.add((constr.tv1, constr.tv2, "dashed", "forward", ">="))
elif isinstance(constr, SameWidth):
assert constr.tv1 in nodes and constr.tv2 in nodes
edges.add((constr.tv1, constr.tv2, "dashed", "none",
"same_width"))
else:
assert False, "Can't display constraint {}".format(constr)

View File

@@ -59,6 +59,11 @@ class ValueType(object):
"""Return the number of lanes."""
assert False, "Abstract"
def width(self):
# type: () -> int
"""Return the total number of bits of an instance of this type."""
return self.lane_count() * self.lane_bits()
def wider_or_equal(self, other):
# type: (ValueType) -> bool
"""

View File

@@ -513,6 +513,13 @@ class TypeSet(object):
assert len(types) == 1
return types[0]
def widths(self):
# type: () -> Set[int]
""" Return a set of the widths of all possible types in self"""
scalar_w = self.ints.union(self.floats.union(self.bools))
scalar_w = scalar_w.union(self.bitvecs)
return set(w * l for l in self.lanes for w in scalar_w)
class TypeVar(object):
"""

View File

@@ -10,6 +10,8 @@ try:
from typing import Union, Iterator, Sequence, Iterable, List, Dict # noqa
from typing import Optional, Set # noqa
from .ast import Expr, VarMap # noqa
from .ti import TypeConstraint # noqa
from .typevar import TypeVar # noqa
DefApply = Union[Def, Apply]
except ImportError:
pass
@@ -89,7 +91,8 @@ class XForm(object):
An instruction transformation consists of a source and destination pattern.
Patterns are expressed in *register transfer language* as tuples of
`ast.Def` or `ast.Expr` nodes.
`ast.Def` or `ast.Expr` nodes. A pattern may optionally have a sequence of
TypeConstraints, that additionally limit the set of cases when it applies.
A legalization pattern must have a source pattern containing only a single
instruction.
@@ -111,8 +114,8 @@ class XForm(object):
)
"""
def __init__(self, src, dst):
# type: (Rtl, Rtl) -> None
def __init__(self, src, dst, constraints=None):
# type: (Rtl, Rtl, Optional[Sequence[TypeConstraint]]) -> None
self.src = src
self.dst = dst
# Variables that are inputs to the source pattern.
@@ -146,6 +149,18 @@ class XForm(object):
raw_ti.normalize()
self.ti = raw_ti.extract()
def interp_tv(tv):
# type: (TypeVar) -> TypeVar
""" Convert typevars according to symtab """
if not tv.name.startswith("typeof_"):
return tv
return symtab[tv.name[len("typeof_"):]].get_typevar()
if constraints is not None:
for c in constraints:
type_m = {tv: interp_tv(tv) for tv in c.tvs()}
self.ti.add_constraint(c.translate(type_m))
# Sanity: The set of inferred free typevars should be a subset of the
# TVs corresponding to Vars appearing in src
free_typevars = set(self.ti.free_typevars())