diff --git a/.gitignore b/.gitignore index 0ed3a9bc00b783501a6eea5b322c7b2e914d038f..ff664eac0e1e96201aba7422f2e35c26f30f171b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build .*.sw[po] +.sw[po] *~ *.pyc *.pyo diff --git a/doc/reference.rst b/doc/reference.rst index 83883dce5975171a91a357176bf305422bd3b7aa..1f19611d1df126967c8cdcf766c125c464bda2a9 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -50,6 +50,9 @@ optional. * `<float32>` declares `lhs` as a temporary variable, with shape given by the ranges of the `lhs` subscripts. (Note that in this case, the `lhs` subscripts must be pure inames, not expressions, for now.) + Instead of a concrete type, an empty set of angle brackets `<>` may be + given to indicate that type inference should figure out the type of the + temporary. * `[i,j|k,l]` specifies the inames within which this instruction is run. Independent copies of the inames `k` and `l` will be made for this diff --git a/loopy/__init__.py b/loopy/__init__.py index 3c72b50e431ca8e4d1ebe1a11a6664adcd346dea..d23cc67076a26581ebbe33eabe2a75ed46fa69f7 100644 --- a/loopy/__init__.py +++ b/loopy/__init__.py @@ -46,6 +46,9 @@ __all__ = ["ScalarArg", "ArrayArg", "ConstantArrayArg", "ImageArg", "LoopKernel" "precompute", "add_prefetch" ] +class infer_type: + pass + # }}} # {{{ dimension split diff --git a/loopy/codegen/expression.py b/loopy/codegen/expression.py index 7a32ac76256158209e9c4834b7366cffaf642756..fc28f1d7662a8db3914131550950f2a1a4f0b19d 100644 --- a/loopy/codegen/expression.py +++ b/loopy/codegen/expression.py @@ -8,6 +8,9 @@ from pymbolic.mapper import CombineMapper # {{{ type inference +class TypeInferenceFailure(RuntimeError): + pass + class TypeInferenceMapper(CombineMapper): def __init__(self, kernel, temporary_variables=None): self.kernel = kernel @@ -33,7 +36,7 @@ class TypeInferenceMapper(CombineMapper): pass else: if not result is other: - raise TypeError("nothing known about result of operation on " + raise TypeInferenceFailure("nothing known about result of operation on " "'%s' and '%s'" % (result, other)) return result @@ -60,14 +63,20 @@ class TypeInferenceMapper(CombineMapper): pass try: - return self.temporary_variables[expr.name].dtype + result = self.temporary_variables[expr.name].dtype except KeyError: pass + else: + from loopy import infer_type + if result is infer_type: + raise TypeInferenceFailure("attempted type inference on " + "variable requiring type inference") + return result if expr.name in self.kernel.all_inames(): return np.dtype(np.int16) # don't force single-precision upcast - raise RuntimeError("type inference: nothing known about '%s'" % expr.name) + raise TypeInferenceFailure("nothing known about '%s'" % expr.name) def map_lookup(self, expr): agg_result = self.rec(expr.aggregate) diff --git a/loopy/creation.py b/loopy/creation.py index 40df171be4787d123e406238724d0c2f84d18b3a..71806998f22d063d4a6d4ab3380084e6483998ce 100644 --- a/loopy/creation.py +++ b/loopy/creation.py @@ -96,6 +96,9 @@ def create_temporaries(knl): new_insns = [] new_temp_vars = knl.temporary_variables.copy() + from loopy.codegen.expression import TypeInferenceMapper + tim = TypeInferenceMapper(knl, new_temp_vars) + for insn in knl.instructions: from loopy.kernel import ( find_var_base_indices_and_shape_from_inames, @@ -104,6 +107,13 @@ def create_temporaries(knl): if insn.temp_var_type is not None: assignee_name = insn.get_assignee_var_name() + temp_var_type = insn.temp_var_type + from loopy import infer_type + if temp_var_type is infer_type: + # FIXME dependencies among type-inferred variables + # are not allowed yet. + temp_var_type = tim(insn.expression) + assignee_indices = [] from pymbolic.primitives import Variable for index_expr in insn.get_assignee_indices(): @@ -123,7 +133,7 @@ def create_temporaries(knl): new_temp_vars[assignee_name] = TemporaryVariable( name=assignee_name, - dtype=np.dtype(insn.temp_var_type), + dtype=temp_var_type, is_local=None, base_indices=base_indices, shape=shape) diff --git a/loopy/kernel.py b/loopy/kernel.py index 034e7b05541ae54e02a46223a118c8fd741b7daa..76ffe4ed41208e785fd034eb2c209cc6697d275f 100644 --- a/loopy/kernel.py +++ b/loopy/kernel.py @@ -293,6 +293,12 @@ class Instruction(Record): boostable_into=None, temp_var_type=None, duplicate_inames_and_tags=[]): + from loopy.symbolic import parse + if isinstance(assignee, str): + assignee = parse(assignee) + if isinstance(expression, str): + assignee = parse(expression) + assert isinstance(forced_iname_deps, set) assert isinstance(insn_deps, set) @@ -557,7 +563,7 @@ class LoopKernel(Record): "(?P<iname_deps_and_tags>[\s\w,:.]*)" "(?:\|(?P<duplicate_inames_and_tags>[\s\w,:.]*))?" "\])?" - "\s*(?:\<(?P<temp_var_type>.+?)\>)?" + "\s*(?:\<(?P<temp_var_type>.*?)\>)?" "\s*(?P<lhs>.+?)\s*(?<!\:)=\s*(?P<rhs>.+?)" "\s*?(?:\:\s*(?P<insn_deps>[\s\w,]+))?$" ) @@ -648,7 +654,11 @@ class LoopKernel(Record): duplicate_inames_and_tags = [] if groups["temp_var_type"] is not None: - temp_var_type = groups["temp_var_type"] + if groups["temp_var_type"]: + temp_var_type = np.dtype(groups["temp_var_type"]) + else: + from loopy import infer_type + temp_var_type = infer_type else: temp_var_type = None