diff --git a/loopy/__init__.py b/loopy/__init__.py index 911f239e5..b10f5ee4b 100644 --- a/loopy/__init__.py +++ b/loopy/__init__.py @@ -25,6 +25,7 @@ import os from typing import TYPE_CHECKING +from warnings import warn from pytools import strtobool @@ -217,7 +218,7 @@ from loopy.translation_unit import TranslationUnit, for_each_kernel, make_program from loopy.type_inference import infer_unknown_types from loopy.types import LoopyType, NumpyType, ToLoopyTypeConvertible, to_loopy_type -from loopy.typing import PreambleGenerator, auto +from loopy.typing import AUTO, PreambleGenerator from loopy.version import MOST_RECENT_LANGUAGE_VERSION, VERSION @@ -226,6 +227,7 @@ __all__ = [ + "AUTO", "MOST_RECENT_LANGUAGE_VERSION", "VERSION", "ASTBuilderBase", @@ -308,7 +310,6 @@ "allocate_temporaries_for_base_storage", "assignment_to_subst", "assume", - "auto", "auto_test_vs_ref", "buffer_array", "c_preprocess", @@ -587,7 +588,7 @@ def make_copy_kernel(new_dim_tags, old_dim_tags=None): "output[%s] = input[%s]" % (command_indices, command_indices), lang_version=MOST_RECENT_LANGUAGE_VERSION, - default_offset=auto) + default_offset=AUTO) result = tag_array_axes(result, "input", old_dim_tags) result = tag_array_axes(result, "output", new_dim_tags) @@ -707,4 +708,11 @@ def _set_up_default_target(): # }}} +def __getattr__(name: str): + if name == "auto": + warn("auto is deprecated and will be removed in 2027.x. Use AUTO.", + DeprecationWarning, stacklevel=2) + return AUTO + + # vim: foldmethod=marker diff --git a/loopy/check.py b/loopy/check.py index 5d8ab73fc..066ca16e3 100644 --- a/loopy/check.py +++ b/loopy/check.py @@ -72,7 +72,7 @@ check_each_kernel, ) from loopy.type_inference import TypeReader -from loopy.typing import auto, not_none +from loopy.typing import AUTO, not_none if TYPE_CHECKING: @@ -253,7 +253,7 @@ def ensure_depends_only_on_arguments( what = f"offset of argument '{arg.name}'" if arg.offset is None: continue - if arg.offset is auto: + if arg.offset is AUTO: pass elif isinstance(arg.offset, (int, np.integer, ExpressionNode, str)): ensure_depends_only_on_arguments(what, arg.offset) @@ -270,7 +270,7 @@ def ensure_depends_only_on_arguments( if isinstance(dim_tag, FixedStrideArrayDimTag): what = (f"stride for axis {iaxis+1} (1-based) of " f"of argument '{arg.name}'") - if dim_tag.stride is auto: + if dim_tag.stride is AUTO: pass elif isinstance( dim_tag.stride, (int, np.integer, ExpressionNode)): @@ -291,7 +291,7 @@ def ensure_depends_only_on_arguments( for tv in kernel.temporary_variables.values(): what = f"offset of temporary '{tv.name}'" - if tv.offset is auto: + if tv.offset is AUTO: pass elif isinstance(tv.offset, (int, np.integer, ExpressionNode, str)): ensure_depends_only_on_arguments(what, tv.offset) @@ -303,7 +303,7 @@ def ensure_depends_only_on_arguments( if isinstance(dim_tag, FixedStrideArrayDimTag): what = ("axis stride for axis " f"{iaxis+1} (1-based) of temporary '{tv.name}'") - if dim_tag.stride is auto: + if dim_tag.stride is AUTO: raise LoopyError(f"The {what}" f" is 'auto', " "which is not allowed.") elif isinstance(dim_tag.stride, (int, np.integer, ExpressionNode)): @@ -345,9 +345,9 @@ def map_subscript(self, expr): def _check_for_integer_subscript_indices_inner(kernel, callables_table): - from loopy.kernel.data import auto - if any(arg.dtype in [None, auto] for arg in kernel.args) or ( - any(tv.dtype in [None, auto] + from loopy.kernel.data import AUTO + if any(arg.dtype in [None, AUTO] for arg in kernel.args) or ( + any(tv.dtype in [None, AUTO] for tv in kernel.temporary_variables.values())): # some types are not resolved => do not check. return @@ -571,11 +571,11 @@ def check_for_unused_inames(kernel: LoopKernel) -> None: def _is_racing_iname_tag(tv: TemporaryVariable, tag: InameImplementationTag) -> bool: from loopy.kernel.data import ( + AUTO, AddressSpace, ConcurrentTag, GroupInameTag, LocalInameTagBase, - auto, ) if tv.address_space == AddressSpace.PRIVATE: @@ -591,7 +591,7 @@ def _is_racing_iname_tag(tv: TemporaryVariable, tag: InameImplementationTag) -> elif tv.address_space == AddressSpace.GLOBAL: return isinstance(tag, ConcurrentTag) - elif tv.address_space == auto: + elif tv.address_space == AUTO: raise LoopyError("scope of temp var '%s' has not yet been" "determined" % tv.name) @@ -1045,7 +1045,7 @@ def declares_nosync_with(kernel, var_address_space, dep_a, dep_b): return ab_nosync and ba_nosync -def _get_address_space(kernel: LoopKernel, var: str) -> AddressSpace | type[auto]: +def _get_address_space(kernel: LoopKernel, var: str) -> AddressSpace | AUTO: from loopy.kernel.data import ArrayArg, ValueArg if var in kernel.temporary_variables: address_space = kernel.temporary_variables[var].address_space @@ -1659,7 +1659,7 @@ def check_that_shapes_and_strides_are_arguments(kernel: LoopKernel) -> None: for dim_tag in arg.dim_tags: if isinstance(dim_tag, FixedStrideArrayDimTag): - if dim_tag.stride is lp.auto: + if dim_tag.stride is lp.AUTO: continue deps = get_dependencies(dim_tag.stride) diff --git a/loopy/kernel/array.py b/loopy/kernel/array.py index e3bf03c4c..c3eb47ea1 100644 --- a/loopy/kernel/array.py +++ b/loopy/kernel/array.py @@ -46,7 +46,7 @@ from loopy.diagnostic import LoopyError from loopy.symbolic import flatten from loopy.types import LoopyType -from loopy.typing import ShapeType, auto, is_integer +from loopy.typing import AUTO, ShapeType, is_integer if TYPE_CHECKING: @@ -160,7 +160,7 @@ def stringify(self, include_target_axis): result += "N%d:" % self.layout_nesting_level import loopy as lp - if self.stride is lp.auto: + if self.stride is lp.AUTO: result += "stride:auto" else: result += "stride:"+str(self.stride) @@ -173,21 +173,21 @@ def __str__(self): return self.stringify(True) def map_expr(self, mapper): - from loopy.kernel.data import auto + from loopy.kernel.data import AUTO - if self.stride is auto: + if self.stride is AUTO: # lp.auto not an expr => do not map return self return self.copy(stride=mapper(self.stride)) def depends_on(self): - from loopy.kernel.data import auto + from loopy.kernel.data import AUTO from loopy.symbolic import DependencyMapper - if self.stride is auto: + if self.stride is AUTO: return frozenset() - return DependencyMapper(composite_leaves=auto)(self.stride) + return DependencyMapper(composite_leaves=AUTO)(self.stride) class ComputedStrideArrayDimTag(_StrideArrayDimTagBase): @@ -310,7 +310,7 @@ def _parse_array_dim_tag(tag, default_target_axis, nesting_levels): return ( has_explicit_nesting_level, is_optional, FixedStrideArrayDimTag( - lp.auto, target_axis, + lp.AUTO, target_axis, layout_nesting_level=nesting_level)) else: from loopy.symbolic import parse @@ -489,7 +489,7 @@ def convert_computed_to_fixed_dim_tags( name: str, num_user_axes: int | None, num_target_axes: int, - shape: ShapeType | type[auto] | None, + shape: ShapeType | AUTO | None, dim_tags: Sequence[ArrayDimImplementationTag], ) -> Sequence[ArrayDimImplementationTag] | None: @@ -544,7 +544,7 @@ def convert_computed_to_fixed_dim_tags( if vector_dim is None: stride_so_far = 1 else: - if shape is None or shape is lp.auto: + if shape is None or shape is lp.AUTO: # unable to normalize without known shape return None @@ -581,7 +581,7 @@ def convert_computed_to_fixed_dim_tags( target_axis=dim_tag.target_axis, layout_nesting_level=dim_tag.layout_nesting_level) - if shape is None or shape is lp.auto: + if shape is None or shape is lp.AUTO: # unable to normalize without known shape return None assert isinstance(shape, tuple) @@ -601,7 +601,7 @@ def convert_computed_to_fixed_dim_tags( elif isinstance(dim_tag, FixedStrideArrayDimTag): stride_so_far = dim_tag.stride - if stride_so_far is lp.auto: + if stride_so_far is lp.AUTO: stride_so_far = None else: @@ -617,20 +617,20 @@ def convert_computed_to_fixed_dim_tags( # {{{ array base class (for arguments and temporary arrays) ToShapeLikeConvertible: TypeAlias = (tuple[Expression | str, ...] - | Expression | type[auto] | str | tuple[str, ...]) + | Expression | AUTO | str | tuple[str, ...]) def _parse_shape_or_strides( x: ToShapeLikeConvertible, - ) -> ShapeType | type[auto]: + ) -> ShapeType | AUTO: from pymbolic import parse if x == "auto": raise ValueError("use of 'auto' as a shape or stride won't work " "any more--use loopy.auto instead") - if x is auto: - return auto + if x is AUTO: + return AUTO x_parsed = x if not isinstance(x, str) else parse(x) @@ -640,7 +640,7 @@ def _parse_shape_or_strides( if isinstance(x_parsed, tuple): x_tup: tuple[Expression | str, ...] = x_parsed else: - assert x_parsed is not auto + assert x_parsed is not AUTO x_tup = (cast("Expression", x_parsed),) def parse_arith(x: Expression | str) -> ArithmeticExpression: @@ -690,7 +690,7 @@ class ArrayBase(ImmutableRecord, Taggable): cannot be performed without knowledge of the exact *dtype*. """ - shape: ShapeType | type[auto] | None + shape: ShapeType | AUTO | None """ May be one of the following: @@ -818,11 +818,11 @@ def __init__(self, name, dtype=None, shape=None, dim_tags=None, offset=0, dtype = to_loopy_type(dtype, allow_auto=True, allow_none=True, for_atomic=for_atomic) - if dtype is lp.auto: + if dtype is lp.AUTO: raise ValueError("dtype may not be lp.auto") - strides_known = strides is not None and strides is not lp.auto - shape_known = shape is not None and shape is not lp.auto + strides_known = strides is not None and strides is not lp.AUTO + shape_known = shape is not None and shape is not lp.AUTO if strides_known: strides = _parse_shape_or_strides(strides) @@ -1001,7 +1001,7 @@ def stringify(self, include_typename): if include_typename: info_entries.append(type(self).__name__) - assert self.dtype is not lp.auto + assert self.dtype is not lp.AUTO type_str = "" if self.dtype is None else str(self.dtype) @@ -1009,7 +1009,7 @@ def stringify(self, include_typename): if self.shape is None: info_entries.append("shape: unknown") - elif self.shape is lp.auto: + elif self.shape is lp.AUTO: info_entries.append("shape: auto") else: # shape is iterable @@ -1067,8 +1067,8 @@ def num_target_axes(self): return len(target_axes) def num_user_axes(self, require_answer=True): - from loopy import auto - if self.shape not in (None, auto): + from loopy import AUTO + if self.shape is not None and self.shape is not AUTO: return len(self.shape) if self.dim_tags is not None: return len(self.dim_tags) @@ -1086,7 +1086,7 @@ def map_exprs(self, mapper: Callable[[Expression], Expression]) -> Self: kwargs: dict[str, Any] = {} import loopy as lp - if self.shape is not None and self.shape is not lp.auto: + if self.shape is not None and self.shape is not lp.AUTO: assert isinstance(self.shape, tuple) def none_pass_mapper(s: Expression | None) -> Expression | None: @@ -1234,7 +1234,7 @@ def _apply_offset(sub: ArithmeticExpression, ary: ArrayBase) -> ArithmeticExpres # is declared. return sub - if ary.offset is lp.auto: + if ary.offset is lp.AUTO: raise AssertionError( f"Offset for '{ary.name}' should have been replaced " "with an actual argument by " @@ -1346,7 +1346,7 @@ def eval_expr_assert_integer_constant(i, expr) -> int: "vector (%d)" % (ary.name, i, dim_tag.stride, vector_size)) - elif stride is lp.auto: + elif stride is lp.AUTO: raise AssertionError( f"Stride for axis {i+1} (1-based) of " "'{array_name}' should have been replaced " diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 9de077d7b..398097b52 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -83,7 +83,7 @@ InameStrSet, PreambleGenerator, SymbolMangler, - auto, + AUTO, is_integer, not_none, ) @@ -1147,7 +1147,7 @@ class ArgumentGuesser: instructions: Sequence[InstructionBase] subst_rules: dict[str, SubstitutionRule] temporary_variables: dict[str, TemporaryVariable] - default_offset: int | type[auto] + default_offset: int | AUTO submap: SubstitutionRuleExpander @@ -1161,7 +1161,7 @@ def __init__(self, instructions: Sequence[InstructionBase], temporary_variables: dict[str, TemporaryVariable], subst_rules: dict[str, SubstitutionRule], - default_offset: int | type[auto]) -> None: + default_offset: int | AUTO) -> None: self.domains = domains self.instructions = instructions self.temporary_variables = temporary_variables @@ -1225,7 +1225,7 @@ def make_new_arg(self, arg_name: str) -> KernelArgument: # other writable type of variable is an argument. return ArrayArg(arg_name, - shape=lp.auto, + shape=lp.AUTO, offset=self.default_offset, address_space=AddressSpace.GLOBAL) @@ -1235,7 +1235,7 @@ def make_new_arg(self, arg_name: str) -> KernelArgument: return ValueArg(arg_name) else: return ArrayArg( - arg_name, shape=lp.auto, offset=self.default_offset, + arg_name, shape=lp.AUTO, offset=self.default_offset, address_space=AddressSpace.GLOBAL) def convert_names_to_full_args( @@ -1439,7 +1439,7 @@ def add_assignment(base_name: str | None, new_temp_vars.append(TemporaryVariable( name=new_var_name, dtype=dtype, - address_space=lp.auto, + address_space=lp.AUTO, shape=())) from pymbolic.primitives import Variable @@ -1517,7 +1517,7 @@ def add_sequential_dependencies(knl: LoopKernel) -> LoopKernel: # {{{ temporary variable creation def create_temporaries(knl: LoopKernel, - default_order: str | type[auto] | None) -> LoopKernel: + default_order: str | AUTO | None) -> LoopKernel: new_insns: list[InstructionBase] = [] new_temp_vars = dict(knl.temporary_variables) @@ -1544,9 +1544,9 @@ def create_temporaries(knl: LoopKernel, new_temp_vars[assignee_name] = lp.TemporaryVariable( name=assignee_name, dtype=temp_var_type.value, - address_space=lp.auto, - base_indices=lp.auto, - shape=lp.auto, + address_space=lp.AUTO, + base_indices=lp.AUTO, + shape=lp.AUTO, order=default_order) if isinstance(insn, Assignment): @@ -1632,7 +1632,7 @@ def determine_shapes_of_temporaries(knl: LoopKernel) -> LoopKernel: scalar_vars: set[str] = set() for tv in knl.temporary_variables.values(): - if tv.shape is lp.auto or tv.base_indices is lp.auto: + if tv.shape is lp.AUTO or tv.base_indices is lp.AUTO: vars_needing_shape_inference.add(tv.name) from pymbolic.primitives import Variable @@ -1699,17 +1699,17 @@ def feed_assignee_of_instruction( for tv in knl.temporary_variables.values(): if tv.name in scalar_vars: - if tv.base_indices is lp.auto: + if tv.base_indices is lp.AUTO: tv = tv.copy(base_indices=()) changed = True - if tv.shape is lp.auto: + if tv.shape is lp.AUTO: tv = tv.copy(shape=()) changed = True else: - if tv.base_indices is lp.auto: + if tv.base_indices is lp.AUTO: tv = tv.copy(base_indices=var_to_base_indices[tv.name]) changed = True - if tv.shape is lp.auto: + if tv.shape is lp.AUTO: tv = tv.copy(shape=var_to_shape[tv.name]) changed = True new_temp_vars[tv.name] = tv @@ -1725,7 +1725,7 @@ def feed_assignee_of_instruction( # {{{ guess argument shapes def guess_arg_shape_if_requested(kernel: LoopKernel, - default_order: str | type[auto] | None) -> LoopKernel: + default_order: str | AUTO | None) -> LoopKernel: new_args: list[KernelArgument] = [] import loopy as lp @@ -1734,13 +1734,13 @@ def guess_arg_shape_if_requested(kernel: LoopKernel, var_names = [ arg.name for arg in kernel.args - if isinstance(arg, ArrayBase) and arg.shape is lp.auto] + if isinstance(arg, ArrayBase) and arg.shape is lp.AUTO] shapes = guess_var_shape(kernel, var_names) if var_names else [] count = 0 for arg in kernel.args: - if isinstance(arg, ArrayBase) and arg.shape is lp.auto: + if isinstance(arg, ArrayBase) and arg.shape is lp.AUTO: shape = shapes[count] count = count + 1 arg = arg.copy(shape=shape) @@ -1755,7 +1755,7 @@ def guess_arg_shape_if_requested(kernel: LoopKernel, # {{{ apply default_order to args def apply_default_order_to_args(kernel: LoopKernel, - default_order: str | type[auto] | None) -> LoopKernel: + default_order: str | AUTO | None) -> LoopKernel: from loopy.kernel.array import ArrayBase processed_args: list[KernelArgument] = [] @@ -1767,16 +1767,16 @@ def apply_default_order_to_args(kernel: LoopKernel, else: # leave them the way they are pass - elif default_order is auto: + elif default_order is AUTO: if arg.dim_tags is None and arg.shape is not None: - assert arg.shape is not auto + assert arg.shape is not AUTO arg = arg.copy( dim_tags=tuple( - FixedStrideArrayDimTag(auto) + FixedStrideArrayDimTag(AUTO) for i in range(len(arg.shape)))) arg = arg.copy( dim_tags=tuple( - FixedStrideArrayDimTag(auto) + FixedStrideArrayDimTag(AUTO) if isinstance(dim_tag, FixedStrideArrayDimTag) else dim_tag for dim_tag in arg.dim_tags)) @@ -2118,7 +2118,7 @@ def _convert_array_to_slices(arg: Expression) -> Expression: # second row if 'A' is 3 x 3 array. if isinstance(arg, Variable): if (arg.name in self.knl.temporary_variables): - if self.knl.temporary_variables[arg.name].shape in (auto, None): + if self.knl.temporary_variables[arg.name].shape in (AUTO, None): # do not convert arrays with unknown shapes to slices. # (If an array of unknown shape was passed in error, will be # caught and raised during preprocessing). @@ -2131,7 +2131,7 @@ def _convert_array_to_slices(arg: Expression) -> Expression: array_arg_shape = () else: - if self.knl.arg_dict[arg.name].shape in (auto, None): + if self.knl.arg_dict[arg.name].shape in (AUTO, None): # do not convert arrays with unknown shapes to slices. # (If an array of unknown shape was passed in error, will # be caught and raised during preprocessing). @@ -2223,8 +2223,8 @@ def make_function( substitutions: Mapping[str, SubstitutionRule] | None = None, preambles: Sequence[tuple[str, str]] | None = (), preamble_generators: Sequence[PreambleGenerator] = (), - default_order: Literal["C", "F"] | type[auto] = "C", - default_offset: Literal[0] | type[auto] | None = None, + default_order: Literal["C", "F"] | AUTO = "C", + default_offset: Literal[0] | AUTO | None = None, symbol_manglers: Sequence[SymbolMangler] = (), assumptions: isl.BasicSet | str | None = "", silenced_warnings: str | Sequence[str] = (), @@ -2657,8 +2657,8 @@ def make_kernel( substitutions: Mapping[str, SubstitutionRule] | None = None, preambles: Sequence[tuple[str, str]] | None = (), preamble_generators: Sequence[PreambleGenerator] = (), - default_order: Literal["C", "F"] | type[auto] = "C", - default_offset: Literal[0] | type[auto] | None = None, + default_order: Literal["C", "F"] | AUTO = "C", + default_offset: Literal[0] | AUTO | None = None, symbol_manglers: Sequence[SymbolMangler] = (), assumptions: isl.BasicSet | str | None = "", silenced_warnings: str | Sequence[str] = (), diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index 52bf0b286..b9be2ca0d 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -57,7 +57,7 @@ VarAtomicity, make_assignment, ) -from loopy.typing import ShapeType, auto +from loopy.typing import ShapeType, AUTO if TYPE_CHECKING: @@ -365,14 +365,14 @@ class AddressSpace(IntEnum): GLOBAL = 2 @classmethod - def stringify(cls, val: AddressSpace | type[auto]) -> str: + def stringify(cls, val: AddressSpace | AUTO) -> str: if val == cls.PRIVATE: return "private" elif val == cls.LOCAL: return "local" elif val == cls.GLOBAL: return "global" - elif val is auto: + elif val is AUTO: return "" else: raise ValueError("unexpected value of AddressSpace") @@ -409,7 +409,7 @@ def __init__(self, **kwargs): dtype, allow_auto=True, allow_none=True, for_atomic=for_atomic) import loopy as lp - if dtype is lp.auto: + if dtype is lp.AUTO: raise TypeError("dtype may not be lp.auto") kwargs["dtype"] = dtype @@ -486,7 +486,7 @@ def __init__(self, *args, **kwargs): def __str__(self): # Don't mention the type of array arg if shape is known # FIXME: Why? - include_typename = self.shape in (None, auto) + include_typename = self.shape in (None, AUTO) aspace_str = AddressSpace.stringify(self.address_space) @@ -610,7 +610,7 @@ def __init__(self, def __str__(self): import loopy as lp - assert self.dtype is not lp.auto + assert self.dtype is not lp.AUTO type_str = "" if self.dtype is None else str(self.dtype) @@ -649,7 +649,7 @@ class TemporaryVariable(ArrayBase): storage_shape: ShapeType | None base_indices: tuple[Expression, ...] | None - address_space: AddressSpace | type[auto] + address_space: AddressSpace | AUTO base_storage: str | None """The name of a storage array that is to be used to actually hold the data in this temporary, or *None*. If not *None* or the name @@ -692,8 +692,8 @@ def __init__( self, name: str, dtype: ToLoopyTypeConvertible = None, - shape: ShapeType | type[auto] | None = auto, - address_space: AddressSpace | type[auto] | None = None, + shape: ShapeType | AUTO | None = AUTO, + address_space: AddressSpace | AUTO | None = None, dim_tags: Sequence[ArrayDimImplementationTag] | None = None, offset: Expression | str | None = 0, dim_names: tuple[str, ...] | None = None, @@ -717,7 +717,7 @@ def __init__( """ if address_space is None: - address_space = auto + address_space = AUTO if initializer is None: pass @@ -729,7 +729,7 @@ def __init__( % name) from loopy.types import NumpyType, to_loopy_type - if dtype is auto or dtype is None: + if dtype is AUTO or dtype is None: dtype = NumpyType(initializer.dtype) elif to_loopy_type(dtype) != to_loopy_type(initializer.dtype): raise LoopyError( @@ -738,7 +738,7 @@ def __init__( "dtype of array." % name) - if shape is auto: + if shape is AUTO: shape = initializer.shape else: if shape != initializer.shape: @@ -758,7 +758,7 @@ def __init__( from loopy.kernel.array import _parse_shape_or_strides shape = _parse_shape_or_strides(shape) - if base_indices is None and shape is not auto and shape is not None: + if base_indices is None and shape is not AUTO and shape is not None: assert isinstance(shape, tuple) base_indices = (0,) * len(shape) @@ -813,7 +813,7 @@ def nbytes(self) -> Expression: else: if self.shape is None: raise ValueError("shape is None") - if self.shape is auto: + if self.shape is AUTO: raise ValueError("shape is auto") shape = cast("tuple[ArithmeticExpression]", self.shape) @@ -824,7 +824,7 @@ def nbytes(self) -> Expression: return product(si for si in shape)*self.dtype.itemsize def __str__(self) -> str: - if self.address_space is auto: + if self.address_space is AUTO: aspace_str = "auto" else: aspace_str = AddressSpace.stringify(self.address_space) diff --git a/loopy/kernel/function_interface.py b/loopy/kernel/function_interface.py index 9f31abe28..7964ac7f9 100644 --- a/loopy/kernel/function_interface.py +++ b/loopy/kernel/function_interface.py @@ -138,9 +138,9 @@ def __post_init__(self) -> None: # {{{ sanity checks from loopy.kernel.array import ArrayDimImplementationTag - from loopy.typing import auto + from loopy.typing import AUTO - assert isinstance(self.shape, tuple) or self.shape in [None, auto] + assert isinstance(self.shape, tuple) or self.shape in [None, AUTO] assert isinstance(self.dim_tags, tuple) or self.dim_tags is None if self.dim_tags: @@ -180,13 +180,13 @@ def depends_on(self) -> frozenset[str]: Returns :class:`frozenset` of all the variable names the :class:`ArrayArgDescriptor` depends on. """ - from loopy.typing import auto + from loopy.typing import AUTO result: set[p.Variable] = set() if self.shape: dep_mapper = DependencyMapper(composite_leaves=False) for axis_len in self.shape: - if axis_len not in [None, auto]: + if axis_len not in [None, AUTO]: result |= cast("set[p.Variable]", dep_mapper(axis_len)) if self.dim_tags: @@ -220,7 +220,7 @@ def map_subscript(self, expr: p.Subscript) -> None: @override def map_variable(self, expr: p.Variable) -> None: from loopy.kernel.data import ArrayArg, TemporaryVariable - from loopy.typing import auto + from loopy.typing import AUTO if expr.name in self.kernel.all_inames(): # inames are scalar @@ -231,7 +231,7 @@ def map_variable(self, expr: p.Variable) -> None: if var is not None: if isinstance(var, (ArrayArg, TemporaryVariable)) and ( - var.shape != () and var.shape is not auto): + var.shape != () and var.shape is not AUTO): raise LoopyError("Array regions can only passed as sub-array refs.") @override @@ -1165,11 +1165,11 @@ def with_name(self, name: CallableId) -> Self: @override def is_type_specialized(self) -> bool: - from loopy.typing import auto + from loopy.typing import AUTO return (self.arg_id_to_dtype is not None - and all(arg.dtype not in [None, auto] + and all(arg.dtype not in [None, AUTO] for arg in self.subkernel.args) - and all(tv.dtype not in [None, auto] + and all(tv.dtype not in [None, AUTO] for tv in self.subkernel.temporary_variables.values())) # }}} diff --git a/loopy/kernel/instruction.py b/loopy/kernel/instruction.py index 7bea68a24..ecaced93a 100644 --- a/loopy/kernel/instruction.py +++ b/loopy/kernel/instruction.py @@ -1756,7 +1756,7 @@ def _check_and_fix_temp_var_type( DeprecationWarning, stacklevel=1 + stacklevel) return lp.Optional() - elif temp_var_type is lp.auto: + elif temp_var_type is lp.AUTO: warn("temp_var_type should be Optional(None) if " "unspecified, not auto. This usage will be disallowed soon.", DeprecationWarning, stacklevel=1 + stacklevel) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index 4c416ebd5..aa0b1fead 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -164,7 +164,7 @@ def _add_dtypes(kernel, dtype_dict): if new_dtype is not None: new_dtype = np.dtype(new_dtype) tv = new_temp_vars[tv_name] - if (tv.dtype is not None and tv.dtype is not lp.auto) \ + if (tv.dtype is not None and tv.dtype is not lp.AUTO) \ and tv.dtype != new_dtype: raise RuntimeError( "temporary variable '%s' already has a different dtype " diff --git a/loopy/preprocess.py b/loopy/preprocess.py index ffdd4801e..9ef5f215d 100644 --- a/loopy/preprocess.py +++ b/loopy/preprocess.py @@ -49,7 +49,7 @@ KernelArgument, ValueArg, _ArraySeparationInfo, - auto, + AUTO, filter_iname_tags_by_type, ) from loopy.kernel.function_interface import ( @@ -244,7 +244,7 @@ def make_args_for_offsets_and_strides(kernel: LoopKernel) -> LoopKernel: for arg in kernel.args: if isinstance(arg, ArrayArg) and not arg._separation_info: what = f"offset for argument '{arg.name}'" - if arg.offset is auto: + if arg.offset is AUTO: offset_name = vng(arg.name+"_offset") additional_args.append(ValueArg( offset_name, kernel.index_dtype)) @@ -263,7 +263,7 @@ def make_args_for_offsets_and_strides(kernel: LoopKernel) -> LoopKernel: if isinstance(dim_tag, FixedStrideArrayDimTag): what = ("axis stride for axis " f"{iaxis+1} (1-based) of '{arg.name}'") - if dim_tag.stride is auto: + if dim_tag.stride is AUTO: stride_name = vng(f"{arg.name}_stride{iaxis}") dim_tag = dim_tag.copy(stride=Variable(stride_name)) additional_args.append(ValueArg( @@ -301,7 +301,7 @@ def zero_offsets_and_strides(kernel: LoopKernel) -> LoopKernel: new_args = [] for arg in kernel.args: if isinstance(arg, ArrayArg): - if arg.offset is auto: + if arg.offset is AUTO: made_changes = True arg = arg.copy(offset=0) elif isinstance(arg.offset, (int, np.integer, ExpressionNode, str)): @@ -362,7 +362,7 @@ def find_temporary_address_space(kernel): # Only fill out for variables that do not yet know if they're # local. (I.e. those generated by implicit temporary generation.) - if temp_var.address_space is not lp.auto: + if temp_var.address_space is not lp.AUTO: new_temp_vars[temp_var.name] = temp_var continue @@ -673,7 +673,7 @@ def infer_arg_descr(t_unit: TranslationUnit) -> TranslationUnit: :attr:`loopy.InKernelCallable.arg_id_to_descr` inferred for all the callables. """ - from loopy import ValueArg, auto + from loopy import ValueArg, AUTO from loopy.kernel.array import ArrayBase from loopy.kernel.function_interface import ArrayArgDescriptor, ValueArgDescriptor from loopy.translation_unit import make_clbl_inf_ctx, resolve_callables @@ -685,7 +685,7 @@ def infer_arg_descr(t_unit: TranslationUnit) -> TranslationUnit: for e in t_unit.entrypoints: def _tuple_or_none(s): - if isinstance(s, tuple) or s in [None, auto]: + if isinstance(s, tuple) or s in [None, AUTO]: return s else: return s, @@ -693,7 +693,7 @@ def _tuple_or_none(s): arg_id_to_descr: dict[str, ArgDescriptor] = {} for arg in t_unit[e].args: if isinstance(arg, ArrayBase): - if arg.shape not in (None, auto): + if arg.shape not in (None, AUTO): arg_id_to_descr[arg.name] = ArrayArgDescriptor( _tuple_or_none(arg.shape), arg.address_space, arg.dim_tags) diff --git a/loopy/statistics.py b/loopy/statistics.py index 99010c21e..7350ae8a7 100644 --- a/loopy/statistics.py +++ b/loopy/statistics.py @@ -1165,7 +1165,7 @@ def get_iname_strides(tag_to_iname_dict): if isinstance(axis_tag, FixedStrideArrayDimTag): axis_tag_stride = axis_tag.stride - if axis_tag_stride is lp.auto: + if axis_tag_stride is lp.AUTO: total_iname_stride = None break diff --git a/loopy/target/c/__init__.py b/loopy/target/c/__init__.py index 42a0b5730..8743338dc 100644 --- a/loopy/target/c/__init__.py +++ b/loopy/target/c/__init__.py @@ -71,7 +71,7 @@ from loopy.target import ASTBuilderBase, DummyHostASTBuilder, TargetBase from loopy.tools import remove_common_indentation from loopy.types import AtomicType, LoopyType, NumpyType, to_loopy_type -from loopy.typing import InameStr, auto +from loopy.typing import InameStr, AUTO if TYPE_CHECKING: @@ -1203,7 +1203,7 @@ def get_temporary_arg_decl( self, temp_var: TemporaryVariable, is_written: bool) -> Declarator: if temp_var.address_space == AddressSpace.GLOBAL: from cgen import RestrictPointer - assert temp_var.address_space is not auto + assert temp_var.address_space is not AUTO arg_decl: Declarator = RestrictPointer( self.wrap_decl_for_address_space( diff --git a/loopy/target/execution.py b/loopy/target/execution.py index 818322c6b..d144d78e4 100644 --- a/loopy/target/execution.py +++ b/loopy/target/execution.py @@ -49,7 +49,7 @@ from loopy.kernel import KernelState, LoopKernel from loopy.tools import LoopyKeyBuilder, caches from loopy.types import LoopyType, NumpyType -from loopy.typing import auto, integer_expr_or_err +from loopy.typing import AUTO, integer_expr_or_err from loopy.version import DATA_MODEL_VERSION @@ -183,7 +183,7 @@ def generate_integer_arg_finding_from_array_data( arg = kernel.arg_dict[arg_name] assert arg.dtype is not None if isinstance(arg, ArrayArg): - assert arg.shape is not auto + assert arg.shape is not AUTO if isinstance(arg.shape, tuple): for axis_nr, shape_i in enumerate(arg.shape): if shape_i is not None: diff --git a/loopy/transform/buffer.py b/loopy/transform/buffer.py index a2c7b5430..939abd4e8 100644 --- a/loopy/transform/buffer.py +++ b/loopy/transform/buffer.py @@ -237,7 +237,7 @@ def buffer_array_for_single_kernel(kernel, callables_table, var_name, if temporary_scope is None: import loopy as lp - temporary_scope = lp.auto + temporary_scope = lp.AUTO # }}} diff --git a/loopy/transform/concatenate.py b/loopy/transform/concatenate.py index ba33dc1c2..d2ba021dc 100644 --- a/loopy/transform/concatenate.py +++ b/loopy/transform/concatenate.py @@ -37,7 +37,7 @@ from pytools import all_equal from loopy.kernel import LoopKernel -from loopy.kernel.data import ArrayArg, KernelArgument, TemporaryVariable, auto +from loopy.kernel.data import ArrayArg, KernelArgument, TemporaryVariable, AUTO from loopy.symbolic import SubstitutionRuleMappingContext from loopy.translation_unit import for_each_kernel @@ -71,7 +71,7 @@ def concatenate_arrays( arrays = [] for array_name in array_names: ary = kernel.get_var_descriptor(array_name) - if ary.shape is None or ary.shape is auto: + if ary.shape is None or ary.shape is AUTO: raise ValueError(f"Shape of temporary variable '{array_name}' is " "unknown. Cannot merge with unknown shapes") diff --git a/loopy/transform/data.py b/loopy/transform/data.py index 932a8f3de..b57531a4b 100644 --- a/loopy/transform/data.py +++ b/loopy/transform/data.py @@ -40,7 +40,7 @@ from loopy.kernel.function_interface import CallableKernel, ScalarCallable from loopy.translation_unit import CallablesTable, TranslationUnit, for_each_kernel from loopy.types import LoopyType -from loopy.typing import assert_tuple, auto +from loopy.typing import AUTO, assert_tuple if TYPE_CHECKING: @@ -1071,7 +1071,7 @@ def allocate_temporaries_for_base_storage(kernel: LoopKernel, made_changes = True assert isinstance(tv.dtype, LoopyType) - if tv.address_space is auto: + if tv.address_space is AUTO: raise LoopyError("When allocating base storage for temporary " f"'{tv.name}', the address space of the temporary " "was not yet determined (set to 'auto').") diff --git a/loopy/transform/precompute.py b/loopy/transform/precompute.py index 7fabaface..5b5640d59 100644 --- a/loopy/transform/precompute.py +++ b/loopy/transform/precompute.py @@ -61,7 +61,7 @@ from loopy.types import LoopyType, ToLoopyTypeConvertible, to_loopy_type from loopy.typing import ( Expression, - auto, + AUTO, integer_expr_or_err, integer_or_err, not_none, @@ -401,7 +401,7 @@ def precompute_for_single_kernel( dtype: ToLoopyTypeConvertible | None = None, fetch_bounding_box: bool = False, - temporary_address_space: AddressSpace | type[auto] | None = None, + temporary_address_space: AddressSpace | AUTO | None = None, compute_insn_id: str | None = None, _enable_mirgecom_workaround: bool = False, ) -> LoopKernel: @@ -1082,7 +1082,7 @@ def add_assumptions(d): loopy_type = to_loopy_type(dtype, allow_none=True) if temporary_address_space is None: - temporary_address_space = lp.auto + temporary_address_space = lp.AUTO new_temp_shape = tuple(abm.non1_storage_shape) @@ -1136,9 +1136,9 @@ def add_assumptions(d): if temporary_address_space == temp_var.address_space: pass - elif temporary_address_space is lp.auto: + elif temporary_address_space is lp.AUTO: temporary_address_space = temp_var.address_space - elif temp_var.address_space is lp.auto: + elif temp_var.address_space is lp.AUTO: pass else: raise LoopyError("Existing and new temporary '%s' do not " diff --git a/loopy/transform/save.py b/loopy/transform/save.py index c7463e32a..fb59e95ca 100644 --- a/loopy/transform/save.py +++ b/loopy/transform/save.py @@ -49,7 +49,7 @@ RunInstruction, ) from loopy.schedule.tools import get_block_boundaries -from loopy.typing import InameStr, auto, not_none +from loopy.typing import InameStr, AUTO, not_none if TYPE_CHECKING: @@ -526,10 +526,10 @@ def auto_promote_temporary(self, temporary_name): return backing_temporary def save_or_reload_impl(self, temporary, subkernel, mode, - promoted_temporary=auto): + promoted_temporary=AUTO): assert mode in ("save", "reload") - if promoted_temporary is auto: + if promoted_temporary is AUTO: promoted_temporary = self.auto_promote_temporary(temporary) if promoted_temporary is None: diff --git a/loopy/type_inference.py b/loopy/type_inference.py index 90c8175e0..f98164a9d 100644 --- a/loopy/type_inference.py +++ b/loopy/type_inference.py @@ -612,7 +612,7 @@ def map_variable(self, expr: p.Variable | TaggedVariable): # pyright: ignore[re import loopy as lp from loopy.kernel.data import KernelArgument, TemporaryVariable if isinstance(obj, (KernelArgument, TemporaryVariable)): - assert obj.dtype is not lp.auto + assert obj.dtype is not lp.AUTO result = [obj.dtype] if result[0] is None: self.symbols_with_unknown_types.add(expr.name) @@ -806,7 +806,7 @@ def map_variable(self, expr): import loopy as lp from loopy.kernel.data import KernelArgument, TemporaryVariable if isinstance(obj, (KernelArgument, TemporaryVariable)): - assert obj.dtype is not lp.auto + assert obj.dtype is not lp.AUTO result = [obj.dtype] if result[0] is None: raise DependencyTypeInferenceFailure( @@ -941,12 +941,12 @@ def infer_unknown_types_for_a_single_kernel( import loopy as lp for tv in kernel.temporary_variables.values(): - assert tv.dtype is not lp.auto + assert tv.dtype is not lp.AUTO if tv.dtype is None: names_for_type_inference.append(tv.name) for arg in kernel.args: - assert arg.dtype is not lp.auto + assert arg.dtype is not lp.AUTO if arg.dtype is None: names_for_type_inference.append(arg.name) @@ -1167,7 +1167,7 @@ def infer_unknown_types( ) -> TranslationUnit: """Infer types on temporaries and arguments.""" from loopy.translation_unit import resolve_callables - from loopy.typing import auto + from loopy.typing import AUTO t_unit = resolve_callables(t_unit) @@ -1187,7 +1187,7 @@ def infer_unknown_types( for e in t_unit.entrypoints: logger.debug(f"Entering entrypoint: {e}") arg_id_to_dtype: dict[int | str, LoopyType] = {arg.name: arg.dtype for arg in - t_unit[e].args if arg.dtype not in (None, auto)} + t_unit[e].args if arg.dtype not in (None, AUTO)} new_callable, clbl_inf_ctx = cast( "CallableKernel", t_unit.callables_table[e] ).with_types(arg_id_to_dtype, clbl_inf_ctx) diff --git a/loopy/types.py b/loopy/types.py index bced31e43..54afa0b12 100644 --- a/loopy/types.py +++ b/loopy/types.py @@ -31,7 +31,7 @@ from typing_extensions import override from loopy.diagnostic import LoopyError -from loopy.typing import auto +from loopy.typing import AUTO if TYPE_CHECKING: @@ -243,7 +243,7 @@ def __eq__(self, other: object) -> bool: ToLoopyTypeConvertible: TypeAlias = """( - type[auto] + AUTO | DTypeLike | LoopyType | str @@ -268,20 +268,20 @@ def to_loopy_type(dtype: ToLoopyTypeConvertible, def to_loopy_type(dtype: ToLoopyTypeConvertible, *, allow_auto: Literal[True], allow_none: bool = False, for_atomic: bool = False - ) -> type[auto] | LoopyType | None: ... + ) -> AUTO | LoopyType | None: ... def to_loopy_type(dtype: ToLoopyTypeConvertible, allow_auto: bool = False, allow_none: bool = False, for_atomic: bool = False - ) -> type[auto] | LoopyType | None: + ) -> AUTO | LoopyType | None: if dtype is None: if allow_none: return None else: raise LoopyError("dtype may not be none") - elif dtype is auto: + elif dtype is AUTO: if allow_auto: return dtype else: diff --git a/loopy/typing.py b/loopy/typing.py index bb3b00284..9d9a238de 100644 --- a/loopy/typing.py +++ b/loopy/typing.py @@ -21,7 +21,7 @@ .. currentmodule:: loopy -.. autoclass:: auto +.. autodata:: AUTO """ @@ -52,9 +52,10 @@ from typing import TYPE_CHECKING, TypeAlias, TypeVar +from warnings import warn import numpy as np -from typing_extensions import TypeIs +from typing_extensions import Sentinel, TypeIs from pymbolic.primitives import ExpressionNode from pymbolic.typing import ArithmeticExpression, Expression, Integer @@ -87,11 +88,13 @@ SymbolMangler: TypeAlias = "Callable[[LoopKernel, str], tuple[LoopyType, str] | None]" -class auto: # noqa: N801 - """A generic placeholder object for something that should be automatically - determined. See, for example, the *shape* or *strides* argument of - :class:`~loopy.ArrayArg`. - """ +# This needs to be upper case in order to function correctly. +# https://github.com/microsoft/pyright/issues/10744 +AUTO = Sentinel("AUTO") +"""A generic placeholder object for something that should be automatically +determined. See, for example, the *shape* or *strides* argument of +:class:`~loopy.ArrayArg`. +""" T = TypeVar("T") @@ -126,3 +129,10 @@ def integer_expr_or_err(expr: Expression) -> Integer | ExpressionNode: def assert_tuple(obj: tuple[ElT, ...] | object) -> tuple[ElT, ...]: assert isinstance(obj, tuple) return obj + + +def __getattr__(name: str): + if name == "auto": + warn("auto is deprecated and will be removed in 2027.x. Use AUTO.", + DeprecationWarning, stacklevel=2) + return AUTO diff --git a/test/test_apps.py b/test/test_apps.py index 5355642cf..d4f4e7dc7 100644 --- a/test/test_apps.py +++ b/test/test_apps.py @@ -57,9 +57,9 @@ def test_convolution(ctx_factory: cl.CtxFactory): * f[ifeat, f_w+f_x, f_w+f_y, icolor]) """, [ - lp.GlobalArg("f", dtype, shape=lp.auto), - lp.GlobalArg("img", dtype, shape=lp.auto), - lp.GlobalArg("out", dtype, shape=lp.auto), + lp.GlobalArg("f", dtype, shape=lp.AUTO), + lp.GlobalArg("img", dtype, shape=lp.AUTO), + lp.GlobalArg("out", dtype, shape=lp.AUTO), "..." ], assumptions="f_w>=1 and im_w, im_h >= 2*f_w+1 and nfeats>=1 and nimgs>=0", @@ -125,9 +125,9 @@ def test_convolution_with_nonzero_base(ctx_factory: cl.CtxFactory): * f[ifeat, f_w+f_x, f_w+f_y, icolor]) """, [ - lp.GlobalArg("f", dtype, shape=lp.auto), - lp.GlobalArg("img", dtype, shape=lp.auto), - lp.GlobalArg("out", dtype, shape=lp.auto), + lp.GlobalArg("f", dtype, shape=lp.AUTO), + lp.GlobalArg("img", dtype, shape=lp.AUTO), + lp.GlobalArg("out", dtype, shape=lp.AUTO), "..." ], assumptions="f_w>=1 and im_w, im_h >= 2*f_w+1 and nfeats>=1 and nimgs>=0", diff --git a/test/test_c_execution.py b/test/test_c_execution.py index 255a78c71..d86483f00 100644 --- a/test/test_c_execution.py +++ b/test/test_c_execution.py @@ -40,8 +40,8 @@ def test_c_target(): "{ [i]: 0<=i b = 6.0 * float_pos[k] output[k] = 2.0 * b """, [lp.ValueArg("K", is_input=True), - lp.GlobalArg("float_pos", np.float32, shape=lp.auto, + lp.GlobalArg("float_pos", np.float32, shape=lp.AUTO, is_input=True, is_output=False), - lp.GlobalArg("output", np.uint8, shape=lp.auto, is_input=False, + lp.GlobalArg("output", np.uint8, shape=lp.AUTO, is_input=False, is_output=True)], target=lp.ISPCTarget(), assumptions="1