diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index 94b31df12dae516d3539438b7e4ed66ed765e697..e1941122d12577ff6cdeae5185ac40241a080d96 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -346,6 +346,14 @@ class TemporaryVariable(ArrayBase): A :class:`bool` indicating whether the variable may be written during its lifetime. If *True*, *initializer* must be given. + + .. attribute:: _base_storage_access_may_be_aliasing + + Whether the temporary is used to alias the underlying base storage. + Defaults to *False*. If *False*, C-based code generators will declare + the temporary as a ``restrict`` const pointer to the base storage + memory location. If *True*, the restrict part is omitted on this + declaration. """ min_target_axes = 0 @@ -358,12 +366,14 @@ class TemporaryVariable(ArrayBase): "base_storage", "initializer", "read_only", + "_base_storage_access_may_be_aliasing", ] def __init__(self, name, dtype=None, shape=(), scope=auto, dim_tags=None, offset=0, dim_names=None, strides=None, order=None, base_indices=None, storage_shape=None, - base_storage=None, initializer=None, read_only=False, **kwargs): + base_storage=None, initializer=None, read_only=False, + _base_storage_access_may_be_aliasing=False, **kwargs): """ :arg dtype: :class:`loopy.auto` or a :class:`numpy.dtype` :arg shape: :class:`loopy.auto` or a shape tuple @@ -419,6 +429,13 @@ class TemporaryVariable(ArrayBase): "mutually exclusive" % name) + if base_storage is None and _base_storage_access_may_be_aliasing: + raise LoopyError( + "temporary variable '%s': " + "_base_storage_access_may_be_aliasing option, but no " + "base_storage given!" + % name) + ArrayBase.__init__(self, name=intern(name), dtype=dtype, shape=shape, dim_tags=dim_tags, offset=offset, dim_names=dim_names, @@ -428,6 +445,8 @@ class TemporaryVariable(ArrayBase): base_storage=base_storage, initializer=initializer, read_only=read_only, + _base_storage_access_may_be_aliasing=( + _base_storage_access_may_be_aliasing), **kwargs) @property @@ -489,7 +508,10 @@ class TemporaryVariable(ArrayBase): and ( (self.initializer is None and other.initializer is None) or np.array_equal(self.initializer, other.initializer)) - and self.read_only == other.read_only) + and self.read_only == other.read_only + and (self._base_storage_access_may_be_aliasing + == other._base_storage_access_may_be_aliasing) + ) def update_persistent_hash(self, key_hash, key_builder): """Custom hash computation function for use with diff --git a/loopy/target/c/__init__.py b/loopy/target/c/__init__.py index a2ad682505bbdb7ed5977a28e201ebc6655c7784..90f45ed4d205cf40d2d13df891aa1a7b38c25411 100644 --- a/loopy/target/c/__init__.py +++ b/loopy/target/c/__init__.py @@ -307,6 +307,12 @@ class _ConstRestrictPointer(Pointer): return sub_tp, ("*const __restrict__ %s" % sub_decl) +class _ConstPointer(Pointer): + def get_decl_pait(self): + sub_tp, sub_decl = self.subdecl.get_decl_pair() + return sub_tp, ("*const %s" % sub_decl) + + class CASTBuilder(ASTBuilderBase): # {{{ library @@ -462,13 +468,17 @@ class CASTBuilder(ASTBuilderBase): temp_var_decl = self.wrap_temporary_decl( temp_var_decl, tv.scope) - # The 'restrict' part of this is a complete lie--of course - # all these temporaries are aliased. But we're promising to - # not use them to shovel data from one representation to the - # other. That counts, right? - - cast_decl = _ConstRestrictPointer(cast_decl) - temp_var_decl = _ConstRestrictPointer(temp_var_decl) + if tv._base_storage_access_may_be_aliasing: + ptrtype = _ConstPointer + else: + # The 'restrict' part of this is a complete lie--of course + # all these temporaries are aliased. But we're promising to + # not use them to shovel data from one representation to the + # other. That counts, right? + ptrtype = _ConstRestrictPointer + + cast_decl = ptrtype(cast_decl) + temp_var_decl = ptrtype(temp_var_decl) cast_tp, cast_d = cast_decl.get_decl_pair() temp_var_decl = Initializer(