numba-cuda 0.17.0__py3-none-any.whl → 0.18.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of numba-cuda might be problematic. Click here for more details.

Files changed (64) hide show
  1. numba_cuda/VERSION +1 -1
  2. numba_cuda/numba/cuda/__init__.py +0 -8
  3. numba_cuda/numba/cuda/_internal/cuda_fp16.py +14225 -0
  4. numba_cuda/numba/cuda/api_util.py +6 -0
  5. numba_cuda/numba/cuda/cgutils.py +1291 -0
  6. numba_cuda/numba/cuda/codegen.py +32 -14
  7. numba_cuda/numba/cuda/compiler.py +113 -10
  8. numba_cuda/numba/cuda/core/caching.py +741 -0
  9. numba_cuda/numba/cuda/core/callconv.py +338 -0
  10. numba_cuda/numba/cuda/core/codegen.py +168 -0
  11. numba_cuda/numba/cuda/core/compiler.py +205 -0
  12. numba_cuda/numba/cuda/core/typed_passes.py +139 -0
  13. numba_cuda/numba/cuda/cudadecl.py +0 -268
  14. numba_cuda/numba/cuda/cudadrv/devicearray.py +3 -0
  15. numba_cuda/numba/cuda/cudadrv/driver.py +2 -1
  16. numba_cuda/numba/cuda/cudadrv/nvvm.py +1 -1
  17. numba_cuda/numba/cuda/cudaimpl.py +4 -178
  18. numba_cuda/numba/cuda/debuginfo.py +469 -3
  19. numba_cuda/numba/cuda/device_init.py +0 -1
  20. numba_cuda/numba/cuda/dispatcher.py +310 -11
  21. numba_cuda/numba/cuda/extending.py +2 -1
  22. numba_cuda/numba/cuda/fp16.py +348 -0
  23. numba_cuda/numba/cuda/intrinsics.py +1 -1
  24. numba_cuda/numba/cuda/libdeviceimpl.py +2 -1
  25. numba_cuda/numba/cuda/lowering.py +1833 -8
  26. numba_cuda/numba/cuda/mathimpl.py +2 -90
  27. numba_cuda/numba/cuda/nvvmutils.py +2 -1
  28. numba_cuda/numba/cuda/printimpl.py +2 -1
  29. numba_cuda/numba/cuda/serialize.py +264 -0
  30. numba_cuda/numba/cuda/simulator/__init__.py +2 -0
  31. numba_cuda/numba/cuda/simulator/dispatcher.py +7 -0
  32. numba_cuda/numba/cuda/stubs.py +0 -308
  33. numba_cuda/numba/cuda/target.py +13 -5
  34. numba_cuda/numba/cuda/testing.py +156 -5
  35. numba_cuda/numba/cuda/tests/complex_usecases.py +113 -0
  36. numba_cuda/numba/cuda/tests/core/serialize_usecases.py +110 -0
  37. numba_cuda/numba/cuda/tests/core/test_serialize.py +359 -0
  38. numba_cuda/numba/cuda/tests/cudadrv/test_context_stack.py +10 -4
  39. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_ndarray.py +33 -0
  40. numba_cuda/numba/cuda/tests/cudadrv/test_runtime.py +2 -2
  41. numba_cuda/numba/cuda/tests/cudadrv/test_streams.py +1 -0
  42. numba_cuda/numba/cuda/tests/cudapy/extensions_usecases.py +1 -1
  43. numba_cuda/numba/cuda/tests/cudapy/test_caching.py +5 -10
  44. numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +15 -0
  45. numba_cuda/numba/cuda/tests/cudapy/test_complex.py +1 -1
  46. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +381 -0
  47. numba_cuda/numba/cuda/tests/cudapy/test_enums.py +1 -1
  48. numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1 -1
  49. numba_cuda/numba/cuda/tests/cudapy/test_inspect.py +108 -24
  50. numba_cuda/numba/cuda/tests/cudapy/test_intrinsics.py +37 -23
  51. numba_cuda/numba/cuda/tests/cudapy/test_operator.py +43 -27
  52. numba_cuda/numba/cuda/tests/cudapy/test_ufuncs.py +26 -9
  53. numba_cuda/numba/cuda/tests/cudapy/test_warning.py +27 -2
  54. numba_cuda/numba/cuda/tests/enum_usecases.py +56 -0
  55. numba_cuda/numba/cuda/tests/nocuda/test_library_lookup.py +1 -2
  56. numba_cuda/numba/cuda/tests/nocuda/test_nvvm.py +1 -1
  57. numba_cuda/numba/cuda/utils.py +785 -0
  58. numba_cuda/numba/cuda/vector_types.py +1 -1
  59. {numba_cuda-0.17.0.dist-info → numba_cuda-0.18.1.dist-info}/METADATA +18 -4
  60. {numba_cuda-0.17.0.dist-info → numba_cuda-0.18.1.dist-info}/RECORD +63 -50
  61. numba_cuda/numba/cuda/cpp_function_wrappers.cu +0 -46
  62. {numba_cuda-0.17.0.dist-info → numba_cuda-0.18.1.dist-info}/WHEEL +0 -0
  63. {numba_cuda-0.17.0.dist-info → numba_cuda-0.18.1.dist-info}/licenses/LICENSE +0 -0
  64. {numba_cuda-0.17.0.dist-info → numba_cuda-0.18.1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,1822 @@
1
- from numba.core.lowering import Lower
2
- from llvmlite import ir
3
- from numba.core import ir as numba_ir
4
- from numba.core import types
1
+ from collections import namedtuple, defaultdict
2
+ import operator
3
+ import warnings
4
+ from functools import partial
5
+
6
+ from llvmlite import ir as llvm_ir
7
+
8
+ from numba.core import (
9
+ typing,
10
+ utils,
11
+ types,
12
+ ir,
13
+ debuginfo,
14
+ funcdesc,
15
+ generators,
16
+ config,
17
+ ir_utils,
18
+ cgutils,
19
+ removerefctpass,
20
+ targetconfig,
21
+ )
22
+ from numba.core.errors import (
23
+ LoweringError,
24
+ new_error_context,
25
+ TypingError,
26
+ LiteralTypingError,
27
+ UnsupportedError,
28
+ NumbaDebugInfoWarning,
29
+ )
30
+ from numba.core.funcdesc import default_mangler
31
+ from numba.core.environment import Environment
32
+ from numba.core.analysis import compute_use_defs, must_use_alloca
33
+ from numba.misc.firstlinefinder import get_func_body_first_lineno
34
+ from numba import version_info
35
+
36
+ numba_version = version_info.short
37
+ del version_info
38
+ if numba_version > (0, 60):
39
+ from numba.misc.coverage_support import get_registered_loc_notify
40
+
41
+
42
+ _VarArgItem = namedtuple("_VarArgItem", ("vararg", "index"))
43
+
44
+
45
+ class BaseLower(object):
46
+ """
47
+ Lower IR to LLVM
48
+ """
49
+
50
+ def __init__(self, context, library, fndesc, func_ir, metadata=None):
51
+ self.library = library
52
+ self.fndesc = fndesc
53
+ self.blocks = utils.SortedMap(func_ir.blocks.items())
54
+ self.func_ir = func_ir
55
+ self.generator_info = func_ir.generator_info
56
+ self.metadata = metadata
57
+ self.flags = targetconfig.ConfigStack.top_or_none()
58
+
59
+ # Initialize LLVM
60
+ self.module = self.library.create_ir_module(self.fndesc.unique_name)
61
+
62
+ # Python execution environment (will be available to the compiled
63
+ # function).
64
+ self.env = Environment.from_fndesc(self.fndesc)
65
+
66
+ # Internal states
67
+ self.blkmap = {}
68
+ self.pending_phis = {}
69
+ self.varmap = {}
70
+ self.firstblk = min(self.blocks.keys())
71
+ self.loc = -1
72
+
73
+ # Specializes the target context as seen inside the Lowerer
74
+ # This adds:
75
+ # - environment: the python execution environment
76
+ self.context = context.subtarget(
77
+ environment=self.env, fndesc=self.fndesc
78
+ )
79
+
80
+ # Debuginfo
81
+ dibuildercls = (
82
+ self.context.DIBuilder
83
+ if self.context.enable_debuginfo
84
+ else debuginfo.DummyDIBuilder
85
+ )
86
+
87
+ # debuginfo def location
88
+ self.defn_loc = self._compute_def_location()
89
+
90
+ directives_only = self.flags.dbg_directives_only
91
+ self.debuginfo = dibuildercls(
92
+ module=self.module,
93
+ filepath=func_ir.loc.filename,
94
+ cgctx=context,
95
+ directives_only=directives_only,
96
+ )
97
+
98
+ if numba_version > (0, 60):
99
+ # Loc notify objects
100
+ self._loc_notify_registry = get_registered_loc_notify()
101
+
102
+ # Subclass initialization
103
+ self.init()
104
+
105
+ @property
106
+ def call_conv(self):
107
+ return self.context.call_conv
108
+
109
+ def init(self):
110
+ pass
111
+
112
+ def init_pyapi(self):
113
+ """
114
+ Init the Python API and Environment Manager for the function being
115
+ lowered.
116
+ """
117
+ if self.pyapi is not None:
118
+ return
119
+ self.pyapi = self.context.get_python_api(self.builder)
120
+
121
+ # Store environment argument for later use
122
+ self.env_manager = self.context.get_env_manager(self.builder)
123
+ self.env_body = self.env_manager.env_body
124
+ self.envarg = self.env_manager.env_ptr
125
+
126
+ def _compute_def_location(self):
127
+ # Debuginfo requires source to be accurate. Find it and warn if not
128
+ # found. If it's not found, use the func_ir line + 1, this assumes that
129
+ # the function definition is decorated with a 1 line jit decorator.
130
+ defn_loc = self.func_ir.loc.with_lineno(self.func_ir.loc.line + 1)
131
+ if self.context.enable_debuginfo:
132
+ fn = self.func_ir.func_id.func
133
+ optional_lno = get_func_body_first_lineno(fn)
134
+ if optional_lno is not None:
135
+ # -1 as lines start at 1 and this is an offset.
136
+ offset = optional_lno - 1
137
+ defn_loc = self.func_ir.loc.with_lineno(offset)
138
+ else:
139
+ msg = (
140
+ "Could not find source for function: "
141
+ f"{self.func_ir.func_id.func}. Debug line information "
142
+ "may be inaccurate."
143
+ )
144
+ warnings.warn(NumbaDebugInfoWarning(msg))
145
+ return defn_loc
146
+
147
+ def pre_lower(self):
148
+ """
149
+ Called before lowering all blocks.
150
+ """
151
+ # A given Lower object can be used for several LL functions
152
+ # (for generators) and it's important to use a new API and
153
+ # EnvironmentManager.
154
+ self.pyapi = None
155
+ self.debuginfo.mark_subprogram(
156
+ function=self.builder.function,
157
+ qualname=self.fndesc.qualname,
158
+ argnames=self.fndesc.args,
159
+ argtypes=self.fndesc.argtypes,
160
+ line=self.defn_loc.line,
161
+ )
162
+
163
+ # When full debug info is enabled, disable inlining where possible, to
164
+ # improve the quality of the debug experience. 'alwaysinline' functions
165
+ # cannot have inlining disabled.
166
+ attributes = self.builder.function.attributes
167
+ full_debug = self.flags.debuginfo and not self.flags.dbg_directives_only
168
+ if full_debug and "alwaysinline" not in attributes:
169
+ attributes.add("noinline")
170
+
171
+ def post_lower(self):
172
+ """
173
+ Called after all blocks are lowered
174
+ """
175
+ self.debuginfo.finalize()
176
+ if numba_version > (0, 60):
177
+ for notify in self._loc_notify_registry:
178
+ notify.close()
179
+
180
+ def pre_block(self, block):
181
+ """
182
+ Called before lowering a block.
183
+ """
184
+
185
+ def post_block(self, block):
186
+ """
187
+ Called after lowering a block.
188
+ """
189
+
190
+ def return_dynamic_exception(self, exc_class, exc_args, nb_types, loc=None):
191
+ self.call_conv.return_dynamic_user_exc(
192
+ self.builder,
193
+ exc_class,
194
+ exc_args,
195
+ nb_types,
196
+ loc=loc,
197
+ func_name=self.func_ir.func_id.func_name,
198
+ )
199
+
200
+ def return_exception(self, exc_class, exc_args=None, loc=None):
201
+ """Propagate exception to the caller."""
202
+ self.call_conv.return_user_exc(
203
+ self.builder,
204
+ exc_class,
205
+ exc_args,
206
+ loc=loc,
207
+ func_name=self.func_ir.func_id.func_name,
208
+ )
209
+
210
+ def set_exception(self, exc_class, exc_args=None, loc=None):
211
+ """Set exception state in the current function."""
212
+ self.call_conv.set_static_user_exc(
213
+ self.builder,
214
+ exc_class,
215
+ exc_args,
216
+ loc=loc,
217
+ func_name=self.func_ir.func_id.func_name,
218
+ )
219
+
220
+ def emit_environment_object(self):
221
+ """Emit a pointer to hold the Environment object."""
222
+ # Define global for the environment and initialize it to NULL
223
+ envname = self.context.get_env_name(self.fndesc)
224
+ self.context.declare_env_global(self.module, envname)
225
+
226
+ def lower(self):
227
+ # Emit the Env into the module
228
+ self.emit_environment_object()
229
+ if self.generator_info is None:
230
+ self.genlower = None
231
+ self.lower_normal_function(self.fndesc)
232
+ else:
233
+ self.genlower = self.GeneratorLower(self)
234
+ self.gentype = self.genlower.gentype
235
+
236
+ self.genlower.lower_init_func(self)
237
+ self.genlower.lower_next_func(self)
238
+ if self.gentype.has_finalizer:
239
+ self.genlower.lower_finalize_func(self)
240
+
241
+ if config.DUMP_LLVM:
242
+ utils.dump_llvm(self.fndesc, self.module)
243
+
244
+ # Special optimization to remove NRT on functions that do not need it.
245
+ if self.context.enable_nrt and self.generator_info is None:
246
+ removerefctpass.remove_unnecessary_nrt_usage(
247
+ self.function, context=self.context, fndesc=self.fndesc
248
+ )
249
+
250
+ # Run target specific post lowering transformation
251
+ self.context.post_lowering(self.module, self.library)
252
+
253
+ # Materialize LLVM Module
254
+ self.library.add_ir_module(self.module)
255
+
256
+ def extract_function_arguments(self):
257
+ self.fnargs = self.call_conv.decode_arguments(
258
+ self.builder, self.fndesc.argtypes, self.function
259
+ )
260
+ return self.fnargs
261
+
262
+ def lower_normal_function(self, fndesc):
263
+ """
264
+ Lower non-generator *fndesc*.
265
+ """
266
+ self.setup_function(fndesc)
267
+
268
+ # Init argument values
269
+ self.extract_function_arguments()
270
+ entry_block_tail = self.lower_function_body()
271
+
272
+ # Close tail of entry block, do not emit debug metadata else the
273
+ # unconditional jump gets associated with the metadata from the function
274
+ # body end.
275
+ with debuginfo.suspend_emission(self.builder):
276
+ self.builder.position_at_end(entry_block_tail)
277
+ self.builder.branch(self.blkmap[self.firstblk])
278
+
279
+ def lower_function_body(self):
280
+ """
281
+ Lower the current function's body, and return the entry block.
282
+ """
283
+ # Init Python blocks
284
+ for offset in self.blocks:
285
+ bname = "B%s" % offset
286
+ self.blkmap[offset] = self.function.append_basic_block(bname)
287
+
288
+ self.pre_lower()
289
+ # pre_lower() may have changed the current basic block
290
+ entry_block_tail = self.builder.basic_block
291
+
292
+ self.debug_print(
293
+ "# function begin: {0}".format(self.fndesc.unique_name)
294
+ )
295
+
296
+ # Lower all blocks
297
+ for offset, block in sorted(self.blocks.items()):
298
+ bb = self.blkmap[offset]
299
+ self.builder.position_at_end(bb)
300
+ self.debug_print(f"# lower block: {offset}")
301
+ self.lower_block(block)
302
+ self.post_lower()
303
+ return entry_block_tail
304
+
305
+ def lower_block(self, block):
306
+ """
307
+ Lower the given block.
308
+ """
309
+ self.pre_block(block)
310
+ for inst in block.body:
311
+ self.loc = inst.loc
312
+ defaulterrcls = partial(LoweringError, loc=self.loc)
313
+ with new_error_context(
314
+ 'lowering "{inst}" at {loc}',
315
+ inst=inst,
316
+ loc=self.loc,
317
+ errcls_=defaulterrcls,
318
+ ):
319
+ self.lower_inst(inst)
320
+ self.post_block(block)
321
+
322
+ def create_cpython_wrapper(self, release_gil=False):
323
+ """
324
+ Create CPython wrapper(s) around this function (or generator).
325
+ """
326
+ if self.genlower:
327
+ self.context.create_cpython_wrapper(
328
+ self.library,
329
+ self.genlower.gendesc,
330
+ self.env,
331
+ self.call_helper,
332
+ release_gil=release_gil,
333
+ )
334
+ self.context.create_cpython_wrapper(
335
+ self.library,
336
+ self.fndesc,
337
+ self.env,
338
+ self.call_helper,
339
+ release_gil=release_gil,
340
+ )
341
+
342
+ def create_cfunc_wrapper(self):
343
+ """
344
+ Create C wrapper around this function.
345
+ """
346
+ if self.genlower:
347
+ raise UnsupportedError("generator as a first-class function type")
348
+ self.context.create_cfunc_wrapper(
349
+ self.library, self.fndesc, self.env, self.call_helper
350
+ )
351
+
352
+ def setup_function(self, fndesc):
353
+ # Setup function
354
+ self.function = self.context.declare_function(self.module, fndesc)
355
+ if self.flags.dbg_optnone:
356
+ attrset = self.function.attributes
357
+ if "alwaysinline" not in attrset:
358
+ attrset.add("optnone")
359
+ attrset.add("noinline")
360
+ self.entry_block = self.function.append_basic_block("entry")
361
+ self.builder = llvm_ir.IRBuilder(self.entry_block)
362
+ self.call_helper = self.call_conv.init_call_helper(self.builder)
363
+
364
+ def typeof(self, varname):
365
+ return self.fndesc.typemap[varname]
366
+
367
+ def notify_loc(self, loc: ir.Loc) -> None:
368
+ """Called when a new instruction with the given `loc` is about to be
369
+ lowered.
370
+ """
371
+ if numba_version > (0, 60):
372
+ for notify_obj in self._loc_notify_registry:
373
+ notify_obj.notify(loc)
374
+ else:
375
+ pass
376
+
377
+ def debug_print(self, msg):
378
+ if config.DEBUG_JIT:
379
+ self.context.debug_print(
380
+ self.builder, f"DEBUGJIT [{self.fndesc.qualname}]: {msg}"
381
+ )
382
+
383
+ def print_variable(self, msg, varname):
384
+ """Helper to emit ``print(msg, varname)`` for debugging.
385
+
386
+ Parameters
387
+ ----------
388
+ msg : str
389
+ Literal string to be printed.
390
+ varname : str
391
+ A variable name whose value will be printed.
392
+ """
393
+ argtys = (types.literal(msg), self.fndesc.typemap[varname])
394
+ args = (
395
+ self.context.get_dummy_value(),
396
+ self.loadvar(varname),
397
+ )
398
+ sig = typing.signature(types.none, *argtys)
399
+
400
+ impl = self.context.get_function(print, sig)
401
+ impl(self.builder, args)
402
+
403
+
404
+ class Lower(BaseLower):
405
+ GeneratorLower = generators.GeneratorLower
406
+
407
+ def init(self):
408
+ super().init()
409
+ # find all singly assigned variables
410
+ self._find_singly_assigned_variable()
411
+
412
+ @property
413
+ def _disable_sroa_like_opt(self):
414
+ """Flags that the SROA like optimisation that Numba performs (which
415
+ prevent alloca and subsequent load/store for locals) should be disabled.
416
+ Currently, this is conditional solely on the presence of a request for
417
+ the emission of debug information."""
418
+ if self.flags is None:
419
+ return False
420
+
421
+ return self.flags.debuginfo and not self.flags.dbg_directives_only
422
+
423
+ def _find_singly_assigned_variable(self):
424
+ func_ir = self.func_ir
425
+ blocks = func_ir.blocks
426
+
427
+ sav = set()
428
+
429
+ if not self.func_ir.func_id.is_generator:
430
+ use_defs = compute_use_defs(blocks)
431
+ alloca_vars = must_use_alloca(blocks)
432
+
433
+ # Compute where variables are defined
434
+ var_assign_map = defaultdict(set)
435
+ for blk, vl in use_defs.defmap.items():
436
+ for var in vl:
437
+ var_assign_map[var].add(blk)
438
+
439
+ # Compute where variables are used
440
+ var_use_map = defaultdict(set)
441
+ for blk, vl in use_defs.usemap.items():
442
+ for var in vl:
443
+ var_use_map[var].add(blk)
444
+
445
+ # Keep only variables that are defined locally and used locally
446
+ for var in var_assign_map:
447
+ if var not in alloca_vars and len(var_assign_map[var]) == 1:
448
+ # Usemap does not keep locally defined variables.
449
+ if len(var_use_map[var]) == 0:
450
+ # Ensure that the variable is not defined multiple times
451
+ # in the block
452
+ [defblk] = var_assign_map[var]
453
+ assign_stmts = self.blocks[defblk].find_insts(ir.Assign)
454
+ assigns = [
455
+ stmt
456
+ for stmt in assign_stmts
457
+ if stmt.target.name == var
458
+ ]
459
+ if len(assigns) == 1:
460
+ sav.add(var)
461
+
462
+ self._singly_assigned_vars = sav
463
+ self._blk_local_varmap = {}
464
+
465
+ def pre_block(self, block):
466
+ from numba.core.unsafe import eh
467
+
468
+ super(Lower, self).pre_block(block)
469
+ self._cur_ir_block = block
470
+
471
+ if block == self.firstblk:
472
+ # create slots for all the vars, irrespective of whether they are
473
+ # initialized, SSA will pick this up and warn users about using
474
+ # uninitialized variables. Slots are added as alloca in the first
475
+ # block
476
+ bb = self.blkmap[self.firstblk]
477
+ self.builder.position_at_end(bb)
478
+ all_names = set()
479
+ for block in self.blocks.values():
480
+ for x in block.find_insts(ir.Del):
481
+ if x.value not in all_names:
482
+ all_names.add(x.value)
483
+ for name in all_names:
484
+ fetype = self.typeof(name)
485
+ self._alloca_var(name, fetype)
486
+
487
+ # Detect if we are in a TRY block by looking for a call to
488
+ # `eh.exception_check`.
489
+ for call in block.find_exprs(op="call"):
490
+ defn = ir_utils.guard(
491
+ ir_utils.get_definition,
492
+ self.func_ir,
493
+ call.func,
494
+ )
495
+ if defn is not None and isinstance(defn, ir.Global):
496
+ if defn.value is eh.exception_check:
497
+ if isinstance(block.terminator, ir.Branch):
498
+ targetblk = self.blkmap[block.terminator.truebr]
499
+ # NOTE: This hacks in an attribute for call_conv to
500
+ # pick up. This hack is no longer needed when
501
+ # all old-style implementations are gone.
502
+ self.builder._in_try_block = {"target": targetblk}
503
+ break
504
+
505
+ def post_block(self, block):
506
+ # Clean-up
507
+ try:
508
+ del self.builder._in_try_block
509
+ except AttributeError:
510
+ pass
511
+
512
+ def lower_inst(self, inst):
513
+ # Set debug location for all subsequent LL instructions
514
+ self.debuginfo.mark_location(self.builder, self.loc.line)
515
+ self.notify_loc(self.loc)
516
+ self.debug_print(str(inst))
517
+ if isinstance(inst, ir.Assign):
518
+ ty = self.typeof(inst.target.name)
519
+ val = self.lower_assign(ty, inst)
520
+ argidx = None
521
+ # If this is a store from an arg, like x = arg.x then tell debuginfo
522
+ # that this is the arg
523
+ if isinstance(inst.value, ir.Arg):
524
+ # NOTE: debug location is the `def <func>` line
525
+ self.debuginfo.mark_location(self.builder, self.defn_loc.line)
526
+ argidx = inst.value.index + 1 # args start at 1
527
+ self.storevar(val, inst.target.name, argidx=argidx)
528
+
529
+ elif isinstance(inst, ir.Branch):
530
+ cond = self.loadvar(inst.cond.name)
531
+ tr = self.blkmap[inst.truebr]
532
+ fl = self.blkmap[inst.falsebr]
533
+
534
+ condty = self.typeof(inst.cond.name)
535
+ pred = self.context.cast(self.builder, cond, condty, types.boolean)
536
+ assert pred.type == llvm_ir.IntType(1), (
537
+ "cond is not i1: %s" % pred.type
538
+ )
539
+ self.builder.cbranch(pred, tr, fl)
540
+
541
+ elif isinstance(inst, ir.Jump):
542
+ target = self.blkmap[inst.target]
543
+ self.builder.branch(target)
544
+
545
+ elif isinstance(inst, ir.Return):
546
+ if self.generator_info:
547
+ # StopIteration
548
+ self.genlower.return_from_generator(self)
549
+ return
550
+ val = self.loadvar(inst.value.name)
551
+ oty = self.typeof(inst.value.name)
552
+ ty = self.fndesc.restype
553
+ if isinstance(ty, types.Optional):
554
+ # If returning an optional type
555
+ self.call_conv.return_optional_value(self.builder, ty, oty, val)
556
+ return
557
+ assert ty == oty, (
558
+ "type '{}' does not match return type '{}'".format(oty, ty)
559
+ )
560
+ retval = self.context.get_return_value(self.builder, ty, val)
561
+ self.call_conv.return_value(self.builder, retval)
562
+
563
+ elif isinstance(inst, ir.PopBlock):
564
+ pass # this is just a marker
565
+
566
+ elif isinstance(inst, ir.StaticSetItem):
567
+ signature = self.fndesc.calltypes[inst]
568
+ assert signature is not None
569
+ try:
570
+ impl = self.context.get_function("static_setitem", signature)
571
+ except NotImplementedError:
572
+ return self.lower_setitem(
573
+ inst.target, inst.index_var, inst.value, signature
574
+ )
575
+ else:
576
+ target = self.loadvar(inst.target.name)
577
+ value = self.loadvar(inst.value.name)
578
+ valuety = self.typeof(inst.value.name)
579
+ value = self.context.cast(
580
+ self.builder, value, valuety, signature.args[2]
581
+ )
582
+ return impl(self.builder, (target, inst.index, value))
583
+
584
+ elif isinstance(inst, ir.Print):
585
+ self.lower_print(inst)
586
+
587
+ elif isinstance(inst, ir.SetItem):
588
+ signature = self.fndesc.calltypes[inst]
589
+ assert signature is not None
590
+ return self.lower_setitem(
591
+ inst.target, inst.index, inst.value, signature
592
+ )
593
+
594
+ elif isinstance(inst, ir.StoreMap):
595
+ signature = self.fndesc.calltypes[inst]
596
+ assert signature is not None
597
+ return self.lower_setitem(inst.dct, inst.key, inst.value, signature)
598
+
599
+ elif isinstance(inst, ir.DelItem):
600
+ target = self.loadvar(inst.target.name)
601
+ index = self.loadvar(inst.index.name)
602
+
603
+ targetty = self.typeof(inst.target.name)
604
+ indexty = self.typeof(inst.index.name)
605
+
606
+ signature = self.fndesc.calltypes[inst]
607
+ assert signature is not None
608
+
609
+ op = operator.delitem
610
+ fnop = self.context.typing_context.resolve_value_type(op)
611
+ callsig = fnop.get_call_type(
612
+ self.context.typing_context,
613
+ signature.args,
614
+ {},
615
+ )
616
+ impl = self.context.get_function(fnop, callsig)
617
+
618
+ assert targetty == signature.args[0]
619
+ index = self.context.cast(
620
+ self.builder, index, indexty, signature.args[1]
621
+ )
622
+
623
+ return impl(self.builder, (target, index))
624
+
625
+ elif isinstance(inst, ir.Del):
626
+ self.delvar(inst.value)
627
+
628
+ elif isinstance(inst, ir.SetAttr):
629
+ target = self.loadvar(inst.target.name)
630
+ value = self.loadvar(inst.value.name)
631
+ signature = self.fndesc.calltypes[inst]
632
+
633
+ targetty = self.typeof(inst.target.name)
634
+ valuety = self.typeof(inst.value.name)
635
+ assert signature is not None
636
+ assert signature.args[0] == targetty
637
+ impl = self.context.get_setattr(inst.attr, signature)
638
+
639
+ # Convert argument to match
640
+ value = self.context.cast(
641
+ self.builder, value, valuety, signature.args[1]
642
+ )
643
+
644
+ return impl(self.builder, (target, value))
645
+
646
+ elif isinstance(inst, ir.DynamicRaise):
647
+ self.lower_dynamic_raise(inst)
648
+
649
+ elif isinstance(inst, ir.DynamicTryRaise):
650
+ self.lower_try_dynamic_raise(inst)
651
+
652
+ elif isinstance(inst, ir.StaticRaise):
653
+ self.lower_static_raise(inst)
654
+
655
+ elif isinstance(inst, ir.StaticTryRaise):
656
+ self.lower_static_try_raise(inst)
657
+
658
+ else:
659
+ raise NotImplementedError(type(inst))
660
+
661
+ def lower_setitem(self, target_var, index_var, value_var, signature):
662
+ target = self.loadvar(target_var.name)
663
+ value = self.loadvar(value_var.name)
664
+ index = self.loadvar(index_var.name)
665
+
666
+ targetty = self.typeof(target_var.name)
667
+ valuety = self.typeof(value_var.name)
668
+ indexty = self.typeof(index_var.name)
669
+
670
+ op = operator.setitem
671
+ fnop = self.context.typing_context.resolve_value_type(op)
672
+ callsig = fnop.get_call_type(
673
+ self.context.typing_context,
674
+ signature.args,
675
+ {},
676
+ )
677
+ impl = self.context.get_function(fnop, callsig)
678
+
679
+ # Convert argument to match
680
+ if isinstance(targetty, types.Optional):
681
+ target = self.context.cast(
682
+ self.builder, target, targetty, targetty.type
683
+ )
684
+ else:
685
+ ul = types.unliteral
686
+ assert ul(targetty) == ul(signature.args[0])
687
+
688
+ index = self.context.cast(
689
+ self.builder, index, indexty, signature.args[1]
690
+ )
691
+ value = self.context.cast(
692
+ self.builder, value, valuety, signature.args[2]
693
+ )
694
+
695
+ return impl(self.builder, (target, index, value))
696
+
697
+ def lower_try_dynamic_raise(self, inst):
698
+ # Numba is a bit limited in what it can do with exceptions in a try
699
+ # block. Thus, it is safe to use the same code as the static try raise.
700
+ self.lower_static_try_raise(inst)
701
+
702
+ def lower_dynamic_raise(self, inst):
703
+ exc_args = inst.exc_args
704
+ args = []
705
+ nb_types = []
706
+ for exc_arg in exc_args:
707
+ if isinstance(exc_arg, ir.Var):
708
+ # dynamic values
709
+ typ = self.typeof(exc_arg.name)
710
+ val = self.loadvar(exc_arg.name)
711
+ self.incref(typ, val)
712
+ else:
713
+ typ = None
714
+ val = exc_arg
715
+ nb_types.append(typ)
716
+ args.append(val)
717
+
718
+ self.return_dynamic_exception(
719
+ inst.exc_class, tuple(args), tuple(nb_types), loc=self.loc
720
+ )
721
+
722
+ def lower_static_raise(self, inst):
723
+ if inst.exc_class is None:
724
+ # Reraise
725
+ self.return_exception(None, loc=self.loc)
726
+ else:
727
+ self.return_exception(inst.exc_class, inst.exc_args, loc=self.loc)
728
+
729
+ def lower_static_try_raise(self, inst):
730
+ if inst.exc_class is None:
731
+ # Reraise
732
+ self.set_exception(None, loc=self.loc)
733
+ else:
734
+ self.set_exception(inst.exc_class, inst.exc_args, loc=self.loc)
735
+
736
+ def lower_assign(self, ty, inst):
737
+ value = inst.value
738
+ # In nopython mode, closure vars are frozen like globals
739
+ if isinstance(value, (ir.Const, ir.Global, ir.FreeVar)):
740
+ res = self.context.get_constant_generic(
741
+ self.builder, ty, value.value
742
+ )
743
+ self.incref(ty, res)
744
+ return res
745
+
746
+ elif isinstance(value, ir.Expr):
747
+ return self.lower_expr(ty, value)
748
+
749
+ elif isinstance(value, ir.Var):
750
+ val = self.loadvar(value.name)
751
+ oty = self.typeof(value.name)
752
+ res = self.context.cast(self.builder, val, oty, ty)
753
+ self.incref(ty, res)
754
+ return res
755
+
756
+ elif isinstance(value, ir.Arg):
757
+ # Suspend debug info else all the arg repacking ends up being
758
+ # associated with some line or other and it's actually just a detail
759
+ # of Numba's CC.
760
+ with debuginfo.suspend_emission(self.builder):
761
+ # Cast from the argument type to the local variable type
762
+ # (note the "arg.FOO" convention as used in typeinfer)
763
+ argty = self.typeof("arg." + value.name)
764
+ if isinstance(argty, types.Omitted):
765
+ pyval = argty.value
766
+ tyctx = self.context.typing_context
767
+ valty = tyctx.resolve_value_type_prefer_literal(pyval)
768
+ # use the type of the constant value
769
+ const = self.context.get_constant_generic(
770
+ self.builder,
771
+ valty,
772
+ pyval,
773
+ )
774
+ # cast it to the variable type
775
+ res = self.context.cast(self.builder, const, valty, ty)
776
+ else:
777
+ val = self.fnargs[value.index]
778
+ res = self.context.cast(self.builder, val, argty, ty)
779
+ self.incref(ty, res)
780
+ return res
781
+
782
+ elif isinstance(value, ir.Yield):
783
+ res = self.lower_yield(ty, value)
784
+ self.incref(ty, res)
785
+ return res
786
+
787
+ raise NotImplementedError(type(value), value)
788
+
789
+ def lower_yield(self, retty, inst):
790
+ yp = self.generator_info.yield_points[inst.index]
791
+ assert yp.inst is inst
792
+ y = generators.LowerYield(self, yp, yp.live_vars)
793
+ y.lower_yield_suspend()
794
+ # Yield to caller
795
+ val = self.loadvar(inst.value.name)
796
+ typ = self.typeof(inst.value.name)
797
+ actual_rettyp = self.gentype.yield_type
798
+
799
+ # cast the local val to the type yielded
800
+ yret = self.context.cast(self.builder, val, typ, actual_rettyp)
801
+
802
+ # get the return repr of yielded value
803
+ retval = self.context.get_return_value(
804
+ self.builder,
805
+ actual_rettyp,
806
+ yret,
807
+ )
808
+
809
+ # return
810
+ self.call_conv.return_value(self.builder, retval)
811
+
812
+ # Resumption point
813
+ y.lower_yield_resume()
814
+ # None is returned by the yield expression
815
+ return self.context.get_constant_generic(self.builder, retty, None)
816
+
817
+ def lower_binop(self, resty, expr, op):
818
+ # if op in utils.OPERATORS_TO_BUILTINS:
819
+ # map operator.the_op => the corresponding types.Function()
820
+ # TODO: is this looks dodgy ...
821
+ op = self.context.typing_context.resolve_value_type(op)
822
+
823
+ lhs = expr.lhs
824
+ rhs = expr.rhs
825
+ static_lhs = expr.static_lhs
826
+ static_rhs = expr.static_rhs
827
+ lty = self.typeof(lhs.name)
828
+ rty = self.typeof(rhs.name)
829
+ lhs = self.loadvar(lhs.name)
830
+ rhs = self.loadvar(rhs.name)
831
+
832
+ # Convert argument to match
833
+ signature = self.fndesc.calltypes[expr]
834
+ lhs = self.context.cast(self.builder, lhs, lty, signature.args[0])
835
+ rhs = self.context.cast(self.builder, rhs, rty, signature.args[1])
836
+
837
+ def cast_result(res):
838
+ return self.context.cast(
839
+ self.builder, res, signature.return_type, resty
840
+ )
841
+
842
+ # First try with static operands, if known
843
+ def try_static_impl(tys, args):
844
+ if any(a is ir.UNDEFINED for a in args):
845
+ return None
846
+ try:
847
+ if isinstance(op, types.Function):
848
+ static_sig = op.get_call_type(
849
+ self.context.typing_context, tys, {}
850
+ )
851
+ else:
852
+ static_sig = typing.signature(signature.return_type, *tys)
853
+ except TypingError:
854
+ return None
855
+ try:
856
+ static_impl = self.context.get_function(op, static_sig)
857
+ return static_impl(self.builder, args)
858
+ except NotImplementedError:
859
+ return None
860
+
861
+ res = try_static_impl(
862
+ (_lit_or_omitted(static_lhs), _lit_or_omitted(static_rhs)),
863
+ (static_lhs, static_rhs),
864
+ )
865
+ if res is not None:
866
+ return cast_result(res)
867
+
868
+ res = try_static_impl(
869
+ (_lit_or_omitted(static_lhs), rty),
870
+ (static_lhs, rhs),
871
+ )
872
+ if res is not None:
873
+ return cast_result(res)
874
+
875
+ res = try_static_impl(
876
+ (lty, _lit_or_omitted(static_rhs)),
877
+ (lhs, static_rhs),
878
+ )
879
+ if res is not None:
880
+ return cast_result(res)
881
+
882
+ # Normal implementation for generic arguments
883
+
884
+ sig = op.get_call_type(self.context.typing_context, signature.args, {})
885
+ impl = self.context.get_function(op, sig)
886
+ res = impl(self.builder, (lhs, rhs))
887
+ return cast_result(res)
888
+
889
+ def lower_getitem(self, resty, expr, value, index, signature):
890
+ baseval = self.loadvar(value.name)
891
+ indexval = self.loadvar(index.name)
892
+ # Get implementation of getitem
893
+ op = operator.getitem
894
+ fnop = self.context.typing_context.resolve_value_type(op)
895
+ callsig = fnop.get_call_type(
896
+ self.context.typing_context,
897
+ signature.args,
898
+ {},
899
+ )
900
+ impl = self.context.get_function(fnop, callsig)
901
+
902
+ argvals = (baseval, indexval)
903
+ argtyps = (self.typeof(value.name), self.typeof(index.name))
904
+ castvals = [
905
+ self.context.cast(self.builder, av, at, ft)
906
+ for av, at, ft in zip(argvals, argtyps, signature.args)
907
+ ]
908
+ res = impl(self.builder, castvals)
909
+ return self.context.cast(
910
+ self.builder, res, signature.return_type, resty
911
+ )
912
+
913
+ def _cast_var(self, var, ty):
914
+ """
915
+ Cast a Numba IR variable to the given Numba type, returning a
916
+ low-level value.
917
+ """
918
+ if isinstance(var, _VarArgItem):
919
+ varty = self.typeof(var.vararg.name)[var.index]
920
+ val = self.builder.extract_value(
921
+ self.loadvar(var.vararg.name), var.index
922
+ )
923
+ else:
924
+ varty = self.typeof(var.name)
925
+ val = self.loadvar(var.name)
926
+ return self.context.cast(self.builder, val, varty, ty)
927
+
928
+ def fold_call_args(self, fnty, signature, pos_args, vararg, kw_args):
929
+ if vararg:
930
+ # Inject *args from function call
931
+ # The lowering will be done in _cast_var() above.
932
+ tp_vararg = self.typeof(vararg.name)
933
+ assert isinstance(tp_vararg, types.BaseTuple)
934
+ pos_args = pos_args + [
935
+ _VarArgItem(vararg, i) for i in range(len(tp_vararg))
936
+ ]
937
+
938
+ # Fold keyword arguments and resolve default argument values
939
+ pysig = signature.pysig
940
+ if pysig is None:
941
+ if kw_args:
942
+ raise NotImplementedError(
943
+ "unsupported keyword arguments when calling %s" % (fnty,)
944
+ )
945
+ argvals = [
946
+ self._cast_var(var, sigty)
947
+ for var, sigty in zip(pos_args, signature.args)
948
+ ]
949
+ else:
950
+
951
+ def normal_handler(index, param, var):
952
+ return self._cast_var(var, signature.args[index])
953
+
954
+ def default_handler(index, param, default):
955
+ return self.context.get_constant_generic(
956
+ self.builder, signature.args[index], default
957
+ )
958
+
959
+ def stararg_handler(index, param, vars):
960
+ stararg_ty = signature.args[index]
961
+ assert isinstance(stararg_ty, types.BaseTuple), stararg_ty
962
+ values = [
963
+ self._cast_var(var, sigty)
964
+ for var, sigty in zip(vars, stararg_ty)
965
+ ]
966
+ return cgutils.make_anonymous_struct(self.builder, values)
967
+
968
+ argvals = typing.fold_arguments(
969
+ pysig,
970
+ pos_args,
971
+ dict(kw_args),
972
+ normal_handler,
973
+ default_handler,
974
+ stararg_handler,
975
+ )
976
+ return argvals
977
+
978
+ def lower_print(self, inst):
979
+ """
980
+ Lower a ir.Print()
981
+ """
982
+ # We handle this, as far as possible, as a normal call to built-in
983
+ # print(). This will make it easy to undo the special ir.Print
984
+ # rewrite when it becomes unnecessary (e.g. when we have native
985
+ # strings).
986
+ sig = self.fndesc.calltypes[inst]
987
+ assert sig.return_type == types.none
988
+ fnty = self.context.typing_context.resolve_value_type(print)
989
+
990
+ # Fix the call signature to inject any constant-inferred
991
+ # string argument
992
+ pos_tys = list(sig.args)
993
+ pos_args = list(inst.args)
994
+ for i in range(len(pos_args)):
995
+ if i in inst.consts:
996
+ pyval = inst.consts[i]
997
+ if isinstance(pyval, str):
998
+ pos_tys[i] = types.literal(pyval)
999
+
1000
+ fixed_sig = typing.signature(sig.return_type, *pos_tys)
1001
+ fixed_sig = fixed_sig.replace(pysig=sig.pysig)
1002
+
1003
+ argvals = self.fold_call_args(fnty, sig, pos_args, inst.vararg, {})
1004
+ impl = self.context.get_function(print, fixed_sig)
1005
+ impl(self.builder, argvals)
1006
+
1007
+ def lower_call(self, resty, expr):
1008
+ signature = self.fndesc.calltypes[expr]
1009
+ self.debug_print("# lower_call: expr = {0}".format(expr))
1010
+ if isinstance(signature.return_type, types.Phantom):
1011
+ return self.context.get_dummy_value()
1012
+
1013
+ fnty = self.typeof(expr.func.name)
1014
+
1015
+ if isinstance(fnty, types.ObjModeDispatcher):
1016
+ res = self._lower_call_ObjModeDispatcher(fnty, expr, signature)
1017
+
1018
+ elif isinstance(fnty, types.ExternalFunction):
1019
+ res = self._lower_call_ExternalFunction(fnty, expr, signature)
1020
+
1021
+ elif isinstance(fnty, types.ExternalFunctionPointer):
1022
+ res = self._lower_call_ExternalFunctionPointer(
1023
+ fnty, expr, signature
1024
+ )
1025
+
1026
+ elif isinstance(fnty, types.RecursiveCall):
1027
+ res = self._lower_call_RecursiveCall(fnty, expr, signature)
1028
+
1029
+ elif isinstance(fnty, types.FunctionType):
1030
+ res = self._lower_call_FunctionType(fnty, expr, signature)
1031
+
1032
+ else:
1033
+ res = self._lower_call_normal(fnty, expr, signature)
1034
+
1035
+ # If lowering the call returned None, interpret that as returning dummy
1036
+ # value if the return type of the function is void, otherwise there is
1037
+ # a problem
1038
+ if res is None:
1039
+ if signature.return_type == types.void:
1040
+ res = self.context.get_dummy_value()
1041
+ else:
1042
+ raise LoweringError(
1043
+ msg="non-void function returns None from implementation",
1044
+ loc=self.loc,
1045
+ )
1046
+
1047
+ return self.context.cast(
1048
+ self.builder, res, signature.return_type, resty
1049
+ )
1050
+
1051
+ def _lower_call_ObjModeDispatcher(self, fnty, expr, signature):
1052
+ from numba.core.pythonapi import ObjModeUtils
1053
+
1054
+ self.init_pyapi()
1055
+ # Acquire the GIL
1056
+ gil_state = self.pyapi.gil_ensure()
1057
+ # Fix types
1058
+ argnames = [a.name for a in expr.args]
1059
+ argtypes = [self.typeof(a) for a in argnames]
1060
+ argvalues = [self.loadvar(a) for a in argnames]
1061
+ for v, ty in zip(argvalues, argtypes):
1062
+ # Because .from_native_value steal the reference
1063
+ self.incref(ty, v)
1064
+
1065
+ argobjs = [
1066
+ self.pyapi.from_native_value(atyp, aval, self.env_manager)
1067
+ for atyp, aval in zip(argtypes, argvalues)
1068
+ ]
1069
+
1070
+ # Load objmode dispatcher
1071
+ callee = ObjModeUtils(self.pyapi).load_dispatcher(fnty, argtypes)
1072
+ # Make Call
1073
+ ret_obj = self.pyapi.call_function_objargs(callee, argobjs)
1074
+ has_exception = cgutils.is_null(self.builder, ret_obj)
1075
+ with self.builder.if_else(has_exception) as (then, orelse):
1076
+ # Handles exception
1077
+ # This branch must exit the function
1078
+ with then:
1079
+ # Clean arg
1080
+ for obj in argobjs:
1081
+ self.pyapi.decref(obj)
1082
+
1083
+ # Release the GIL
1084
+ self.pyapi.gil_release(gil_state)
1085
+
1086
+ # Return and signal exception
1087
+ self.call_conv.return_exc(self.builder)
1088
+
1089
+ # Handles normal return
1090
+ with orelse:
1091
+ # Fix output value
1092
+ native = self.pyapi.to_native_value(
1093
+ fnty.dispatcher.output_types,
1094
+ ret_obj,
1095
+ )
1096
+ output = native.value
1097
+
1098
+ # Release objs
1099
+ self.pyapi.decref(ret_obj)
1100
+ for obj in argobjs:
1101
+ self.pyapi.decref(obj)
1102
+
1103
+ # cleanup output
1104
+ if callable(native.cleanup):
1105
+ native.cleanup()
1106
+
1107
+ # Release the GIL
1108
+ self.pyapi.gil_release(gil_state)
1109
+
1110
+ # Error during unboxing
1111
+ with self.builder.if_then(native.is_error):
1112
+ self.call_conv.return_exc(self.builder)
1113
+
1114
+ return output
1115
+
1116
+ def _lower_call_ExternalFunction(self, fnty, expr, signature):
1117
+ # Handle a named external function
1118
+ self.debug_print("# external function")
1119
+ argvals = self.fold_call_args(
1120
+ fnty,
1121
+ signature,
1122
+ expr.args,
1123
+ expr.vararg,
1124
+ expr.kws,
1125
+ )
1126
+ fndesc = funcdesc.ExternalFunctionDescriptor(
1127
+ fnty.symbol, fnty.sig.return_type, fnty.sig.args
1128
+ )
1129
+ func = self.context.declare_external_function(
1130
+ self.builder.module, fndesc
1131
+ )
1132
+ return self.context.call_external_function(
1133
+ self.builder,
1134
+ func,
1135
+ fndesc.argtypes,
1136
+ argvals,
1137
+ )
1138
+
1139
+ def _lower_call_ExternalFunctionPointer(self, fnty, expr, signature):
1140
+ # Handle a C function pointer
1141
+ self.debug_print("# calling external function pointer")
1142
+ argvals = self.fold_call_args(
1143
+ fnty,
1144
+ signature,
1145
+ expr.args,
1146
+ expr.vararg,
1147
+ expr.kws,
1148
+ )
1149
+ pointer = self.loadvar(expr.func.name)
1150
+ # If the external function pointer uses libpython
1151
+ if fnty.requires_gil:
1152
+ self.init_pyapi()
1153
+ # Acquire the GIL
1154
+ gil_state = self.pyapi.gil_ensure()
1155
+ # Make PyObjects
1156
+ newargvals = []
1157
+ pyvals = []
1158
+ for exptyp, gottyp, aval in zip(
1159
+ fnty.sig.args, signature.args, argvals
1160
+ ):
1161
+ # Adjust argument values to pyobjects
1162
+ if exptyp == types.ffi_forced_object:
1163
+ self.incref(gottyp, aval)
1164
+ obj = self.pyapi.from_native_value(
1165
+ gottyp,
1166
+ aval,
1167
+ self.env_manager,
1168
+ )
1169
+ newargvals.append(obj)
1170
+ pyvals.append(obj)
1171
+ else:
1172
+ newargvals.append(aval)
1173
+
1174
+ # Call external function
1175
+ res = self.context.call_function_pointer(
1176
+ self.builder,
1177
+ pointer,
1178
+ newargvals,
1179
+ fnty.cconv,
1180
+ )
1181
+ # Release PyObjects
1182
+ for obj in pyvals:
1183
+ self.pyapi.decref(obj)
1184
+
1185
+ # Release the GIL
1186
+ self.pyapi.gil_release(gil_state)
1187
+ # If the external function pointer does NOT use libpython
1188
+ else:
1189
+ res = self.context.call_function_pointer(
1190
+ self.builder,
1191
+ pointer,
1192
+ argvals,
1193
+ fnty.cconv,
1194
+ )
1195
+ return res
1196
+
1197
+ def _lower_call_RecursiveCall(self, fnty, expr, signature):
1198
+ # Recursive call
1199
+ argvals = self.fold_call_args(
1200
+ fnty,
1201
+ signature,
1202
+ expr.args,
1203
+ expr.vararg,
1204
+ expr.kws,
1205
+ )
1206
+ rec_ov = fnty.get_overloads(signature.args)
1207
+ mangler = self.context.mangler or default_mangler
1208
+ abi_tags = self.fndesc.abi_tags
1209
+ mangled_name = mangler(
1210
+ rec_ov.qualname, signature.args, abi_tags=abi_tags, uid=rec_ov.uid
1211
+ )
1212
+ # special case self recursion
1213
+ if self.builder.function.name.startswith(mangled_name):
1214
+ res = self.context.call_internal(
1215
+ self.builder,
1216
+ self.fndesc,
1217
+ signature,
1218
+ argvals,
1219
+ )
1220
+ else:
1221
+ res = self.context.call_unresolved(
1222
+ self.builder,
1223
+ mangled_name,
1224
+ signature,
1225
+ argvals,
1226
+ )
1227
+ return res
1228
+
1229
+ def _lower_call_FunctionType(self, fnty, expr, signature):
1230
+ self.debug_print("# calling first-class function type")
1231
+ sig = types.unliteral(signature)
1232
+ if not fnty.check_signature(signature):
1233
+ # value dependent polymorphism?
1234
+ raise UnsupportedError(
1235
+ f"mismatch of function types:"
1236
+ f" expected {fnty} but got {types.FunctionType(sig)}"
1237
+ )
1238
+ argvals = self.fold_call_args(
1239
+ fnty,
1240
+ sig,
1241
+ expr.args,
1242
+ expr.vararg,
1243
+ expr.kws,
1244
+ )
1245
+ return self.__call_first_class_function_pointer(
1246
+ fnty.ftype,
1247
+ expr.func.name,
1248
+ sig,
1249
+ argvals,
1250
+ )
1251
+
1252
+ def __call_first_class_function_pointer(self, ftype, fname, sig, argvals):
1253
+ """
1254
+ Calls a first-class function pointer.
1255
+
1256
+ This function is responsible for calling a first-class function pointer,
1257
+ which can either be a JIT-compiled function or a Python function. It
1258
+ determines if a JIT address is available, and if so, calls the function
1259
+ using the JIT address. Otherwise, it calls the function using a function
1260
+ pointer obtained from the `__get_first_class_function_pointer` method.
1261
+
1262
+ Args:
1263
+ ftype: The type of the function.
1264
+ fname: The name of the function.
1265
+ sig: The signature of the function.
1266
+ argvals: The argument values to pass to the function.
1267
+
1268
+ Returns:
1269
+ The result of calling the function.
1270
+ """
1271
+ context = self.context
1272
+ builder = self.builder
1273
+ # Determine if jit address is available
1274
+ fstruct = self.loadvar(fname)
1275
+ struct = cgutils.create_struct_proxy(self.typeof(fname))(
1276
+ context, builder, value=fstruct
1277
+ )
1278
+ jit_addr = struct.jit_addr
1279
+ jit_addr.name = f"jit_addr_of_{fname}"
1280
+
1281
+ ctx = context
1282
+ res_slot = cgutils.alloca_once(
1283
+ builder, ctx.get_value_type(sig.return_type)
1284
+ )
1285
+
1286
+ if_jit_addr_is_null = builder.if_else(
1287
+ cgutils.is_null(builder, jit_addr), likely=False
1288
+ )
1289
+ with if_jit_addr_is_null as (then, orelse):
1290
+ with then:
1291
+ func_ptr = self.__get_first_class_function_pointer(
1292
+ ftype, fname, sig
1293
+ )
1294
+ res = builder.call(func_ptr, argvals)
1295
+ builder.store(res, res_slot)
1296
+
1297
+ with orelse:
1298
+ llty = ctx.call_conv.get_function_type(
1299
+ sig.return_type, sig.args
1300
+ ).as_pointer()
1301
+ func_ptr = builder.bitcast(jit_addr, llty)
1302
+ # call
1303
+ status, res = ctx.call_conv.call_function(
1304
+ builder, func_ptr, sig.return_type, sig.args, argvals
1305
+ )
1306
+ with cgutils.if_unlikely(builder, status.is_error):
1307
+ context.call_conv.return_status_propagate(builder, status)
1308
+ builder.store(res, res_slot)
1309
+ return builder.load(res_slot)
1310
+
1311
+ def __get_first_class_function_pointer(self, ftype, fname, sig):
1312
+ from numba.experimental.function_type import lower_get_wrapper_address
1313
+
1314
+ llty = self.context.get_value_type(ftype)
1315
+ fstruct = self.loadvar(fname)
1316
+ addr = self.builder.extract_value(
1317
+ fstruct, 0, name="addr_of_%s" % (fname)
1318
+ )
1319
+
1320
+ fptr = cgutils.alloca_once(
1321
+ self.builder, llty, name="fptr_of_%s" % (fname)
1322
+ )
1323
+ with self.builder.if_else(
1324
+ cgutils.is_null(self.builder, addr), likely=False
1325
+ ) as (then, orelse):
1326
+ with then:
1327
+ self.init_pyapi()
1328
+ # Acquire the GIL
1329
+ gil_state = self.pyapi.gil_ensure()
1330
+ pyaddr = self.builder.extract_value(
1331
+ fstruct, 1, name="pyaddr_of_%s" % (fname)
1332
+ )
1333
+ # try to recover the function address, see
1334
+ # test_zero_address BadToGood example in
1335
+ # test_function_type.py
1336
+ addr1 = lower_get_wrapper_address(
1337
+ self.context,
1338
+ self.builder,
1339
+ pyaddr,
1340
+ sig,
1341
+ failure_mode="ignore",
1342
+ )
1343
+ with self.builder.if_then(
1344
+ cgutils.is_null(self.builder, addr1), likely=False
1345
+ ):
1346
+ self.return_exception(
1347
+ RuntimeError,
1348
+ exc_args=(f"{ftype} function address is null",),
1349
+ loc=self.loc,
1350
+ )
1351
+ addr2 = self.pyapi.long_as_voidptr(addr1)
1352
+ self.builder.store(self.builder.bitcast(addr2, llty), fptr)
1353
+ self.pyapi.decref(addr1)
1354
+ self.pyapi.gil_release(gil_state)
1355
+ with orelse:
1356
+ self.builder.store(self.builder.bitcast(addr, llty), fptr)
1357
+ return self.builder.load(fptr)
1358
+
1359
+ def _lower_call_normal(self, fnty, expr, signature):
1360
+ # Normal function resolution
1361
+ self.debug_print("# calling normal function: {0}".format(fnty))
1362
+ self.debug_print("# signature: {0}".format(signature))
1363
+ if isinstance(fnty, types.ObjModeDispatcher):
1364
+ argvals = expr.func.args
1365
+ else:
1366
+ argvals = self.fold_call_args(
1367
+ fnty,
1368
+ signature,
1369
+ expr.args,
1370
+ expr.vararg,
1371
+ expr.kws,
1372
+ )
1373
+ tname = expr.target
1374
+ if tname is not None:
1375
+ from numba.core.target_extension import resolve_dispatcher_from_str
1376
+
1377
+ disp = resolve_dispatcher_from_str(tname)
1378
+ hw_ctx = disp.targetdescr.target_context
1379
+ impl = hw_ctx.get_function(fnty, signature)
1380
+ else:
1381
+ impl = self.context.get_function(fnty, signature)
1382
+ if signature.recvr:
1383
+ # The "self" object is passed as the function object
1384
+ # for bounded function
1385
+ the_self = self.loadvar(expr.func.name)
1386
+ # Prepend the self reference
1387
+ argvals = [the_self] + list(argvals)
1388
+
1389
+ res = impl(self.builder, argvals, self.loc)
1390
+ return res
1391
+
1392
+ def lower_expr(self, resty, expr):
1393
+ if expr.op == "binop":
1394
+ return self.lower_binop(resty, expr, expr.fn)
1395
+ elif expr.op == "inplace_binop":
1396
+ lty = self.typeof(expr.lhs.name)
1397
+ if lty.mutable:
1398
+ return self.lower_binop(resty, expr, expr.fn)
1399
+ else:
1400
+ # inplace operators on non-mutable types reuse the same
1401
+ # definition as the corresponding copying operators.)
1402
+ return self.lower_binop(resty, expr, expr.immutable_fn)
1403
+ elif expr.op == "unary":
1404
+ val = self.loadvar(expr.value.name)
1405
+ typ = self.typeof(expr.value.name)
1406
+ func_ty = self.context.typing_context.resolve_value_type(expr.fn)
1407
+ # Get function
1408
+ signature = self.fndesc.calltypes[expr]
1409
+ impl = self.context.get_function(func_ty, signature)
1410
+ # Convert argument to match
1411
+ val = self.context.cast(self.builder, val, typ, signature.args[0])
1412
+ res = impl(self.builder, [val])
1413
+ res = self.context.cast(
1414
+ self.builder, res, signature.return_type, resty
1415
+ )
1416
+ return res
1417
+
1418
+ elif expr.op == "call":
1419
+ res = self.lower_call(resty, expr)
1420
+ return res
1421
+
1422
+ elif expr.op == "pair_first":
1423
+ val = self.loadvar(expr.value.name)
1424
+ ty = self.typeof(expr.value.name)
1425
+ res = self.context.pair_first(self.builder, val, ty)
1426
+ self.incref(resty, res)
1427
+ return res
1428
+
1429
+ elif expr.op == "pair_second":
1430
+ val = self.loadvar(expr.value.name)
1431
+ ty = self.typeof(expr.value.name)
1432
+ res = self.context.pair_second(self.builder, val, ty)
1433
+ self.incref(resty, res)
1434
+ return res
1435
+
1436
+ elif expr.op in ("getiter", "iternext"):
1437
+ val = self.loadvar(expr.value.name)
1438
+ ty = self.typeof(expr.value.name)
1439
+ signature = self.fndesc.calltypes[expr]
1440
+ impl = self.context.get_function(expr.op, signature)
1441
+ [fty] = signature.args
1442
+ castval = self.context.cast(self.builder, val, ty, fty)
1443
+ res = impl(self.builder, (castval,))
1444
+ res = self.context.cast(
1445
+ self.builder, res, signature.return_type, resty
1446
+ )
1447
+ return res
1448
+
1449
+ elif expr.op == "exhaust_iter":
1450
+ val = self.loadvar(expr.value.name)
1451
+ ty = self.typeof(expr.value.name)
1452
+ # Unpack optional
1453
+ if isinstance(ty, types.Optional):
1454
+ val = self.context.cast(self.builder, val, ty, ty.type)
1455
+ ty = ty.type
1456
+
1457
+ # If we have a tuple, we needn't do anything
1458
+ # (and we can't iterate over the heterogeneous ones).
1459
+ if isinstance(ty, types.BaseTuple):
1460
+ assert ty == resty
1461
+ self.incref(ty, val)
1462
+ return val
1463
+
1464
+ itemty = ty.iterator_type.yield_type
1465
+ tup = self.context.get_constant_undef(resty)
1466
+ pairty = types.Pair(itemty, types.boolean)
1467
+ getiter_sig = typing.signature(ty.iterator_type, ty)
1468
+ getiter_impl = self.context.get_function("getiter", getiter_sig)
1469
+ iternext_sig = typing.signature(pairty, ty.iterator_type)
1470
+ iternext_impl = self.context.get_function("iternext", iternext_sig)
1471
+ iterobj = getiter_impl(self.builder, (val,))
1472
+ # We call iternext() as many times as desired (`expr.count`).
1473
+ for i in range(expr.count):
1474
+ pair = iternext_impl(self.builder, (iterobj,))
1475
+ is_valid = self.context.pair_second(self.builder, pair, pairty)
1476
+ with cgutils.if_unlikely(
1477
+ self.builder, self.builder.not_(is_valid)
1478
+ ):
1479
+ self.return_exception(ValueError, loc=self.loc)
1480
+ item = self.context.pair_first(self.builder, pair, pairty)
1481
+ tup = self.builder.insert_value(tup, item, i)
1482
+
1483
+ # Call iternext() once more to check that the iterator
1484
+ # is exhausted.
1485
+ pair = iternext_impl(self.builder, (iterobj,))
1486
+ is_valid = self.context.pair_second(self.builder, pair, pairty)
1487
+ with cgutils.if_unlikely(self.builder, is_valid):
1488
+ self.return_exception(ValueError, loc=self.loc)
1489
+
1490
+ self.decref(ty.iterator_type, iterobj)
1491
+ return tup
1492
+
1493
+ elif expr.op == "getattr":
1494
+ val = self.loadvar(expr.value.name)
1495
+ ty = self.typeof(expr.value.name)
1496
+
1497
+ if isinstance(resty, types.BoundFunction):
1498
+ # if we are getting out a method, assume we have typed this
1499
+ # properly and just build a bound function object
1500
+ casted = self.context.cast(self.builder, val, ty, resty.this)
1501
+ res = self.context.get_bound_function(
1502
+ self.builder, casted, resty.this
1503
+ )
1504
+ self.incref(resty, res)
1505
+ return res
1506
+ else:
1507
+ impl = self.context.get_getattr(ty, expr.attr)
1508
+ attrty = self.context.typing_context.resolve_getattr(
1509
+ ty, expr.attr
1510
+ )
1511
+
1512
+ if impl is None:
1513
+ # ignore the attribute
1514
+ return self.context.get_dummy_value()
1515
+ else:
1516
+ res = impl(self.context, self.builder, ty, val, expr.attr)
1517
+
1518
+ # Cast the attribute type to the expected output type
1519
+ res = self.context.cast(self.builder, res, attrty, resty)
1520
+ return res
1521
+
1522
+ elif expr.op == "static_getitem":
1523
+ signature = typing.signature(
1524
+ resty,
1525
+ self.typeof(expr.value.name),
1526
+ _lit_or_omitted(expr.index),
1527
+ )
1528
+ try:
1529
+ # Both get_function() and the returned implementation can
1530
+ # raise NotImplementedError if the types aren't supported
1531
+ impl = self.context.get_function("static_getitem", signature)
1532
+ return impl(
1533
+ self.builder, (self.loadvar(expr.value.name), expr.index)
1534
+ )
1535
+ except NotImplementedError:
1536
+ if expr.index_var is None:
1537
+ raise
1538
+ # Fall back on the generic getitem() implementation
1539
+ # for this type.
1540
+ signature = self.fndesc.calltypes[expr]
1541
+ return self.lower_getitem(
1542
+ resty, expr, expr.value, expr.index_var, signature
1543
+ )
1544
+ elif expr.op == "typed_getitem":
1545
+ signature = typing.signature(
1546
+ resty,
1547
+ self.typeof(expr.value.name),
1548
+ self.typeof(expr.index.name),
1549
+ )
1550
+ impl = self.context.get_function("typed_getitem", signature)
1551
+ return impl(
1552
+ self.builder,
1553
+ (self.loadvar(expr.value.name), self.loadvar(expr.index.name)),
1554
+ )
1555
+ elif expr.op == "getitem":
1556
+ signature = self.fndesc.calltypes[expr]
1557
+ return self.lower_getitem(
1558
+ resty, expr, expr.value, expr.index, signature
1559
+ )
1560
+
1561
+ elif expr.op == "build_tuple":
1562
+ itemvals = [self.loadvar(i.name) for i in expr.items]
1563
+ itemtys = [self.typeof(i.name) for i in expr.items]
1564
+ castvals = [
1565
+ self.context.cast(self.builder, val, fromty, toty)
1566
+ for val, toty, fromty in zip(itemvals, resty, itemtys)
1567
+ ]
1568
+ tup = self.context.make_tuple(self.builder, resty, castvals)
1569
+ self.incref(resty, tup)
1570
+ return tup
1571
+
1572
+ elif expr.op == "build_list":
1573
+ itemvals = [self.loadvar(i.name) for i in expr.items]
1574
+ itemtys = [self.typeof(i.name) for i in expr.items]
1575
+ if isinstance(resty, types.LiteralList):
1576
+ castvals = [
1577
+ self.context.cast(self.builder, val, fromty, toty)
1578
+ for val, toty, fromty in zip(itemvals, resty.types, itemtys)
1579
+ ]
1580
+ tup = self.context.make_tuple(
1581
+ self.builder, types.Tuple(resty.types), castvals
1582
+ )
1583
+ self.incref(resty, tup)
1584
+ return tup
1585
+ else:
1586
+ castvals = [
1587
+ self.context.cast(self.builder, val, fromty, resty.dtype)
1588
+ for val, fromty in zip(itemvals, itemtys)
1589
+ ]
1590
+ return self.context.build_list(self.builder, resty, castvals)
1591
+
1592
+ elif expr.op == "build_set":
1593
+ # Insert in reverse order, as Python does
1594
+ items = expr.items[::-1]
1595
+ itemvals = [self.loadvar(i.name) for i in items]
1596
+ itemtys = [self.typeof(i.name) for i in items]
1597
+ castvals = [
1598
+ self.context.cast(self.builder, val, fromty, resty.dtype)
1599
+ for val, fromty in zip(itemvals, itemtys)
1600
+ ]
1601
+ return self.context.build_set(self.builder, resty, castvals)
1602
+
1603
+ elif expr.op == "build_map":
1604
+ items = expr.items
1605
+ keys, values = [], []
1606
+ key_types, value_types = [], []
1607
+ for k, v in items:
1608
+ key = self.loadvar(k.name)
1609
+ keytype = self.typeof(k.name)
1610
+ val = self.loadvar(v.name)
1611
+ valtype = self.typeof(v.name)
1612
+ keys.append(key)
1613
+ values.append(val)
1614
+ key_types.append(keytype)
1615
+ value_types.append(valtype)
1616
+ return self.context.build_map(
1617
+ self.builder,
1618
+ resty,
1619
+ list(zip(key_types, value_types)),
1620
+ list(zip(keys, values)),
1621
+ )
1622
+
1623
+ elif expr.op == "cast":
1624
+ val = self.loadvar(expr.value.name)
1625
+ ty = self.typeof(expr.value.name)
1626
+ castval = self.context.cast(self.builder, val, ty, resty)
1627
+ self.incref(resty, castval)
1628
+ return castval
1629
+
1630
+ elif expr.op == "phi":
1631
+ raise LoweringError("PHI not stripped")
1632
+
1633
+ elif expr.op == "null":
1634
+ return self.context.get_constant_null(resty)
1635
+
1636
+ elif expr.op == "undef":
1637
+ # Numba does not raise an UnboundLocalError for undefined variables.
1638
+ # The variable is set to zero.
1639
+ return self.context.get_constant_null(resty)
1640
+
1641
+ elif expr.op in self.context.special_ops:
1642
+ res = self.context.special_ops[expr.op](self, expr)
1643
+ return res
1644
+
1645
+ raise NotImplementedError(expr)
1646
+
1647
+ def _alloca_var(self, name, fetype):
1648
+ """
1649
+ Ensure the given variable has an allocated stack slot (if needed).
1650
+ """
1651
+ if name in self.varmap:
1652
+ # quit early
1653
+ return
1654
+
1655
+ # If the name is used in multiple blocks or lowering with debuginfo...
1656
+ if (
1657
+ name not in self._singly_assigned_vars
1658
+ ) or self._disable_sroa_like_opt:
1659
+ # If not already defined, allocate it
1660
+ ptr = self.alloca(name, fetype)
1661
+ # Remember the pointer
1662
+ self.varmap[name] = ptr
1663
+
1664
+ def getvar(self, name):
1665
+ """
1666
+ Get a pointer to the given variable's slot.
1667
+ """
1668
+ if not self._disable_sroa_like_opt:
1669
+ assert name not in self._blk_local_varmap
1670
+ assert name not in self._singly_assigned_vars
1671
+ if name not in self.varmap:
1672
+ # Allocate undefined variable as needed.
1673
+ # NOTE: Py3.12 use of LOAD_FAST_AND_CLEAR will allow variable be
1674
+ # referenced before it is defined.
1675
+ self._alloca_var(name, self.typeof(name))
1676
+ return self.varmap[name]
1677
+
1678
+ def loadvar(self, name):
1679
+ """
1680
+ Load the given variable's value.
1681
+ """
1682
+ if name in self._blk_local_varmap and not self._disable_sroa_like_opt:
1683
+ return self._blk_local_varmap[name]
1684
+ ptr = self.getvar(name)
1685
+
1686
+ # Don't associate debuginfo with the load for a function arg else it
1687
+ # creates instructions ahead of the first source line of the
1688
+ # function which then causes problems with breaking on the function
1689
+ # symbol (it hits the symbol, not the first line).
1690
+ if name in self.func_ir.arg_names:
1691
+ with debuginfo.suspend_emission(self.builder):
1692
+ return self.builder.load(ptr)
1693
+ else:
1694
+ return self.builder.load(ptr)
1695
+
1696
+ def storevar(self, value, name, argidx=None):
1697
+ """
1698
+ Store the value into the given variable.
1699
+ """
1700
+ fetype = self.typeof(name)
1701
+ # Define if not already
1702
+ self._alloca_var(name, fetype)
1703
+
1704
+ # Store variable
1705
+ if (
1706
+ name in self._singly_assigned_vars
1707
+ and not self._disable_sroa_like_opt
1708
+ ):
1709
+ self._blk_local_varmap[name] = value
1710
+ else:
1711
+ if argidx is None:
1712
+ # Clean up existing value stored in the variable, not needed
1713
+ # if it's an arg
1714
+ old = self.loadvar(name)
1715
+ self.decref(fetype, old)
1716
+
1717
+ # stack stored variable
1718
+ ptr = self.getvar(name)
1719
+ if value.type != ptr.type.pointee:
1720
+ msg = (
1721
+ "Storing {value.type} to ptr of {ptr.type.pointee} "
1722
+ "('{name}'). FE type {fetype}"
1723
+ ).format(value=value, ptr=ptr, fetype=fetype, name=name)
1724
+ raise AssertionError(msg)
1725
+
1726
+ # If this store is associated with an argument to the function (i.e.
1727
+ # store following reassemble from CC splatting structs as many args
1728
+ # to the function) then mark this variable as such.
1729
+ if argidx is not None:
1730
+ with debuginfo.suspend_emission(self.builder):
1731
+ self.builder.store(value, ptr)
1732
+ loc = self.defn_loc # the line with `def <func>`
1733
+ lltype = self.context.get_value_type(fetype)
1734
+ sizeof = self.context.get_abi_sizeof(lltype)
1735
+ datamodel = self.context.data_model_manager[fetype]
1736
+ self.debuginfo.mark_variable(
1737
+ self.builder,
1738
+ ptr,
1739
+ name=name,
1740
+ lltype=lltype,
1741
+ size=sizeof,
1742
+ line=loc.line,
1743
+ datamodel=datamodel,
1744
+ argidx=argidx,
1745
+ )
1746
+ else:
1747
+ self.builder.store(value, ptr)
1748
+
1749
+ def delvar(self, name):
1750
+ """
1751
+ Delete the given variable.
1752
+ """
1753
+ fetype = self.typeof(name)
1754
+
1755
+ # Out-of-order
1756
+ if (
1757
+ name not in self._blk_local_varmap
1758
+ and not self._disable_sroa_like_opt
1759
+ ):
1760
+ if name in self._singly_assigned_vars:
1761
+ self._singly_assigned_vars.discard(name)
1762
+
1763
+ # Define if not already (may happen if the variable is deleted
1764
+ # at the beginning of a loop, but only set later in the loop)
1765
+ self._alloca_var(name, fetype)
1766
+
1767
+ if name in self._blk_local_varmap and not self._disable_sroa_like_opt:
1768
+ llval = self._blk_local_varmap[name]
1769
+ self.decref(fetype, llval)
1770
+ else:
1771
+ ptr = self.getvar(name)
1772
+ self.decref(fetype, self.builder.load(ptr))
1773
+ # Zero-fill variable to avoid double frees on subsequent dels
1774
+ self.builder.store(llvm_ir.Constant(ptr.type.pointee, None), ptr)
1775
+
1776
+ def alloca(self, name, type):
1777
+ lltype = self.context.get_value_type(type)
1778
+ datamodel = self.context.data_model_manager[type]
1779
+ return self.alloca_lltype(name, lltype, datamodel=datamodel)
1780
+
1781
+ def alloca_lltype(self, name, lltype, datamodel=None):
1782
+ # Is user variable?
1783
+ is_uservar = not name.startswith("$")
1784
+ # Allocate space for variable
1785
+ aptr = cgutils.alloca_once(self.builder, lltype, name=name, zfill=False)
1786
+
1787
+ # Emit debug info for user variable
1788
+ if is_uservar:
1789
+ # Don't associate debuginfo with the alloca for a function arg, this
1790
+ # is handled by the first store to the alloca so that repacking the
1791
+ # splatted args from the CC is dealt with.
1792
+ if name not in self.func_ir.arg_names:
1793
+ sizeof = self.context.get_abi_sizeof(lltype)
1794
+ self.debuginfo.mark_variable(
1795
+ self.builder,
1796
+ aptr,
1797
+ name=name,
1798
+ lltype=lltype,
1799
+ size=sizeof,
1800
+ line=self.loc.line,
1801
+ datamodel=datamodel,
1802
+ )
1803
+ return aptr
1804
+
1805
+ def incref(self, typ, val):
1806
+ if not self.context.enable_nrt:
1807
+ return
1808
+
1809
+ self.context.nrt.incref(self.builder, typ, val)
1810
+
1811
+ def decref(self, typ, val):
1812
+ if not self.context.enable_nrt:
1813
+ return
1814
+
1815
+ # do not associate decref with "use", it creates "jumpy" line info as
1816
+ # the decrefs are usually where the ir.Del nodes are, which is at the
1817
+ # end of the block.
1818
+ with debuginfo.suspend_emission(self.builder):
1819
+ self.context.nrt.decref(self.builder, typ, val)
5
1820
 
6
1821
 
7
1822
  class CUDALower(Lower):
@@ -23,8 +1838,8 @@ class CUDALower(Lower):
23
1838
  # Emit debug value for user variable
24
1839
  fetype = self.typeof(name)
25
1840
  lltype = self.context.get_value_type(fetype)
26
- int_type = (ir.IntType,)
27
- real_type = ir.FloatType, ir.DoubleType
1841
+ int_type = (llvm_ir.IntType,)
1842
+ real_type = llvm_ir.FloatType, llvm_ir.DoubleType
28
1843
  if isinstance(lltype, int_type + real_type):
29
1844
  index = name.find(".")
30
1845
  src_name = name[:index] if index > 0 else name
@@ -61,7 +1876,7 @@ class CUDALower(Lower):
61
1876
  poly_map = {}
62
1877
  # pre-scan all blocks
63
1878
  for block in self.blocks.values():
64
- for x in block.find_insts(numba_ir.Assign):
1879
+ for x in block.find_insts(ir.Assign):
65
1880
  if x.target.name.startswith("$"):
66
1881
  continue
67
1882
  ssa_name = x.target.name
@@ -104,7 +1919,7 @@ class CUDALower(Lower):
104
1919
  # Any member of this union type shoud type cast ptr to fetype
105
1920
  lltype = self.context.get_value_type(fetype)
106
1921
  castptr = self.builder.bitcast(
107
- self.poly_var_loc_map[src_name], ir.PointerType(lltype)
1922
+ self.poly_var_loc_map[src_name], llvm_ir.PointerType(lltype)
108
1923
  )
109
1924
  # Remember the pointer
110
1925
  self.varmap[name] = castptr
@@ -120,3 +1935,13 @@ class CUDALower(Lower):
120
1935
  # lowering with debuginfo
121
1936
  or self._disable_sroa_like_opt
122
1937
  )
1938
+
1939
+
1940
+ def _lit_or_omitted(value):
1941
+ """Returns a Literal instance if the type of value is supported;
1942
+ otherwise, return `Omitted(value)`.
1943
+ """
1944
+ try:
1945
+ return types.literal(value)
1946
+ except LiteralTypingError:
1947
+ return types.Omitted(value)