Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
06d69dd
Abstract out the call to array allocator as an intrinsic.
sklam May 24, 2021
81cba5d
Cleanup previous staging.
sklam May 25, 2021
c15fac1
Adding classmethod Array._allocate
sklam May 25, 2021
ac2708c
Use align instead of dtype
sklam May 25, 2021
ffcb989
Use array type to determine the classmethod
sklam May 25, 2021
b683418
Convert operator module functions to overloads.
stuartarchibald May 26, 2021
81ed617
Fix Black-Scholes test
stuartarchibald May 26, 2021
2b31732
Fix test_array_exprs
stuartarchibald May 26, 2021
64ca8bc
Flake8
stuartarchibald May 26, 2021
7ddd4d5
Fix error handling test
stuartarchibald May 26, 2021
37530ba
Fix debug test
stuartarchibald May 26, 2021
2cb8766
Fix up cache test
stuartarchibald May 26, 2021
2c0582c
Remove compile_isolated from svml tests
stuartarchibald May 27, 2021
6b8c62e
Fix test_debug in 32-bit platforms
sklam Jun 2, 2021
4188fe5
Fix fastmath propagation in SVML.
sklam Jun 3, 2021
b1b4fe3
Run SVML tests in isolated processes
sklam Jun 7, 2021
a5e7c43
Add inheriting behavior for error_model
sklam Jun 2, 2021
49f1dd8
Avoid compile_isolated in looplifting tests
sklam Jun 2, 2021
4024a9a
Revert "Convert operator module functions to overloads."
sklam Jun 8, 2021
57ebd93
Merge branch 'pr/7058' with revert of 0e323f5 into enh/arrayallocapi
sklam Jun 8, 2021
30b4eab
Revert patches specific to overload operators
sklam Jun 8, 2021
cec66fd
Test target specific overload_classmethod for allocator
stuartarchibald Jun 17, 2021
c5c08bb
Fix overload_method and attribute lookup not respecting hw class
sklam Jun 18, 2021
693f759
Fix typo
sklam Jun 23, 2021
609533a
Fix incorrect caching of BoundFunction due to target-overload
sklam Jun 23, 2021
1230e55
Merge branch 'master' into enh/arrayallocapi
sklam Jun 23, 2021
8fee312
Fix ir inlining test due to `inline` option in kwargs
sklam Jun 23, 2021
6c21b6d
More kwargs fixes
sklam Jun 24, 2021
144a840
Cleanup
sklam Jun 24, 2021
344c5b3
Apply suggestions from code review
sklam Jun 25, 2021
179767a
Remove dead code
sklam Jun 25, 2021
a5c48e6
Add timeout to avoid test hanging
sklam Jun 25, 2021
049923d
Remove redundant target_override and put nopython flag into jit_options
sklam Jun 25, 2021
f756fd0
PEP8
sklam Jun 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ exclude =
numba/tests/test_buffer_protocol.py
numba/tests/test_casting.py
numba/tests/test_lists.py
numba/tests/test_blackscholes.py
numba/tests/test_array_analysis.py
numba/tests/test_serialize.py
numba/tests/test_iteration.py
Expand Down
2 changes: 2 additions & 0 deletions numba/core/cpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,8 @@ def finalize(self, flags, options):

flags.inherit_if_not_set("fastmath")

flags.inherit_if_not_set("error_model", default="python")

# Add "target_backend" as a option that inherits from the caller
flags.inherit_if_not_set("target_backend")

Expand Down
11 changes: 11 additions & 0 deletions numba/core/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,17 @@ def __init__(self, exception):
self.old_exception = exception


class InternalTargetMismatchError(InternalError):
"""For signalling a target mismatch error occurred internally within the
compiler.
"""
def __init__(self, kind, target_hw, hw_clazz):
msg = (f"{kind.title()} being resolved on a target from which it does "
f"not inherit. Local target is {target_hw}, declared "
f"target class is {hw_clazz}.")
super().__init__(msg)


