numba-cuda 0.23.0__cp313-cp313-win_amd64.whl → 0.24.0__cp313-cp313-win_amd64.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.
Files changed (74) hide show
  1. numba_cuda/VERSION +1 -1
  2. numba_cuda/numba/cuda/__init__.py +4 -1
  3. numba_cuda/numba/cuda/_compat.py +47 -0
  4. numba_cuda/numba/cuda/cext/_dispatcher.cp313-win_amd64.pyd +0 -0
  5. numba_cuda/numba/cuda/cext/_dispatcher.cpp +8 -2
  6. numba_cuda/numba/cuda/cext/_hashtable.cpp +5 -0
  7. numba_cuda/numba/cuda/cext/_helperlib.cp313-win_amd64.pyd +0 -0
  8. numba_cuda/numba/cuda/cext/_pymodule.h +1 -1
  9. numba_cuda/numba/cuda/cext/_typeconv.cp313-win_amd64.pyd +0 -0
  10. numba_cuda/numba/cuda/cext/_typeof.cpp +56 -8
  11. numba_cuda/numba/cuda/cext/mviewbuf.c +7 -1
  12. numba_cuda/numba/cuda/cext/mviewbuf.cp313-win_amd64.pyd +0 -0
  13. numba_cuda/numba/cuda/cloudpickle/cloudpickle.py +4 -5
  14. numba_cuda/numba/cuda/codegen.py +4 -2
  15. numba_cuda/numba/cuda/compiler.py +5 -5
  16. numba_cuda/numba/cuda/core/annotations/pretty_annotate.py +1 -1
  17. numba_cuda/numba/cuda/core/base.py +6 -10
  18. numba_cuda/numba/cuda/core/bytecode.py +21 -13
  19. numba_cuda/numba/cuda/core/byteflow.py +336 -90
  20. numba_cuda/numba/cuda/core/compiler.py +3 -4
  21. numba_cuda/numba/cuda/core/compiler_machinery.py +3 -3
  22. numba_cuda/numba/cuda/core/config.py +5 -7
  23. numba_cuda/numba/cuda/core/controlflow.py +17 -9
  24. numba_cuda/numba/cuda/core/inline_closurecall.py +11 -10
  25. numba_cuda/numba/cuda/core/interpreter.py +255 -96
  26. numba_cuda/numba/cuda/core/ir_utils.py +8 -17
  27. numba_cuda/numba/cuda/core/pythonapi.py +3 -0
  28. numba_cuda/numba/cuda/core/rewrites/static_binop.py +1 -1
  29. numba_cuda/numba/cuda/core/ssa.py +2 -2
  30. numba_cuda/numba/cuda/core/transforms.py +4 -6
  31. numba_cuda/numba/cuda/core/typed_passes.py +1 -1
  32. numba_cuda/numba/cuda/core/typeinfer.py +3 -3
  33. numba_cuda/numba/cuda/core/untyped_passes.py +11 -10
  34. numba_cuda/numba/cuda/cpython/unicode.py +2 -2
  35. numba_cuda/numba/cuda/cpython/unicode_support.py +1 -3
  36. numba_cuda/numba/cuda/cudadrv/devicearray.py +4 -4
  37. numba_cuda/numba/cuda/cudadrv/driver.py +13 -11
  38. numba_cuda/numba/cuda/cudadrv/nvrtc.py +71 -32
  39. numba_cuda/numba/cuda/debuginfo.py +10 -79
  40. numba_cuda/numba/cuda/deviceufunc.py +3 -6
  41. numba_cuda/numba/cuda/dispatcher.py +5 -19
  42. numba_cuda/numba/cuda/libdeviceimpl.py +1 -2
  43. numba_cuda/numba/cuda/lowering.py +0 -28
  44. numba_cuda/numba/cuda/memory_management/nrt.py +1 -1
  45. numba_cuda/numba/cuda/np/arrayobj.py +7 -9
  46. numba_cuda/numba/cuda/np/numpy_support.py +7 -10
  47. numba_cuda/numba/cuda/np/polynomial/polynomial_functions.py +4 -3
  48. numba_cuda/numba/cuda/testing.py +4 -8
  49. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_driver.py +66 -4
  50. numba_cuda/numba/cuda/tests/cudadrv/test_events.py +1 -1
  51. numba_cuda/numba/cuda/tests/cudadrv/test_linker.py +2 -2
  52. numba_cuda/numba/cuda/tests/cudadrv/test_module_callbacks.py +1 -1
  53. numba_cuda/numba/cuda/tests/cudadrv/test_nvjitlink.py +26 -4
  54. numba_cuda/numba/cuda/tests/cudapy/test_analysis.py +61 -9
  55. numba_cuda/numba/cuda/tests/cudapy/test_atomics.py +6 -0
  56. numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +12 -1
  57. numba_cuda/numba/cuda/tests/cudapy/test_complex.py +13 -0
  58. numba_cuda/numba/cuda/tests/cudapy/test_copy_propagate.py +1 -1
  59. numba_cuda/numba/cuda/tests/cudapy/test_debug.py +1 -1
  60. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +12 -7
  61. numba_cuda/numba/cuda/tests/cudapy/test_dispatcher.py +1 -1
  62. numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1 -1
  63. numba_cuda/numba/cuda/tests/cudapy/test_vector_type.py +37 -35
  64. numba_cuda/numba/cuda/tests/cudapy/test_warp_ops.py +8 -7
  65. numba_cuda/numba/cuda/tests/support.py +11 -0
  66. numba_cuda/numba/cuda/types/cuda_functions.py +1 -1
  67. numba_cuda/numba/cuda/typing/asnumbatype.py +37 -2
  68. numba_cuda/numba/cuda/typing/typeof.py +9 -16
  69. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/METADATA +4 -13
  70. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/RECORD +74 -73
  71. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/WHEEL +0 -0
  72. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/licenses/LICENSE +0 -0
  73. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/licenses/LICENSE.numba +0 -0
  74. {numba_cuda-0.23.0.dist-info → numba_cuda-0.24.0.dist-info}/top_level.txt +0 -0
