Handle bound instructions in pattern type inference (#113)

This commit is contained in:
d1m0
2017-07-11 08:39:22 -07:00
committed by Jakob Stoklund Olesen
parent fc11ae7b72
commit f837dcf4b7
2 changed files with 115 additions and 8 deletions

View File

@@ -1,8 +1,9 @@
from __future__ import absolute_import from __future__ import absolute_import
from base.instructions import vselect, vsplit, vconcat, iconst, iadd, bint,\ from base.instructions import vselect, vsplit, vconcat, iconst, iadd, bint,\
b1, icmp, iadd_cout, iadd_cin b1, icmp, iadd_cout, iadd_cin, uextend, ireduce
from base.legalize import narrow, expand from base.legalize import narrow, expand
from base.immediates import intcc from base.immediates import intcc
from base.types import i32, i8
from .typevar import TypeVar from .typevar import TypeVar
from .ast import Var, Def from .ast import Var, Def
from .xform import Rtl, XForm from .xform import Rtl, XForm
@@ -171,7 +172,7 @@ class TestRTL(TypeCheckingBaseTest):
) )
ti = TypeEnv() ti = TypeEnv()
self.assertEqual(ti_rtl(r, ti), self.assertEqual(ti_rtl(r, ti),
"On line 1: fail ti on `typeof_v2` <: `2`: " + "On line 1: fail ti on `typeof_v2` <: `1`: " +
"Error: empty type created when unifying " + "Error: empty type created when unifying " +
"`typeof_v2` and `half_vector(typeof_v2)`") "`typeof_v2` and `half_vector(typeof_v2)`")
@@ -303,6 +304,21 @@ class TestRTL(TypeCheckingBaseTest):
self.v0: itype, self.v0: itype,
}, [])) }, []))
def test_fully_bound_inst_inference_bad(self):
# Incompatible bound instructions fail accordingly
r = Rtl(
self.v3 << uextend.i32(self.v1),
self.v4 << uextend.i16(self.v2),
self.v5 << iadd(self.v3, self.v4),
)
ti = TypeEnv()
typing = ti_rtl(r, ti)
self.assertEqual(typing,
"On line 2: fail ti on `typeof_v4` <: `4`: " +
"Error: empty type created when unifying " +
"`typeof_v4` and `typeof_v5`")
class TestXForm(TypeCheckingBaseTest): class TestXForm(TypeCheckingBaseTest):
def test_iadd_cout(self): def test_iadd_cout(self):
@@ -414,3 +430,89 @@ class TestXForm(TypeCheckingBaseTest):
# xform # xform
for concrete_typing in concrete_typings_list: for concrete_typing in concrete_typings_list:
check_concrete_typing_xform(concrete_typing, xform) check_concrete_typing_xform(concrete_typing, xform)
def test_bound_inst_inference(self):
# First example from issue #26
x = XForm(
Rtl(
self.v0 << iadd(self.v1, self.v2),
),
Rtl(
self.v3 << uextend.i32(self.v1),
self.v4 << uextend.i32(self.v2),
self.v5 << iadd(self.v3, self.v4),
self.v0 << ireduce(self.v5)
))
itype = TypeVar("t", "", ints=True, simd=True)
i32t = TypeVar.singleton(i32)
check_typing(x.ti, ({
self.v0: itype,
self.v1: itype,
self.v2: itype,
self.v3: i32t,
self.v4: i32t,
self.v5: i32t,
}, []), x.symtab)
def test_bound_inst_inference1(self):
# Second example taken from issue #26
x = XForm(
Rtl(
self.v0 << iadd(self.v1, self.v2),
),
Rtl(
self.v3 << uextend(self.v1),
self.v4 << uextend(self.v2),
self.v5 << iadd.i32(self.v3, self.v4),
self.v0 << ireduce(self.v5)
))
itype = TypeVar("t", "", ints=True, simd=True)
i32t = TypeVar.singleton(i32)
check_typing(x.ti, ({
self.v0: itype,
self.v1: itype,
self.v2: itype,
self.v3: i32t,
self.v4: i32t,
self.v5: i32t,
}, []), x.symtab)
def test_fully_bound_inst_inference(self):
# Second example taken from issue #26 with complete bounds
x = XForm(
Rtl(
self.v0 << iadd(self.v1, self.v2),
),
Rtl(
self.v3 << uextend.i32.i8(self.v1),
self.v4 << uextend.i32.i8(self.v2),
self.v5 << iadd(self.v3, self.v4),
self.v0 << ireduce(self.v5)
))
i8t = TypeVar.singleton(i8)
i32t = TypeVar.singleton(i32)
check_typing(x.ti, ({
self.v0: i8t,
self.v1: i8t,
self.v2: i8t,
self.v3: i32t,
self.v4: i32t,
self.v5: i32t,
}, []), x.symtab)
def test_fully_bound_inst_inference_bad(self):
# Can't force a mistyped XForm using bound instructions
with self.assertRaises(AssertionError):
XForm(
Rtl(
self.v0 << iadd(self.v1, self.v2),
),
Rtl(
self.v3 << uextend.i32.i8(self.v1),
self.v4 << uextend.i32.i16(self.v2),
self.v5 << iadd(self.v3, self.v4),
self.v0 << ireduce(self.v5)
))

View File

@@ -606,14 +606,19 @@ def ti_def(definition, typ):
expr = definition.expr expr = definition.expr
inst = expr.inst inst = expr.inst
# Create a map m mapping each free typevar in the signature of definition # Create a dict m mapping each free typevar in the signature of definition
# to a fresh copy of itself # to a fresh copy of itself.
all_formal_tvs = \ if inst.is_polymorphic:
[inst.outs[i].typevar for i in inst.value_results] +\ free_formal_tvs = [inst.ctrl_typevar] + inst.other_typevars
[inst.ins[i].typevar for i in inst.value_opnums] else:
free_formal_tvs = [tv for tv in all_formal_tvs if not tv.is_derived] free_formal_tvs = []
m = {tv: tv.get_fresh_copy(str(typ.get_uid())) for tv in free_formal_tvs} m = {tv: tv.get_fresh_copy(str(typ.get_uid())) for tv in free_formal_tvs}
# Update m with any explicitly bound type vars
for (idx, bound_typ) in enumerate(expr.typevars):
m[free_formal_tvs[idx]] = TypeVar.singleton(bound_typ)
# Get fresh copies for each typevar in the signature (both free and # Get fresh copies for each typevar in the signature (both free and
# derived) # derived)
fresh_formal_tvs = \ fresh_formal_tvs = \