Add insturction semantics. Add semantics for vsplit,vconcat,iadd. Add initial tests
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
a12fa86e60
commit
a5fe64440f
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
"""
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user