Documentation nits; Sematnics syntax cleanup

This commit is contained in:
Dimo
2017-07-21 16:46:20 -07:00
committed by Jakob Stoklund Olesen
parent 40c86d58b9
commit 9258283e14
10 changed files with 103 additions and 94 deletions

View File

@@ -2,11 +2,10 @@ from __future__ import absolute_import
from semantics.primitives import prim_to_bv, prim_from_bv, bvsplit, bvconcat,\ from semantics.primitives import prim_to_bv, prim_from_bv, bvsplit, bvconcat,\
bvadd bvadd
from .instructions import vsplit, vconcat, iadd from .instructions import vsplit, vconcat, iadd
from cdsl.xform import XForm, Rtl from cdsl.xform import Rtl
from cdsl.ast import Var from cdsl.ast import Var
from cdsl.typevar import TypeSet from cdsl.typevar import TypeSet
from cdsl.ti import InTypeset from cdsl.ti import InTypeset
import semantics.types # noqa
x = Var('x') x = Var('x')
y = Var('y') y = Var('y')
@@ -28,30 +27,32 @@ bvhi = Var('bvhi')
ScalarTS = TypeSet(lanes=(1, 1), ints=True, floats=True, bools=True) ScalarTS = TypeSet(lanes=(1, 1), ints=True, floats=True, bools=True)
vsplit.set_semantics( vsplit.set_semantics(
XForm(Rtl((lo, hi) << vsplit(x)), (lo, hi) << vsplit(x),
Rtl(bvx << prim_to_bv(x), Rtl(
(bvlo, bvhi) << bvsplit(bvx), bvx << prim_to_bv(x),
lo << prim_from_bv(bvlo), (bvlo, bvhi) << bvsplit(bvx),
hi << prim_from_bv(bvhi)))) lo << prim_from_bv(bvlo),
hi << prim_from_bv(bvhi)
))
vconcat.set_semantics( vconcat.set_semantics(
XForm(Rtl(x << vconcat(lo, hi)), x << vconcat(lo, hi),
Rtl(bvlo << prim_to_bv(lo), Rtl(
bvhi << prim_to_bv(hi), bvlo << prim_to_bv(lo),
bvx << bvconcat(bvlo, bvhi), bvhi << prim_to_bv(hi),
x << prim_from_bv(bvx)))) bvx << bvconcat(bvlo, bvhi),
x << prim_from_bv(bvx)
))
iadd.set_semantics([ iadd.set_semantics(
XForm(Rtl(a << iadd(x, y)), a << iadd(x, y),
Rtl(bvx << prim_to_bv(x), (Rtl(bvx << prim_to_bv(x),
bvy << prim_to_bv(y), bvy << prim_to_bv(y),
bva << bvadd(bvx, bvy), bva << bvadd(bvx, bvy),
a << prim_from_bv(bva)), a << prim_from_bv(bva)),
constraints=[InTypeset(x.get_typevar(), ScalarTS)]), [InTypeset(x.get_typevar(), ScalarTS)]),
XForm(Rtl(a << iadd(x, y)), Rtl((xlo, xhi) << vsplit(x),
Rtl((xlo, xhi) << vsplit(x), (ylo, yhi) << vsplit(y),
(ylo, yhi) << vsplit(y), alo << iadd(xlo, ylo),
alo << iadd(xlo, ylo), ahi << iadd(xhi, yhi),
ahi << iadd(xhi, yhi), a << vconcat(alo, ahi)))
a << vconcat(alo, ahi)))
])

View File

