Skip to content
4 changes: 2 additions & 2 deletions docs/source/developer/threading_implementation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ The general pattern for using ``get_num_threads`` in code generation is

.. code:: python

import llvmlite.llvmpy.core as lc
from llvmlite import ir as llvmir

get_num_threads = cgutils.get_or_insert_function(builder.module
lc.Type.function(lc.Type.int(types.intp.bitwidth), []),
llvmir.FunctionType(llvmir.IntType(types.intp.bitwidth), []),
name="get_num_threads")

num_threads = builder.call(get_num_threads, [])
Expand Down
2 changes: 1 addition & 1 deletion numba/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ def printf(self, builder, format_string, *args):
cstr = self.insert_const_string(mod, format_string)
else:
cstr = format_string
fnty = Type.function(Type.int(), (GENERIC_POINTER,), var_arg=True)
fnty = llvmir.FunctionType(llvmir.IntType(32), (GENERIC_POINTER,), var_arg=True)
Comment thread
esc marked this conversation as resolved.
Resolved
fn = cgutils.get_or_insert_function(mod, fnty, "printf")
return builder.call(fn, (cstr,) + tuple(args))

Expand Down
18 changes: 18 additions & 0 deletions numba/core/boxing.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,24 @@ def unbox_slice(typ, obj, c):
sli.step = step
return NativeValue(sli._getvalue(), is_error=c.builder.not_(ok))

@box(types.SliceLiteral)
def box_slice_literal(typ, val, c):
slice_lit = typ.literal_value
slice_fields = []
for field_name in ("start", "stop", "step"):
field_obj = getattr(slice_lit, field_name)
field_val = (
c.pyapi.make_none()
if field_obj is None
else c.pyapi.from_native_value(
types.literal(field_obj), field_obj, c.env_manager
)
)
slice_fields.append(field_val)
slice_val = c.pyapi.slice_new(*slice_fields)
for field_obj in slice_fields:
c.pyapi.decref(field_obj)
return slice_val

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like this might also work?

@box(types.SliceLiteral)
def box_slice_literal(typ, val, c):
    py_ctor, py_args = typ.literal_value.__reduce__()
    serialized_ctor = c.pyapi.serialize_object(py_ctor)
    serialized_args = c.pyapi.serialize_object(py_args)
    ctor = c.pyapi.unserialize(serialized_ctor)
    args = c.pyapi.unserialize(serialized_args)
    obj = c.pyapi.call(ctor, args)
    c.pyapi.decref(ctor)
    c.pyapi.decref(args)
    return obj

avoids needing to add slice_new to the pyapi too.

@njriasan njriasan Jun 14, 2022 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stuartarchibald I'm happy to update this code if you would like but I don't understand why this change is necessary/preferred. Is there a concern that creating native literals will have gaps/performs worse?


@unbox(types.StringLiteral)
def unbox_string_literal(typ, obj, c):
Expand Down
4 changes: 4 additions & 0 deletions numba/core/pythonapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,10 @@ def complex_imag_as_double(self, cobj):
#
# Concrete slice API
#
def slice_new(self, start, stop, step):
Comment thread
esc marked this conversation as resolved.
Resolved
fnty = ir.FunctionType(self.pyobj, [self.pyobj, self.pyobj, self.pyobj])
fn = self._get_function(fnty, name="PySlice_New")
return self.builder.call(fn, [start, stop, step])

def slice_as_ints(self, obj):
"""
Expand Down
22 changes: 21 additions & 1 deletion numba/tests/test_slices.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import numpy as np

from numba import jit, typeof, TypingError
from numba import jit, literally, njit, typeof, TypingError
from numba.core import utils, types
from numba.tests.support import TestCase, MemoryLeakMixin
from numba.core.types.functions import _header_lead
Expand Down Expand Up @@ -207,6 +207,26 @@ def test_literal_slice_distinct(self):
self.assertNotEqual(sl1, sl2)
self.assertEqual(sl1, sl3)

def test_literal_slice_boxing(self):
Comment thread
esc marked this conversation as resolved.
Resolved
"""
Tests that a literal slice can be used
as an argument to a JIT function.
"""
Comment thread
esc marked this conversation as resolved.
Resolved
@njit
def f(x):
return literally(x)

slices = (
slice(1, 4, 2),
slice(1, 2),
slice(1),
slice(None, 1, 1),
slice(1, None, 1),
slice(None, None, 1)
)
for sl in slices:
self.assertEqual(sl, f(sl))

Comment thread
esc marked this conversation as resolved.
Resolved

if __name__ == '__main__':
unittest.main()