@@ -27,7 +27,7 @@ from numba.cuda.core.unsafe import eh
27
27
  from numba.cuda.cpython.unsafe.tuple import unpack_single_tuple
28
28
 
29
29
 
30
- if PYVERSION in ((3, 12), (3, 13)):
30
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
31
31
  # Operands for CALL_INTRINSIC_1
32
32
  from numba.cuda.core.byteflow import CALL_INTRINSIC_1_Operand as ci1op
33
33
  elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
@@ -774,7 +774,7 @@ def peep_hole_list_to_tuple(func_ir):
774
774
  _DEBUG = False
775
775
 
776
776
  # For all blocks
777
- for offset, blk in func_ir.blocks.items():
777
+ for blk in func_ir.blocks.values():
778
778
  # keep doing the peephole rewrite until nothing is left that matches
779
779
  while True:
780
780
  # first try and find a matching region
@@ -1003,11 +1003,12 @@ def peep_hole_delete_with_exit(func_ir):
1003
1003
  if isinstance(stmt, ir.assign_types):
1004
1004
  dead_vars.add(stmt.target)
1005
1005
 
1006
- new_body = []
1007
- for stmt in blk.body:
1006
+ new_body = [
1007
+ stmt
1008
+ for stmt in blk.body
1008
1009
  # Skip any statements that uses anyone of the dead variable.
1009
- if not (set(stmt.list_vars()) & dead_vars):
1010
- new_body.append(stmt)
1010
+ if not (set(stmt.list_vars()) & dead_vars)
1011
+ ]
1011
1012
  blk.body.clear()
1012
1013
  blk.body.extend(new_body)
1013
1014
 
@@ -1323,8 +1324,7 @@ def _build_new_build_map(func_ir, name, old_body, old_lineno, new_items):
1323
1324
  if len(literal_keys) == len(new_items):
1324
1325
  # All keys must be literals to have any literal values.
1325
1326
  literal_value = {x: y for x, y in zip(literal_keys, values)}
1326
- for i, k in enumerate(literal_keys):
1327
- value_indexes[k] = i
1327
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
1328
1328
  else:
1329
1329
  literal_value = None
1330
1330
 
@@ -1390,14 +1390,14 @@ class Interpreter(object):
1390
1390
  self.current_block = None
1391
1391
  self.current_block_offset = None
1392
1392
  last_active_offset = 0
1393
- for _, inst_blocks in self.cfa.blocks.items():
1393
+ for inst_blocks in self.cfa.blocks.values():
1394
1394
  if inst_blocks.body:
1395
1395
  last_active_offset = max(
1396
1396
  last_active_offset, max(inst_blocks.body)
1397
1397
  )
1398
1398
  self.last_active_offset = last_active_offset
1399
1399
 
1400
- if PYVERSION in ((3, 12), (3, 13)):
1400
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
1401
1401
  self.active_exception_entries = tuple(
1402
1402
  [
1403
1403
  entry
@@ -1417,7 +1417,7 @@ class Interpreter(object):
1417
1417
  # Interpret loop
1418
1418
  for inst, kws in self._iter_inst():
1419
1419
  self._dispatch(inst, kws)
1420
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1420
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1421
1421
  # Insert end of try markers
1422
1422
  self._end_try_blocks()
1423
1423
  elif PYVERSION in (
@@ -1445,12 +1445,12 @@ class Interpreter(object):
1445
1445
  # post process the IR to rewrite opcodes/byte sequences that are too
1446
1446
  # involved to risk handling as part of direct interpretation
1447
1447
  peepholes = []
1448
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1448
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1449
1449
  peepholes.append(peep_hole_split_at_pop_block)
1450
- if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13)):
1450
+ if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
1451
1451
  peepholes.append(peep_hole_list_to_tuple)
1452
1452
  peepholes.append(peep_hole_delete_with_exit)
1453
- if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
1453
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13), (3, 14)):
1454
1454
  # peep_hole_call_function_ex_to_call_function_kw