@@ -102,15 +102,17 @@ class Def(object):
def vars(self): def vars(self):
# type: () -> Set[Var] # type: () -> Set[Var]
""" Return the set of all Vars that appear in self""" """Return the set of all Vars in self that correspond to SSA values"""
return self.definitions().union(self.uses()) return self.definitions().union(self.uses())
def substitution(self, other, s): def substitution(self, other, s):
# type: (Def, VarMap) -> Optional[VarMap] # type: (Def, VarMap) -> Optional[VarMap]
""" """
If the Defs self and other agree structurally, return a variable If the Defs self and other agree structurally, return a variable
substitution to transform self ot other. Two Defs agree structurally substitution to transform self to other. Otherwise return None. Two
if the contained Apply's agree structurally. Defs agree structurally if there exists a Var substitution, that can
transform one into the other. See Apply.substitution() for more
details.
""" """
s = self.expr.substitution(other.expr, s) s = self.expr.substitution(other.expr, s)
@@ -378,7 +380,7 @@ class Apply(Expr):
def vars(self): def vars(self):
# type: () -> Set[Var] # type: () -> Set[Var]
""" Return the set of all Vars that appear in self""" """Return the set of all Vars in self that correspond to SSA values"""
res = set() res = set()
for i in self.inst.value_opnums: for i in self.inst.value_opnums:
arg = self.args[i] arg = self.args[i]
@@ -390,8 +392,8 @@ class Apply(Expr):
# type: (Apply, VarMap) -> Optional[VarMap] # type: (Apply, VarMap) -> Optional[VarMap]
""" """
If the application self and other agree structurally, return a variable If the application self and other agree structurally, return a variable
substitution to transform self ot other. Two applications agree substitution to transform self to other. Otherwise return None. Two
structurally if: applications agree structurally if:
1) They are over the same instruction 1) They are over the same instruction
2) Every Var v in self, maps to a single Var w in other. I.e for 2) Every Var v in self, maps to a single Var w in other. I.e for
each use of v in self, w is used in the corresponding place in each use of v in self, w is used in the corresponding place in

View File

@@ -9,15 +9,16 @@ try:
from typing import Union, Sequence, List, Tuple, Any, TYPE_CHECKING # noqa from typing import Union, Sequence, List, Tuple, Any, TYPE_CHECKING # noqa
from typing import Dict # noqa from typing import Dict # noqa
if TYPE_CHECKING: if TYPE_CHECKING:
from .ast import Expr, Apply, Var # noqa from .ast import Expr, Apply, Var, Def # noqa
from .typevar import TypeVar # noqa from .typevar import TypeVar # noqa
from .ti import TypeConstraint # noqa from .ti import TypeConstraint # noqa
from .xform import XForm from .xform import XForm, Rtl
# List of operands for ins/outs: # List of operands for ins/outs:
OpList = Union[Sequence[Operand], Operand] OpList = Union[Sequence[Operand], Operand]
ConstrList = Union[Sequence[TypeConstraint], TypeConstraint] ConstrList = Union[Sequence[TypeConstraint], TypeConstraint]
MaybeBoundInst = Union['Instruction', 'BoundInstruction'] MaybeBoundInst = Union['Instruction', 'BoundInstruction']
InstructionSemantics = List[XForm] InstructionSemantics = Sequence[XForm]
RtlCase = Union[Rtl, Tuple[Rtl, Sequence[TypeConstraint]]]
except ImportError: except ImportError:
pass pass
@@ -336,15 +337,23 @@ class Instruction(object):
from .ast import Apply # noqa from .ast import Apply # noqa
return Apply(self, args) return Apply(self, args)
def set_semantics(self, sem): def set_semantics(self, src, *dsts):
# type: (Union[XForm, InstructionSemantics]) -> None # type: (Union[Def, Apply], *RtlCase) -> None
"""Set our semantics.""" """Set our semantics."""
from semantics import verify_semantics from semantics import verify_semantics
from .xform import XForm, Rtl
if not isinstance(sem, list): sem = [] # type: List[XForm]
sem = [sem] for dst in dsts:
if isinstance(dst, Rtl):
sem.append(XForm(Rtl(src).copy({}), dst))
else:
assert isinstance(dst, tuple)
sem.append(XForm(Rtl(src).copy({}), dst[0],
constraints=dst[1]))
verify_semantics(self, Rtl(src), sem)
verify_semantics(self, sem)
self.semantics = sem self.semantics = sem

View File