class RequireLiteralValue(TypingError):
"""
For signalling that a function's typing requires a constant value for
Expand Down
6 changes: 4 additions & 2 deletions numba/core/extending.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,12 @@ def _overload_method_common(typ, attr, **kwargs):
from numba.core.typing.templates import make_overload_method_template

def decorate(overload_func):
copied_kwargs = kwargs.copy() # avoid mutating parent dict
template = make_overload_method_template(
typ, attr, overload_func,
inline=kwargs.get('inline', 'never'),
prefer_literal=kwargs.get('prefer_literal', False)
inline=copied_kwargs.pop('inline', 'never'),
prefer_literal=copied_kwargs.pop('prefer_literal', False),
**copied_kwargs,
)
infer_getattr(template)
overload(overload_func, **kwargs)(overload_func)
Expand Down
30 changes: 30 additions & 0 deletions numba/core/target_extension.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from abc import ABC, abstractmethod
from numba.core.registry import DelayedRegistry, CPUDispatcher
from numba.core.decorators import jit
from numba.core.errors import InternalTargetMismatchError
from threading import local as tls


Expand Down Expand Up @@ -77,6 +78,35 @@ def resolve_dispatcher_from_str(target_str):
return dispatcher_registry[target_hw]


def _get_local_target_checked(tyctx, hwstr, reason):
"""Returns the local target if it is compatible with the given target
name during a type resolution; otherwise, raises an exception.

Parameters
----------
tyctx: typing context
hwstr: str
target name to check against
reason: str
Reason for the resolution. Expects a noun.
Returns
-------
target_hw : Target

Raises
------
InternalTargetMismatchError
"""
# Get the class for the target declared by the function
hw_clazz = resolve_target_str(hwstr)
# get the local target
target_hw = get_local_target(tyctx)
# make sure the target_hw is in the MRO for hw_clazz else bail
if not target_hw.inherits_from(hw_clazz):
raise InternalTargetMismatchError(reason, target_hw, hw_clazz)
return target_hw


class JitDecorator(ABC):

@abstractmethod
Expand Down
5 changes: 4 additions & 1 deletion numba/core/types/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,10 @@ def copy(self, this):

@property
def key(self):
return self.typing_key, self.this
# FIXME: With target-overload, the MethodTemplate can change depending
# on the target.
unique_impl = getattr(self.template, "_overload_func", None)
return self.typing_key, self.this, unique_impl

def get_impl_key(self, sig):
"""
Expand Down
28 changes: 27 additions & 1 deletion numba/core/typing/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,33 @@ def core(typ):
return attrty

def find_matching_getattr_template(self, typ, attr):
for template in self._get_attribute_templates(typ):
from numba.core.target_extension import (target_registry,
get_local_target)

templates = list(self._get_attribute_templates(typ))

# get the current target target
target_hw = get_local_target(self)

# fish out templates that are specific to the target if a target is
# specified
DEFAULT_TARGET = 'generic'
usable = []
for ix, temp_cls in enumerate(templates):
md = getattr(temp_cls, "metadata", {})
hw = md.get('target', DEFAULT_TARGET)
if hw is not None:
hw_clazz = target_registry[hw]
if target_hw.inherits_from(hw_clazz):
usable.append((temp_cls, hw_clazz, ix))

# sort templates based on target specificity
def key(x):
return target_hw.__mro__.index(x[1])

order = [x[0] for x in sorted(usable, key=key)]
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved

for template in order:
return_type = template.resolve(typ, attr)
if return_type is not None:
return {
Expand Down
107 changes: 56 additions & 51 deletions numba/core/typing/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@

import numba
from numba.core import types, utils
from numba.core.errors import TypingError, InternalError
from numba.core.errors import (
TypingError,
InternalError,
InternalTargetMismatchError,
)
from numba.core.cpu_options import InlineOptions

# info store for inliner callback functions e.g. cost model
Expand Down Expand Up @@ -887,23 +891,13 @@ def generic(self, args, kws):
"""
Type the intrinsic by the arguments.
"""
from numba.core.target_extension import (get_local_target,
resolve_target_str,
from numba.core.target_extension import (_get_local_target_checked,
dispatcher_registry)
from numba.core.imputils import builtin_registry

cache_key = self.context, args, tuple(kws.items())
hwstr = self.metadata.get('target', 'generic')
# Get the class for the target declared by the function
hw_clazz = resolve_target_str(hwstr)
# get the local target
target_hw = get_local_target(self.context)
# make sure the target_hw is in the MRO for hw_clazz else bail
if not target_hw.inherits_from(hw_clazz):
msg = (f"Intrinsic being resolved on a target from which it does "
f"not inherit. Local target is {target_hw}, declared "
f"target class is {hw_clazz}.")
raise InternalError(msg)
target_hw = _get_local_target_checked(self.context, hwstr, "intrinsic")
disp = dispatcher_registry[target_hw]
tgtctx = disp.targetdescr.target_context
# This is all workarounds...
Expand Down Expand Up @@ -990,28 +984,12 @@ def make_intrinsic_template(handle, defn, name, kwargs):


class AttributeTemplate(object):
_initialized = False

def __init__(self, context):
self._lazy_class_init()
self.context = context

def resolve(self, value, attr):
return self._resolve(value, attr)

@classmethod
def _lazy_class_init(cls):
if not cls._initialized:
cls.do_class_init()
cls._initialized = True

@classmethod
def do_class_init(cls):
"""
Class-wide initialization. Can be overridden by subclasses to
register permanent typing or target hooks.
"""

def _resolve(self, value, attr):
fn = getattr(self, "resolve_%s" % attr, None)
if fn is None:
Expand All @@ -1038,15 +1016,33 @@ class _OverloadAttributeTemplate(AttributeTemplate):
def __init__(self, context):
super(_OverloadAttributeTemplate, self).__init__(context)
self.context = context
self._init_once()

@classmethod
def do_class_init(cls):
"""
Register attribute implementation.
def _get_target_registry(self):
"""Returns the registry for the current target
"""
from numba.core.imputils import lower_getattr
from numba.core.target_extension import (_get_local_target_checked,
dispatcher_registry)
hwstr = self.metadata.get('target', 'generic')
target_hw = _get_local_target_checked(self.context, hwstr, "attribute")
# Get resgistry for the current hardware
disp = dispatcher_registry[target_hw]
tgtctx = disp.targetdescr.target_context
tgtctx.refresh()
if builtin_registry in tgtctx._registries:
reg = builtin_registry
else:
# Pick a registry in which to install intrinsics
registries = iter(tgtctx._registries)
reg = next(registries)
return reg
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved

def _init_once(self):
cls = type(self)
attr = cls._attr

lower_getattr = self._get_target_registry().lower_getattr

@lower_getattr(cls.key, attr)
def getattr_impl(context, builder, typ, value):
typingctx = context.typing_context
Expand Down Expand Up @@ -1082,24 +1078,30 @@ class _OverloadMethodTemplate(_OverloadAttributeTemplate):
"""
is_method = True

@classmethod
def do_class_init(cls):
def _init_once(self):
"""
Register generic method implementation.
Overriding parent definition
"""
from numba.core.imputils import lower_builtin
attr = cls._attr
attr = self._attr

@lower_builtin((cls.key, attr), cls.key, types.VarArg(types.Any))
def method_impl(context, builder, sig, args):
typ = sig.args[0]
typing_context = context.typing_context
fnty = cls._get_function_type(typing_context, typ)
sig = cls._get_signature(typing_context, fnty, sig.args, {})
call = context.get_function(fnty, sig)
# Link dependent library
context.add_linking_libs(getattr(call, 'libs', ()))
return call(builder, args)
try:
registry = self._get_target_registry()
except InternalTargetMismatchError:
# Target mismatch. Do not register attribute lookup here.
pass
else:
lower_builtin = registry.lower

@lower_builtin((self.key, attr), self.key, types.VarArg(types.Any))
def method_impl(context, builder, sig, args):
typ = sig.args[0]
typing_context = context.typing_context
fnty = self._get_function_type(typing_context, typ)
sig = self._get_signature(typing_context, fnty, sig.args, {})
call = context.get_function(fnty, sig)
# Link dependent library
context.add_linking_libs(getattr(call, 'libs', ()))
return call(builder, args)

def _resolve(self, typ, attr):
if self._attr != attr:
Expand Down Expand Up @@ -1132,7 +1134,8 @@ def generic(_, args, kws):

def make_overload_attribute_template(typ, attr, overload_func, inline,
prefer_literal=False,
base=_OverloadAttributeTemplate):
base=_OverloadAttributeTemplate,
**kwargs):
"""
Make a template class for attribute *attr* of *typ* overloaded by
*overload_func*.
Expand All @@ -1145,20 +1148,22 @@ def make_overload_attribute_template(typ, attr, overload_func, inline,
_inline_overloads={},
_overload_func=staticmethod(overload_func),
prefer_literal=prefer_literal,
metadata=kwargs,
)
obj = type(base)(name, (base,), dct)
return obj


def make_overload_method_template(typ, attr, overload_func, inline,
prefer_literal=False):
prefer_literal=False, **kwargs):
"""
Make a template class for method *attr* of *typ* overloaded by
*overload_func*.
"""
return make_overload_attribute_template(
typ, attr, overload_func, inline=inline,
base=_OverloadMethodTemplate, prefer_literal=prefer_literal,
**kwargs,
)


Expand Down
42 changes: 39 additions & 3 deletions numba/np/arrayobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from numba.cpython import slicing
from numba.cpython.unsafe.tuple import tuple_setitem, build_full_slice_tuple
from numba.core.overload_glue import glue_lowering
from numba.core.extending import overload_classmethod


def set_range_metadata(builder, load, lower_bound, upper_bound):
Expand Down Expand Up @@ -3475,10 +3476,16 @@ def _empty_nd_impl(context, builder, arrtype, shapes):
" the maximum possible size.",)
)

align = context.get_preferred_array_alignment(arrtype.dtype)
meminfo = context.nrt.meminfo_alloc_aligned(builder, size=allocsize,
align=align)
dtype = arrtype.dtype
align_val = context.get_preferred_array_alignment(dtype)
align = context.get_constant(types.uint32, align_val)
args = (context.get_dummy_value(), allocsize, align)

mip = types.MemInfoPointer(types.voidptr)
arytypeclass = types.TypeRef(type(arrtype))
argtypes = signature(mip, arytypeclass, types.intp, types.uint32)

meminfo = context.compile_internal(builder, _call_allocator, argtypes, args)
data = context.nrt.meminfo_data(builder, meminfo)

intp_t = context.get_value_type(types.intp)
Expand All @@ -3495,6 +3502,35 @@ def _empty_nd_impl(context, builder, arrtype, shapes):
return ary


@overload_classmethod(types.Array, "_allocate")
def _ol_array_allocate(cls, allocsize, align):
"""Implements a Numba-only default target (cpu) classmethod on the array type.
"""
def impl(cls, allocsize, align):
return intrin_alloc(allocsize, align)
return impl


def _call_allocator(arrtype, size, align):
"""Trampoline to call the intrinsic used for allocation
"""
return arrtype._allocate(size, align)


@intrinsic
def intrin_alloc(typingctx, allocsize, align):
"""Intrinsic to call into the allocator for Array
"""
def codegen(context, builder, signature, args):
[allocsize, align] = args
meminfo = context.nrt.meminfo_alloc_aligned(builder, allocsize, align)
return meminfo

mip = types.MemInfoPointer(types.voidptr) # return untyped pointer
sig = signature(mip, allocsize, align)
return sig, codegen


def _zero_fill_array(context, builder, ary):
"""
Zero-fill an array. The array must be contiguous.
Expand Down
Loading