moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
146
cranelift/codegen/meta-python/semantics/elaborate.py
Normal file
146
cranelift/codegen/meta-python/semantics/elaborate.py
Normal file
@@ -0,0 +1,146 @@
|
||||
"""
|
||||
Tools to elaborate a given Rtl with concrete types into its semantically
|
||||
equivalent primitive version. Its elaborated primitive version contains only
|
||||
primitive cranelift instructions, which map well to SMTLIB functions.
|
||||
"""
|
||||
from .primitives import GROUP as PRIMITIVES, prim_to_bv, prim_from_bv
|
||||
from cdsl.xform import Rtl
|
||||
from cdsl.ast import Var
|
||||
|
||||
try:
|
||||
from typing import TYPE_CHECKING, Dict, Union, List, Set, Tuple # noqa
|
||||
from cdsl.xform import XForm # noqa
|
||||
from cdsl.ast import Def, VarAtomMap # noqa
|
||||
from cdsl.ti import VarTyping # noqa
|
||||
except ImportError:
|
||||
TYPE_CHECKING = False
|
||||
|
||||
|
||||
def find_matching_xform(d):
|
||||
# type: (Def) -> XForm
|
||||
"""
|
||||
Given a concrete Def d, find the unique semantic XForm x in
|
||||
d.expr.inst.semantics that applies to it.
|
||||
"""
|
||||
res = [] # type: List[XForm]
|
||||
typing = {v: v.get_typevar() for v in d.vars()} # type: VarTyping
|
||||
|
||||
for x in d.expr.inst.semantics:
|
||||
subst = d.substitution(x.src.rtl[0], {})
|
||||
|
||||
# There may not be a substitution if there are concrete Enumerator
|
||||
# values in the src pattern. (e.g. specifying the semantics of icmp.eq,
|
||||
# icmp.ge... as separate transforms)
|
||||
if (subst is None):
|
||||
continue
|
||||
|
||||
inner_typing = {} # type: VarTyping
|
||||
for (v, tv) in typing.items():
|
||||
inner_v = subst[v]
|
||||
assert isinstance(inner_v, Var)
|
||||
inner_typing[inner_v] = tv
|
||||
|
||||
if x.ti.permits(inner_typing):
|
||||
res.append(x)
|
||||
|
||||
assert len(res) == 1, "Couldn't find semantic transform for {}".format(d)
|
||||
return res[0]
|
||||
|
||||
|
||||
def cleanup_semantics(r, outputs):
|
||||
# type: (Rtl, Set[Var]) -> Rtl
|
||||
"""
|
||||
The elaboration process creates a lot of redundant prim_to_bv conversions.
|
||||
Cleanup the following cases:
|
||||
|
||||
1) prim_to_bv/prim_from_bv pair:
|
||||
a.0 << prim_from_bv(bva.0)
|
||||
...
|
||||
bva.1 << prim_to_bv(a.0) <-- redundant, replace by bva.0
|
||||
...
|
||||
|
||||
2) prim_to_bv/prim_to-bv pair:
|
||||
bva.0 << prim_to_bv(a)
|
||||
...
|
||||
bva.1 << prim_to_bv(a) <-- redundant, replace by bva.0
|
||||
...
|
||||
"""
|
||||
new_defs = [] # type: List[Def]
|
||||
subst_m = {v: v for v in r.vars()} # type: VarAtomMap
|
||||
definition = {} # type: Dict[Var, Def]
|
||||
prim_to_bv_map = {} # type: Dict[Var, Def]
|
||||
|
||||
# Pass 1: Remove redundant prim_to_bv
|
||||
for d in r.rtl:
|
||||
inst = d.expr.inst
|
||||
|
||||
if (inst == prim_to_bv):
|
||||
arg = d.expr.args[0]
|
||||
df = d.defs[0]
|
||||
assert isinstance(arg, Var)
|
||||
|
||||
if arg in definition:
|
||||
def_loc = definition[arg]
|
||||
if def_loc.expr.inst == prim_from_bv:
|
||||
assert isinstance(def_loc.expr.args[0], Var)
|
||||
subst_m[df] = def_loc.expr.args[0]
|
||||
continue
|
||||
|
||||
if arg in prim_to_bv_map:
|
||||
subst_m[df] = prim_to_bv_map[arg].defs[0]
|
||||
continue
|
||||
|
||||
prim_to_bv_map[arg] = d
|
||||
|
||||
new_def = d.copy(subst_m)
|
||||
|
||||
for v in new_def.defs:
|
||||
assert v not in definition # Guaranteed by SSA
|
||||
definition[v] = new_def
|
||||
|
||||
new_defs.append(new_def)
|
||||
|
||||
# Pass 2: Remove dead prim_from_bv
|
||||
live = set(outputs) # type: Set[Var]
|
||||
for d in new_defs:
|
||||
live = live.union(d.uses())
|
||||
|
||||
new_defs = [d for d in new_defs if not (d.expr.inst == prim_from_bv and
|
||||
d.defs[0] not in live)]
|
||||
|
||||
return Rtl(*new_defs)
|
||||
|
||||
|
||||
def elaborate(r):
|
||||
# type: (Rtl) -> Rtl
|
||||
"""
|
||||
Given a concrete Rtl r, return a semantically equivalent Rtl r1 containing
|
||||
only primitive instructions.
|
||||
"""
|
||||
fp = False
|
||||
primitives = set(PRIMITIVES.instructions)
|
||||
idx = 0
|
||||
|
||||
res = Rtl(*r.rtl)
|
||||
outputs = res.definitions()
|
||||
|
||||
while not fp:
|
||||
assert res.is_concrete()
|
||||
new_defs = [] # type: List[Def]
|
||||
fp = True
|
||||
|
||||
for d in res.rtl:
|
||||
inst = d.expr.inst
|
||||
|
||||
if (inst not in primitives):
|
||||
t = find_matching_xform(d)
|
||||
transformed = t.apply(Rtl(d), str(idx))
|
||||
idx += 1
|
||||
new_defs.extend(transformed.rtl)
|
||||
fp = False
|
||||
else:
|
||||
new_defs.append(d)
|
||||
|
||||
res.rtl = tuple(new_defs)
|
||||
|
||||
return cleanup_semantics(res, outputs)
|
||||
Reference in New Issue
Block a user