@@ -89,10 +89,7 @@ class ScalarType(ValueType):
self._vectors = dict() # type: Dict[int, VectorType] self._vectors = dict() # type: Dict[int, VectorType]
# Assign numbers starting from 1. (0 is VOID). # Assign numbers starting from 1. (0 is VOID).
ValueType.all_scalars.append(self) ValueType.all_scalars.append(self)
# Numbers are only valid for Cretone types that get emitted to Rust. self.number = len(ValueType.all_scalars)
# This excludes BVTypes
self.number = len([x for x in ValueType.all_scalars
if not isinstance(x, BVType)])
assert self.number < 16, 'Too many scalar types' assert self.number < 16, 'Too many scalar types'
def __repr__(self): def __repr__(self):
@@ -249,7 +246,7 @@ class BoolType(ScalarType):
return self.bits return self.bits
class BVType(ScalarType): class BVType(ValueType):
"""A flat bitvector type. Used for semantics description only.""" """A flat bitvector type. Used for semantics description only."""
def __init__(self, bits): def __init__(self, bits):
@@ -268,7 +265,11 @@ class BVType(ScalarType):
@staticmethod @staticmethod
def with_bits(bits): def with_bits(bits):
# type: (int) -> BVType # type: (int) -> BVType
typ = ValueType.by_name('bv{:d}'.format(bits)) name = 'bv{:d}'.format(bits)
if name not in ValueType._registry:
return BVType(bits)
typ = ValueType.by_name(name)
if TYPE_CHECKING: if TYPE_CHECKING:
return cast(BVType, typ) return cast(BVType, typ)
else: else:
@@ -278,3 +279,8 @@ class BVType(ScalarType):
# type: () -> int # type: () -> int
"""Return the number of bits in a lane.""" """Return the number of bits in a lane."""
return self.bits return self.bits
def lane_count(self):
# type: () -> int
"""Return the number of lane. For BVtypes always 1."""
return 1

View File

@@ -501,7 +501,8 @@ class TypeSet(object):
for bits in self.bools: for bits in self.bools:
yield by(types.BoolType.with_bits(bits), nlanes) yield by(types.BoolType.with_bits(bits), nlanes)
for bits in self.bitvecs: for bits in self.bitvecs:
yield by(types.BVType.with_bits(bits), nlanes) assert nlanes == 1
yield types.BVType.with_bits(bits)
def get_singleton(self): def get_singleton(self):
# type: () -> types.ValueType # type: () -> types.ValueType
@@ -572,12 +573,17 @@ class TypeVar(object):
def singleton(typ): def singleton(typ):
# type: (types.ValueType) -> TypeVar # type: (types.ValueType) -> TypeVar
"""Create a type variable that can only assume a single type.""" """Create a type variable that can only assume a single type."""
scalar = None # type: ValueType
if isinstance(typ, types.VectorType): if isinstance(typ, types.VectorType):
scalar = typ.base scalar = typ.base
lanes = (typ.lanes, typ.lanes) lanes = (typ.lanes, typ.lanes)
elif isinstance(typ, types.ScalarType): elif isinstance(typ, types.ScalarType):
scalar = typ scalar = typ
lanes = (1, 1) lanes = (1, 1)
else:
assert isinstance(typ, types.BVType)
scalar = typ
lanes = (1, 1)
ints = None ints = None
floats = None floats = None

View File

@@ -55,7 +55,7 @@ class Rtl(object):
def vars(self): def vars(self):
# type: () -> Set[Var] # type: () -> Set[Var]
""" Return the set of all Vars that appear in self""" """Return the set of all Vars in self that correspond to SSA values"""
return reduce(lambda x, y: x.union(y), return reduce(lambda x, y: x.union(y),
[d.vars() for d in self.rtl], [d.vars() for d in self.rtl],
set([])) set([]))

View File

