Classify Vars in patterns.
There's 4 classes of variables, depending on whether they have defs in the source and destination patterns. Add more XForm verification: In a legalize XForm, all source defs must be outputs. Fix a legalize pattern bug caught by this.
This commit is contained in:
@@ -2,9 +2,6 @@
|
|||||||
set -e
|
set -e
|
||||||
cd $(dirname "$0")
|
cd $(dirname "$0")
|
||||||
|
|
||||||
echo "=== Python unit tests ==="
|
|
||||||
python -m unittest discover
|
|
||||||
|
|
||||||
runif() {
|
runif() {
|
||||||
if command -v "$1" > /dev/null; then
|
if command -v "$1" > /dev/null; then
|
||||||
echo "=== $1 ==="
|
echo "=== $1 ==="
|
||||||
@@ -19,13 +16,17 @@ runif() {
|
|||||||
# Install pylint with 'pip install pylint'.
|
# Install pylint with 'pip install pylint'.
|
||||||
runif pylint --py3k --reports=no -- *.py cretonne isa
|
runif pylint --py3k --reports=no -- *.py cretonne isa
|
||||||
|
|
||||||
# Then run the unit tests again with Python 3.
|
|
||||||
# We get deprecation warnings about assertRaisesRegexp which was renamed in
|
|
||||||
# Python 3, but there doesn't seem to be an easy workaround.
|
|
||||||
runif python3 -Wignore:Deprecation -m unittest discover
|
|
||||||
|
|
||||||
# Style linting.
|
# Style linting.
|
||||||
runif flake8 .
|
runif flake8 .
|
||||||
|
|
||||||
# Type checking.
|
# Type checking.
|
||||||
runif mypy --py2 build.py
|
runif mypy --py2 build.py
|
||||||
|
|
||||||
|
echo "=== Python unit tests ==="
|
||||||
|
python -m unittest discover
|
||||||
|
|
||||||
|
# Then run the unit tests again with Python 3.
|
||||||
|
# We get deprecation warnings about assertRaisesRegexp which was renamed in
|
||||||
|
# Python 3, but there doesn't seem to be an easy workaround.
|
||||||
|
runif python3 -Wignore:Deprecation -m unittest discover
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,24 @@ class Expr(object):
|
|||||||
class Var(Expr):
|
class Var(Expr):
|
||||||
"""
|
"""
|
||||||
A free variable.
|
A free variable.
|
||||||
|
|
||||||
|
When variables are used in `XForms` with source ans destination patterns,
|
||||||
|
they are classified as follows:
|
||||||
|
|
||||||
|
Input values
|
||||||
|
Uses in the source pattern with no preceding def. These may appear as
|
||||||
|
inputs in the destination pattern too, but no new inputs can be
|
||||||
|
introduced.
|
||||||
|
Output values
|
||||||
|
Variables that are defined in both the source and destination pattern.
|
||||||
|
These values may have uses outside the source pattern, and the
|
||||||
|
destination pattern must compute the same value.
|
||||||
|
Intermediate values
|
||||||
|
Values that are defined in the source pattern, but not in the
|
||||||
|
destination pattern. These may have uses outside the source pattern, so
|
||||||
|
the defining instruction can't be deleted immediately.
|
||||||
|
Temporary values
|
||||||
|
Values that are defined only in the destination pattern.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
@@ -82,15 +100,42 @@ class Var(Expr):
|
|||||||
# See XForm._rewrite_defs().
|
# See XForm._rewrite_defs().
|
||||||
self.defctx = 0
|
self.defctx = 0
|
||||||
|
|
||||||
|
# Context bits for `defctx` indicating which pattern has defines of this
|
||||||
|
# var.
|
||||||
|
SRCCTX = 1
|
||||||
|
DSTCTX = 2
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
# type: () -> str
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
# type: () -> str
|
||||||
s = self.name
|
s = self.name
|
||||||
if self.defctx:
|
if self.defctx:
|
||||||
s += ", d={:02b}".format(self.defctx)
|
s += ", d={:02b}".format(self.defctx)
|
||||||
return "Var({})".format(s)
|
return "Var({})".format(s)
|
||||||
|
|
||||||
|
def is_input(self):
|
||||||
|
# type: () -> bool
|
||||||
|
"""Is this an input value to the source pattern?"""
|
||||||
|
return self.defctx == 0
|
||||||
|
|
||||||
|
def is_output(self):
|
||||||
|
"""Is this an output value, defined in both src and dest patterns?"""
|
||||||
|
# type: () -> bool
|
||||||
|
return self.defctx == self.SRCCTX | self.DSTCTX
|
||||||
|
|
||||||
|
def is_intermediate(self):
|
||||||
|
"""Is this an intermediate value, defined only in the src pattern?"""
|
||||||
|
# type: () -> bool
|
||||||
|
return self.defctx == self.SRCCTX
|
||||||
|
|
||||||
|
def is_temp(self):
|
||||||
|
"""Is this a temp value, defined only in the dest pattern?"""
|
||||||
|
# type: () -> bool
|
||||||
|
return self.defctx == self.DSTCTX
|
||||||
|
|
||||||
|
|
||||||
class Apply(Expr):
|
class Apply(Expr):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -114,5 +114,5 @@ expand.legalize(
|
|||||||
Rtl(
|
Rtl(
|
||||||
(a1, b1) << isub_bout(x, y),
|
(a1, b1) << isub_bout(x, y),
|
||||||
(a, b2) << isub_bout(a1, b_in),
|
(a, b2) << isub_bout(a1, b_in),
|
||||||
c << bor(b1, b2)
|
b << bor(b1, b2)
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
SRCCTX = 1
|
|
||||||
DSTCTX = 2
|
|
||||||
|
|
||||||
|
|
||||||
def canonicalize_defapply(node):
|
def canonicalize_defapply(node):
|
||||||
# type: (DefApply) -> Def
|
# type: (DefApply) -> Def
|
||||||
"""
|
"""
|
||||||
@@ -87,13 +83,13 @@ class XForm(object):
|
|||||||
# Rewrite variables in src and dst RTL lists to our own copies.
|
# Rewrite variables in src and dst RTL lists to our own copies.
|
||||||
# Map name -> private Var.
|
# Map name -> private Var.
|
||||||
symtab = dict() # type: Dict[str, Var]
|
symtab = dict() # type: Dict[str, Var]
|
||||||
self._rewrite_rtl(src, symtab, SRCCTX)
|
self._rewrite_rtl(src, symtab, Var.SRCCTX)
|
||||||
num_src_inputs = len(self.inputs)
|
num_src_inputs = len(self.inputs)
|
||||||
self._rewrite_rtl(dst, symtab, DSTCTX)
|
self._rewrite_rtl(dst, symtab, Var.DSTCTX)
|
||||||
|
|
||||||
# Check for inconsistently used inputs.
|
# Check for inconsistently used inputs.
|
||||||
for i in self.inputs:
|
for i in self.inputs:
|
||||||
if i.defctx:
|
if not i.is_input():
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
"'{}' used as both input and def".format(i))
|
"'{}' used as both input and def".format(i))
|
||||||
|
|
||||||
@@ -189,6 +185,22 @@ class XForm(object):
|
|||||||
self.inputs.append(var)
|
self.inputs.append(var)
|
||||||
yield var
|
yield var
|
||||||
|
|
||||||
|
def verify_legalize(self):
|
||||||
|
# type: () -> None
|
||||||
|
"""
|
||||||
|
Verify that this is a valid legalization XForm.
|
||||||
|
|
||||||
|
- The source pattern must describe a single instruction.
|
||||||
|
- All values defined in the output pattern must be defined in the
|
||||||
|
destination pattern.
|
||||||
|
"""
|
||||||
|
assert len(self.src.rtl) == 1, "Legalize needs single instruction."
|
||||||
|
defs, expr = self.src.rtl[0].defs_expr()
|
||||||
|
for d in defs:
|
||||||
|
if not d.is_output():
|
||||||
|
raise AssertionError(
|
||||||
|
'{} not defined in dest pattern'.format(d))
|
||||||
|
|
||||||
|
|
||||||
class XFormGroup(object):
|
class XFormGroup(object):
|
||||||
"""
|
"""
|
||||||
@@ -209,4 +221,6 @@ class XFormGroup(object):
|
|||||||
:param src: Single `Def` or `Apply` to be legalized.
|
:param src: Single `Def` or `Apply` to be legalized.
|
||||||
:param dst: `Rtl` list of replacement instructions.
|
:param dst: `Rtl` list of replacement instructions.
|
||||||
"""
|
"""
|
||||||
self.xforms.append(XForm(Rtl(src), dst))
|
xform = XForm(Rtl(src), dst)
|
||||||
|
xform.verify_legalize()
|
||||||
|
self.xforms.append(xform)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from cretonne.ast import Def, Apply # noqa
|
|||||||
from cretonne.xform import XForm, XFormGroup # noqa
|
from cretonne.xform import XForm, XFormGroup # noqa
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Union # noqa
|
from typing import Union
|
||||||
DefApply = Union[Def, Apply]
|
DefApply = Union[Def, Apply]
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user