1455
1455
  # depends on peep_hole_list_to_tuple converting
1456
1456
  # any large number of arguments from a list to a
@@ -1483,7 +1483,7 @@ class Interpreter(object):
1483
1483
 
1484
1484
  See also: _insert_try_block_end
1485
1485
  """
1486
- assert PYVERSION in ((3, 11), (3, 12), (3, 13))
1486
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14))
1487
1487
  graph = self.cfa.graph
1488
1488
  for offset, block in self.blocks.items():
1489
1489
  # Get current blockstack
@@ -1591,7 +1591,7 @@ class Interpreter(object):
1591
1591
  self.dfainfo = self.dfa.infos[self.current_block_offset]
1592
1592
  self.assigner = Assigner()
1593
1593
  # Check out-of-scope syntactic-block
1594
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1594
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1595
1595
  # This is recreating pre-3.11 code structure
1596
1596
  while self.syntax_blocks:
1597
1597
  if offset >= self.syntax_blocks[-1].exit:
@@ -1778,7 +1778,7 @@ class Interpreter(object):
1778
1778
  val = self.get(varname)
1779
1779
  except ir.NotDefinedError:
1780
1780
  # Hack to make sure exception variables are defined
1781
- assert PYVERSION in ((3, 11), (3, 12), (3, 13)), (
1781
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)), (
1782
1782
  "unexpected missing definition"
1783
1783
  )
1784
1784
  val = ir.Const(value=None, loc=self.loc)
@@ -1838,7 +1838,7 @@ class Interpreter(object):
1838
1838
  if self._DEBUG_PRINT:
1839
1839
  print(inst)
1840
1840
  assert self.current_block is not None
1841
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1841
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
1842
1842
  if self.syntax_blocks:
1843
1843
  top = self.syntax_blocks[-1]
1844
1844
  if isinstance(top, ir.with_types):
@@ -1929,6 +1929,14 @@ class Interpreter(object):
1929
1929
  def op_NOP(self, inst):
1930
1930
  pass
1931
1931
 
1932
+ if PYVERSION in ((3, 14),):
1933
+ # New in 3.14
1934
+ op_NOT_TAKEN = op_NOP
1935
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
1936
+ pass
1937
+ else:
1938
+ raise NotImplementedError(PYVERSION)
1939
+
1932
1940
  def op_RESUME(self, inst):
1933
1941
  pass
1934
1942
 
@@ -2028,7 +2036,7 @@ class Interpreter(object):
2028
2036
  )
2029
2037
  self.store(value=sliceinst, name=res)
2030
2038
 
2031
- if PYVERSION in ((3, 12), (3, 13)):
2039
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2032
2040
 
2033
2041
  def op_BINARY_SLICE(
2034
2042
  self, inst, start, end, container, res, slicevar, temp_res
@@ -2050,7 +2058,7 @@ class Interpreter(object):
2050
2058
  else:
2051
2059
  raise NotImplementedError(PYVERSION)
2052
2060
 
2053
- if PYVERSION in ((3, 12), (3, 13)):
2061
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2054
2062
 
2055
2063
  def op_STORE_SLICE(
2056
2064
  self, inst, start, end, container, value, res, slicevar
@@ -2320,7 +2328,7 @@ class Interpreter(object):
2320
2328
  srcname = self.code_locals[inst.arg]
2321
2329
  self.store(value=self.get(srcname), name=res)
2322
2330
 
2323
- if PYVERSION in ((3, 13),):
2331
+ if PYVERSION in ((3, 13), (3, 14)):
2324
2332
 
2325
2333
  def op_LOAD_FAST(self, inst, res, as_load_deref=False):
2326
2334
  if as_load_deref:
@@ -2331,7 +2339,7 @@ class Interpreter(object):
2331
2339
  else:
2332
2340
  op_LOAD_FAST = _op_LOAD_FAST
2333
2341
 
2334
- if PYVERSION in ((3, 13),):
2342
+ if PYVERSION in ((3, 13), (3, 14)):
2335
2343
 
2336
2344
  def op_LOAD_FAST_LOAD_FAST(self, inst, res1, res2):
2337
2345
  oparg = inst.arg
@@ -2369,7 +2377,7 @@ class Interpreter(object):
2369
2377
  else:
2370
2378
  raise NotImplementedError(PYVERSION)
2371
2379
 
2372
- if PYVERSION in ((3, 12), (3, 13)):
2380
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2373
2381
  op_LOAD_FAST_CHECK = op_LOAD_FAST
2374
2382
 
2375
2383
  def op_LOAD_FAST_AND_CLEAR(self, inst, res):
@@ -2387,6 +2395,16 @@ class Interpreter(object):
2387
2395
  else:
2388
2396
  raise NotImplementedError(PYVERSION)
2389
2397
 
2398
+ if PYVERSION in ((3, 14),):
2399
+ # New in 3.14.
2400
+ op_LOAD_FAST_BORROW = op_LOAD_FAST
2401
+ op_LOAD_FAST_BORROW_LOAD_FAST_BORROW = op_LOAD_FAST_LOAD_FAST
2402
+
2403
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2404
+ pass
2405
+ else:
2406
+ raise NotImplementedError(PYVERSION)
2407
+
2390
2408
  def op_STORE_FAST(self, inst, value):
2391
2409
  dstname = self.code_locals[inst.arg]
2392
2410
  value = self.get(value)
@@ -2420,7 +2438,7 @@ class Interpreter(object):
2420
2438
 
2421
2439
  def op_LOAD_ATTR(self, inst, item, res):
2422
2440
  item = self.get(item)
2423
- if PYVERSION in ((3, 12), (3, 13)):
2441
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
2424
2442
  attr = self.code_names[inst.arg >> 1]
2425
2443
  elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2426
2444
  attr = self.code_names[inst.arg]
@@ -2430,28 +2448,85 @@ class Interpreter(object):
2430
2448
  self.store(getattr, res)
2431
2449
 
2432
2450
  def op_LOAD_CONST(self, inst, res):
2433
- value = self.code_consts[inst.arg]
2434
- if isinstance(value, tuple):
2451
+ # New in 3.14: slice is loaded via LOAD_CONST. The value is the
2452
+ # slice object itself, so we get the start, stop and step from it
2453
+ # directly and then proceed with the code in `BUILD_SLICE`. It may also
2454
+ # be a tuple containing a slice, so we need to account for that too.
2455
+ def process_slice(value):
2456
+ start = self.store(
2457
+ ir.Const(value.start, loc=self.loc),
2458
+ name=f"$const_{value.start}",
2459
+ redefine=True,
2460
+ )
2461
+ stop = self.store(
2462
+ ir.Const(value.stop, loc=self.loc),
2463
+ name=f"$const_{value.stop}",
2464
+ redefine=True,
2465
+ )
2466
+
2467
+ slicevar = self.store(
2468
+ value=ir.Global("slice", slice, loc=self.loc),
2469
+ name="$const_slice",
2470
+ redefine=True,
2471
+ )
2472
+
2473
+ if value.step is None:
2474
+ params = (start, stop)
2475
+ else:
2476
+ step = self.store(
2477
+ ir.Const(value.step, loc=self.loc),
2478
+ name=f"$const_{value.step}",
2479
+ redefine=True,
2480
+ )
2481
+ params = (start, stop, step)
2482
+
2483
+ return ir.Expr.call(slicevar, params, (), loc=self.loc)
2484
+
2485
+ def process_args(value):
2435
2486
  st = []
2436
2487
  for x in value:
2437
- nm = "$const_%s" % str(x)
2438
- val_const = ir.Const(x, loc=self.loc)
2439
- target = self.store(val_const, name=nm, redefine=True)
2440
- st.append(target)
2441
- const = ir.Expr.build_tuple(st, loc=self.loc)
2488
+ if isinstance(x, slice):
2489
+ st.append(
2490
+ self.store(
2491
+ process_slice(x),
2492
+ name="$const_my_slice",
2493
+ redefine=True,
2494
+ )
2495
+ )
2496
+ else:
2497
+ st.append(
2498
+ self.store(
2499
+ ir.Const(x, loc=self.loc),
2500
+ name=f"$const_{x}",
2501
+ redefine=True,
2502
+ )
2503
+ )
2504
+ return st
2505
+
2506
+ value = self.code_consts[inst.arg]
2507
+
2508
+ if isinstance(value, tuple):
2509
+ const = ir.Expr.build_tuple(process_args(value), loc=self.loc)
2442
2510
  elif isinstance(value, frozenset):
2443
- st = []
2444
- for x in value:
2445
- nm = "$const_%s" % str(x)
2446
- val_const = ir.Const(x, loc=self.loc)
2447
- target = self.store(val_const, name=nm, redefine=True)
2448
- st.append(target)
2449
- const = ir.Expr.build_set(st, loc=self.loc)
2511
+ const = ir.Expr.build_set(process_args(value), loc=self.loc)
2512
+ elif isinstance(value, slice):
2513
+ const = process_slice(value)
2450
2514
  else:
2451
2515
  const = ir.Const(value, loc=self.loc)
2452
2516
  self.store(const, res)
2453
2517
 
2454
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2518
+ if PYVERSION in ((3, 14),):
2519
+ # New in 3.14
2520
+ def op_LOAD_SMALL_INT(self, inst, res):
2521
+ value = inst.arg
2522
+ const = ir.Const(value, loc=self.loc)
2523
+ self.store(const, res)
2524
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2525
+ pass
2526
+ else:
2527
+ raise NotImplementedError(PYVERSION)
2528
+
2529
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2455
2530
 
2456
2531
  def op_LOAD_GLOBAL(self, inst, idx, res):
2457
2532
  name = self.code_names[idx]
@@ -2474,7 +2549,7 @@ class Interpreter(object):
2474
2549
  def op_COPY_FREE_VARS(self, inst):
2475
2550
  pass
2476
2551
 
2477
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2552
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2478
2553
 
2479
2554
  def op_LOAD_DEREF(self, inst, res):
2480
2555
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -2508,12 +2583,12 @@ class Interpreter(object):
2508
2583
  else:
2509
2584
  raise NotImplementedError(PYVERSION)
2510
2585
 
2511
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2586
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2512
2587
 
2513
2588
  def op_MAKE_CELL(self, inst):
2514
2589
  pass # ignored bytecode
2515
2590
 
2516
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2591
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
2517
2592
 
2518
2593
  def op_STORE_DEREF(self, inst, value):
2519
2594
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -2561,39 +2636,46 @@ class Interpreter(object):
2561
2636
  exit_fn_obj = ir.Const(None, loc=self.loc)
2562
2637
  self.store(value=exit_fn_obj, name=exitfn)
2563
2638
 
2564
- def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
2565
- assert self.blocks[inst.offset] is self.current_block
2566
- if PYVERSION in ((3, 12), (3, 13)):
2567
- # Python 3.12 hack for handling nested with blocks
2568
- if end > self.last_active_offset:
2569
- # Use exception entries to figure out end of syntax block
2570
- end = max(
2571
- [
2572
- ex.end
2573
- for ex in self.active_exception_entries
2574
- if ex.target == end
2575
- ]
2639
+ if PYVERSION in ((3, 14),):
2640
+ # Replaced by LOAD_SPECIAL in 3.14.
2641
+ pass
2642
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2643
+
2644
+ def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
2645
+ assert self.blocks[inst.offset] is self.current_block
2646
+ if PYVERSION in ((3, 12), (3, 13)):
2647
+ # Python 3.12 hack for handling nested with blocks
2648
+ if end > self.last_active_offset:
2649
+ # Use exception entries to figure out end of syntax block
2650
+ end = max(
2651
+ [
2652
+ ex.end
2653
+ for ex in self.active_exception_entries
2654
+ if ex.target == end
2655
+ ]
2656
+ )
2657
+ elif PYVERSION in ((3, 10), (3, 11)):
2658
+ pass
2659
+ else:
2660
+ raise NotImplementedError(PYVERSION)
2661
+ # Handle with
2662
+ wth = ir.With(inst.offset, exit=end)
2663
+ self.syntax_blocks.append(wth)
2664
+ ctxmgr = self.get(contextmanager)
2665
+ self.current_block.append(
2666
+ ir.EnterWith(
2667
+ contextmanager=ctxmgr,
2668
+ begin=inst.offset,
2669
+ end=end,
2670
+ loc=self.loc,
2576
2671
  )
2577
- elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2578
- pass
2579
- else:
2580
- raise NotImplementedError(PYVERSION)
2581
- # Handle with
2582
- wth = ir.With(inst.offset, exit=end)
2583
- self.syntax_blocks.append(wth)
2584
- ctxmgr = self.get(contextmanager)
2585
- self.current_block.append(
2586
- ir.EnterWith(
2587
- contextmanager=ctxmgr,
2588
- begin=inst.offset,
2589
- end=end,
2590
- loc=self.loc,
2591
2672
  )
2592
- )
2593
2673
 
2594
- # Store exit function
2595
- exit_fn_obj = ir.Const(None, loc=self.loc)
2596
- self.store(value=exit_fn_obj, name=exitfn)
2674
+ # Store exit function
2675
+ exit_fn_obj = ir.Const(None, loc=self.loc)
2676
+ self.store(value=exit_fn_obj, name=exitfn)
2677
+ else:
2678
+ raise NotImplementedError(PYVERSION)
2597
2679
 
2598
2680
  def op_SETUP_FINALLY(self, inst):
2599
2681
  # Removed since python3.11
@@ -2632,7 +2714,7 @@ class Interpreter(object):
2632
2714
  expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
2633
2715
  self.store(expr, res)
2634
2716
 
2635
- if PYVERSION in ((3, 13),):
2717
+ if PYVERSION in ((3, 13), (3, 14)):
2636
2718
 
2637
2719
  def op_CALL_KW(self, inst, func, args, kw_names, res):
2638
2720
  func = self.get(func)
@@ -2807,9 +2889,7 @@ class Interpreter(object):
2807
2889
  # store the index of the actual used value for a given key, this is
2808
2890
  # used when lowering to pull the right value out into the tuple repr
2809
2891
  # of a mixed value type dictionary.
2810
- value_indexes = {}
2811
- for i, k in enumerate(keytup):
2812
- value_indexes[k] = i
2892
+ value_indexes = {k: i for i, k in enumerate(keytup)}
2813
2893
 
2814
2894
  expr = ir.Expr.build_map(
2815
2895
  items=items,
@@ -2852,11 +2932,18 @@ class Interpreter(object):
2852
2932
  )
2853
2933
  self.current_block.append(br)
2854
2934
 
2855
- def op_BINARY_SUBSCR(self, inst, target, index, res):
2856
- index = self.get(index)
2857
- target = self.get(target)
2858
- expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2859
- self.store(expr, res)
2935
+ if PYVERSION in ((3, 14),):
2936
+ # Removed in 3.14 -- replaced with BINARY_OP and []
2937
+ pass
2938
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
2939
+
2940
+ def op_BINARY_SUBSCR(self, inst, target, index, res):
2941
+ index = self.get(index)
2942
+ target = self.get(target)
2943
+ expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2944
+ self.store(expr, res)
2945
+ else:
2946
+ raise NotImplementedError(PYVERSION)
2860
2947
 
2861
2948
  def op_STORE_SUBSCR(self, inst, target, index, value):
2862
2949
  index = self.get(index)
@@ -2889,6 +2976,14 @@ class Interpreter(object):
2889
2976
  )
2890
2977
  self.store(expr, res)
2891
2978
 
2979
+ def op_SET_ADD(self, inst, value, target, addvar, res):
2980
+ value = self.get(value)
2981
+ target = self.get(target)
2982
+ addattr = ir.Expr.getattr(target, "add", loc=self.loc)
2983
+ self.store(value=addattr, name=addvar)
2984
+ addinst = ir.Expr.call(self.get(addvar), (value,), (), loc=self.loc)
2985
+ self.store(value=addinst, name=res)
2986
+
2892
2987
  def op_SET_UPDATE(self, inst, target, value, updatevar, res):
2893
2988
  target = self.get(target)
2894
2989
  value = self.get(value)
@@ -2948,12 +3043,10 @@ class Interpreter(object):
2948
3043
  literal_dict = {
2949
3044
  x: _UNKNOWN_VALUE(y[1]) for x, y in zip(literal_keys, got_items)
2950
3045
  }
2951
- for i, k in enumerate(literal_keys):
2952
- value_indexes[k] = i
3046
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
2953
3047
  else:
2954
3048
  literal_dict = {x: y for x, y in zip(literal_keys, literal_values)}
2955
- for i, k in enumerate(literal_keys):
2956
- value_indexes[k] = i
3049
+ value_indexes.update((k, i) for i, k in enumerate(literal_keys))
2957
3050
 
2958
3051
  expr = ir.Expr.build_map(
2959
3052
  items=got_items,
@@ -3009,7 +3102,13 @@ class Interpreter(object):
3009
3102
  self.store(expr, res)
3010
3103
 
3011
3104
  def op_BINARY_OP(self, inst, op, lhs, rhs, res):
3012
- if "=" in op:
3105
+ if op == "[]":
3106
+ # Special case 3.14 -- body of BINARY_SUBSCR now here
3107
+ lhs = self.get(lhs)
3108
+ rhs = self.get(rhs)
3109
+ expr = ir.Expr.getitem(lhs, index=rhs, loc=self.loc)
3110
+ self.store(expr, res)
3111
+ elif "=" in op:
3013
3112
  self._inplace_binop(op[:-1], lhs, rhs, res)
3014
3113
  else:
3015
3114
  self._binop(op, lhs, rhs, res)
@@ -3126,7 +3225,7 @@ class Interpreter(object):
3126
3225
  ret = ir.Return(self.get(castval), loc=self.loc)
3127
3226
  self.current_block.append(ret)
3128
3227
 
3129
- if PYVERSION in ((3, 12), (3, 13)):
3228
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3130
3229
 
3131
3230
  def op_RETURN_CONST(self, inst, retval, castval):
3132
3231
  value = self.code_consts[inst.arg]
@@ -3140,7 +3239,7 @@ class Interpreter(object):
3140
3239
  else:
3141
3240
  raise NotImplementedError(PYVERSION)
3142
3241
 
3143
- if PYVERSION in ((3, 13),):
3242
+ if PYVERSION in ((3, 13), (3, 14)):
3144
3243
 
3145
3244
  def op_TO_BOOL(self, inst, val, res):
3146
3245
  self.store(self.get(val), res) # TODO: just a lazy hack
@@ -3151,7 +3250,7 @@ class Interpreter(object):
3151
3250
  raise NotImplementedError(PYVERSION)
3152
3251
 
3153
3252
  def op_COMPARE_OP(self, inst, lhs, rhs, res):
3154
- if PYVERSION in ((3, 13),):
3253
+ if PYVERSION in ((3, 13), (3, 14)):
3155
3254
  op = dis.cmp_op[inst.arg >> 5]
3156
3255
  # TODO: fifth lowest bit now indicates a forced version to bool.
3157
3256
  elif PYVERSION in ((3, 12),):
@@ -3280,7 +3379,7 @@ class Interpreter(object):
3280
3379
  def op_POP_JUMP_FORWARD_IF_NOT_NONE(self, inst, pred):
3281
3380
  self._jump_if_none(inst, pred, False)
3282
3381
 
3283
- if PYVERSION in ((3, 12), (3, 13)):
3382
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3284
3383
 
3285
3384
  def op_POP_JUMP_IF_NONE(self, inst, pred):
3286
3385
  self._jump_if_none(inst, pred, True)
@@ -3439,7 +3538,7 @@ class Interpreter(object):
3439
3538
  inst, name, code, closure, annotations, kwdefaults, defaults, res
3440
3539
  )
3441
3540
 
3442
- if PYVERSION in ((3, 11), (3, 12), (3, 13)):
3541
+ if PYVERSION in ((3, 11), (3, 12), (3, 13), (3, 14)):
3443
3542
 
3444
3543
  def op_LOAD_CLOSURE(self, inst, res):
3445
3544
  name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
@@ -3581,9 +3680,16 @@ class Interpreter(object):
3581
3680
  )
3582
3681
  self.store(value=appendinst, name=res)
3583
3682
 
3584
- def op_LOAD_ASSERTION_ERROR(self, inst, res):
3585
- gv_fn = ir.Global("AssertionError", AssertionError, loc=self.loc)
3586
- self.store(value=gv_fn, name=res)
3683
+ if PYVERSION in ((3, 14),):
3684
+ # Removed in 3.14
3685
+ pass
3686
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3687
+
3688
+ def op_LOAD_ASSERTION_ERROR(self, inst, res):
3689
+ gv_fn = ir.Global("AssertionError", AssertionError, loc=self.loc)
3690
+ self.store(value=gv_fn, name=res)
3691
+ else:
3692
+ raise NotImplementedError(PYVERSION)
3587
3693
 
3588
3694
  # NOTE: The LOAD_METHOD opcode is implemented as a LOAD_ATTR for ease,
3589
3695
  # however this means a new object (the bound-method instance) could be
@@ -3599,7 +3705,7 @@ class Interpreter(object):
3599
3705
  def op_CALL_METHOD(self, *args, **kws):
3600
3706
  self.op_CALL_FUNCTION(*args, **kws)
3601
3707
 
3602
- if PYVERSION in ((3, 12), (3, 13)):
3708
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3603
3709
 
3604
3710
  def op_CALL_INTRINSIC_1(self, inst, operand, **kwargs):
3605
3711
  if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
@@ -3621,8 +3727,61 @@ class Interpreter(object):
3621
3727
  else:
3622
3728
  raise NotImplementedError(PYVERSION)
3623
3729
 
3730
+ if PYVERSION in ((3, 14),):
3731
+ # New in 3.14, replaces BEFORE_WITH.
3732
+ def op_LOAD_SPECIAL(self, inst, contextmanager, exit_method, block_end):
3733
+ assert self.blocks[inst.offset] is self.current_block
3734
+
3735
+ # Python 3.12 hack for handling nested with blocks
3736
+ if block_end > self.last_active_offset:
3737
+ # Use exception entries to figure out end of syntax block
3738
+ block_end = max(
3739
+ [
3740
+ ex.end
3741
+ for ex in self.active_exception_entries
3742
+ if ex.target == block_end
3743
+ ]
3744
+ )
3745
+
3746
+ # Handle with
3747
+ wth = ir.With(inst.offset, exit=block_end)
3748
+ self.syntax_blocks.append(wth)
3749
+ ctxmgr = self.get(contextmanager)
3750
+ self.current_block.append(
3751
+ ir.EnterWith(
3752
+ contextmanager=ctxmgr,
3753
+ begin=inst.offset,
3754
+ end=block_end,
3755
+ loc=self.loc,
3756
+ )
3757
+ )
3758
+
3759
+ # Store exit function
3760
+ exit_fn_obj = ir.Const(None, loc=self.loc)
3761
+ self.store(value=exit_fn_obj, name=exit_method)
3762
+
3763
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3764
+ pass
3765
+ else:
3766
+ raise NotImplementedError(PYVERSION)
3767
+
3768
+ if PYVERSION in ((3, 14),):
3769
+
3770
+ def op_LOAD_COMMON_CONSTANT(self, inst, res, idx):
3771
+ if isinstance(dis._common_constants[idx], AssertionError):
3772
+ gv_fn = ir.Global(
3773
+ "AssertionError", AssertionError, loc=self.loc
3774
+ )
3775
+ self.store(value=gv_fn, name=res)
3776
+ else:
3777
+ raise NotImplementedError
3778
+ elif PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
3779
+ pass
3780
+ else:
3781
+ raise NotImplementedError(PYVERSION)
3782
+
3624
3783
 
3625
- if PYVERSION in ((3, 12), (3, 13)):
3784
+ if PYVERSION in ((3, 12), (3, 13), (3, 14)):
3626
3785
 
3627
3786
  class INTRINSIC_STOPITERATION_ERROR(AssertionError):
3628
3787
  pass
@@ -389,10 +389,7 @@ def get_name_var_table(blocks):
389
389
  def replace_var_names(blocks, namedict):
390
390
  """replace variables (ir.Var to ir.Var) from dictionary (name -> name)"""
391
391
  # remove identity values to avoid infinite loop
392
- new_namedict = {}
393
- for l, r in namedict.items():
394
- if l != r:
395
- new_namedict[l] = r
392
+ new_namedict = {l: r for l, r in namedict.items() if l != r}
396
393
 
397
394
  def replace_name(var, namedict):
398
395
  assert isinstance(var, ir.var_types)
@@ -415,10 +412,7 @@ def replace_var_callback(var, vardict):
415
412
  def replace_vars(blocks, vardict):
416
413
  """replace variables (ir.Var to ir.Var) from dictionary (name -> ir.Var)"""
417
414
  # remove identity values to avoid infinite loop
418
- new_vardict = {}
419
- for l, r in vardict.items():
420
- if l != r.name:
421
- new_vardict[l] = r
415
+ new_vardict = {l: r for l, r in vardict.items() if l != r.name}
422
416
  visit_vars(blocks, replace_var_callback, new_vardict)
423
417
 
424
418
 
@@ -591,11 +585,9 @@ def flatten_labels(blocks):
591
585
  def remove_dels(blocks):
592
586
  """remove ir.Del nodes"""
593
587
  for block in blocks.values():
594
- new_body = []
595
- for stmt in block.body:
596
- if not isinstance(stmt, ir.del_types):
597
- new_body.append(stmt)
598
- block.body = new_body
588
+ block.body = [
589
+ stmt for stmt in block.body if not isinstance(stmt, ir.del_types)
590
+ ]
599
591
  return
600
592
 
601
593
 
@@ -1076,7 +1068,7 @@ def init_copy_propagate_data(blocks, entry, typemap):
1076
1068
  gen_copies, extra_kill = get_block_copies(blocks, typemap)
1077
1069
  # set of all program copies
1078
1070
  all_copies = set()
1079
- for l, s in gen_copies.items():
1071
+ for l in gen_copies.keys():
1080
1072
  all_copies |= gen_copies[l]
1081
1073
  kill_copies = {}
1082
1074
  for label, gen_set in gen_copies.items():
@@ -1122,8 +1114,7 @@ def get_block_copies(blocks, typemap):
1122
1114
  for T, f in copy_propagate_extensions.items():
1123
1115
  if isinstance(stmt, T):
1124
1116
  gen_set, kill_set = f(stmt, typemap)
1125
- for lhs, rhs in gen_set:
1126
- assign_dict[lhs] = rhs
1117
+ assign_dict.update(gen_set)
1127
1118
  # if a=b is in dict and b is killed, a is also killed
1128
1119
  new_assign_dict = {}
1129
1120
  for l, r in assign_dict.items():
@@ -1933,7 +1924,7 @@ def compile_to_numba_ir(
1933
1924
  # rename all variables to avoid conflict
1934
1925
  var_table = get_name_var_table(f_ir.blocks)
1935
1926
  new_var_dict = {}
1936
- for name, var in var_table.items():
1927
+ for name in var_table.keys():
1937
1928
  new_var_dict[name] = mk_unique_var(name)
1938
1929
  replace_var_names(f_ir.blocks, new_var_dict)
1939
1930