@@ -4,52 +4,45 @@ from cdsl.ti import TypeEnv, ti_rtl, get_type_env
try: try:
from typing import List, Dict, Tuple # noqa from typing import List, Dict, Tuple # noqa
from cdsl.ast import Var # noqa from cdsl.ast import Var # noqa
from cdsl.xform import XForm # noqa from cdsl.xform import XForm, Rtl # noqa
from cdsl.ti import VarTyping # noqa from cdsl.ti import VarTyping # noqa
from cdsl.instructions import Instruction, InstructionSemantics # noqa from cdsl.instructions import Instruction, InstructionSemantics # noqa
except ImportError: except ImportError:
pass pass
def verify_semantics(inst, sem): def verify_semantics(inst, src, xforms):
# type: (Instruction, InstructionSemantics) -> None # type: (Instruction, Rtl, InstructionSemantics) -> None
""" """
Verify that the semantics sem correctly describes the instruction inst. Verify that the semantics transforms in xforms correctly describe the
This involves checking that: instruction described by the src Rtl. This involves checking that:
1) For all XForms x \in sem, x.src consists of a single instance of 1) For all XForms x \in xforms, there is a Var substitution form src to
inst x.src
2) For any possible concrete typing of inst there is exactly 1 XForm x 2) For any possible concrete typing of src there is exactly 1 XForm x
in sem that applies. in xforms that applies.
""" """
# 1) The source rtl is always a single instance of inst. # 0) The source rtl is always a single instruction
for xform in sem: assert len(src.rtl) == 1
assert len(xform.src.rtl) == 1 and\
xform.src.rtl[0].expr.inst == inst,\ # 1) For all XForms x, x.src is structurally equivalent to src
"XForm {} doesn't describe instruction {}."\ for x in xforms:
.format(xform, inst) assert src.substitution(x.src, {}) is not None,\
"XForm {} doesn't describe instruction {}.".format(x, src)
# 2) Any possible typing for the instruction should be covered by # 2) Any possible typing for the instruction should be covered by
# exactly ONE semantic XForm # exactly ONE semantic XForm
inst_rtl = sem[0].src typenv = get_type_env(ti_rtl(src, TypeEnv()))
typenv = get_type_env(ti_rtl(inst_rtl, TypeEnv())) typenv.normalize()
typenv = typenv.extract()
# This bit is awkward. Concrete typing is defined in terms of the vars
# of one Rtl. We arbitrarily picked that Rtl to be sem[0].src. For any
# other XForms in sem, we must build a substitution form
# sem[0].src->sem[N].src, before we can check if sem[N] permits one of
# the concrete typings of our Rtl.
# TODO: Can this be made cleaner?
subst = [inst_rtl.substitution(x.src, {}) for x in sem]
assert not any(x is None for x in subst)
sub_sem = list(zip(subst, sem)) # type: List[Tuple[Dict[Var, Var], XForm]] # noqa
def subst_typing(typing, sub):
# type: (VarTyping, Dict[Var, Var]) -> VarTyping
return {sub[v]: tv for (v, tv) in typing.items()}
for t in typenv.concrete_typings(): for t in typenv.concrete_typings():
matching_xforms = [x for (s, x) in sub_sem matching_xforms = [] # type: List[XForm]
if x.ti.permits(subst_typing(t, s))] for x in xforms:
# Translate t using x.symtab
t = {x.symtab[str(v)]: tv for (v, tv) in t.items()}
if (x.ti.permits(t)):
matching_xforms.append(x)
assert len(matching_xforms) == 1,\ assert len(matching_xforms) == 1,\
("Possible typing {} of {} not matched by exactly one case " + ("Possible typing {} of {} not matched by exactly one case " +
": {}").format(t, inst, matching_xforms) ": {}").format(t, inst, matching_xforms)

View File

@@ -81,6 +81,7 @@ def find_matching_xform(d):
for x in d.expr.inst.semantics: for x in d.expr.inst.semantics:
subst = d.substitution(x.src.rtl[0], {}) subst = d.substitution(x.src.rtl[0], {})
assert subst is not None
if x.ti.permits({subst[v]: tv for (v, tv) in typing.items()}): if x.ti.permits({subst[v]: tv for (v, tv) in typing.items()}):
res.append(x) res.append(x)

View File

@@ -232,16 +232,16 @@ class TestElaborate(TestCase):
def test_elaborate_iadd_simple(self): def test_elaborate_iadd_simple(self):
# type: () -> None # type: () -> None
i32.by(2) # Make sure i32x2 exists. i32.by(2) # Make sure i32x2 exists.
r = Rtl(
self.v0 << iadd.i32(self.v1, self.v2),
)
sem = elaborate(cleanup_concrete_rtl(r))
x = Var('x') x = Var('x')
y = Var('y') y = Var('y')
a = Var('a') a = Var('a')
bvx = Var('bvx') bvx = Var('bvx')
bvy = Var('bvy') bvy = Var('bvy')
bva = Var('bva') bva = Var('bva')
r = Rtl(
a << iadd.i32(x, y),
)
sem = elaborate(cleanup_concrete_rtl(r))
assert concrete_rtls_eq(sem, cleanup_concrete_rtl(Rtl( assert concrete_rtls_eq(sem, cleanup_concrete_rtl(Rtl(
bvx << prim_to_bv.i32(x), bvx << prim_to_bv.i32(x),

View File

@@ -1,9 +0,0 @@
"""
The semantics.types module predefines all the Cretone primitive bitvector
types.
"""
from cdsl.types import BVType
from cdsl.typevar import MAX_BITVEC, int_log2
for width in range(0, int_log2(MAX_BITVEC)+1):
BVType(2**width)