def map_constant(self, expr): if is_integer(expr): for tp in [np.int32, np.int64]: iinfo = np.iinfo(tp) if iinfo.min <= expr <= iinfo.max: return [NumpyType(np.dtype(tp))] else: raise TypeInferenceFailure("integer constant '%s' too large" % expr) dt = np.asarray(expr).dtype if hasattr(expr, "dtype"): return [NumpyType(expr.dtype)] elif isinstance(expr, np.number): # Numpy types are sized return [NumpyType(np.dtype(type(expr)))] elif dt.kind == "f": # deduce the smaller type by default return [NumpyType(np.dtype(np.float32))] elif dt.kind == "c": if np.complex64(expr) == np.complex128(expr): # (COMPLEX_GUESS_LOGIC) # No precision is lost by 'guessing' single precision, use that. # This at least covers simple cases like '1j'. return [NumpyType(np.dtype(np.complex64))] # Codegen for complex types depends on exactly correct types. # Refuse temptation to guess. raise TypeInferenceFailure("Complex constant '%s' needs to " "be sized for type inference " % expr) else: raise TypeInferenceFailure("Cannot deduce type of constant '%s'" % expr)
def map_variable(self, expr): if expr.name in self.kernel.all_inames(): return [self.kernel.index_dtype] result = self.kernel.mangle_symbol( self.kernel.target.get_device_ast_builder(), expr.name) if result is not None: result_dtype, _ = result return [result_dtype] obj = self.new_assignments.get(expr.name) if obj is None: obj = self.kernel.arg_dict.get(expr.name) if obj is None: obj = self.kernel.temporary_variables.get(expr.name) if obj is None: raise TypeInferenceFailure("name not known in type inference: %s" % expr.name) from loopy.kernel.data import TemporaryVariable, KernelArgument import loopy as lp if isinstance(obj, TemporaryVariable): result = [obj.dtype] if result[0] is lp.auto: self.symbols_with_unknown_types.add(expr.name) return [] else: return result elif isinstance(obj, KernelArgument): result = [obj.dtype] if result[0] is None: self.symbols_with_unknown_types.add(expr.name) return [] else: return result else: raise RuntimeError("unexpected type inference " "object type for '%s'" % expr.name)
def combine(dtype_sets): """ :arg dtype_sets: A list of lists, where each of the inner lists consists of either zero or one type. An empty list is consistent with any type. A list with a type requires that an operation be valid in conjunction with that type. """ dtype_sets = list(dtype_sets) from loopy.types import LoopyType, NumpyType assert all( all(isinstance(dtype, LoopyType) for dtype in dtype_set) for dtype_set in dtype_sets) assert all(0 <= len(dtype_set) <= 1 for dtype_set in dtype_sets) from pytools import is_single_valued dtypes = [dtype for dtype_set in dtype_sets for dtype in dtype_set] if not all(isinstance(dtype, NumpyType) for dtype in dtypes): if not is_single_valued(dtypes): raise TypeInferenceFailure( "Nothing known about operations between '%s'" % ", ".join(str(dtype) for dtype in dtypes)) return [dtypes[0]] numpy_dtypes = [dtype.dtype for dtype in dtypes] if not numpy_dtypes: return [] if is_single_valued(numpy_dtypes): return [dtypes[0]] result = numpy_dtypes.pop() while numpy_dtypes: other = numpy_dtypes.pop() if result.fields is None and other.fields is None: if (result, other) in [(np.int32, np.float32), (np.float32, np.int32)]: # numpy makes this a double. I disagree. result = np.dtype(np.float32) else: result = (np.empty(0, dtype=result) + np.empty(0, dtype=other)).dtype elif result.fields is None and other.fields is not None: # assume the non-native type takes over # (This is used for vector types.) result = other elif result.fields is not None and other.fields is None: # assume the non-native type takes over # (This is used for vector types.) pass else: if result is not other: raise TypeInferenceFailure( "nothing known about result of operation on " "'%s' and '%s'" % (result, other)) return [NumpyType(result)]