numba-cuda 0.22.0__cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.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 (487) hide show
  1. _numba_cuda_redirector.pth +4 -0
  2. _numba_cuda_redirector.py +89 -0
  3. numba_cuda/VERSION +1 -0
  4. numba_cuda/__init__.py +6 -0
  5. numba_cuda/_version.py +11 -0
  6. numba_cuda/numba/cuda/__init__.py +70 -0
  7. numba_cuda/numba/cuda/_internal/cuda_bf16.py +16394 -0
  8. numba_cuda/numba/cuda/_internal/cuda_fp16.py +8112 -0
  9. numba_cuda/numba/cuda/api.py +580 -0
  10. numba_cuda/numba/cuda/api_util.py +76 -0
  11. numba_cuda/numba/cuda/args.py +72 -0
  12. numba_cuda/numba/cuda/bf16.py +397 -0
  13. numba_cuda/numba/cuda/cache_hints.py +287 -0
  14. numba_cuda/numba/cuda/cext/__init__.py +2 -0
  15. numba_cuda/numba/cuda/cext/_devicearray.cpp +159 -0
  16. numba_cuda/numba/cuda/cext/_devicearray.cpython-313-aarch64-linux-gnu.so +0 -0
  17. numba_cuda/numba/cuda/cext/_devicearray.h +29 -0
  18. numba_cuda/numba/cuda/cext/_dispatcher.cpp +1098 -0
  19. numba_cuda/numba/cuda/cext/_dispatcher.cpython-313-aarch64-linux-gnu.so +0 -0
  20. numba_cuda/numba/cuda/cext/_hashtable.cpp +532 -0
  21. numba_cuda/numba/cuda/cext/_hashtable.h +135 -0
  22. numba_cuda/numba/cuda/cext/_helperlib.c +71 -0
  23. numba_cuda/numba/cuda/cext/_helperlib.cpython-313-aarch64-linux-gnu.so +0 -0
  24. numba_cuda/numba/cuda/cext/_helpermod.c +82 -0
  25. numba_cuda/numba/cuda/cext/_pymodule.h +38 -0
  26. numba_cuda/numba/cuda/cext/_typeconv.cpp +206 -0
  27. numba_cuda/numba/cuda/cext/_typeconv.cpython-313-aarch64-linux-gnu.so +0 -0
  28. numba_cuda/numba/cuda/cext/_typeof.cpp +1159 -0
  29. numba_cuda/numba/cuda/cext/_typeof.h +19 -0
  30. numba_cuda/numba/cuda/cext/capsulethunk.h +111 -0
  31. numba_cuda/numba/cuda/cext/mviewbuf.c +385 -0
  32. numba_cuda/numba/cuda/cext/mviewbuf.cpython-313-aarch64-linux-gnu.so +0 -0
  33. numba_cuda/numba/cuda/cext/typeconv.cpp +212 -0
  34. numba_cuda/numba/cuda/cext/typeconv.hpp +101 -0
  35. numba_cuda/numba/cuda/cg.py +67 -0
  36. numba_cuda/numba/cuda/cgutils.py +1294 -0
  37. numba_cuda/numba/cuda/cloudpickle/__init__.py +21 -0
  38. numba_cuda/numba/cuda/cloudpickle/cloudpickle.py +1598 -0
  39. numba_cuda/numba/cuda/cloudpickle/cloudpickle_fast.py +17 -0
  40. numba_cuda/numba/cuda/codegen.py +541 -0
  41. numba_cuda/numba/cuda/compiler.py +1396 -0
  42. numba_cuda/numba/cuda/core/analysis.py +758 -0
  43. numba_cuda/numba/cuda/core/annotations/__init__.py +0 -0
  44. numba_cuda/numba/cuda/core/annotations/pretty_annotate.py +288 -0
  45. numba_cuda/numba/cuda/core/annotations/type_annotations.py +305 -0
  46. numba_cuda/numba/cuda/core/base.py +1332 -0
  47. numba_cuda/numba/cuda/core/boxing.py +1411 -0
  48. numba_cuda/numba/cuda/core/bytecode.py +728 -0
  49. numba_cuda/numba/cuda/core/byteflow.py +2346 -0
  50. numba_cuda/numba/cuda/core/caching.py +744 -0
  51. numba_cuda/numba/cuda/core/callconv.py +392 -0
  52. numba_cuda/numba/cuda/core/codegen.py +171 -0
  53. numba_cuda/numba/cuda/core/compiler.py +199 -0
  54. numba_cuda/numba/cuda/core/compiler_lock.py +85 -0
  55. numba_cuda/numba/cuda/core/compiler_machinery.py +497 -0
  56. numba_cuda/numba/cuda/core/config.py +650 -0
  57. numba_cuda/numba/cuda/core/consts.py +124 -0
  58. numba_cuda/numba/cuda/core/controlflow.py +989 -0
  59. numba_cuda/numba/cuda/core/entrypoints.py +57 -0
  60. numba_cuda/numba/cuda/core/environment.py +66 -0
  61. numba_cuda/numba/cuda/core/errors.py +917 -0
  62. numba_cuda/numba/cuda/core/event.py +511 -0
  63. numba_cuda/numba/cuda/core/funcdesc.py +330 -0
  64. numba_cuda/numba/cuda/core/generators.py +387 -0
  65. numba_cuda/numba/cuda/core/imputils.py +509 -0
  66. numba_cuda/numba/cuda/core/inline_closurecall.py +1787 -0
  67. numba_cuda/numba/cuda/core/interpreter.py +3617 -0
  68. numba_cuda/numba/cuda/core/ir.py +1812 -0
  69. numba_cuda/numba/cuda/core/ir_utils.py +2638 -0
  70. numba_cuda/numba/cuda/core/optional.py +129 -0
  71. numba_cuda/numba/cuda/core/options.py +262 -0
  72. numba_cuda/numba/cuda/core/postproc.py +249 -0
  73. numba_cuda/numba/cuda/core/pythonapi.py +1859 -0
  74. numba_cuda/numba/cuda/core/registry.py +46 -0
  75. numba_cuda/numba/cuda/core/removerefctpass.py +123 -0
  76. numba_cuda/numba/cuda/core/rewrites/__init__.py +26 -0
  77. numba_cuda/numba/cuda/core/rewrites/ir_print.py +91 -0
  78. numba_cuda/numba/cuda/core/rewrites/registry.py +104 -0
  79. numba_cuda/numba/cuda/core/rewrites/static_binop.py +41 -0
  80. numba_cuda/numba/cuda/core/rewrites/static_getitem.py +189 -0
  81. numba_cuda/numba/cuda/core/rewrites/static_raise.py +100 -0
  82. numba_cuda/numba/cuda/core/sigutils.py +68 -0
  83. numba_cuda/numba/cuda/core/ssa.py +498 -0
  84. numba_cuda/numba/cuda/core/targetconfig.py +330 -0
  85. numba_cuda/numba/cuda/core/tracing.py +231 -0
  86. numba_cuda/numba/cuda/core/transforms.py +956 -0
  87. numba_cuda/numba/cuda/core/typed_passes.py +867 -0
  88. numba_cuda/numba/cuda/core/typeinfer.py +1950 -0
  89. numba_cuda/numba/cuda/core/unsafe/__init__.py +0 -0
  90. numba_cuda/numba/cuda/core/unsafe/bytes.py +67 -0
  91. numba_cuda/numba/cuda/core/unsafe/eh.py +67 -0
  92. numba_cuda/numba/cuda/core/unsafe/refcount.py +98 -0
  93. numba_cuda/numba/cuda/core/untyped_passes.py +1979 -0
  94. numba_cuda/numba/cuda/cpython/builtins.py +1153 -0
  95. numba_cuda/numba/cuda/cpython/charseq.py +1218 -0
  96. numba_cuda/numba/cuda/cpython/cmathimpl.py +560 -0
  97. numba_cuda/numba/cuda/cpython/enumimpl.py +103 -0
  98. numba_cuda/numba/cuda/cpython/iterators.py +167 -0
  99. numba_cuda/numba/cuda/cpython/listobj.py +1326 -0
  100. numba_cuda/numba/cuda/cpython/mathimpl.py +499 -0
  101. numba_cuda/numba/cuda/cpython/numbers.py +1475 -0
  102. numba_cuda/numba/cuda/cpython/rangeobj.py +289 -0
  103. numba_cuda/numba/cuda/cpython/slicing.py +322 -0
  104. numba_cuda/numba/cuda/cpython/tupleobj.py +456 -0
  105. numba_cuda/numba/cuda/cpython/unicode.py +2865 -0
  106. numba_cuda/numba/cuda/cpython/unicode_support.py +1597 -0
  107. numba_cuda/numba/cuda/cpython/unsafe/__init__.py +0 -0
  108. numba_cuda/numba/cuda/cpython/unsafe/numbers.py +64 -0
  109. numba_cuda/numba/cuda/cpython/unsafe/tuple.py +92 -0
  110. numba_cuda/numba/cuda/cuda_paths.py +691 -0
  111. numba_cuda/numba/cuda/cudadecl.py +543 -0
  112. numba_cuda/numba/cuda/cudadrv/__init__.py +14 -0
  113. numba_cuda/numba/cuda/cudadrv/devicearray.py +954 -0
  114. numba_cuda/numba/cuda/cudadrv/devices.py +249 -0
  115. numba_cuda/numba/cuda/cudadrv/driver.py +3238 -0
  116. numba_cuda/numba/cuda/cudadrv/drvapi.py +435 -0
  117. numba_cuda/numba/cuda/cudadrv/dummyarray.py +562 -0
  118. numba_cuda/numba/cuda/cudadrv/enums.py +613 -0
  119. numba_cuda/numba/cuda/cudadrv/error.py +48 -0
  120. numba_cuda/numba/cuda/cudadrv/libs.py +220 -0
  121. numba_cuda/numba/cuda/cudadrv/linkable_code.py +184 -0
  122. numba_cuda/numba/cuda/cudadrv/mappings.py +14 -0
  123. numba_cuda/numba/cuda/cudadrv/ndarray.py +26 -0
  124. numba_cuda/numba/cuda/cudadrv/nvrtc.py +193 -0
  125. numba_cuda/numba/cuda/cudadrv/nvvm.py +756 -0
  126. numba_cuda/numba/cuda/cudadrv/rtapi.py +13 -0
  127. numba_cuda/numba/cuda/cudadrv/runtime.py +34 -0
  128. numba_cuda/numba/cuda/cudaimpl.py +983 -0
  129. numba_cuda/numba/cuda/cudamath.py +149 -0
  130. numba_cuda/numba/cuda/datamodel/__init__.py +7 -0
  131. numba_cuda/numba/cuda/datamodel/cuda_manager.py +66 -0
  132. numba_cuda/numba/cuda/datamodel/cuda_models.py +1446 -0
  133. numba_cuda/numba/cuda/datamodel/cuda_packer.py +224 -0
  134. numba_cuda/numba/cuda/datamodel/cuda_registry.py +22 -0
  135. numba_cuda/numba/cuda/datamodel/cuda_testing.py +153 -0
  136. numba_cuda/numba/cuda/datamodel/manager.py +11 -0
  137. numba_cuda/numba/cuda/datamodel/models.py +9 -0
  138. numba_cuda/numba/cuda/datamodel/packer.py +9 -0
  139. numba_cuda/numba/cuda/datamodel/registry.py +11 -0
  140. numba_cuda/numba/cuda/datamodel/testing.py +11 -0
  141. numba_cuda/numba/cuda/debuginfo.py +997 -0
  142. numba_cuda/numba/cuda/decorators.py +294 -0
  143. numba_cuda/numba/cuda/descriptor.py +35 -0
  144. numba_cuda/numba/cuda/device_init.py +155 -0
  145. numba_cuda/numba/cuda/deviceufunc.py +1021 -0
  146. numba_cuda/numba/cuda/dispatcher.py +2463 -0
  147. numba_cuda/numba/cuda/errors.py +72 -0
  148. numba_cuda/numba/cuda/extending.py +697 -0
  149. numba_cuda/numba/cuda/flags.py +178 -0
  150. numba_cuda/numba/cuda/fp16.py +357 -0
  151. numba_cuda/numba/cuda/include/12/cuda_bf16.h +5118 -0
  152. numba_cuda/numba/cuda/include/12/cuda_bf16.hpp +3865 -0
  153. numba_cuda/numba/cuda/include/12/cuda_fp16.h +5363 -0
  154. numba_cuda/numba/cuda/include/12/cuda_fp16.hpp +3483 -0
  155. numba_cuda/numba/cuda/include/13/cuda_bf16.h +5118 -0
  156. numba_cuda/numba/cuda/include/13/cuda_bf16.hpp +3865 -0
  157. numba_cuda/numba/cuda/include/13/cuda_fp16.h +5363 -0
  158. numba_cuda/numba/cuda/include/13/cuda_fp16.hpp +3483 -0
  159. numba_cuda/numba/cuda/initialize.py +24 -0
  160. numba_cuda/numba/cuda/intrinsics.py +531 -0
  161. numba_cuda/numba/cuda/itanium_mangler.py +214 -0
  162. numba_cuda/numba/cuda/kernels/__init__.py +2 -0
  163. numba_cuda/numba/cuda/kernels/reduction.py +265 -0
  164. numba_cuda/numba/cuda/kernels/transpose.py +65 -0
  165. numba_cuda/numba/cuda/libdevice.py +3386 -0
  166. numba_cuda/numba/cuda/libdevicedecl.py +20 -0
  167. numba_cuda/numba/cuda/libdevicefuncs.py +1060 -0
  168. numba_cuda/numba/cuda/libdeviceimpl.py +88 -0
  169. numba_cuda/numba/cuda/locks.py +19 -0
  170. numba_cuda/numba/cuda/lowering.py +1980 -0
  171. numba_cuda/numba/cuda/mathimpl.py +374 -0
  172. numba_cuda/numba/cuda/memory_management/__init__.py +4 -0
  173. numba_cuda/numba/cuda/memory_management/memsys.cu +99 -0
  174. numba_cuda/numba/cuda/memory_management/memsys.cuh +22 -0
  175. numba_cuda/numba/cuda/memory_management/nrt.cu +212 -0
  176. numba_cuda/numba/cuda/memory_management/nrt.cuh +48 -0
  177. numba_cuda/numba/cuda/memory_management/nrt.py +390 -0
  178. numba_cuda/numba/cuda/memory_management/nrt_context.py +438 -0
  179. numba_cuda/numba/cuda/misc/appdirs.py +594 -0
  180. numba_cuda/numba/cuda/misc/cffiimpl.py +24 -0
  181. numba_cuda/numba/cuda/misc/coverage_support.py +43 -0
  182. numba_cuda/numba/cuda/misc/dump_style.py +41 -0
  183. numba_cuda/numba/cuda/misc/findlib.py +75 -0
  184. numba_cuda/numba/cuda/misc/firstlinefinder.py +96 -0
  185. numba_cuda/numba/cuda/misc/gdb_hook.py +240 -0
  186. numba_cuda/numba/cuda/misc/literal.py +28 -0
  187. numba_cuda/numba/cuda/misc/llvm_pass_timings.py +412 -0
  188. numba_cuda/numba/cuda/misc/special.py +94 -0
  189. numba_cuda/numba/cuda/models.py +56 -0
  190. numba_cuda/numba/cuda/np/arraymath.py +5130 -0
  191. numba_cuda/numba/cuda/np/arrayobj.py +7635 -0
  192. numba_cuda/numba/cuda/np/extensions.py +11 -0
  193. numba_cuda/numba/cuda/np/linalg.py +3087 -0
  194. numba_cuda/numba/cuda/np/math/__init__.py +0 -0
  195. numba_cuda/numba/cuda/np/math/cmathimpl.py +558 -0
  196. numba_cuda/numba/cuda/np/math/mathimpl.py +487 -0
  197. numba_cuda/numba/cuda/np/math/numbers.py +1461 -0
  198. numba_cuda/numba/cuda/np/npdatetime.py +969 -0
  199. numba_cuda/numba/cuda/np/npdatetime_helpers.py +217 -0
  200. numba_cuda/numba/cuda/np/npyfuncs.py +1808 -0
  201. numba_cuda/numba/cuda/np/npyimpl.py +1027 -0
  202. numba_cuda/numba/cuda/np/numpy_support.py +798 -0
  203. numba_cuda/numba/cuda/np/polynomial/__init__.py +4 -0
  204. numba_cuda/numba/cuda/np/polynomial/polynomial_core.py +242 -0
  205. numba_cuda/numba/cuda/np/polynomial/polynomial_functions.py +380 -0
  206. numba_cuda/numba/cuda/np/ufunc/__init__.py +4 -0
  207. numba_cuda/numba/cuda/np/ufunc/decorators.py +203 -0
  208. numba_cuda/numba/cuda/np/ufunc/sigparse.py +68 -0
  209. numba_cuda/numba/cuda/np/ufunc/ufuncbuilder.py +65 -0
  210. numba_cuda/numba/cuda/np/ufunc_db.py +1282 -0
  211. numba_cuda/numba/cuda/np/unsafe/__init__.py +0 -0
  212. numba_cuda/numba/cuda/np/unsafe/ndarray.py +84 -0
  213. numba_cuda/numba/cuda/nvvmutils.py +254 -0
  214. numba_cuda/numba/cuda/printimpl.py +126 -0
  215. numba_cuda/numba/cuda/random.py +308 -0
  216. numba_cuda/numba/cuda/reshape_funcs.cu +156 -0
  217. numba_cuda/numba/cuda/serialize.py +267 -0
  218. numba_cuda/numba/cuda/simulator/__init__.py +63 -0
  219. numba_cuda/numba/cuda/simulator/_internal/__init__.py +4 -0
  220. numba_cuda/numba/cuda/simulator/_internal/cuda_bf16.py +2 -0
  221. numba_cuda/numba/cuda/simulator/api.py +179 -0
  222. numba_cuda/numba/cuda/simulator/bf16.py +4 -0
  223. numba_cuda/numba/cuda/simulator/compiler.py +38 -0
  224. numba_cuda/numba/cuda/simulator/cudadrv/__init__.py +11 -0
  225. numba_cuda/numba/cuda/simulator/cudadrv/devicearray.py +462 -0
  226. numba_cuda/numba/cuda/simulator/cudadrv/devices.py +122 -0
  227. numba_cuda/numba/cuda/simulator/cudadrv/driver.py +66 -0
  228. numba_cuda/numba/cuda/simulator/cudadrv/drvapi.py +7 -0
  229. numba_cuda/numba/cuda/simulator/cudadrv/dummyarray.py +7 -0
  230. numba_cuda/numba/cuda/simulator/cudadrv/error.py +10 -0
  231. numba_cuda/numba/cuda/simulator/cudadrv/libs.py +10 -0
  232. numba_cuda/numba/cuda/simulator/cudadrv/linkable_code.py +61 -0
  233. numba_cuda/numba/cuda/simulator/cudadrv/nvrtc.py +11 -0
  234. numba_cuda/numba/cuda/simulator/cudadrv/nvvm.py +32 -0
  235. numba_cuda/numba/cuda/simulator/cudadrv/runtime.py +22 -0
  236. numba_cuda/numba/cuda/simulator/dispatcher.py +11 -0
  237. numba_cuda/numba/cuda/simulator/kernel.py +320 -0
  238. numba_cuda/numba/cuda/simulator/kernelapi.py +509 -0
  239. numba_cuda/numba/cuda/simulator/memory_management/__init__.py +4 -0
  240. numba_cuda/numba/cuda/simulator/memory_management/nrt.py +21 -0
  241. numba_cuda/numba/cuda/simulator/reduction.py +19 -0
  242. numba_cuda/numba/cuda/simulator/tests/support.py +4 -0
  243. numba_cuda/numba/cuda/simulator/vector_types.py +65 -0
  244. numba_cuda/numba/cuda/simulator_init.py +18 -0
  245. numba_cuda/numba/cuda/stubs.py +624 -0
  246. numba_cuda/numba/cuda/target.py +505 -0
  247. numba_cuda/numba/cuda/testing.py +347 -0
  248. numba_cuda/numba/cuda/tests/__init__.py +62 -0
  249. numba_cuda/numba/cuda/tests/benchmarks/__init__.py +0 -0
  250. numba_cuda/numba/cuda/tests/benchmarks/test_kernel_launch.py +119 -0
  251. numba_cuda/numba/cuda/tests/cloudpickle_main_class.py +9 -0
  252. numba_cuda/numba/cuda/tests/core/serialize_usecases.py +113 -0
  253. numba_cuda/numba/cuda/tests/core/test_itanium_mangler.py +83 -0
  254. numba_cuda/numba/cuda/tests/core/test_serialize.py +371 -0
  255. numba_cuda/numba/cuda/tests/cudadrv/__init__.py +9 -0
  256. numba_cuda/numba/cuda/tests/cudadrv/test_array_attr.py +147 -0
  257. numba_cuda/numba/cuda/tests/cudadrv/test_context_stack.py +161 -0
  258. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_array_slicing.py +397 -0
  259. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_auto_context.py +24 -0
  260. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_devicerecord.py +180 -0
  261. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_driver.py +313 -0
  262. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_memory.py +191 -0
  263. numba_cuda/numba/cuda/tests/cudadrv/test_cuda_ndarray.py +621 -0
  264. numba_cuda/numba/cuda/tests/cudadrv/test_deallocations.py +247 -0
  265. numba_cuda/numba/cuda/tests/cudadrv/test_detect.py +100 -0
  266. numba_cuda/numba/cuda/tests/cudadrv/test_emm_plugins.py +200 -0
  267. numba_cuda/numba/cuda/tests/cudadrv/test_events.py +53 -0
  268. numba_cuda/numba/cuda/tests/cudadrv/test_host_alloc.py +72 -0
  269. numba_cuda/numba/cuda/tests/cudadrv/test_init.py +138 -0
  270. numba_cuda/numba/cuda/tests/cudadrv/test_inline_ptx.py +43 -0
  271. numba_cuda/numba/cuda/tests/cudadrv/test_is_fp16.py +15 -0
  272. numba_cuda/numba/cuda/tests/cudadrv/test_linkable_code.py +58 -0
  273. numba_cuda/numba/cuda/tests/cudadrv/test_linker.py +348 -0
  274. numba_cuda/numba/cuda/tests/cudadrv/test_managed_alloc.py +128 -0
  275. numba_cuda/numba/cuda/tests/cudadrv/test_module_callbacks.py +301 -0
  276. numba_cuda/numba/cuda/tests/cudadrv/test_nvjitlink.py +174 -0
  277. numba_cuda/numba/cuda/tests/cudadrv/test_nvrtc.py +28 -0
  278. numba_cuda/numba/cuda/tests/cudadrv/test_nvvm_driver.py +185 -0
  279. numba_cuda/numba/cuda/tests/cudadrv/test_pinned.py +39 -0
  280. numba_cuda/numba/cuda/tests/cudadrv/test_profiler.py +23 -0
  281. numba_cuda/numba/cuda/tests/cudadrv/test_reset_device.py +38 -0
  282. numba_cuda/numba/cuda/tests/cudadrv/test_runtime.py +48 -0
  283. numba_cuda/numba/cuda/tests/cudadrv/test_select_device.py +44 -0
  284. numba_cuda/numba/cuda/tests/cudadrv/test_streams.py +127 -0
  285. numba_cuda/numba/cuda/tests/cudapy/__init__.py +9 -0
  286. numba_cuda/numba/cuda/tests/cudapy/cache_usecases.py +231 -0
  287. numba_cuda/numba/cuda/tests/cudapy/cache_with_cpu_usecases.py +50 -0
  288. numba_cuda/numba/cuda/tests/cudapy/cg_cache_usecases.py +36 -0
  289. numba_cuda/numba/cuda/tests/cudapy/complex_usecases.py +116 -0
  290. numba_cuda/numba/cuda/tests/cudapy/enum_usecases.py +59 -0
  291. numba_cuda/numba/cuda/tests/cudapy/extensions_usecases.py +62 -0
  292. numba_cuda/numba/cuda/tests/cudapy/jitlink.ptx +28 -0
  293. numba_cuda/numba/cuda/tests/cudapy/overload_usecases.py +33 -0
  294. numba_cuda/numba/cuda/tests/cudapy/recursion_usecases.py +104 -0
  295. numba_cuda/numba/cuda/tests/cudapy/test_alignment.py +47 -0
  296. numba_cuda/numba/cuda/tests/cudapy/test_analysis.py +1122 -0
  297. numba_cuda/numba/cuda/tests/cudapy/test_array.py +344 -0
  298. numba_cuda/numba/cuda/tests/cudapy/test_array_alignment.py +268 -0
  299. numba_cuda/numba/cuda/tests/cudapy/test_array_args.py +203 -0
  300. numba_cuda/numba/cuda/tests/cudapy/test_array_methods.py +63 -0
  301. numba_cuda/numba/cuda/tests/cudapy/test_array_reductions.py +360 -0
  302. numba_cuda/numba/cuda/tests/cudapy/test_atomics.py +1815 -0
  303. numba_cuda/numba/cuda/tests/cudapy/test_bfloat16.py +599 -0
  304. numba_cuda/numba/cuda/tests/cudapy/test_bfloat16_bindings.py +377 -0
  305. numba_cuda/numba/cuda/tests/cudapy/test_blackscholes.py +160 -0
  306. numba_cuda/numba/cuda/tests/cudapy/test_boolean.py +27 -0
  307. numba_cuda/numba/cuda/tests/cudapy/test_byteflow.py +98 -0
  308. numba_cuda/numba/cuda/tests/cudapy/test_cache_hints.py +210 -0
  309. numba_cuda/numba/cuda/tests/cudapy/test_caching.py +683 -0
  310. numba_cuda/numba/cuda/tests/cudapy/test_casting.py +265 -0
  311. numba_cuda/numba/cuda/tests/cudapy/test_cffi.py +42 -0
  312. numba_cuda/numba/cuda/tests/cudapy/test_compiler.py +718 -0
  313. numba_cuda/numba/cuda/tests/cudapy/test_complex.py +370 -0
  314. numba_cuda/numba/cuda/tests/cudapy/test_complex_kernel.py +23 -0
  315. numba_cuda/numba/cuda/tests/cudapy/test_const_string.py +142 -0
  316. numba_cuda/numba/cuda/tests/cudapy/test_constmem.py +178 -0
  317. numba_cuda/numba/cuda/tests/cudapy/test_cooperative_groups.py +193 -0
  318. numba_cuda/numba/cuda/tests/cudapy/test_copy_propagate.py +131 -0
  319. numba_cuda/numba/cuda/tests/cudapy/test_cuda_array_interface.py +438 -0
  320. numba_cuda/numba/cuda/tests/cudapy/test_cuda_jit_no_types.py +94 -0
  321. numba_cuda/numba/cuda/tests/cudapy/test_datetime.py +101 -0
  322. numba_cuda/numba/cuda/tests/cudapy/test_debug.py +105 -0
  323. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo.py +978 -0
  324. numba_cuda/numba/cuda/tests/cudapy/test_debuginfo_types.py +476 -0
  325. numba_cuda/numba/cuda/tests/cudapy/test_device_func.py +500 -0
  326. numba_cuda/numba/cuda/tests/cudapy/test_dispatcher.py +820 -0
  327. numba_cuda/numba/cuda/tests/cudapy/test_enums.py +152 -0
  328. numba_cuda/numba/cuda/tests/cudapy/test_errors.py +111 -0
  329. numba_cuda/numba/cuda/tests/cudapy/test_exception.py +170 -0
  330. numba_cuda/numba/cuda/tests/cudapy/test_extending.py +1088 -0
  331. numba_cuda/numba/cuda/tests/cudapy/test_extending_types.py +71 -0
  332. numba_cuda/numba/cuda/tests/cudapy/test_fastmath.py +265 -0
  333. numba_cuda/numba/cuda/tests/cudapy/test_flow_control.py +1433 -0
  334. numba_cuda/numba/cuda/tests/cudapy/test_forall.py +57 -0
  335. numba_cuda/numba/cuda/tests/cudapy/test_freevar.py +34 -0
  336. numba_cuda/numba/cuda/tests/cudapy/test_frexp_ldexp.py +69 -0
  337. numba_cuda/numba/cuda/tests/cudapy/test_globals.py +62 -0
  338. numba_cuda/numba/cuda/tests/cudapy/test_gufunc.py +474 -0
  339. numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scalar.py +167 -0
  340. numba_cuda/numba/cuda/tests/cudapy/test_gufunc_scheduling.py +92 -0
  341. numba_cuda/numba/cuda/tests/cudapy/test_idiv.py +39 -0
  342. numba_cuda/numba/cuda/tests/cudapy/test_inline.py +170 -0
  343. numba_cuda/numba/cuda/tests/cudapy/test_inspect.py +255 -0
  344. numba_cuda/numba/cuda/tests/cudapy/test_intrinsics.py +1219 -0
  345. numba_cuda/numba/cuda/tests/cudapy/test_ipc.py +263 -0
  346. numba_cuda/numba/cuda/tests/cudapy/test_ir.py +598 -0
  347. numba_cuda/numba/cuda/tests/cudapy/test_ir_utils.py +276 -0
  348. numba_cuda/numba/cuda/tests/cudapy/test_iterators.py +101 -0
  349. numba_cuda/numba/cuda/tests/cudapy/test_lang.py +68 -0
  350. numba_cuda/numba/cuda/tests/cudapy/test_laplace.py +123 -0
  351. numba_cuda/numba/cuda/tests/cudapy/test_libdevice.py +194 -0
  352. numba_cuda/numba/cuda/tests/cudapy/test_lineinfo.py +220 -0
  353. numba_cuda/numba/cuda/tests/cudapy/test_localmem.py +173 -0
  354. numba_cuda/numba/cuda/tests/cudapy/test_make_function_to_jit_function.py +364 -0
  355. numba_cuda/numba/cuda/tests/cudapy/test_mandel.py +47 -0
  356. numba_cuda/numba/cuda/tests/cudapy/test_math.py +842 -0
  357. numba_cuda/numba/cuda/tests/cudapy/test_matmul.py +76 -0
  358. numba_cuda/numba/cuda/tests/cudapy/test_minmax.py +78 -0
  359. numba_cuda/numba/cuda/tests/cudapy/test_montecarlo.py +25 -0
  360. numba_cuda/numba/cuda/tests/cudapy/test_multigpu.py +145 -0
  361. numba_cuda/numba/cuda/tests/cudapy/test_multiprocessing.py +39 -0
  362. numba_cuda/numba/cuda/tests/cudapy/test_multithreads.py +82 -0
  363. numba_cuda/numba/cuda/tests/cudapy/test_nondet.py +53 -0
  364. numba_cuda/numba/cuda/tests/cudapy/test_operator.py +504 -0
  365. numba_cuda/numba/cuda/tests/cudapy/test_optimization.py +93 -0
  366. numba_cuda/numba/cuda/tests/cudapy/test_overload.py +402 -0
  367. numba_cuda/numba/cuda/tests/cudapy/test_powi.py +128 -0
  368. numba_cuda/numba/cuda/tests/cudapy/test_print.py +193 -0
  369. numba_cuda/numba/cuda/tests/cudapy/test_py2_div_issue.py +37 -0
  370. numba_cuda/numba/cuda/tests/cudapy/test_random.py +117 -0
  371. numba_cuda/numba/cuda/tests/cudapy/test_record_dtype.py +614 -0
  372. numba_cuda/numba/cuda/tests/cudapy/test_recursion.py +130 -0
  373. numba_cuda/numba/cuda/tests/cudapy/test_reduction.py +94 -0
  374. numba_cuda/numba/cuda/tests/cudapy/test_retrieve_autoconverted_arrays.py +83 -0
  375. numba_cuda/numba/cuda/tests/cudapy/test_serialize.py +86 -0
  376. numba_cuda/numba/cuda/tests/cudapy/test_slicing.py +40 -0
  377. numba_cuda/numba/cuda/tests/cudapy/test_sm.py +457 -0
  378. numba_cuda/numba/cuda/tests/cudapy/test_sm_creation.py +233 -0
  379. numba_cuda/numba/cuda/tests/cudapy/test_ssa.py +454 -0
  380. numba_cuda/numba/cuda/tests/cudapy/test_stream_api.py +56 -0
  381. numba_cuda/numba/cuda/tests/cudapy/test_sync.py +277 -0
  382. numba_cuda/numba/cuda/tests/cudapy/test_tracing.py +200 -0
  383. numba_cuda/numba/cuda/tests/cudapy/test_transpose.py +90 -0
  384. numba_cuda/numba/cuda/tests/cudapy/test_typeconv.py +333 -0
  385. numba_cuda/numba/cuda/tests/cudapy/test_typeinfer.py +538 -0
  386. numba_cuda/numba/cuda/tests/cudapy/test_ufuncs.py +585 -0
  387. numba_cuda/numba/cuda/tests/cudapy/test_userexc.py +42 -0
  388. numba_cuda/numba/cuda/tests/cudapy/test_vector_type.py +485 -0
  389. numba_cuda/numba/cuda/tests/cudapy/test_vectorize.py +312 -0
  390. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_complex.py +23 -0
  391. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_decor.py +183 -0
  392. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_device.py +40 -0
  393. numba_cuda/numba/cuda/tests/cudapy/test_vectorize_scalar_arg.py +40 -0
  394. numba_cuda/numba/cuda/tests/cudapy/test_warning.py +206 -0
  395. numba_cuda/numba/cuda/tests/cudapy/test_warp_ops.py +446 -0
  396. numba_cuda/numba/cuda/tests/cudasim/__init__.py +9 -0
  397. numba_cuda/numba/cuda/tests/cudasim/support.py +9 -0
  398. numba_cuda/numba/cuda/tests/cudasim/test_cudasim_issues.py +111 -0
  399. numba_cuda/numba/cuda/tests/data/__init__.py +2 -0
  400. numba_cuda/numba/cuda/tests/data/cta_barrier.cu +28 -0
  401. numba_cuda/numba/cuda/tests/data/cuda_include.cu +10 -0
  402. numba_cuda/numba/cuda/tests/data/error.cu +12 -0
  403. numba_cuda/numba/cuda/tests/data/include/add.cuh +8 -0
  404. numba_cuda/numba/cuda/tests/data/jitlink.cu +28 -0
  405. numba_cuda/numba/cuda/tests/data/jitlink.ptx +49 -0
  406. numba_cuda/numba/cuda/tests/data/warn.cu +12 -0
  407. numba_cuda/numba/cuda/tests/doc_examples/__init__.py +9 -0
  408. numba_cuda/numba/cuda/tests/doc_examples/ffi/__init__.py +2 -0
  409. numba_cuda/numba/cuda/tests/doc_examples/ffi/functions.cu +54 -0
  410. numba_cuda/numba/cuda/tests/doc_examples/ffi/include/mul.cuh +8 -0
  411. numba_cuda/numba/cuda/tests/doc_examples/ffi/saxpy.cu +14 -0
  412. numba_cuda/numba/cuda/tests/doc_examples/test_cg.py +86 -0
  413. numba_cuda/numba/cuda/tests/doc_examples/test_cpointer.py +68 -0
  414. numba_cuda/numba/cuda/tests/doc_examples/test_cpu_gpu_compat.py +81 -0
  415. numba_cuda/numba/cuda/tests/doc_examples/test_ffi.py +141 -0
  416. numba_cuda/numba/cuda/tests/doc_examples/test_laplace.py +160 -0
  417. numba_cuda/numba/cuda/tests/doc_examples/test_matmul.py +180 -0
  418. numba_cuda/numba/cuda/tests/doc_examples/test_montecarlo.py +119 -0
  419. numba_cuda/numba/cuda/tests/doc_examples/test_random.py +66 -0
  420. numba_cuda/numba/cuda/tests/doc_examples/test_reduction.py +80 -0
  421. numba_cuda/numba/cuda/tests/doc_examples/test_sessionize.py +206 -0
  422. numba_cuda/numba/cuda/tests/doc_examples/test_ufunc.py +53 -0
  423. numba_cuda/numba/cuda/tests/doc_examples/test_vecadd.py +76 -0
  424. numba_cuda/numba/cuda/tests/nocuda/__init__.py +9 -0
  425. numba_cuda/numba/cuda/tests/nocuda/test_dummyarray.py +452 -0
  426. numba_cuda/numba/cuda/tests/nocuda/test_function_resolution.py +48 -0
  427. numba_cuda/numba/cuda/tests/nocuda/test_import.py +63 -0
  428. numba_cuda/numba/cuda/tests/nocuda/test_library_lookup.py +252 -0
  429. numba_cuda/numba/cuda/tests/nocuda/test_nvvm.py +59 -0
  430. numba_cuda/numba/cuda/tests/nrt/__init__.py +9 -0
  431. numba_cuda/numba/cuda/tests/nrt/test_nrt.py +387 -0
  432. numba_cuda/numba/cuda/tests/nrt/test_nrt_refct.py +124 -0
  433. numba_cuda/numba/cuda/tests/support.py +900 -0
  434. numba_cuda/numba/cuda/typeconv/__init__.py +4 -0
  435. numba_cuda/numba/cuda/typeconv/castgraph.py +137 -0
  436. numba_cuda/numba/cuda/typeconv/rules.py +63 -0
  437. numba_cuda/numba/cuda/typeconv/typeconv.py +121 -0
  438. numba_cuda/numba/cuda/types/__init__.py +233 -0
  439. numba_cuda/numba/cuda/types/__init__.pyi +167 -0
  440. numba_cuda/numba/cuda/types/abstract.py +9 -0
  441. numba_cuda/numba/cuda/types/common.py +9 -0
  442. numba_cuda/numba/cuda/types/containers.py +9 -0
  443. numba_cuda/numba/cuda/types/cuda_abstract.py +533 -0
  444. numba_cuda/numba/cuda/types/cuda_common.py +110 -0
  445. numba_cuda/numba/cuda/types/cuda_containers.py +971 -0
  446. numba_cuda/numba/cuda/types/cuda_function_type.py +230 -0
  447. numba_cuda/numba/cuda/types/cuda_functions.py +798 -0
  448. numba_cuda/numba/cuda/types/cuda_iterators.py +120 -0
  449. numba_cuda/numba/cuda/types/cuda_misc.py +569 -0
  450. numba_cuda/numba/cuda/types/cuda_npytypes.py +690 -0
  451. numba_cuda/numba/cuda/types/cuda_scalars.py +280 -0
  452. numba_cuda/numba/cuda/types/ext_types.py +101 -0
  453. numba_cuda/numba/cuda/types/function_type.py +11 -0
  454. numba_cuda/numba/cuda/types/functions.py +9 -0
  455. numba_cuda/numba/cuda/types/iterators.py +9 -0
  456. numba_cuda/numba/cuda/types/misc.py +9 -0
  457. numba_cuda/numba/cuda/types/npytypes.py +9 -0
  458. numba_cuda/numba/cuda/types/scalars.py +9 -0
  459. numba_cuda/numba/cuda/typing/__init__.py +19 -0
  460. numba_cuda/numba/cuda/typing/arraydecl.py +939 -0
  461. numba_cuda/numba/cuda/typing/asnumbatype.py +130 -0
  462. numba_cuda/numba/cuda/typing/bufproto.py +70 -0
  463. numba_cuda/numba/cuda/typing/builtins.py +1209 -0
  464. numba_cuda/numba/cuda/typing/cffi_utils.py +219 -0
  465. numba_cuda/numba/cuda/typing/cmathdecl.py +47 -0
  466. numba_cuda/numba/cuda/typing/collections.py +138 -0
  467. numba_cuda/numba/cuda/typing/context.py +782 -0
  468. numba_cuda/numba/cuda/typing/ctypes_utils.py +125 -0
  469. numba_cuda/numba/cuda/typing/dictdecl.py +63 -0
  470. numba_cuda/numba/cuda/typing/enumdecl.py +74 -0
  471. numba_cuda/numba/cuda/typing/listdecl.py +147 -0
  472. numba_cuda/numba/cuda/typing/mathdecl.py +158 -0
  473. numba_cuda/numba/cuda/typing/npdatetime.py +322 -0
  474. numba_cuda/numba/cuda/typing/npydecl.py +749 -0
  475. numba_cuda/numba/cuda/typing/setdecl.py +115 -0
  476. numba_cuda/numba/cuda/typing/templates.py +1446 -0
  477. numba_cuda/numba/cuda/typing/typeof.py +301 -0
  478. numba_cuda/numba/cuda/ufuncs.py +746 -0
  479. numba_cuda/numba/cuda/utils.py +724 -0
  480. numba_cuda/numba/cuda/vector_types.py +214 -0
  481. numba_cuda/numba/cuda/vectorizers.py +260 -0
  482. numba_cuda-0.22.0.dist-info/METADATA +109 -0
  483. numba_cuda-0.22.0.dist-info/RECORD +487 -0
  484. numba_cuda-0.22.0.dist-info/WHEEL +6 -0
  485. numba_cuda-0.22.0.dist-info/licenses/LICENSE +26 -0
  486. numba_cuda-0.22.0.dist-info/licenses/LICENSE.numba +24 -0
  487. numba_cuda-0.22.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3617 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
4
+ import builtins
5
+ import collections
6
+ import dis
7
+ import operator
8
+ import logging
9
+ import textwrap
10
+
11
+ from numba.cuda.core import errors
12
+ from numba.cuda.core import config, ir
13
+ from numba.cuda.errors import UnsupportedBytecodeError
14
+ from numba.cuda.core.errors import (
15
+ NotDefinedError,
16
+ error_extras,
17
+ )
18
+ from numba.cuda.core import ir_utils
19
+ from numba.cuda.utils import (
20
+ PYVERSION,
21
+ BINOPS_TO_OPERATORS,
22
+ INPLACE_BINOPS_TO_OPERATORS,
23
+ )
24
+ from numba.cuda.utils import _lazy_pformat
25
+ from numba.cuda.core.byteflow import Flow, AdaptDFA, AdaptCFA, BlockKind
26
+ from numba.cuda.core.unsafe import eh
27
+ from numba.cuda.cpython.unsafe.tuple import unpack_single_tuple
28
+
29
+
30
+ if PYVERSION in ((3, 12), (3, 13)):
31
+ # Operands for CALL_INTRINSIC_1
32
+ from numba.cuda.core.byteflow import CALL_INTRINSIC_1_Operand as ci1op
33
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
34
+ pass
35
+ else:
36
+ raise NotImplementedError(PYVERSION)
37
+
38
+
39
+ class _UNKNOWN_VALUE(object):
40
+ """Represents an unknown value, this is for ease of debugging purposes only."""
41
+
42
+ def __init__(self, varname):
43
+ self._varname = varname
44
+
45
+ def __repr__(self):
46
+ return "_UNKNOWN_VALUE({})".format(self._varname)
47
+
48
+
49
+ _logger = logging.getLogger(__name__)
50
+
51
+
52
+ class Assigner(object):
53
+ """
54
+ This object keeps track of potential assignment simplifications
55
+ inside a code block.
56
+ For example `$O.1 = x` followed by `y = $0.1` can be simplified
57
+ into `y = x`, but it's not possible anymore if we have `x = z`
58
+ in-between those two instructions.
59
+
60
+ NOTE: this is not only an optimization, but is actually necessary
61
+ due to certain limitations of Numba - such as only accepting the
62
+ returning of an array passed as function argument.
63
+ """
64
+
65
+ def __init__(self):
66
+ # { destination variable name -> source Var object }
67
+ self.dest_to_src = {}
68
+ # Basically a reverse mapping of dest_to_src:
69
+ # { source variable name -> all destination names in dest_to_src }
70
+ self.src_invalidate = collections.defaultdict(list)
71
+ self.unused_dests = set()
72
+
73
+ def assign(self, srcvar, destvar):
74
+ """
75
+ Assign *srcvar* to *destvar*. Return either *srcvar* or a possible
76
+ simplified assignment source (earlier assigned to *srcvar*).
77
+ """
78
+ srcname = srcvar.name
79
+ destname = destvar.name
80
+ if destname in self.src_invalidate:
81
+ # destvar will change, invalidate all previously known
82
+ # simplifications
83
+ for d in self.src_invalidate.pop(destname):
84
+ self.dest_to_src.pop(d)
85
+ if srcname in self.dest_to_src:
86
+ srcvar = self.dest_to_src[srcname]
87
+ if destvar.is_temp:
88
+ self.dest_to_src[destname] = srcvar
89
+ self.src_invalidate[srcname].append(destname)
90
+ self.unused_dests.add(destname)
91
+ return srcvar
92
+
93
+ def get_assignment_source(self, destname):
94
+ """
95
+ Get a possible assignment source (a ir.Var instance) to replace
96
+ *destname*, otherwise None.
97
+ """
98
+ if destname in self.dest_to_src:
99
+ return self.dest_to_src[destname]
100
+ self.unused_dests.discard(destname)
101
+ return None
102
+
103
+
104
+ def _remove_assignment_definition(old_body, idx, func_ir, already_deleted_defs):
105
+ """
106
+ Deletes the definition defined for old_body at index idx
107
+ from func_ir. We assume this stmt will be deleted from
108
+ new_body.
109
+
110
+ In some optimizations we may update the same variable multiple times.
111
+ In this situation, we only need to delete a particular definition once,
112
+ this is tracked in already_deleted_def, which is a map from
113
+ assignment name to the set of values that have already been
114
+ deleted.
115
+ """
116
+ lhs = old_body[idx].target.name
117
+ rhs = old_body[idx].value
118
+ if rhs in func_ir._definitions[lhs]:
119
+ func_ir._definitions[lhs].remove(rhs)
120
+ already_deleted_defs[lhs].add(rhs)
121
+ elif rhs not in already_deleted_defs[lhs]:
122
+ raise UnsupportedBytecodeError(
123
+ "Inconsistency found in the definitions while executing"
124
+ " a peephole optimization. This suggests an internal"
125
+ " error or inconsistency elsewhere in the compiler."
126
+ )
127
+
128
+
129
+ def _call_function_ex_replace_kws_small(
130
+ old_body,
131
+ keyword_expr,
132
+ new_body,
133
+ buildmap_idx,
134
+ func_ir,
135
+ already_deleted_defs,
136
+ ):
137
+ """
138
+ Extracts the kws args passed as varkwarg
139
+ for CALL_FUNCTION_EX. This pass is taken when
140
+ n_kws <= 15 and the bytecode looks like:
141
+
142
+ # Start for each argument
143
+ LOAD_FAST # Load each argument.
144
+ # End for each argument
145
+ ...
146
+ BUILD_CONST_KEY_MAP # Build a map
147
+
148
+ In the generated IR, the varkwarg refers
149
+ to a single build_map that contains all of the
150
+ kws. In addition to returning the kws, this
151
+ function updates new_body to remove all usage
152
+ of the map.
153
+ """
154
+ kws = keyword_expr.items.copy()
155
+ # kws are required to have constant keys.
156
+ # We update these with the value_indexes
157
+ value_indexes = keyword_expr.value_indexes
158
+ for key, index in value_indexes.items():
159
+ kws[index] = (key, kws[index][1])
160
+ # Remove the build_map by setting the list
161
+ # index to None. Nones will be removed later.
162
+ new_body[buildmap_idx] = None
163
+ # Remove the definition.
164
+ _remove_assignment_definition(
165
+ old_body, buildmap_idx, func_ir, already_deleted_defs
166
+ )
167
+ return kws
168
+
169
+
170
+ def _call_function_ex_replace_kws_large(
171
+ old_body,
172
+ buildmap_name,
173
+ buildmap_idx,
174
+ search_end,
175
+ new_body,
176
+ func_ir,
177
+ errmsg,
178
+ already_deleted_defs,
179
+ ):
180
+ """
181
+ Extracts the kws args passed as varkwarg
182
+ for CALL_FUNCTION_EX. This pass is taken when
183
+ n_kws > 15 and the bytecode looks like:
184
+
185
+ BUILD_MAP # Construct the map
186
+ # Start for each argument
187
+ LOAD_CONST # Load a constant for the name of the argument
188
+ LOAD_FAST # Load each argument.
189
+ MAP_ADD # Append the (key, value) pair to the map
190
+ # End for each argument
191
+
192
+ In the IR generated, the initial build map is empty and a series
193
+ of setitems are applied afterwards. THE IR looks like:
194
+
195
+ $build_map_var = build_map(items=[])
196
+ $constvar = const(str, ...) # create the const key
197
+ # CREATE THE ARGUMENT, This may take multiple lines.
198
+ $created_arg = ...
199
+ $var = getattr(
200
+ value=$build_map_var,
201
+ attr=__setitem__,
202
+ )
203
+ $unused_var = call $var($constvar, $created_arg)
204
+
205
+ We iterate through the IR, deleting all usages of the buildmap
206
+ from the new_body, and adds the kws to a new kws list.
207
+ """
208
+ # Remove the build_map from the body.
209
+ new_body[buildmap_idx] = None
210
+ # Remove the definition.
211
+ _remove_assignment_definition(
212
+ old_body, buildmap_idx, func_ir, already_deleted_defs
213
+ )
214
+ kws = []
215
+ search_start = buildmap_idx + 1
216
+ while search_start <= search_end:
217
+ # The first value must be a constant.
218
+ const_stmt = old_body[search_start]
219
+ if not (
220
+ isinstance(const_stmt, ir.Assign)
221
+ and isinstance(const_stmt.value, ir.Const)
222
+ ):
223
+ # We cannot handle this format so raise the
224
+ # original error message.
225
+ raise UnsupportedBytecodeError(errmsg)
226
+ key_var_name = const_stmt.target.name
227
+ key_val = const_stmt.value.value
228
+ search_start += 1
229
+ # Now we need to search for a getattr with setitem
230
+ found_getattr = False
231
+ while search_start <= search_end and not found_getattr:
232
+ getattr_stmt = old_body[search_start]
233
+ if (
234
+ isinstance(getattr_stmt, ir.Assign)
235
+ and isinstance(getattr_stmt.value, ir.Expr)
236
+ and getattr_stmt.value.op == "getattr"
237
+ and (getattr_stmt.value.value.name == buildmap_name)
238
+ and getattr_stmt.value.attr == "__setitem__"
239
+ ):
240
+ found_getattr = True
241
+ else:
242
+ # If the argument is "created" in JIT, then there
243
+ # will be intermediate operations in between setitems.
244
+ # For example we have arg5=pow(arg5, 2),
245
+ # then the IR would look like:
246
+ #
247
+ # # Creation of the constant key.
248
+ # $const44.26 = const(str, arg5)
249
+ #
250
+ # # Argument creation. This is the section we are skipping
251
+ # $46load_global.27 = global(pow: <built-in function pow>)
252
+ # $const50.29 = const(int, 2)
253
+ # $call.30 = call $46load_global.27(arg5, $const50.29)
254
+ #
255
+ # # Setitem with arg5
256
+ # $54map_add.31 = getattr(value=$map.2, attr=__setitem__)
257
+ # $54map_add.32 = call $54map_add.31($const44.26, $call.30)
258
+ search_start += 1
259
+ if not found_getattr or search_start == search_end:
260
+ # We cannot handle this format so raise the
261
+ # original error message.
262
+ raise UnsupportedBytecodeError(errmsg)
263
+ setitem_stmt = old_body[search_start + 1]
264
+ if not (
265
+ isinstance(setitem_stmt, ir.Assign)
266
+ and isinstance(setitem_stmt.value, ir.Expr)
267
+ and setitem_stmt.value.op == "call"
268
+ and (setitem_stmt.value.func.name == getattr_stmt.target.name)
269
+ and len(setitem_stmt.value.args) == 2
270
+ and (setitem_stmt.value.args[0].name == key_var_name)
271
+ ):
272
+ # A call statement should always immediately follow the
273
+ # getattr. If for some reason this doesn't match the code
274
+ # format, we raise the original error message. This check
275
+ # is meant as a precaution.
276
+ raise UnsupportedBytecodeError(errmsg)
277
+ arg_var = setitem_stmt.value.args[1]
278
+ # Append the (key, value) pair.
279
+ kws.append((key_val, arg_var))
280
+ # Remove the __setitem__ getattr and call
281
+ new_body[search_start] = None
282
+ new_body[search_start + 1] = None
283
+ # Remove the definitions.
284
+ _remove_assignment_definition(
285
+ old_body, search_start, func_ir, already_deleted_defs
286
+ )
287
+ _remove_assignment_definition(
288
+ old_body, search_start + 1, func_ir, already_deleted_defs
289
+ )
290
+ search_start += 2
291
+ return kws
292
+
293
+
294
+ def _call_function_ex_replace_args_small(
295
+ old_body,
296
+ tuple_expr,
297
+ new_body,
298
+ buildtuple_idx,
299
+ func_ir,
300
+ already_deleted_defs,
301
+ ):
302
+ """
303
+ Extracts the args passed as vararg
304
+ for CALL_FUNCTION_EX. This pass is taken when
305
+ n_args <= 30 and the bytecode looks like:
306
+
307
+ # Start for each argument
308
+ LOAD_FAST # Load each argument.
309
+ # End for each argument
310
+ ...
311
+ BUILD_TUPLE # Create a tuple of the arguments
312
+
313
+ In the IR generated, the vararg refer
314
+ to a single build_tuple that contains all of the
315
+ args. In addition to returning the args, this
316
+ function updates new_body to remove all usage
317
+ of the tuple.
318
+ """
319
+ # Delete the build tuple
320
+ new_body[buildtuple_idx] = None
321
+ # Remove the definition.
322
+ _remove_assignment_definition(
323
+ old_body, buildtuple_idx, func_ir, already_deleted_defs
324
+ )
325
+ # Return the args.
326
+ return tuple_expr.items
327
+
328
+
329
+ def _call_function_ex_replace_args_large(
330
+ old_body,
331
+ vararg_stmt,
332
+ new_body,
333
+ search_end,
334
+ func_ir,
335
+ errmsg,
336
+ already_deleted_defs,
337
+ ):
338
+ """
339
+ Extracts the args passed as vararg
340
+ for CALL_FUNCTION_EX. This pass is taken when
341
+ n_args > 30 and the bytecode looks like:
342
+
343
+ BUILD_TUPLE # Create a list to append to
344
+ # Start for each argument
345
+ LOAD_FAST # Load each argument.
346
+ LIST_APPEND # Add the argument to the list
347
+ # End for each argument
348
+ ...
349
+ LIST_TO_TUPLE # Convert the args to a tuple.
350
+
351
+ In the IR generated, the tuple is created by concatenating
352
+ together several 1 element tuples to an initial empty tuple.
353
+ We traverse backwards in the IR, collecting args, until we
354
+ find the original empty tuple. For example, the IR might
355
+ look like:
356
+
357
+ $orig_tuple = build_tuple(items=[])
358
+ $first_var = build_tuple(items=[Var(arg0, test.py:6)])
359
+ $next_tuple = $orig_tuple + $first_var
360
+ ...
361
+ $final_var = build_tuple(items=[Var(argn, test.py:6)])
362
+ $final_tuple = $prev_tuple + $final_var
363
+ $varargs_var = $final_tuple
364
+ """
365
+ # We traverse to the front of the block to look for the original
366
+ # tuple.
367
+ search_start = 0
368
+ total_args = []
369
+ if isinstance(vararg_stmt, ir.Assign) and isinstance(
370
+ vararg_stmt.value, ir.Var
371
+ ):
372
+ target_name = vararg_stmt.value.name
373
+ # If there is an initial assignment, delete it
374
+ new_body[search_end] = None
375
+ # Remove the definition.
376
+ _remove_assignment_definition(
377
+ old_body, search_end, func_ir, already_deleted_defs
378
+ )
379
+ search_end -= 1
380
+ else:
381
+ # There must always be an initial assignment
382
+ # https://github.com/numba/numba/blob/59fa2e335be68148b3bd72a29de3ff011430038d/numba/core/interpreter.py#L259-L260
383
+ # If this changes we may need to support this branch.
384
+ raise AssertionError("unreachable")
385
+ # Traverse backwards to find all concatenations
386
+ # until eventually reaching the original empty tuple.
387
+ while search_end >= search_start:
388
+ concat_stmt = old_body[search_end]
389
+ if (
390
+ isinstance(concat_stmt, ir.Assign)
391
+ and concat_stmt.target.name == target_name
392
+ and isinstance(concat_stmt.value, ir.Expr)
393
+ and concat_stmt.value.op == "build_tuple"
394
+ and not concat_stmt.value.items
395
+ ):
396
+ new_body[search_end] = None
397
+ # Remove the definition.
398
+ _remove_assignment_definition(
399
+ old_body, search_end, func_ir, already_deleted_defs
400
+ )
401
+ # If we have reached the build_tuple we exit.
402
+ break
403
+ else:
404
+ # We expect to find another arg to append.
405
+ # The first stmt must be a binop "add"
406
+ if (search_end == search_start) or not (
407
+ isinstance(concat_stmt, ir.Assign)
408
+ and (concat_stmt.target.name == target_name)
409
+ and isinstance(concat_stmt.value, ir.Expr)
410
+ and concat_stmt.value.op == "binop"
411
+ and concat_stmt.value.fn == operator.add
412
+ ):
413
+ # We cannot handle this format.
414
+ raise UnsupportedBytecodeError(errmsg)
415
+ lhs_name = concat_stmt.value.lhs.name
416
+ rhs_name = concat_stmt.value.rhs.name
417
+ # The previous statement should be a
418
+ # build_tuple containing the arg.
419
+ arg_tuple_stmt = old_body[search_end - 1]
420
+ if not (
421
+ isinstance(arg_tuple_stmt, ir.Assign)
422
+ and isinstance(arg_tuple_stmt.value, ir.Expr)
423
+ and (arg_tuple_stmt.value.op == "build_tuple")
424
+ and len(arg_tuple_stmt.value.items) == 1
425
+ ):
426
+ # We cannot handle this format.
427
+ raise UnsupportedBytecodeError(errmsg)
428
+ if arg_tuple_stmt.target.name == lhs_name:
429
+ # The tuple should always be generated on the RHS.
430
+ raise AssertionError("unreachable")
431
+ elif arg_tuple_stmt.target.name == rhs_name:
432
+ target_name = lhs_name
433
+ else:
434
+ # We cannot handle this format.
435
+ raise UnsupportedBytecodeError(errmsg)
436
+ total_args.append(arg_tuple_stmt.value.items[0])
437
+ new_body[search_end] = None
438
+ new_body[search_end - 1] = None
439
+ # Remove the definitions.
440
+ _remove_assignment_definition(
441
+ old_body, search_end, func_ir, already_deleted_defs
442
+ )
443
+ _remove_assignment_definition(
444
+ old_body, search_end - 1, func_ir, already_deleted_defs
445
+ )
446
+ search_end -= 2
447
+ # Avoid any space between appends
448
+ keep_looking = True
449
+ while search_end >= search_start and keep_looking:
450
+ next_stmt = old_body[search_end]
451
+ if isinstance(next_stmt, ir.Assign) and (
452
+ next_stmt.target.name == target_name
453
+ ):
454
+ keep_looking = False
455
+ else:
456
+ # If the argument is "created" in JIT, then there
457
+ # will be intermediate operations in between appends.
458
+ # For example if the next arg after arg4 is pow(arg5, 2),
459
+ # then the IR would look like:
460
+ #
461
+ # # Appending arg4
462
+ # $arg4_tup = build_tuple(items=[arg4])
463
+ # $append_var.5 = $append_var.4 + $arg4_tup
464
+ #
465
+ # # Creation of arg5.
466
+ # # This is the section that we are skipping.
467
+ # $32load_global.20 = global(pow: <built-in function pow>)
468
+ # $const36.22 = const(int, 2)
469
+ # $call.23 = call $32load_global.20(arg5, $const36.22)
470
+ #
471
+ # # Appending arg5
472
+ # $arg5_tup = build_tuple(items=[$call.23])
473
+ # $append_var.6 = $append_var.5 + $arg5_tup
474
+ search_end -= 1
475
+ if search_end == search_start:
476
+ # If we reached the start we never found the build_tuple.
477
+ # We cannot handle this format so raise the
478
+ # original error message.
479
+ raise UnsupportedBytecodeError(errmsg)
480
+ # Reverse the arguments so we get the correct order.
481
+ return total_args[::-1]
482
+
483
+
484
+ def peep_hole_call_function_ex_to_call_function_kw(func_ir):
485
+ """
486
+ This peephole rewrites a bytecode sequence unique to Python 3.10
487
+ where CALL_FUNCTION_EX is used instead of CALL_FUNCTION_KW because of
488
+ stack limitations set by CPython. This limitation is imposed whenever
489
+ a function call has too many arguments or keyword arguments.
490
+
491
+ https://github.com/python/cpython/blob/a58ebcc701dd6c43630df941481475ff0f615a81/Python/compile.c#L55
492
+ https://github.com/python/cpython/blob/a58ebcc701dd6c43630df941481475ff0f615a81/Python/compile.c#L4442
493
+
494
+ In particular, this change is imposed whenever (n_args / 2) + n_kws > 15.
495
+
496
+ Different bytecode is generated for args depending on if n_args > 30
497
+ or n_args <= 30 and similarly if n_kws > 15 or n_kws <= 15.
498
+
499
+ This function unwraps the *args and **kwargs in the function call
500
+ and places these values directly into the args and kwargs of the call.
501
+ """
502
+ # All changes are local to the a single block
503
+ # so it can be traversed in any order.
504
+ errmsg = textwrap.dedent("""
505
+ CALL_FUNCTION_EX with **kwargs not supported.
506
+ If you are not using **kwargs this may indicate that
507
+ you have a large number of kwargs and are using inlined control
508
+ flow. You can resolve this issue by moving the control flow out of
509
+ the function call. For example, if you have
510
+
511
+ f(a=1 if flag else 0, ...)
512
+
513
+ Replace that with:
514
+
515
+ a_val = 1 if flag else 0
516
+ f(a=a_val, ...)""")
517
+
518
+ # Track which definitions have already been deleted
519
+ already_deleted_defs = collections.defaultdict(set)
520
+ for blk in func_ir.blocks.values():
521
+ blk_changed = False
522
+ new_body = []
523
+ for i, stmt in enumerate(blk.body):
524
+ if (
525
+ isinstance(stmt, ir.Assign)
526
+ and isinstance(stmt.value, ir.Expr)
527
+ and stmt.value.op == "call"
528
+ and stmt.value.varkwarg is not None
529
+ ):
530
+ blk_changed = True
531
+ call = stmt.value
532
+ args = call.args
533
+ kws = call.kws
534
+ # We need to check the call expression contents if
535
+ # it contains either vararg or varkwarg. If it contains
536
+ # varkwarg we need to update the IR. If it just contains
537
+ # vararg we don't need to update the IR, but we need to
538
+ # check if peep_hole_list_to_tuple failed to replace the
539
+ # vararg list with a tuple. If so, we output an error
540
+ # message with suggested code changes.
541
+ vararg = call.vararg
542
+ varkwarg = call.varkwarg
543
+ start_search = i - 1
544
+ # varkwarg should be defined second so we start there.
545
+ varkwarg_loc = start_search
546
+ keyword_def = None
547
+ found = False
548
+ while varkwarg_loc >= 0 and not found:
549
+ keyword_def = blk.body[varkwarg_loc]
550
+ if (
551
+ isinstance(keyword_def, ir.Assign)
552
+ and keyword_def.target.name == varkwarg.name
553
+ ):
554
+ found = True
555
+ else:
556
+ varkwarg_loc -= 1
557
+ if (
558
+ kws
559
+ or not found
560
+ or not (
561
+ isinstance(keyword_def.value, ir.Expr)
562
+ and keyword_def.value.op == "build_map"
563
+ )
564
+ ):
565
+ # If we couldn't find where the kwargs are created
566
+ # then it should be a normal **kwargs call
567
+ # so we produce an unsupported message.
568
+ raise UnsupportedBytecodeError(errmsg)
569
+ # Determine the kws
570
+ if keyword_def.value.items:
571
+ # n_kws <= 15 case.
572
+ # Here the IR looks like a series of
573
+ # constants, then the arguments and finally
574
+ # a build_map that contains all of the pairs.
575
+ # For Example:
576
+ #
577
+ # $const_n = const("arg_name")
578
+ # $arg_n = ...
579
+ # $kwargs_var = build_map(items=[
580
+ # ($const_0, $arg_0),
581
+ # ...,
582
+ # ($const_n, $arg_n),])
583
+ kws = _call_function_ex_replace_kws_small(
584
+ blk.body,
585
+ keyword_def.value,
586
+ new_body,
587
+ varkwarg_loc,
588
+ func_ir,
589
+ already_deleted_defs,
590
+ )
591
+ else:
592
+ # n_kws > 15 case.
593
+ # Here the IR is an initial empty build_map
594
+ # followed by a series of setitems with a constant
595
+ # key and then the argument.
596
+ # For example:
597
+ #
598
+ # $kwargs_var = build_map(items=[])
599
+ # $const_0 = const("arg_name")
600
+ # $arg_0 = ...
601
+ # $my_attr = getattr(const_0, attr=__setitem__)
602
+ # $unused_var = call $my_attr($const_0, $arg_0)
603
+ # ...
604
+ kws = _call_function_ex_replace_kws_large(
605
+ blk.body,
606
+ varkwarg.name,
607
+ varkwarg_loc,
608
+ i - 1,
609
+ new_body,
610
+ func_ir,
611
+ errmsg,
612
+ already_deleted_defs,
613
+ )
614
+ start_search = varkwarg_loc
615
+ # Vararg isn't required to be provided.
616
+ if vararg is not None:
617
+ if args:
618
+ # If we have vararg then args is expected to
619
+ # be an empty list.
620
+ raise UnsupportedBytecodeError(errmsg)
621
+ vararg_loc = start_search
622
+ args_def = None
623
+ found = False
624
+ while vararg_loc >= 0 and not found:
625
+ args_def = blk.body[vararg_loc]
626
+ if (
627
+ isinstance(args_def, ir.Assign)
628
+ and args_def.target.name == vararg.name
629
+ ):
630
+ found = True
631
+ else:
632
+ vararg_loc -= 1
633
+ if not found:
634
+ # If we couldn't find where the args are created
635
+ # then we can't handle this format.
636
+ raise UnsupportedBytecodeError(errmsg)
637
+ if (
638
+ isinstance(args_def.value, ir.Expr)
639
+ and args_def.value.op == "build_tuple"
640
+ ):
641
+ # n_args <= 30 case.
642
+ # Here the IR is a simple build_tuple containing
643
+ # all of the args.
644
+ # For example:
645
+ #
646
+ # $arg_n = ...
647
+ # $varargs = build_tuple(
648
+ # items=[$arg_0, ..., $arg_n]
649
+ # )
650
+ args = _call_function_ex_replace_args_small(
651
+ blk.body,
652
+ args_def.value,
653
+ new_body,
654
+ vararg_loc,
655
+ func_ir,
656
+ already_deleted_defs,
657
+ )
658
+ elif (
659
+ isinstance(args_def.value, ir.Expr)
660
+ and args_def.value.op == "list_to_tuple"
661
+ ):
662
+ # If there is a call with vararg we need to check
663
+ # if the list -> tuple conversion failed and if so
664
+ # throw an error.
665
+ raise UnsupportedBytecodeError(errmsg)
666
+ else:
667
+ # Here the IR is an initial empty build_tuple.
668
+ # Then for each arg, a new tuple with a single
669
+ # element is created and one by one these are
670
+ # added to a growing tuple.
671
+ # For example:
672
+ #
673
+ # $combo_tup_0 = build_tuple(items=[])
674
+ # $arg0 = ...
675
+ # $arg0_tup = build_tuple(items=[$arg0])
676
+ # $combo_tup_1 = $combo_tup_0 + $arg0_tup
677
+ # $arg1 = ...
678
+ # $arg1_tup = build_tuple(items=[$arg1])
679
+ # $combo_tup_2 = $combo_tup_1 + $arg1_tup
680
+ # ...
681
+ # $combo_tup_n = $combo_tup_{n-1} + $argn_tup
682
+ #
683
+ # In addition, the IR contains a final
684
+ # assignment for the varargs that looks like:
685
+ #
686
+ # $varargs_var = $combo_tup_n
687
+ #
688
+ # Here args_def is expected to be a simple assignment.
689
+ args = _call_function_ex_replace_args_large(
690
+ blk.body,
691
+ args_def,
692
+ new_body,
693
+ vararg_loc,
694
+ func_ir,
695
+ errmsg,
696
+ already_deleted_defs,
697
+ )
698
+ # Create a new call updating the args and kws
699
+ new_call = ir.Expr.call(
700
+ call.func, args, kws, call.loc, target=call.target
701
+ )
702
+ # Drop the existing definition for this stmt.
703
+ _remove_assignment_definition(
704
+ blk.body, i, func_ir, already_deleted_defs
705
+ )
706
+ # Update the statement
707
+ stmt = ir.Assign(new_call, stmt.target, stmt.loc)
708
+ # Update the definition
709
+ func_ir._definitions[stmt.target.name].append(new_call)
710
+ elif (
711
+ isinstance(stmt, ir.Assign)
712
+ and isinstance(stmt.value, ir.Expr)
713
+ and stmt.value.op == "call"
714
+ and stmt.value.vararg is not None
715
+ ):
716
+ # If there is a call with vararg we need to check
717
+ # if the list -> tuple conversion failed and if so
718
+ # throw an error.
719
+ call = stmt.value
720
+ vararg_name = call.vararg.name
721
+ if (
722
+ vararg_name in func_ir._definitions
723
+ and len(func_ir._definitions[vararg_name]) == 1
724
+ ):
725
+ # If this value is still a list to tuple raise the
726
+ # exception.
727
+ expr = func_ir._definitions[vararg_name][0]
728
+ if isinstance(expr, ir.Expr) and expr.op == "list_to_tuple":
729
+ raise UnsupportedBytecodeError(errmsg)
730
+
731
+ new_body.append(stmt)
732
+ # Replace the block body if we changed the IR
733
+ if blk_changed:
734
+ blk.body.clear()
735
+ blk.body.extend([x for x in new_body if x is not None])
736
+ return func_ir
737
+
738
+
739
+ def peep_hole_list_to_tuple(func_ir):
740
+ """
741
+ This peephole rewrites a bytecode sequence new to Python 3.9 that looks
742
+ like e.g.:
743
+
744
+ def foo(a):
745
+ return (*a,)
746
+
747
+ 41 0 BUILD_LIST 0
748
+ 2 LOAD_FAST 0 (a)
749
+ 4 LIST_EXTEND 1
750
+ 6 LIST_TO_TUPLE
751
+ 8 RETURN_VAL
752
+
753
+ essentially, the unpacking of tuples is written as a list which is appended
754
+ to/extended and then "magicked" into a tuple by the new LIST_TO_TUPLE
755
+ opcode.
756
+
757
+ This peephole repeatedly analyses the bytecode in a block looking for a
758
+ window between a `LIST_TO_TUPLE` and `BUILD_LIST` and...
759
+
760
+ 1. Turns the BUILD_LIST into a BUILD_TUPLE
761
+ 2. Sets an accumulator's initial value as the target of the BUILD_TUPLE
762
+ 3. Searches for 'extend' on the original list and turns these into binary
763
+ additions on the accumulator.
764
+ 4. Searches for 'append' on the original list and turns these into a
765
+ `BUILD_TUPLE` which is then appended via binary addition to the
766
+ accumulator.
767
+ 5. Assigns the accumulator to the variable that exits the peephole and the
768
+ rest of the block/code refers to as the result of the unpack operation.
769
+ 6. Patches up
770
+ """
771
+ _DEBUG = False
772
+
773
+ # For all blocks
774
+ for offset, blk in func_ir.blocks.items():
775
+ # keep doing the peephole rewrite until nothing is left that matches
776
+ while True:
777
+ # first try and find a matching region
778
+ # i.e. BUILD_LIST...<stuff>...LIST_TO_TUPLE
779
+ def find_postive_region():
780
+ found = False
781
+ for idx in reversed(range(len(blk.body))):
782
+ stmt = blk.body[idx]
783
+ if isinstance(stmt, ir.Assign):
784
+ value = stmt.value
785
+ if (
786
+ isinstance(value, ir.Expr)
787
+ and value.op == "list_to_tuple"
788
+ ):
789
+ target_list = value.info[0]
790
+ found = True
791
+ bt = (idx, stmt)
792
+ if found:
793
+ if isinstance(stmt, ir.Assign):
794
+ if stmt.target.name == target_list:
795
+ region = (bt, (idx, stmt))
796
+ return region
797
+
798
+ region = find_postive_region()
799
+ # if there's a peep hole region then do something with it
800
+ if region is not None:
801
+ peep_hole = blk.body[region[1][0] : region[0][0]]
802
+ if _DEBUG:
803
+ print("\nWINDOW:")
804
+ for x in peep_hole:
805
+ print(x)
806
+ print("")
807
+
808
+ appends = []
809
+ extends = []
810
+ init = region[1][1]
811
+ const_list = init.target.name
812
+ # Walk through the peep_hole and find things that are being
813
+ # "extend"ed and "append"ed to the BUILD_LIST
814
+ for x in peep_hole:
815
+ if isinstance(x, ir.Assign):
816
+ if isinstance(x.value, ir.Expr):
817
+ expr = x.value
818
+ if (
819
+ expr.op == "getattr"
820
+ and expr.value.name == const_list
821
+ ):
822
+ # it's not strictly necessary to split out
823
+ # extends and appends, but it helps with
824
+ # debugging to do so!
825
+ if expr.attr == "extend":
826
+ extends.append(x.target.name)
827
+ elif expr.attr == "append":
828
+ appends.append(x.target.name)
829
+ else:
830
+ assert 0
831
+ # go back through the peep hole build new IR based on it.
832
+ new_hole = []
833
+
834
+ def append_and_fix(x):
835
+ """Adds to the new_hole and fixes up definitions"""
836
+ new_hole.append(x)
837
+ if x.target.name in func_ir._definitions:
838
+ # if there's already a definition, drop it, should only
839
+ # be 1 as the way cpython emits the sequence for
840
+ # `list_to_tuple` should ensure this.
841
+ assert len(func_ir._definitions[x.target.name]) == 1
842
+ func_ir._definitions[x.target.name].clear()
843
+ func_ir._definitions[x.target.name].append(x.value)
844
+
845
+ the_build_list = init.target
846
+
847
+ # Do the transform on the peep hole
848
+ if _DEBUG:
849
+ print("\nBLOCK:")
850
+ blk.dump()
851
+
852
+ # This section basically accumulates list appends and extends
853
+ # as binop(+) on tuples, it drops all the getattr() for extend
854
+ # and append as they are now dead and replaced with binop(+).
855
+ # It also switches out the build_list for a build_tuple and then
856
+ # ensures everything is wired up and defined ok.
857
+ t2l_agn = region[0][1]
858
+ acc = the_build_list
859
+ for x in peep_hole:
860
+ if isinstance(x, ir.Assign):
861
+ if isinstance(x.value, ir.Expr):
862
+ expr = x.value
863
+ if expr.op == "getattr":
864
+ if (
865
+ x.target.name in extends
866
+ or x.target.name in appends
867
+ ):
868
+ # drop definition, it's being wholesale
869
+ # replaced.
870
+ func_ir._definitions.pop(x.target.name)
871
+ continue
872
+ else:
873
+ # a getattr on something we're not
874
+ # interested in
875
+ new_hole.append(x)
876
+ elif expr.op == "call":
877
+ fname = expr.func.name
878
+ if fname in extends or fname in appends:
879
+ arg = expr.args[0]
880
+ if isinstance(arg, ir.Var):
881
+ tmp_name = "%s_var_%s" % (
882
+ fname,
883
+ arg.name,
884
+ )
885
+ if fname in appends:
886
+ bt = ir.Expr.build_tuple(
887
+ [
888
+ arg,
889
+ ],
890
+ expr.loc,
891
+ )
892
+ else:
893
+ # Extend as tuple
894
+ gv_tuple = ir.Global(
895
+ name="tuple",
896
+ value=tuple,
897
+ loc=expr.loc,
898
+ )
899
+ tuple_var = arg.scope.redefine(
900
+ "$_list_extend_gv_tuple",
901
+ loc=expr.loc,
902
+ )
903
+ new_hole.append(
904
+ ir.Assign(
905
+ target=tuple_var,
906
+ value=gv_tuple,
907
+ loc=expr.loc,
908
+ ),
909
+ )
910
+ bt = ir.Expr.call(
911
+ tuple_var,
912
+ (arg,),
913
+ (),
914
+ loc=expr.loc,
915
+ )
916
+ var = ir.Var(
917
+ arg.scope, tmp_name, expr.loc
918
+ )
919
+ asgn = ir.Assign(bt, var, expr.loc)
920
+ append_and_fix(asgn)
921
+ arg = var
922
+
923
+ # this needs to be a binary add
924
+ new = ir.Expr.binop(
925
+ fn=operator.add,
926
+ lhs=acc,
927
+ rhs=arg,
928
+ loc=x.loc,
929
+ )
930
+ asgn = ir.Assign(new, x.target, expr.loc)
931
+ append_and_fix(asgn)
932
+ acc = asgn.target
933
+ else:
934
+ # there could be a call in the unpack, like
935
+ # *(a, x.append(y))
936
+ new_hole.append(x)
937
+ elif (
938
+ expr.op == "build_list"
939
+ and x.target.name == const_list
940
+ ):
941
+ new = ir.Expr.build_tuple(expr.items, expr.loc)
942
+ asgn = ir.Assign(new, x.target, expr.loc)
943
+ # Not a temporary any more
944
+ append_and_fix(asgn)
945
+ else:
946
+ new_hole.append(x)
947
+ else:
948
+ new_hole.append(x)
949
+
950
+ else:
951
+ # stick everything else in as-is
952
+ new_hole.append(x)
953
+ # Finally write the result back into the original build list as
954
+ # everything refers to it.
955
+ append_and_fix(
956
+ ir.Assign(acc, t2l_agn.target, the_build_list.loc)
957
+ )
958
+ if _DEBUG:
959
+ print("\nNEW HOLE:")
960
+ for x in new_hole:
961
+ print(x)
962
+
963
+ # and then update the block body with the modified region
964
+ cpy = blk.body[:]
965
+ head = cpy[: region[1][0]]
966
+ tail = blk.body[region[0][0] + 1 :]
967
+ tmp = head + new_hole + tail
968
+ blk.body.clear()
969
+ blk.body.extend(tmp)
970
+
971
+ if _DEBUG:
972
+ print("\nDUMP post hole:")
973
+ blk.dump()
974
+
975
+ else:
976
+ # else escape
977
+ break
978
+
979
+ return func_ir
980
+
981
+
982
+ def peep_hole_delete_with_exit(func_ir):
983
+ """
984
+ This rewrite removes variables used to store the `__exit__` function
985
+ loaded by SETUP_WITH.
986
+ """
987
+ dead_vars = set()
988
+
989
+ for blk in func_ir.blocks.values():
990
+ for stmt in blk.body:
991
+ # Any statement that uses a variable with the '$setup_with_exitfn'
992
+ # prefix is considered dead.
993
+ used = set(stmt.list_vars())
994
+ for v in used:
995
+ if v.name.startswith("$setup_with_exitfn"):
996
+ dead_vars.add(v)
997
+ # Any assignment that uses any of the dead variable is considered
998
+ # dead.
999
+ if used & dead_vars:
1000
+ if isinstance(stmt, ir.Assign):
1001
+ dead_vars.add(stmt.target)
1002
+
1003
+ new_body = []
1004
+ for stmt in blk.body:
1005
+ # Skip any statements that uses anyone of the dead variable.
1006
+ if not (set(stmt.list_vars()) & dead_vars):
1007
+ new_body.append(stmt)
1008
+ blk.body.clear()
1009
+ blk.body.extend(new_body)
1010
+
1011
+ return func_ir
1012
+
1013
+
1014
+ def peep_hole_fuse_dict_add_updates(func_ir):
1015
+ """
1016
+ This rewrite removes d1._update_from_bytecode(d2)
1017
+ calls that are between two dictionaries, d1 and d2,
1018
+ in the same basic block. This pattern can appear as a
1019
+ result of Python 3.10 bytecode emission changes, which
1020
+ prevent large constant literal dictionaries
1021
+ (> 15 elements) from being constant. If both dictionaries
1022
+ are constant dictionaries defined in the same block and
1023
+ neither is used between the update call, then we replace d1
1024
+ with a new definition that combines the two dictionaries. At
1025
+ the bytecode translation stage we convert DICT_UPDATE into
1026
+ _update_from_bytecode, so we know that _update_from_bytecode
1027
+ always comes from the bytecode change and not user code.
1028
+
1029
+ Python 3.10 may also rewrite the individual dictionaries
1030
+ as an empty build_map + many map_add. Here we again look
1031
+ for an _update_from_bytecode, and if so we replace these
1032
+ with a single constant dictionary.
1033
+
1034
+ When running this algorithm we can always safely remove d2.
1035
+
1036
+ This is the relevant section of the CPython 3.10 that causes
1037
+ this bytecode change:
1038
+ https://github.com/python/cpython/blob/3.10/Python/compile.c#L4048
1039
+ """
1040
+
1041
+ # This algorithm fuses build_map expressions into the largest
1042
+ # possible build map before use. For example, if we have an
1043
+ # IR that looks like this:
1044
+ #
1045
+ # $d1 = build_map([])
1046
+ # $key = const("a")
1047
+ # $value = const(2)
1048
+ # $setitem_func = getattr($d1, "__setitem__")
1049
+ # $unused1 = call (setitem_func, ($key, $value))
1050
+ # $key2 = const("b")
1051
+ # $value2 = const(3)
1052
+ # $d2 = build_map([($key2, $value2)])
1053
+ # $update_func = getattr($d1, "_update_from_bytecode")
1054
+ # $unused2 = call ($update_func, ($d2,))
1055
+ # $othervar = None
1056
+ # $retvar = cast($othervar)
1057
+ # return $retvar
1058
+ #
1059
+ # Then the IR is rewritten such that any __setitem__ and
1060
+ # _update_from_bytecode operations are fused into the original buildmap.
1061
+ # The new buildmap is then added to the
1062
+ # last location where it had previously had encountered a __setitem__,
1063
+ # _update_from_bytecode, or build_map before any other uses.
1064
+ # The new IR would look like:
1065
+ #
1066
+ # $key = const("a")
1067
+ # $value = const(2)
1068
+ # $key2 = const("b")
1069
+ # $value2 = const(3)
1070
+ # $d1 = build_map([($key, $value), ($key2, $value2)])
1071
+ # $othervar = None
1072
+ # $retvar = cast($othervar)
1073
+ # return $retvar
1074
+ #
1075
+ # Note that we don't push $d1 to the bottom of the block. This is because
1076
+ # some values may be found below this block (e.g pop_block) that are pattern
1077
+ # matched in other locations, such as objmode handling. It should be safe to
1078
+ # move a map to the last location at which there was _update_from_bytecode.
1079
+
1080
+ errmsg = textwrap.dedent("""
1081
+ A DICT_UPDATE op-code was encountered that could not be replaced.
1082
+ If you have created a large constant dictionary, this may
1083
+ be an an indication that you are using inlined control
1084
+ flow. You can resolve this issue by moving the control flow out of
1085
+ the dicitonary constructor. For example, if you have
1086
+
1087
+ d = {a: 1 if flag else 0, ...)
1088
+
1089
+ Replace that with:
1090
+
1091
+ a_val = 1 if flag else 0
1092
+ d = {a: a_val, ...)""")
1093
+
1094
+ already_deleted_defs = collections.defaultdict(set)
1095
+ for blk in func_ir.blocks.values():
1096
+ new_body = []
1097
+ # literal map var name -> block idx of the original build_map
1098
+ lit_map_def_idx = {}
1099
+ # literal map var name -> list(map_uses)
1100
+ # This is the index of every build_map or __setitem__
1101
+ # in the IR that will need to be removed if the map
1102
+ # is updated.
1103
+ lit_map_use_idx = collections.defaultdict(list)
1104
+ # literal map var name -> list of key/value items for build map
1105
+ map_updates = {}
1106
+ blk_changed = False
1107
+
1108
+ for i, stmt in enumerate(blk.body):
1109
+ # What instruction should we append
1110
+ new_inst = stmt
1111
+ # Name that should be skipped when tracking used
1112
+ # vars in statement. This is always the lhs with
1113
+ # a build_map.
1114
+ stmt_build_map_out = None
1115
+ if isinstance(stmt, ir.Assign) and isinstance(stmt.value, ir.Expr):
1116
+ if stmt.value.op == "build_map":
1117
+ # Skip the output build_map when looking for used vars.
1118
+ stmt_build_map_out = stmt.target.name
1119
+ # If we encounter a build map add it to the
1120
+ # tracked maps.
1121
+ lit_map_def_idx[stmt.target.name] = i
1122
+ lit_map_use_idx[stmt.target.name].append(i)
1123
+ map_updates[stmt.target.name] = stmt.value.items.copy()
1124
+ elif stmt.value.op == "call" and i > 0:
1125
+ # If we encounter a call we may need to replace
1126
+ # the body
1127
+ func_name = stmt.value.func.name
1128
+ # If we have an update or a setitem
1129
+ # it will be the previous expression.
1130
+ getattr_stmt = blk.body[i - 1]
1131
+ args = stmt.value.args
1132
+ if (
1133
+ isinstance(getattr_stmt, ir.Assign)
1134
+ and getattr_stmt.target.name == func_name
1135
+ and isinstance(getattr_stmt.value, ir.Expr)
1136
+ and getattr_stmt.value.op == "getattr"
1137
+ and getattr_stmt.value.attr
1138
+ in ("__setitem__", "_update_from_bytecode")
1139
+ ):
1140
+ update_map_name = getattr_stmt.value.value.name
1141
+ attr = getattr_stmt.value.attr
1142
+ if (
1143
+ attr == "__setitem__"
1144
+ and update_map_name in lit_map_use_idx
1145
+ ):
1146
+ # If we have a setitem, update the lists
1147
+ map_updates[update_map_name].append(args)
1148
+ # Update the list of instructions that would
1149
+ # need to be removed to include the setitem
1150
+ # and the the getattr
1151
+ lit_map_use_idx[update_map_name].extend([i - 1, i])
1152
+ elif attr == "_update_from_bytecode":
1153
+ d2_map_name = args[0].name
1154
+ if (
1155
+ update_map_name in lit_map_use_idx
1156
+ and d2_map_name in lit_map_use_idx
1157
+ ):
1158
+ # If we have an update and the arg is also
1159
+ # a literal dictionary, fuse the lists.
1160
+ map_updates[update_map_name].extend(
1161
+ map_updates[d2_map_name]
1162
+ )
1163
+ # Delete the old IR for d1 and d2
1164
+ lit_map_use_idx[update_map_name].extend(
1165
+ lit_map_use_idx[d2_map_name]
1166
+ )
1167
+ lit_map_use_idx[update_map_name].append(i - 1)
1168
+ for linenum in lit_map_use_idx[update_map_name]:
1169
+ # Drop the existing definition.
1170
+ _remove_assignment_definition(
1171
+ blk.body,
1172
+ linenum,
1173
+ func_ir,
1174
+ already_deleted_defs,
1175
+ )
1176
+ # Delete it from the new block
1177
+ new_body[linenum] = None
1178
+ # Delete the maps from dicts
1179
+ del lit_map_def_idx[d2_map_name]
1180
+ del lit_map_use_idx[d2_map_name]
1181
+ del map_updates[d2_map_name]
1182
+ # Add d1 as the new instruction, removing the
1183
+ # old definition.
1184
+ _remove_assignment_definition(
1185
+ blk.body, i, func_ir, already_deleted_defs
1186
+ )
1187
+ new_inst = _build_new_build_map(
1188
+ func_ir,
1189
+ update_map_name,
1190
+ blk.body,
1191
+ lit_map_def_idx[update_map_name],
1192
+ map_updates[update_map_name],
1193
+ )
1194
+ # Update d1 in lit_map_use_idx to just the new
1195
+ # definition and clear the previous list.
1196
+ lit_map_use_idx[update_map_name].clear()
1197
+ lit_map_use_idx[update_map_name].append(i)
1198
+ # Mark that this block has been modified
1199
+ blk_changed = True
1200
+ else:
1201
+ # If we cannot remove _update_from_bytecode
1202
+ # Then raise an error for the user.
1203
+ raise UnsupportedBytecodeError(errmsg)
1204
+
1205
+ # Check if we need to drop any maps from being tracked.
1206
+ # Skip the setitem/_update_from_bytecode getattr that
1207
+ # will be removed when handling their call in the next
1208
+ # iteration.
1209
+ if not (
1210
+ isinstance(stmt, ir.Assign)
1211
+ and isinstance(stmt.value, ir.Expr)
1212
+ and stmt.value.op == "getattr"
1213
+ and stmt.value.value.name in lit_map_use_idx
1214
+ and stmt.value.attr in ("__setitem__", "_update_from_bytecode")
1215
+ ):
1216
+ for var in stmt.list_vars():
1217
+ # If a map is used it cannot be fused later in
1218
+ # the block. As a result we delete it from
1219
+ # the dicitonaries
1220
+ if (
1221
+ var.name in lit_map_use_idx
1222
+ and var.name != stmt_build_map_out
1223
+ ):
1224
+ del lit_map_def_idx[var.name]
1225
+ del lit_map_use_idx[var.name]
1226
+ del map_updates[var.name]
1227
+
1228
+ # Append the instruction to the new block
1229
+ new_body.append(new_inst)
1230
+
1231
+ if blk_changed:
1232
+ # If the block is changed replace the block body.
1233
+ blk.body.clear()
1234
+ blk.body.extend([x for x in new_body if x is not None])
1235
+
1236
+ return func_ir
1237
+
1238
+
1239
+ def peep_hole_split_at_pop_block(func_ir):
1240
+ """
1241
+ Split blocks that contain ir.PopBlock.
1242
+
1243
+ This rewrite restores the IR structure to pre 3.11 so that withlifting
1244
+ can work correctly.
1245
+ """
1246
+ new_block_map = {}
1247
+ sorted_blocks = sorted(func_ir.blocks.items())
1248
+ for blk_idx, (label, blk) in enumerate(sorted_blocks):
1249
+ # Gather locations of PopBlock
1250
+ pop_block_locs = []
1251
+ for i, inst in enumerate(blk.body):
1252
+ if isinstance(inst, ir.PopBlock):
1253
+ pop_block_locs.append(i)
1254
+ # Rewrite block with PopBlock
1255
+ if pop_block_locs:
1256
+ new_blocks = []
1257
+ for i in pop_block_locs:
1258
+ before_blk = ir.Block(blk.scope, loc=blk.loc)
1259
+ before_blk.body.extend(blk.body[:i])
1260
+ new_blocks.append(before_blk)
1261
+
1262
+ popblk_blk = ir.Block(blk.scope, loc=blk.loc)
1263
+ popblk_blk.body.append(blk.body[i])
1264
+ new_blocks.append(popblk_blk)
1265
+ # Add jump instructions
1266
+ prev_label = label
1267
+ for newblk in new_blocks:
1268
+ new_block_map[prev_label] = newblk
1269
+ next_label = prev_label + 1
1270
+ newblk.body.append(ir.Jump(next_label, loc=blk.loc))
1271
+ prev_label = next_label
1272
+ # Check prev_label does not exceed current new block label
1273
+ if blk_idx + 1 < len(sorted_blocks):
1274
+ if prev_label >= sorted_blocks[blk_idx + 1][0]:
1275
+ # Panic! Due to heuristic in with-lifting, block labels
1276
+ # must be monotonically increasing. We cannot continue if we
1277
+ # run out of usable label between the two blocks.
1278
+ raise errors.InternalError("POP_BLOCK peephole failed")
1279
+ # Add tail block, which will get the original terminator
1280
+ tail_blk = ir.Block(blk.scope, loc=blk.loc)
1281
+ tail_blk.body.extend(blk.body[pop_block_locs[-1] + 1 :])
1282
+ new_block_map[prev_label] = tail_blk
1283
+
1284
+ func_ir.blocks.update(new_block_map)
1285
+ return func_ir
1286
+
1287
+
1288
+ def _build_new_build_map(func_ir, name, old_body, old_lineno, new_items):
1289
+ """
1290
+ Create a new build_map with a new set of key/value items
1291
+ but all the other info the same.
1292
+ """
1293
+ old_assign = old_body[old_lineno]
1294
+ old_target = old_assign.target
1295
+ old_bm = old_assign.value
1296
+ # Build the literals
1297
+ literal_keys = []
1298
+ # Track the constant key/values to set the literal_value
1299
+ # field of build_map properly
1300
+ values = []
1301
+ for pair in new_items:
1302
+ k, v = pair
1303
+ key_def = ir_utils.guard(ir_utils.get_definition, func_ir, k)
1304
+ if isinstance(key_def, (ir.Const, ir.Global, ir.FreeVar)):
1305
+ literal_keys.append(key_def.value)
1306
+ value_def = ir_utils.guard(ir_utils.get_definition, func_ir, v)
1307
+ if isinstance(value_def, (ir.Const, ir.Global, ir.FreeVar)):
1308
+ values.append(value_def.value)
1309
+ else:
1310
+ # Append unknown value if not a literal.
1311
+ values.append(_UNKNOWN_VALUE(v.name))
1312
+
1313
+ value_indexes = {}
1314
+ if len(literal_keys) == len(new_items):
1315
+ # All keys must be literals to have any literal values.
1316
+ literal_value = {x: y for x, y in zip(literal_keys, values)}
1317
+ for i, k in enumerate(literal_keys):
1318
+ value_indexes[k] = i
1319
+ else:
1320
+ literal_value = None
1321
+
1322
+ # Construct a new build map.
1323
+ new_bm = ir.Expr.build_map(
1324
+ items=new_items,
1325
+ size=len(new_items),
1326
+ literal_value=literal_value,
1327
+ value_indexes=value_indexes,
1328
+ loc=old_bm.loc,
1329
+ )
1330
+
1331
+ # The previous definition has already been removed
1332
+ # when updating the IR in peep_hole_fuse_dict_add_updates
1333
+ func_ir._definitions[name].append(new_bm)
1334
+
1335
+ # Return a new assign.
1336
+ return ir.Assign(
1337
+ new_bm, ir.Var(old_target.scope, name, old_target.loc), new_bm.loc
1338
+ )
1339
+
1340
+
1341
+ class Interpreter(object):
1342
+ """A bytecode interpreter that builds up the IR."""
1343
+
1344
+ _DEBUG_PRINT = False
1345
+
1346
+ def __init__(self, func_id):
1347
+ self.func_id = func_id
1348
+ if self._DEBUG_PRINT:
1349
+ print(func_id.func)
1350
+ self.arg_count = func_id.arg_count
1351
+ self.arg_names = func_id.arg_names
1352
+ self.loc = self.first_loc = ir.Loc.from_function_id(func_id)
1353
+ self.is_generator = func_id.is_generator
1354
+
1355
+ # { inst offset : ir.Block }
1356
+ self.blocks = {}
1357
+ # { name: [definitions] } of local variables
1358
+ self.definitions = collections.defaultdict(list)
1359
+ # A set to keep track of all exception variables.
1360
+ # To be used in _legalize_exception_vars()
1361
+ self._exception_vars = set()
1362
+
1363
+ def interpret(self, bytecode):
1364
+ """
1365
+ Generate IR for this bytecode.
1366
+ """
1367
+ self.bytecode = bytecode
1368
+
1369
+ self.scopes = []
1370
+ global_scope = ir.Scope(parent=None, loc=self.loc)
1371
+ self.scopes.append(global_scope)
1372
+
1373
+ flow = Flow(bytecode)
1374
+ flow.run()
1375
+ self.dfa = AdaptDFA(flow)
1376
+ self.cfa = AdaptCFA(flow)
1377
+ if config.DUMP_CFG:
1378
+ self.cfa.dump()
1379
+
1380
+ # Temp states during interpretation
1381
+ self.current_block = None
1382
+ self.current_block_offset = None
1383
+ last_active_offset = 0
1384
+ for _, inst_blocks in self.cfa.blocks.items():
1385
+ if inst_blocks.body:
1386
+ last_active_offset = max(
1387
+ last_active_offset, max(inst_blocks.body)
1388
+ )
1389
+ self.last_active_offset = last_active_offset
1390
+
1391
+ if PYVERSION in ((3, 12), (3, 13)):
1392
+ self.active_exception_entries = tuple(
1393
+ [
1394
+ entry
1395
+ for entry in self.bytecode.exception_entries
1396
+ if entry.start < self.last_active_offset
1397
+ ]
1398
+ )
1399
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
1400
+ pass
1401
+ else:
1402
+ raise NotImplementedError(PYVERSION)
1403
+ self.syntax_blocks = []
1404
+ self.dfainfo = None
1405
+
1406
+ self.scopes.append(ir.Scope(parent=self.current_scope, loc=self.loc))
1407
+
1408
+ # Interpret loop
1409
+ for inst, kws in self._iter_inst():
1410
+ self._dispatch(inst, kws)
1411
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1412
+ # Insert end of try markers
1413
+ self._end_try_blocks()
1414
+ elif PYVERSION in (
1415
+ (3, 9),
1416
+ (3, 10),
1417
+ ):
1418
+ pass
1419
+ else:
1420
+ raise NotImplementedError(PYVERSION)
1421
+ self._legalize_exception_vars()
1422
+ # Prepare FunctionIR
1423
+ func_ir = ir.FunctionIR(
1424
+ self.blocks,
1425
+ self.is_generator,
1426
+ self.func_id,
1427
+ self.first_loc,
1428
+ self.definitions,
1429
+ self.arg_count,
1430
+ self.arg_names,
1431
+ )
1432
+ _logger.debug(
1433
+ _lazy_pformat(func_ir, lazy_func=lambda x: x.dump_to_string())
1434
+ )
1435
+
1436
+ # post process the IR to rewrite opcodes/byte sequences that are too
1437
+ # involved to risk handling as part of direct interpretation
1438
+ peepholes = []
1439
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1440
+ peepholes.append(peep_hole_split_at_pop_block)
1441
+ if PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12), (3, 13)):
1442
+ peepholes.append(peep_hole_list_to_tuple)
1443
+ peepholes.append(peep_hole_delete_with_exit)
1444
+ if PYVERSION in ((3, 10), (3, 11), (3, 12), (3, 13)):
1445
+ # peep_hole_call_function_ex_to_call_function_kw
1446
+ # depends on peep_hole_list_to_tuple converting
1447
+ # any large number of arguments from a list to a
1448
+ # tuple.
1449
+ peepholes.append(peep_hole_call_function_ex_to_call_function_kw)
1450
+ peepholes.append(peep_hole_fuse_dict_add_updates)
1451
+
1452
+ post_processed_ir = self.post_process(peepholes, func_ir)
1453
+
1454
+ return post_processed_ir
1455
+
1456
+ def post_process(self, peepholes, func_ir):
1457
+ for peep in peepholes:
1458
+ func_ir = peep(func_ir)
1459
+ return func_ir
1460
+
1461
+ def _end_try_blocks(self):
1462
+ """Closes all try blocks by inserting the required marker at the
1463
+ exception handler
1464
+
1465
+ This is only needed for py3.11 because of the changes in exception
1466
+ handling. This merely maps the new py3.11 semantics back to the old way.
1467
+
1468
+ What the code does:
1469
+
1470
+ - For each block, compute the difference of blockstack to its incoming
1471
+ blocks' blockstack.
1472
+ - If the incoming blockstack has an extra TRY, the current block must
1473
+ be the EXCEPT block and we need to insert a marker.
1474
+
1475
+ See also: _insert_try_block_end
1476
+ """
1477
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13))
1478
+ graph = self.cfa.graph
1479
+ for offset, block in self.blocks.items():
1480
+ # Get current blockstack
1481
+ cur_bs = self.dfa.infos[offset].blockstack
1482
+ # Check blockstack of the incoming blocks
1483
+ for inc, _ in graph.predecessors(offset):
1484
+ inc_bs = self.dfa.infos[inc].blockstack
1485
+
1486
+ # find first diff in the blockstack
1487
+ for i, (x, y) in enumerate(zip(cur_bs, inc_bs)):
1488
+ if x != y:
1489
+ break
1490
+ else:
1491
+ i = min(len(cur_bs), len(inc_bs))
1492
+
1493
+ def do_change(remain):
1494
+ while remain:
1495
+ ent = remain.pop()
1496
+ if ent["kind"] == BlockKind("TRY"):
1497
+ # Extend block with marker for end of try
1498
+ self.current_block = block
1499
+ oldbody = list(block.body)
1500
+ block.body.clear()
1501
+ self._insert_try_block_end()
1502
+ block.body.extend(oldbody)
1503
+ return True
1504
+
1505
+ if do_change(list(inc_bs[i:])):
1506
+ break
1507
+
1508
+ def _legalize_exception_vars(self):
1509
+ """Search for unsupported use of exception variables.
1510
+ Note, they cannot be stored into user variable.
1511
+ """
1512
+ # Build a set of exception variables
1513
+ excvars = self._exception_vars.copy()
1514
+ # Propagate the exception variables to LHS of assignment
1515
+ for varname, defnvars in self.definitions.items():
1516
+ for v in defnvars:
1517
+ if isinstance(v, ir.Var):
1518
+ k = v.name
1519
+ if k in excvars:
1520
+ excvars.add(varname)
1521
+ # Filter out the user variables.
1522
+ uservar = list(filter(lambda x: not x.startswith("$"), excvars))
1523
+ if uservar:
1524
+ # Complain about the first user-variable storing an exception
1525
+ first = uservar[0]
1526
+ loc = self.current_scope.get(first).loc
1527
+ msg = "Exception object cannot be stored into variable ({})."
1528
+ raise errors.UnsupportedBytecodeError(msg.format(first), loc=loc)
1529
+
1530
+ def init_first_block(self):
1531
+ # Define variables receiving the function arguments
1532
+ for index, name in enumerate(self.arg_names):
1533
+ val = ir.Arg(index=index, name=name, loc=self.loc)
1534
+ self.store(val, name)
1535
+
1536
+ def _iter_inst(self):
1537
+ for blkct, block in enumerate(self.cfa.iterliveblocks()):
1538
+ firstinst = self.bytecode[block.offset]
1539
+ # If its an END_FOR instruction, the start location of block
1540
+ # is set to start of the FOR loop, so take the location of
1541
+ # next instruction. This only affects the source location
1542
+ # marking and has no impact to semantic.
1543
+ if firstinst.opname == "END_FOR":
1544
+ firstinst = self.bytecode[firstinst.next]
1545
+ self.loc = self.loc.with_lineno(firstinst.lineno)
1546
+ self._start_new_block(block.offset)
1547
+ if blkct == 0:
1548
+ # Is first block
1549
+ self.init_first_block()
1550
+ for offset, kws in self.dfainfo.insts:
1551
+ inst = self.bytecode[offset]
1552
+ self.loc = self.loc.with_lineno(inst.lineno)
1553
+ yield inst, kws
1554
+ self._end_current_block()
1555
+
1556
+ def _start_new_block(self, offset):
1557
+ oldblock = self.current_block
1558
+ self.insert_block(offset)
1559
+
1560
+ tryblk = self.dfainfo.active_try_block if self.dfainfo else None
1561
+ # Ensure the last block is terminated
1562
+ if oldblock is not None and not oldblock.is_terminated:
1563
+ # Handle ending try block.
1564
+ # If there's an active try-block and the handler block is live.
1565
+ if tryblk is not None and tryblk["end"] in self.cfa.graph.nodes():
1566
+ # We are in a try-block, insert a branch to except-block.
1567
+ # This logic cannot be in self._end_current_block()
1568
+ # because we don't know the non-raising next block-offset.
1569
+ branch = ir.Branch(
1570
+ cond=self.get("$exception_check"),
1571
+ truebr=tryblk["end"],
1572
+ falsebr=offset,
1573
+ loc=self.loc,
1574
+ )
1575
+ oldblock.append(branch)
1576
+ # Handle normal case
1577
+ else:
1578
+ jmp = ir.Jump(offset, loc=self.loc)
1579
+ oldblock.append(jmp)
1580
+
1581
+ # Get DFA block info
1582
+ self.dfainfo = self.dfa.infos[self.current_block_offset]
1583
+ self.assigner = Assigner()
1584
+ # Check out-of-scope syntactic-block
1585
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1586
+ # This is recreating pre-3.11 code structure
1587
+ while self.syntax_blocks:
1588
+ if offset >= self.syntax_blocks[-1].exit:
1589
+ synblk = self.syntax_blocks.pop()
1590
+ if isinstance(synblk, ir.With):
1591
+ self.current_block.append(ir.PopBlock(self.loc))
1592
+ else:
1593
+ break
1594
+ # inject try block:
1595
+ newtryblk = self.dfainfo.active_try_block
1596
+ if newtryblk is not None:
1597
+ if newtryblk is not tryblk:
1598
+ self._insert_try_block_begin()
1599
+ elif PYVERSION in (
1600
+ (3, 9),
1601
+ (3, 10),
1602
+ ):
1603
+ while self.syntax_blocks:
1604
+ if offset >= self.syntax_blocks[-1].exit:
1605
+ self.syntax_blocks.pop()
1606
+ else:
1607
+ break
1608
+ else:
1609
+ raise NotImplementedError(PYVERSION)
1610
+
1611
+ def _end_current_block(self):
1612
+ # Handle try block
1613
+ if not self.current_block.is_terminated:
1614
+ tryblk = self.dfainfo.active_try_block
1615
+ if tryblk is not None:
1616
+ self._insert_exception_check()
1617
+ # Handle normal block cleanup
1618
+ self._remove_unused_temporaries()
1619
+ self._insert_outgoing_phis()
1620
+
1621
+ def _inject_call(self, func, gv_name, res_name=None):
1622
+ """A helper function to inject a call to *func* which is a python
1623
+ function.
1624
+ Parameters
1625
+ ----------
1626
+ func : callable
1627
+ The function object to be called.
1628
+ gv_name : str
1629
+ The variable name to be used to store the function object.
1630
+ res_name : str; optional
1631
+ The variable name to be used to store the call result.
1632
+ If ``None``, a name is created automatically.
1633
+ """
1634
+ gv_fn = ir.Global(gv_name, func, loc=self.loc)
1635
+ self.store(value=gv_fn, name=gv_name, redefine=True)
1636
+ callres = ir.Expr.call(self.get(gv_name), (), (), loc=self.loc)
1637
+ res_name = res_name or "$callres_{}".format(gv_name)
1638
+ self.store(value=callres, name=res_name, redefine=True)
1639
+
1640
+ def _insert_try_block_begin(self):
1641
+ """Insert IR-nodes to mark the start of a `try` block."""
1642
+ self._inject_call(eh.mark_try_block, "mark_try_block")
1643
+
1644
+ def _insert_try_block_end(self):
1645
+ """Insert IR-nodes to mark the end of a `try` block."""
1646
+ self._inject_call(eh.end_try_block, "end_try_block")
1647
+
1648
+ def _insert_exception_variables(self):
1649
+ """Insert IR-nodes to initialize the exception variables."""
1650
+ tryblk = self.dfainfo.active_try_block
1651
+ # Get exception variables
1652
+ endblk = tryblk["end"]
1653
+ edgepushed = self.dfainfo.outgoing_edgepushed.get(endblk)
1654
+ # Note: the last value on the stack is the exception value
1655
+ # Note: due to the current limitation, all exception variables are None
1656
+ if edgepushed:
1657
+ const_none = ir.Const(value=None, loc=self.loc)
1658
+ # For each variable going to the handler block.
1659
+ for var in edgepushed:
1660
+ if var in self.definitions:
1661
+ raise AssertionError(
1662
+ "exception variable CANNOT be defined by other code",
1663
+ )
1664
+ self.store(value=const_none, name=var)
1665
+ self._exception_vars.add(var)
1666
+
1667
+ def _insert_exception_check(self):
1668
+ """Called before the end of a block to inject checks if raised."""
1669
+ self._insert_exception_variables()
1670
+ # Do exception check
1671
+ self._inject_call(
1672
+ eh.exception_check, "exception_check", "$exception_check"
1673
+ )
1674
+
1675
+ def _remove_unused_temporaries(self):
1676
+ """
1677
+ Remove assignments to unused temporary variables from the
1678
+ current block.
1679
+ """
1680
+ new_body = []
1681
+ replaced_var = {}
1682
+ for inst in self.current_block.body:
1683
+ # the same temporary is assigned to multiple variables in cases
1684
+ # like a = b[i] = 1, so need to handle replaced temporaries in
1685
+ # later setitem/setattr nodes
1686
+ if (
1687
+ isinstance(inst, (ir.SetItem, ir.SetAttr))
1688
+ and inst.value.name in replaced_var
1689
+ ):
1690
+ inst.value = replaced_var[inst.value.name]
1691
+ elif isinstance(inst, ir.Assign):
1692
+ if (
1693
+ inst.target.is_temp
1694
+ and inst.target.name in self.assigner.unused_dests
1695
+ ):
1696
+ continue
1697
+ # the same temporary is assigned to multiple variables in cases
1698
+ # like a = b = 1, so need to handle replaced temporaries in
1699
+ # later assignments
1700
+ if (
1701
+ isinstance(inst.value, ir.Var)
1702
+ and inst.value.name in replaced_var
1703
+ ):
1704
+ inst.value = replaced_var[inst.value.name]
1705
+ new_body.append(inst)
1706
+ continue
1707
+ # chained unpack cases may reuse temporary
1708
+ # e.g. a = (b, c) = (x, y)
1709
+ if (
1710
+ isinstance(inst.value, ir.Expr)
1711
+ and inst.value.op == "exhaust_iter"
1712
+ and inst.value.value.name in replaced_var
1713
+ ):
1714
+ inst.value.value = replaced_var[inst.value.value.name]
1715
+ new_body.append(inst)
1716
+ continue
1717
+ # eliminate temporary variables that are assigned to user
1718
+ # variables right after creation. E.g.:
1719
+ # $1 = f(); a = $1 -> a = f()
1720
+ # the temporary variable is not reused elsewhere since CPython
1721
+ # bytecode is stack-based and this pattern corresponds to a pop
1722
+ if (
1723
+ isinstance(inst.value, ir.Var)
1724
+ and inst.value.is_temp
1725
+ and new_body
1726
+ and isinstance(new_body[-1], ir.Assign)
1727
+ ):
1728
+ prev_assign = new_body[-1]
1729
+ # _var_used_in_binop check makes sure we don't create a new
1730
+ # inplace binop operation which can fail
1731
+ # (see TestFunctionType.test_in_iter_func_call)
1732
+ if (
1733
+ prev_assign.target.name == inst.value.name
1734
+ and not self._var_used_in_binop(
1735
+ inst.target.name, prev_assign.value
1736
+ )
1737
+ ):
1738
+ replaced_var[inst.value.name] = inst.target
1739
+ prev_assign.target = inst.target
1740
+ # replace temp var definition in target with proper defs
1741
+ self.definitions[inst.target.name].remove(inst.value)
1742
+ self.definitions[inst.target.name].extend(
1743
+ self.definitions.pop(inst.value.name)
1744
+ )
1745
+ continue
1746
+
1747
+ new_body.append(inst)
1748
+
1749
+ self.current_block.body = new_body
1750
+
1751
+ def _var_used_in_binop(self, varname, expr):
1752
+ """return True if 'expr' is a binary expression and 'varname' is used
1753
+ in it as an argument
1754
+ """
1755
+ return (
1756
+ isinstance(expr, ir.Expr)
1757
+ and expr.op in ("binop", "inplace_binop")
1758
+ and (varname == expr.lhs.name or varname == expr.rhs.name)
1759
+ )
1760
+
1761
+ def _insert_outgoing_phis(self):
1762
+ """
1763
+ Add assignments to forward requested outgoing values
1764
+ to subsequent blocks.
1765
+ """
1766
+ for phiname, varname in self.dfainfo.outgoing_phis.items():
1767
+ target = self.current_scope.get_or_define(phiname, loc=self.loc)
1768
+ try:
1769
+ val = self.get(varname)
1770
+ except ir.NotDefinedError:
1771
+ # Hack to make sure exception variables are defined
1772
+ assert PYVERSION in ((3, 11), (3, 12), (3, 13)), (
1773
+ "unexpected missing definition"
1774
+ )
1775
+ val = ir.Const(value=None, loc=self.loc)
1776
+ stmt = ir.Assign(value=val, target=target, loc=self.loc)
1777
+ self.definitions[target.name].append(stmt.value)
1778
+ if not self.current_block.is_terminated:
1779
+ self.current_block.append(stmt)
1780
+ else:
1781
+ self.current_block.insert_before_terminator(stmt)
1782
+
1783
+ def get_global_value(self, name):
1784
+ """
1785
+ Get a global value from the func_global (first) or
1786
+ as a builtins (second). If both failed, return a ir.UNDEFINED.
1787
+ """
1788
+ try:
1789
+ return self.func_id.func.__globals__[name]
1790
+ except KeyError:
1791
+ return getattr(builtins, name, ir.UNDEFINED)
1792
+
1793
+ def get_closure_value(self, index):
1794
+ """
1795
+ Get a value from the cell contained in this function's closure.
1796
+ If not set, return a ir.UNDEFINED.
1797
+ """
1798
+ cell = self.func_id.func.__closure__[index]
1799
+ try:
1800
+ return cell.cell_contents
1801
+ except ValueError:
1802
+ return ir.UNDEFINED
1803
+
1804
+ @property
1805
+ def current_scope(self):
1806
+ return self.scopes[-1]
1807
+
1808
+ @property
1809
+ def code_consts(self):
1810
+ return self.bytecode.co_consts
1811
+
1812
+ @property
1813
+ def code_locals(self):
1814
+ return self.bytecode.co_varnames
1815
+
1816
+ @property
1817
+ def code_names(self):
1818
+ return self.bytecode.co_names
1819
+
1820
+ @property
1821
+ def code_cellvars(self):
1822
+ return self.bytecode.co_cellvars
1823
+
1824
+ @property
1825
+ def code_freevars(self):
1826
+ return self.bytecode.co_freevars
1827
+
1828
+ def _dispatch(self, inst, kws):
1829
+ if self._DEBUG_PRINT:
1830
+ print(inst)
1831
+ assert self.current_block is not None
1832
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
1833
+ if self.syntax_blocks:
1834
+ top = self.syntax_blocks[-1]
1835
+ if isinstance(top, ir.With):
1836
+ if inst.offset >= top.exit:
1837
+ self.current_block.append(ir.PopBlock(loc=self.loc))
1838
+ self.syntax_blocks.pop()
1839
+ elif PYVERSION in (
1840
+ (3, 9),
1841
+ (3, 10),
1842
+ ):
1843
+ pass
1844
+ else:
1845
+ raise NotImplementedError(PYVERSION)
1846
+
1847
+ fname = "op_%s" % inst.opname.replace("+", "_")
1848
+ try:
1849
+ fn = getattr(self, fname)
1850
+ except AttributeError:
1851
+ raise NotImplementedError(inst)
1852
+ else:
1853
+ try:
1854
+ return fn(inst, **kws)
1855
+ except errors.NotDefinedError as e:
1856
+ if e.loc is None:
1857
+ loc = self.loc
1858
+ else:
1859
+ loc = e.loc
1860
+
1861
+ err = errors.NotDefinedError(e.name, loc=loc)
1862
+ if not config.FULL_TRACEBACKS:
1863
+ raise err from None
1864
+ else:
1865
+ m = f"handling op: {inst} | offset: {inst.offset}"
1866
+ err.add_context(m)
1867
+ err.add_context(self.bytecode.dump())
1868
+ raise err
1869
+
1870
+ # --- Scope operations ---
1871
+
1872
+ def store(self, value, name, redefine=False):
1873
+ """
1874
+ Store *value* (a Expr or Var instance) into the variable named *name*
1875
+ (a str object). Returns the target variable.
1876
+ """
1877
+ if redefine or self.current_block_offset in self.cfa.backbone:
1878
+ rename = name not in self.code_cellvars
1879
+ target = self.current_scope.redefine(
1880
+ name, loc=self.loc, rename=rename
1881
+ )
1882
+ else:
1883
+ target = self.current_scope.get_or_define(name, loc=self.loc)
1884
+ if isinstance(value, ir.Var):
1885
+ value = self.assigner.assign(value, target)
1886
+ stmt = ir.Assign(value=value, target=target, loc=self.loc)
1887
+ self.current_block.append(stmt)
1888
+ self.definitions[target.name].append(value)
1889
+ return target
1890
+
1891
+ def get(self, name):
1892
+ """
1893
+ Get the variable (a Var instance) with the given *name*.
1894
+ """
1895
+ # Implicit argument for comprehension starts with '.'
1896
+ # See Parameter class in inspect.py (from Python source)
1897
+ if name[0] == "." and name[1:].isdigit():
1898
+ name = "implicit{}".format(name[1:])
1899
+
1900
+ # Try to simplify the variable lookup by returning an earlier
1901
+ # variable assigned to *name*.
1902
+ var = self.assigner.get_assignment_source(name)
1903
+ if var is None:
1904
+ var = self.current_scope.get(name)
1905
+ return var
1906
+
1907
+ # --- Block operations ---
1908
+
1909
+ def insert_block(self, offset, scope=None, loc=None):
1910
+ scope = scope or self.current_scope
1911
+ loc = loc or self.loc
1912
+ blk = ir.Block(scope=scope, loc=loc)
1913
+ self.blocks[offset] = blk
1914
+ self.current_block = blk
1915
+ self.current_block_offset = offset
1916
+ return blk
1917
+
1918
+ # --- Bytecode handlers ---
1919
+
1920
+ def op_NOP(self, inst):
1921
+ pass
1922
+
1923
+ def op_RESUME(self, inst):
1924
+ pass
1925
+
1926
+ def op_CACHE(self, inst):
1927
+ pass
1928
+
1929
+ def op_PRECALL(self, inst):
1930
+ pass
1931
+
1932
+ def op_PUSH_NULL(self, inst):
1933
+ pass
1934
+
1935
+ def op_RETURN_GENERATOR(self, inst):
1936
+ pass
1937
+
1938
+ def op_PRINT_ITEM(self, inst, item, printvar, res):
1939
+ item = self.get(item)
1940
+ printgv = ir.Global("print", print, loc=self.loc)
1941
+ self.store(value=printgv, name=printvar)
1942
+ call = ir.Expr.call(self.get(printvar), (item,), (), loc=self.loc)
1943
+ self.store(value=call, name=res)
1944
+
1945
+ def op_PRINT_NEWLINE(self, inst, printvar, res):
1946
+ printgv = ir.Global("print", print, loc=self.loc)
1947
+ self.store(value=printgv, name=printvar)
1948
+ call = ir.Expr.call(self.get(printvar), (), (), loc=self.loc)
1949
+ self.store(value=call, name=res)
1950
+
1951
+ def op_UNPACK_SEQUENCE(self, inst, iterable, stores, tupleobj):
1952
+ count = len(stores)
1953
+ # Exhaust the iterable into a tuple-like object
1954
+ tup = ir.Expr.exhaust_iter(
1955
+ value=self.get(iterable), loc=self.loc, count=count
1956
+ )
1957
+ self.store(name=tupleobj, value=tup)
1958
+
1959
+ # then index the tuple-like object to extract the values
1960
+ for i, st in enumerate(stores):
1961
+ expr = ir.Expr.static_getitem(
1962
+ self.get(tupleobj), index=i, index_var=None, loc=self.loc
1963
+ )
1964
+ self.store(expr, st)
1965
+
1966
+ def op_FORMAT_SIMPLE(self, inst, value, res, strvar):
1967
+ # Same as FORMAT_VALUE
1968
+ return self.op_FORMAT_VALUE(inst, value, res, strvar)
1969
+
1970
+ def op_FORMAT_VALUE(self, inst, value, res, strvar):
1971
+ """
1972
+ FORMAT_VALUE(flags): flags argument specifies format spec which is not
1973
+ supported yet. Currently, str() is simply called on the value.
1974
+ https://docs.python.org/3/library/dis.html#opcode-FORMAT_VALUE
1975
+ """
1976
+ value = self.get(value)
1977
+ strgv = ir.Global("str", str, loc=self.loc)
1978
+ self.store(value=strgv, name=strvar)
1979
+ call = ir.Expr.call(self.get(strvar), (value,), (), loc=self.loc)
1980
+ self.store(value=call, name=res)
1981
+
1982
+ def op_BUILD_STRING(self, inst, strings, tmps):
1983
+ """
1984
+ BUILD_STRING(count): Concatenates count strings.
1985
+ Required for supporting f-strings.
1986
+ https://docs.python.org/3/library/dis.html#opcode-BUILD_STRING
1987
+ """
1988
+ count = inst.arg
1989
+ # corner case: f""
1990
+ if count == 0:
1991
+ const = ir.Const("", loc=self.loc)
1992
+ self.store(const, tmps[-1])
1993
+ return
1994
+
1995
+ prev = self.get(strings[0])
1996
+ for other, tmp in zip(strings[1:], tmps):
1997
+ other = self.get(other)
1998
+ expr = ir.Expr.binop(
1999
+ operator.add, lhs=prev, rhs=other, loc=self.loc
2000
+ )
2001
+ self.store(expr, tmp)
2002
+ prev = self.get(tmp)
2003
+
2004
+ def op_BUILD_SLICE(self, inst, start, stop, step, res, slicevar):
2005
+ start = self.get(start)
2006
+ stop = self.get(stop)
2007
+
2008
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2009
+ self.store(value=slicegv, name=slicevar)
2010
+
2011
+ if step is None:
2012
+ sliceinst = ir.Expr.call(
2013
+ self.get(slicevar), (start, stop), (), loc=self.loc
2014
+ )
2015
+ else:
2016
+ step = self.get(step)
2017
+ sliceinst = ir.Expr.call(
2018
+ self.get(slicevar), (start, stop, step), (), loc=self.loc
2019
+ )
2020
+ self.store(value=sliceinst, name=res)
2021
+
2022
+ if PYVERSION in ((3, 12), (3, 13)):
2023
+
2024
+ def op_BINARY_SLICE(
2025
+ self, inst, start, end, container, res, slicevar, temp_res
2026
+ ):
2027
+ start = self.get(start)
2028
+ end = self.get(end)
2029
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2030
+ self.store(value=slicegv, name=slicevar)
2031
+ sliceinst = ir.Expr.call(
2032
+ self.get(slicevar), (start, end), (), loc=self.loc
2033
+ )
2034
+ self.store(value=sliceinst, name=temp_res)
2035
+ index = self.get(temp_res)
2036
+ target = self.get(container)
2037
+ expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2038
+ self.store(expr, res)
2039
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2040
+ pass
2041
+ else:
2042
+ raise NotImplementedError(PYVERSION)
2043
+
2044
+ if PYVERSION in ((3, 12), (3, 13)):
2045
+
2046
+ def op_STORE_SLICE(
2047
+ self, inst, start, end, container, value, res, slicevar
2048
+ ):
2049
+ start = self.get(start)
2050
+ end = self.get(end)
2051
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2052
+ self.store(value=slicegv, name=slicevar)
2053
+ sliceinst = ir.Expr.call(
2054
+ self.get(slicevar), (start, end), (), loc=self.loc
2055
+ )
2056
+ self.store(value=sliceinst, name=res)
2057
+ index = self.get(res)
2058
+ target = self.get(container)
2059
+ value = self.get(value)
2060
+
2061
+ stmt = ir.SetItem(
2062
+ target=target, index=index, value=value, loc=self.loc
2063
+ )
2064
+ self.current_block.append(stmt)
2065
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2066
+ pass
2067
+ else:
2068
+ raise NotImplementedError(PYVERSION)
2069
+
2070
+ def op_SLICE_0(self, inst, base, res, slicevar, indexvar, nonevar):
2071
+ base = self.get(base)
2072
+
2073
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2074
+ self.store(value=slicegv, name=slicevar)
2075
+
2076
+ nonegv = ir.Const(None, loc=self.loc)
2077
+ self.store(value=nonegv, name=nonevar)
2078
+ none = self.get(nonevar)
2079
+
2080
+ index = ir.Expr.call(self.get(slicevar), (none, none), (), loc=self.loc)
2081
+ self.store(value=index, name=indexvar)
2082
+
2083
+ expr = ir.Expr.getitem(base, self.get(indexvar), loc=self.loc)
2084
+ self.store(value=expr, name=res)
2085
+
2086
+ def op_SLICE_1(self, inst, base, start, nonevar, res, slicevar, indexvar):
2087
+ base = self.get(base)
2088
+ start = self.get(start)
2089
+
2090
+ nonegv = ir.Const(None, loc=self.loc)
2091
+ self.store(value=nonegv, name=nonevar)
2092
+ none = self.get(nonevar)
2093
+
2094
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2095
+ self.store(value=slicegv, name=slicevar)
2096
+
2097
+ index = ir.Expr.call(
2098
+ self.get(slicevar), (start, none), (), loc=self.loc
2099
+ )
2100
+ self.store(value=index, name=indexvar)
2101
+
2102
+ expr = ir.Expr.getitem(base, self.get(indexvar), loc=self.loc)
2103
+ self.store(value=expr, name=res)
2104
+
2105
+ def op_SLICE_2(self, inst, base, nonevar, stop, res, slicevar, indexvar):
2106
+ base = self.get(base)
2107
+ stop = self.get(stop)
2108
+
2109
+ nonegv = ir.Const(None, loc=self.loc)
2110
+ self.store(value=nonegv, name=nonevar)
2111
+ none = self.get(nonevar)
2112
+
2113
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2114
+ self.store(value=slicegv, name=slicevar)
2115
+
2116
+ index = ir.Expr.call(
2117
+ self.get(slicevar),
2118
+ (
2119
+ none,
2120
+ stop,
2121
+ ),
2122
+ (),
2123
+ loc=self.loc,
2124
+ )
2125
+ self.store(value=index, name=indexvar)
2126
+
2127
+ expr = ir.Expr.getitem(base, self.get(indexvar), loc=self.loc)
2128
+ self.store(value=expr, name=res)
2129
+
2130
+ def op_SLICE_3(self, inst, base, start, stop, res, slicevar, indexvar):
2131
+ base = self.get(base)
2132
+ start = self.get(start)
2133
+ stop = self.get(stop)
2134
+
2135
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2136
+ self.store(value=slicegv, name=slicevar)
2137
+
2138
+ index = ir.Expr.call(
2139
+ self.get(slicevar), (start, stop), (), loc=self.loc
2140
+ )
2141
+ self.store(value=index, name=indexvar)
2142
+
2143
+ expr = ir.Expr.getitem(base, self.get(indexvar), loc=self.loc)
2144
+ self.store(value=expr, name=res)
2145
+
2146
+ def op_STORE_SLICE_0(self, inst, base, value, slicevar, indexvar, nonevar):
2147
+ base = self.get(base)
2148
+
2149
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2150
+ self.store(value=slicegv, name=slicevar)
2151
+
2152
+ nonegv = ir.Const(None, loc=self.loc)
2153
+ self.store(value=nonegv, name=nonevar)
2154
+ none = self.get(nonevar)
2155
+
2156
+ index = ir.Expr.call(self.get(slicevar), (none, none), (), loc=self.loc)
2157
+ self.store(value=index, name=indexvar)
2158
+
2159
+ stmt = ir.SetItem(
2160
+ base, self.get(indexvar), self.get(value), loc=self.loc
2161
+ )
2162
+ self.current_block.append(stmt)
2163
+
2164
+ def op_STORE_SLICE_1(
2165
+ self, inst, base, start, nonevar, value, slicevar, indexvar
2166
+ ):
2167
+ base = self.get(base)
2168
+ start = self.get(start)
2169
+
2170
+ nonegv = ir.Const(None, loc=self.loc)
2171
+ self.store(value=nonegv, name=nonevar)
2172
+ none = self.get(nonevar)
2173
+
2174
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2175
+ self.store(value=slicegv, name=slicevar)
2176
+
2177
+ index = ir.Expr.call(
2178
+ self.get(slicevar), (start, none), (), loc=self.loc
2179
+ )
2180
+ self.store(value=index, name=indexvar)
2181
+
2182
+ stmt = ir.SetItem(
2183
+ base, self.get(indexvar), self.get(value), loc=self.loc
2184
+ )
2185
+ self.current_block.append(stmt)
2186
+
2187
+ def op_STORE_SLICE_2(
2188
+ self, inst, base, nonevar, stop, value, slicevar, indexvar
2189
+ ):
2190
+ base = self.get(base)
2191
+ stop = self.get(stop)
2192
+
2193
+ nonegv = ir.Const(None, loc=self.loc)
2194
+ self.store(value=nonegv, name=nonevar)
2195
+ none = self.get(nonevar)
2196
+
2197
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2198
+ self.store(value=slicegv, name=slicevar)
2199
+
2200
+ index = ir.Expr.call(
2201
+ self.get(slicevar),
2202
+ (
2203
+ none,
2204
+ stop,
2205
+ ),
2206
+ (),
2207
+ loc=self.loc,
2208
+ )
2209
+ self.store(value=index, name=indexvar)
2210
+
2211
+ stmt = ir.SetItem(
2212
+ base, self.get(indexvar), self.get(value), loc=self.loc
2213
+ )
2214
+ self.current_block.append(stmt)
2215
+
2216
+ def op_STORE_SLICE_3(
2217
+ self, inst, base, start, stop, value, slicevar, indexvar
2218
+ ):
2219
+ base = self.get(base)
2220
+ start = self.get(start)
2221
+ stop = self.get(stop)
2222
+
2223
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2224
+ self.store(value=slicegv, name=slicevar)
2225
+
2226
+ index = ir.Expr.call(
2227
+ self.get(slicevar), (start, stop), (), loc=self.loc
2228
+ )
2229
+ self.store(value=index, name=indexvar)
2230
+ stmt = ir.SetItem(
2231
+ base, self.get(indexvar), self.get(value), loc=self.loc
2232
+ )
2233
+ self.current_block.append(stmt)
2234
+
2235
+ def op_DELETE_SLICE_0(self, inst, base, slicevar, indexvar, nonevar):
2236
+ base = self.get(base)
2237
+
2238
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2239
+ self.store(value=slicegv, name=slicevar)
2240
+
2241
+ nonegv = ir.Const(None, loc=self.loc)
2242
+ self.store(value=nonegv, name=nonevar)
2243
+ none = self.get(nonevar)
2244
+
2245
+ index = ir.Expr.call(self.get(slicevar), (none, none), (), loc=self.loc)
2246
+ self.store(value=index, name=indexvar)
2247
+
2248
+ stmt = ir.DelItem(base, self.get(indexvar), loc=self.loc)
2249
+ self.current_block.append(stmt)
2250
+
2251
+ def op_DELETE_SLICE_1(self, inst, base, start, nonevar, slicevar, indexvar):
2252
+ base = self.get(base)
2253
+ start = self.get(start)
2254
+
2255
+ nonegv = ir.Const(None, loc=self.loc)
2256
+ self.store(value=nonegv, name=nonevar)
2257
+ none = self.get(nonevar)
2258
+
2259
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2260
+ self.store(value=slicegv, name=slicevar)
2261
+
2262
+ index = ir.Expr.call(
2263
+ self.get(slicevar), (start, none), (), loc=self.loc
2264
+ )
2265
+ self.store(value=index, name=indexvar)
2266
+
2267
+ stmt = ir.DelItem(base, self.get(indexvar), loc=self.loc)
2268
+ self.current_block.append(stmt)
2269
+
2270
+ def op_DELETE_SLICE_2(self, inst, base, nonevar, stop, slicevar, indexvar):
2271
+ base = self.get(base)
2272
+ stop = self.get(stop)
2273
+
2274
+ nonegv = ir.Const(None, loc=self.loc)
2275
+ self.store(value=nonegv, name=nonevar)
2276
+ none = self.get(nonevar)
2277
+
2278
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2279
+ self.store(value=slicegv, name=slicevar)
2280
+
2281
+ index = ir.Expr.call(
2282
+ self.get(slicevar),
2283
+ (
2284
+ none,
2285
+ stop,
2286
+ ),
2287
+ (),
2288
+ loc=self.loc,
2289
+ )
2290
+ self.store(value=index, name=indexvar)
2291
+
2292
+ stmt = ir.DelItem(base, self.get(indexvar), loc=self.loc)
2293
+ self.current_block.append(stmt)
2294
+
2295
+ def op_DELETE_SLICE_3(self, inst, base, start, stop, slicevar, indexvar):
2296
+ base = self.get(base)
2297
+ start = self.get(start)
2298
+ stop = self.get(stop)
2299
+
2300
+ slicegv = ir.Global("slice", slice, loc=self.loc)
2301
+ self.store(value=slicegv, name=slicevar)
2302
+
2303
+ index = ir.Expr.call(
2304
+ self.get(slicevar), (start, stop), (), loc=self.loc
2305
+ )
2306
+ self.store(value=index, name=indexvar)
2307
+ stmt = ir.DelItem(base, self.get(indexvar), loc=self.loc)
2308
+ self.current_block.append(stmt)
2309
+
2310
+ def _op_LOAD_FAST(self, inst, res):
2311
+ srcname = self.code_locals[inst.arg]
2312
+ self.store(value=self.get(srcname), name=res)
2313
+
2314
+ if PYVERSION in ((3, 13),):
2315
+
2316
+ def op_LOAD_FAST(self, inst, res, as_load_deref=False):
2317
+ if as_load_deref:
2318
+ self.op_LOAD_DEREF(inst, res)
2319
+ else:
2320
+ self._op_LOAD_FAST(inst, res)
2321
+
2322
+ else:
2323
+ op_LOAD_FAST = _op_LOAD_FAST
2324
+
2325
+ if PYVERSION in ((3, 13),):
2326
+
2327
+ def op_LOAD_FAST_LOAD_FAST(self, inst, res1, res2):
2328
+ oparg = inst.arg
2329
+ oparg1 = oparg >> 4
2330
+ oparg2 = oparg & 15
2331
+ src1 = self.get(self.code_locals[oparg1])
2332
+ src2 = self.get(self.code_locals[oparg2])
2333
+ self.store(value=src1, name=res1)
2334
+ self.store(value=src2, name=res2)
2335
+
2336
+ def op_STORE_FAST_LOAD_FAST(self, inst, store_value, load_res):
2337
+ oparg = inst.arg
2338
+ oparg1 = oparg >> 4
2339
+ oparg2 = oparg & 15
2340
+
2341
+ dstname = self.code_locals[oparg1]
2342
+ dst_value = self.get(store_value)
2343
+ self.store(value=dst_value, name=dstname)
2344
+
2345
+ src_value = self.get(self.code_locals[oparg2])
2346
+ self.store(value=src_value, name=load_res)
2347
+
2348
+ def op_STORE_FAST_STORE_FAST(self, inst, value1, value2):
2349
+ oparg = inst.arg
2350
+ oparg1 = oparg >> 4
2351
+ oparg2 = oparg & 15
2352
+
2353
+ dstname = self.code_locals[oparg1]
2354
+ self.store(value=self.get(value1), name=dstname)
2355
+ dstname = self.code_locals[oparg2]
2356
+ self.store(value=self.get(value2), name=dstname)
2357
+
2358
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
2359
+ pass
2360
+ else:
2361
+ raise NotImplementedError(PYVERSION)
2362
+
2363
+ if PYVERSION in ((3, 12), (3, 13)):
2364
+ op_LOAD_FAST_CHECK = op_LOAD_FAST
2365
+
2366
+ def op_LOAD_FAST_AND_CLEAR(self, inst, res):
2367
+ try:
2368
+ # try the regular LOAD_FAST logic
2369
+ srcname = self.code_locals[inst.arg]
2370
+ self.store(value=self.get(srcname), name=res)
2371
+ except NotDefinedError:
2372
+ # If the variable is not in the scope, set it to `undef`
2373
+ undef = ir.Expr.undef(loc=self.loc)
2374
+ self.store(undef, name=res)
2375
+
2376
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2377
+ pass
2378
+ else:
2379
+ raise NotImplementedError(PYVERSION)
2380
+
2381
+ def op_STORE_FAST(self, inst, value):
2382
+ dstname = self.code_locals[inst.arg]
2383
+ value = self.get(value)
2384
+ self.store(value=value, name=dstname)
2385
+
2386
+ def op_DELETE_FAST(self, inst):
2387
+ dstname = self.code_locals[inst.arg]
2388
+ self.current_block.append(ir.Del(dstname, loc=self.loc))
2389
+
2390
+ def op_DUP_TOPX(self, inst, orig, duped):
2391
+ for src, dst in zip(orig, duped):
2392
+ self.store(value=self.get(src), name=dst)
2393
+
2394
+ op_DUP_TOP = op_DUP_TOPX
2395
+ op_DUP_TOP_TWO = op_DUP_TOPX
2396
+
2397
+ def op_STORE_ATTR(self, inst, target, value):
2398
+ attr = self.code_names[inst.arg]
2399
+ sa = ir.SetAttr(
2400
+ target=self.get(target),
2401
+ value=self.get(value),
2402
+ attr=attr,
2403
+ loc=self.loc,
2404
+ )
2405
+ self.current_block.append(sa)
2406
+
2407
+ def op_DELETE_ATTR(self, inst, target):
2408
+ attr = self.code_names[inst.arg]
2409
+ sa = ir.DelAttr(target=self.get(target), attr=attr, loc=self.loc)
2410
+ self.current_block.append(sa)
2411
+
2412
+ def op_LOAD_ATTR(self, inst, item, res):
2413
+ item = self.get(item)
2414
+ if PYVERSION in ((3, 12), (3, 13)):
2415
+ attr = self.code_names[inst.arg >> 1]
2416
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2417
+ attr = self.code_names[inst.arg]
2418
+ else:
2419
+ raise NotImplementedError(PYVERSION)
2420
+ getattr = ir.Expr.getattr(item, attr, loc=self.loc)
2421
+ self.store(getattr, res)
2422
+
2423
+ def op_LOAD_CONST(self, inst, res):
2424
+ value = self.code_consts[inst.arg]
2425
+ if isinstance(value, tuple):
2426
+ st = []
2427
+ for x in value:
2428
+ nm = "$const_%s" % str(x)
2429
+ val_const = ir.Const(x, loc=self.loc)
2430
+ target = self.store(val_const, name=nm, redefine=True)
2431
+ st.append(target)
2432
+ const = ir.Expr.build_tuple(st, loc=self.loc)
2433
+ elif isinstance(value, frozenset):
2434
+ st = []
2435
+ for x in value:
2436
+ nm = "$const_%s" % str(x)
2437
+ val_const = ir.Const(x, loc=self.loc)
2438
+ target = self.store(val_const, name=nm, redefine=True)
2439
+ st.append(target)
2440
+ const = ir.Expr.build_set(st, loc=self.loc)
2441
+ else:
2442
+ const = ir.Const(value, loc=self.loc)
2443
+ self.store(const, res)
2444
+
2445
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2446
+
2447
+ def op_LOAD_GLOBAL(self, inst, idx, res):
2448
+ name = self.code_names[idx]
2449
+ value = self.get_global_value(name)
2450
+ gl = ir.Global(name, value, loc=self.loc)
2451
+ self.store(gl, res)
2452
+ elif PYVERSION in (
2453
+ (3, 9),
2454
+ (3, 10),
2455
+ ):
2456
+
2457
+ def op_LOAD_GLOBAL(self, inst, res):
2458
+ name = self.code_names[inst.arg]
2459
+ value = self.get_global_value(name)
2460
+ gl = ir.Global(name, value, loc=self.loc)
2461
+ self.store(gl, res)
2462
+ else:
2463
+ raise NotImplementedError(PYVERSION)
2464
+
2465
+ def op_COPY_FREE_VARS(self, inst):
2466
+ pass
2467
+
2468
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2469
+
2470
+ def op_LOAD_DEREF(self, inst, res):
2471
+ name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
2472
+ if name in self.code_cellvars:
2473
+ try:
2474
+ gl = self.get(name)
2475
+ except NotDefinedError:
2476
+ msg = "Unsupported use of cell variable encountered"
2477
+ raise NotImplementedError(msg)
2478
+ elif name in self.code_freevars:
2479
+ idx = self.code_freevars.index(name)
2480
+ value = self.get_closure_value(idx)
2481
+ gl = ir.FreeVar(idx, name, value, loc=self.loc)
2482
+ self.store(gl, res)
2483
+ elif PYVERSION in (
2484
+ (3, 9),
2485
+ (3, 10),
2486
+ ):
2487
+
2488
+ def op_LOAD_DEREF(self, inst, res):
2489
+ n_cellvars = len(self.code_cellvars)
2490
+ if inst.arg < n_cellvars:
2491
+ name = self.code_cellvars[inst.arg]
2492
+ gl = self.get(name)
2493
+ else:
2494
+ idx = inst.arg - n_cellvars
2495
+ name = self.code_freevars[idx]
2496
+ value = self.get_closure_value(idx)
2497
+ gl = ir.FreeVar(idx, name, value, loc=self.loc)
2498
+ self.store(gl, res)
2499
+ else:
2500
+ raise NotImplementedError(PYVERSION)
2501
+
2502
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2503
+
2504
+ def op_MAKE_CELL(self, inst):
2505
+ pass # ignored bytecode
2506
+
2507
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
2508
+
2509
+ def op_STORE_DEREF(self, inst, value):
2510
+ name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
2511
+ value = self.get(value)
2512
+ self.store(value=value, name=name)
2513
+ elif PYVERSION in (
2514
+ (3, 9),
2515
+ (3, 10),
2516
+ ):
2517
+
2518
+ def op_STORE_DEREF(self, inst, value):
2519
+ n_cellvars = len(self.code_cellvars)
2520
+ if inst.arg < n_cellvars:
2521
+ dstname = self.code_cellvars[inst.arg]
2522
+ else:
2523
+ dstname = self.code_freevars[inst.arg - n_cellvars]
2524
+ value = self.get(value)
2525
+ self.store(value=value, name=dstname)
2526
+ else:
2527
+ raise NotImplementedError(PYVERSION)
2528
+
2529
+ def op_SETUP_LOOP(self, inst):
2530
+ assert self.blocks[inst.offset] is self.current_block
2531
+ loop = ir.Loop(inst.offset, exit=(inst.next + inst.arg))
2532
+ self.syntax_blocks.append(loop)
2533
+
2534
+ def op_SETUP_WITH(self, inst, contextmanager, exitfn=None):
2535
+ assert self.blocks[inst.offset] is self.current_block
2536
+ # Handle with
2537
+ exitpt = inst.next + inst.arg
2538
+
2539
+ wth = ir.With(inst.offset, exit=exitpt)
2540
+ self.syntax_blocks.append(wth)
2541
+ ctxmgr = self.get(contextmanager)
2542
+ self.current_block.append(
2543
+ ir.EnterWith(
2544
+ contextmanager=ctxmgr,
2545
+ begin=inst.offset,
2546
+ end=exitpt,
2547
+ loc=self.loc,
2548
+ )
2549
+ )
2550
+
2551
+ # Store exit fn
2552
+ exit_fn_obj = ir.Const(None, loc=self.loc)
2553
+ self.store(value=exit_fn_obj, name=exitfn)
2554
+
2555
+ def op_BEFORE_WITH(self, inst, contextmanager, exitfn, end):
2556
+ assert self.blocks[inst.offset] is self.current_block
2557
+ if PYVERSION in ((3, 12), (3, 13)):
2558
+ # Python 3.12 hack for handling nested with blocks
2559
+ if end > self.last_active_offset:
2560
+ # Use exception entries to figure out end of syntax block
2561
+ end = max(
2562
+ [
2563
+ ex.end
2564
+ for ex in self.active_exception_entries
2565
+ if ex.target == end
2566
+ ]
2567
+ )
2568
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
2569
+ pass
2570
+ else:
2571
+ raise NotImplementedError(PYVERSION)
2572
+ # Handle with
2573
+ wth = ir.With(inst.offset, exit=end)
2574
+ self.syntax_blocks.append(wth)
2575
+ ctxmgr = self.get(contextmanager)
2576
+ self.current_block.append(
2577
+ ir.EnterWith(
2578
+ contextmanager=ctxmgr,
2579
+ begin=inst.offset,
2580
+ end=end,
2581
+ loc=self.loc,
2582
+ )
2583
+ )
2584
+
2585
+ # Store exit function
2586
+ exit_fn_obj = ir.Const(None, loc=self.loc)
2587
+ self.store(value=exit_fn_obj, name=exitfn)
2588
+
2589
+ def op_SETUP_FINALLY(self, inst):
2590
+ # Removed since python3.11
2591
+ self._insert_try_block_begin()
2592
+
2593
+ def op_WITH_CLEANUP(self, inst):
2594
+ "no-op"
2595
+
2596
+ def op_WITH_CLEANUP_START(self, inst):
2597
+ "no-op"
2598
+
2599
+ def op_WITH_CLEANUP_FINISH(self, inst):
2600
+ "no-op"
2601
+
2602
+ def op_END_FINALLY(self, inst):
2603
+ "no-op"
2604
+
2605
+ def op_BEGIN_FINALLY(self, inst, temps):
2606
+ # The *temps* are the exception variables
2607
+ const_none = ir.Const(None, loc=self.loc)
2608
+ for tmp in temps:
2609
+ # Set to None for now
2610
+ self.store(const_none, name=tmp)
2611
+ self._exception_vars.add(tmp)
2612
+
2613
+ def op_CALL(self, inst, func, args, kw_names, res):
2614
+ func = self.get(func)
2615
+ args = [self.get(x) for x in args]
2616
+ if kw_names is not None:
2617
+ assert PYVERSION < (3, 13)
2618
+ names = self.code_consts[kw_names]
2619
+ kwargs = list(zip(names, args[-len(names) :]))
2620
+ args = args[: -len(names)]
2621
+ else:
2622
+ kwargs = ()
2623
+ expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
2624
+ self.store(expr, res)
2625
+
2626
+ if PYVERSION in ((3, 13),):
2627
+
2628
+ def op_CALL_KW(self, inst, func, args, kw_names, res):
2629
+ func = self.get(func)
2630
+ args = [self.get(x) for x in args]
2631
+ consti = int(kw_names.rsplit(".", 2)[-1])
2632
+ names = self.code_consts[consti]
2633
+ kwargs = list(zip(names, args[-len(names) :]))
2634
+ args = args[: -len(names)]
2635
+ expr = ir.Expr.call(func, args, kwargs, loc=self.loc)
2636
+ self.store(expr, res)
2637
+ else:
2638
+ assert PYVERSION < (3, 13)
2639
+
2640
+ def op_CALL_FUNCTION(self, inst, func, args, res):
2641
+ func = self.get(func)
2642
+ args = [self.get(x) for x in args]
2643
+ expr = ir.Expr.call(func, args, (), loc=self.loc)
2644
+ self.store(expr, res)
2645
+
2646
+ def op_CALL_FUNCTION_KW(self, inst, func, args, names, res):
2647
+ func = self.get(func)
2648
+ args = [self.get(x) for x in args]
2649
+ # Find names const
2650
+ names = self.get(names)
2651
+ for inst in self.current_block.body:
2652
+ if isinstance(inst, ir.Assign) and inst.target is names:
2653
+ self.current_block.remove(inst)
2654
+ # scan up the block looking for the values, remove them
2655
+ # and find their name strings
2656
+ named_items = []
2657
+ for x in inst.value.items:
2658
+ for y in self.current_block.body[::-1]:
2659
+ if x == y.target:
2660
+ self.current_block.remove(y)
2661
+ named_items.append(y.value.value)
2662
+ break
2663
+ keys = named_items
2664
+ break
2665
+
2666
+ nkeys = len(keys)
2667
+ posvals = args[:-nkeys]
2668
+ kwvals = args[-nkeys:]
2669
+ keyvalues = list(zip(keys, kwvals))
2670
+
2671
+ expr = ir.Expr.call(func, posvals, keyvalues, loc=self.loc)
2672
+ self.store(expr, res)
2673
+
2674
+ def op_CALL_FUNCTION_EX(self, inst, func, vararg, varkwarg, res):
2675
+ func = self.get(func)
2676
+ vararg = self.get(vararg)
2677
+ if varkwarg is not None:
2678
+ varkwarg = self.get(varkwarg)
2679
+ expr = ir.Expr.call(
2680
+ func, [], [], loc=self.loc, vararg=vararg, varkwarg=varkwarg
2681
+ )
2682
+ self.store(expr, res)
2683
+
2684
+ def _build_tuple_unpack(self, inst, tuples, temps, is_assign):
2685
+ first = self.get(tuples[0])
2686
+ if is_assign:
2687
+ # it's assign-like, defer handling to an intrinsic that will have
2688
+ # type information.
2689
+ # Can deal with tuples only, i.e. y = (*x,). where x = <tuple>
2690
+ gv_name = "unpack_single_tuple"
2691
+ gv_fn = ir.Global(
2692
+ gv_name,
2693
+ unpack_single_tuple,
2694
+ loc=self.loc,
2695
+ )
2696
+ self.store(value=gv_fn, name=gv_name, redefine=True)
2697
+ exc = ir.Expr.call(
2698
+ self.get(gv_name),
2699
+ args=(first,),
2700
+ kws=(),
2701
+ loc=self.loc,
2702
+ )
2703
+ self.store(exc, temps[0])
2704
+ else:
2705
+ loc = self.loc
2706
+ for other, tmp in zip(map(self.get, tuples[1:]), temps):
2707
+ # Emit as `first + tuple(other)`
2708
+ gv_tuple = ir.Global(
2709
+ name="tuple",
2710
+ value=tuple,
2711
+ loc=loc,
2712
+ )
2713
+ tuple_var = self.store(
2714
+ gv_tuple,
2715
+ "$_list_extend_gv_tuple",
2716
+ redefine=True,
2717
+ )
2718
+ tuplify_val = ir.Expr.call(
2719
+ tuple_var,
2720
+ (other,),
2721
+ (),
2722
+ loc=loc,
2723
+ )
2724
+ tuplify_var = self.store(
2725
+ tuplify_val, "$_tuplify", redefine=True
2726
+ )
2727
+ out = ir.Expr.binop(
2728
+ fn=operator.add,
2729
+ lhs=first,
2730
+ rhs=self.get(tuplify_var.name),
2731
+ loc=self.loc,
2732
+ )
2733
+ self.store(out, tmp)
2734
+ first = self.get(tmp)
2735
+
2736
+ def op_BUILD_TUPLE_UNPACK_WITH_CALL(self, inst, tuples, temps, is_assign):
2737
+ # just unpack the input tuple, call inst will be handled afterwards
2738
+ self._build_tuple_unpack(inst, tuples, temps, is_assign)
2739
+
2740
+ def op_BUILD_TUPLE_UNPACK(self, inst, tuples, temps, is_assign):
2741
+ self._build_tuple_unpack(inst, tuples, temps, is_assign)
2742
+
2743
+ def op_LIST_TO_TUPLE(self, inst, const_list, res):
2744
+ expr = ir.Expr.dummy("list_to_tuple", (const_list,), loc=self.loc)
2745
+ self.store(expr, res)
2746
+
2747
+ def op_BUILD_CONST_KEY_MAP(self, inst, keys, keytmps, values, res):
2748
+ # Unpack the constant key-tuple and reused build_map which takes
2749
+ # a sequence of (key, value) pair.
2750
+ keyvar = self.get(keys)
2751
+ # TODO: refactor this pattern. occurred several times.
2752
+ for inst in self.current_block.body:
2753
+ if isinstance(inst, ir.Assign) and inst.target is keyvar:
2754
+ self.current_block.remove(inst)
2755
+ # scan up the block looking for the values, remove them
2756
+ # and find their name strings
2757
+ named_items = []
2758
+ for x in inst.value.items:
2759
+ for y in self.current_block.body[::-1]:
2760
+ if x == y.target:
2761
+ self.current_block.remove(y)
2762
+ named_items.append(y.value.value)
2763
+ break
2764
+ keytup = named_items
2765
+ break
2766
+ assert len(keytup) == len(values)
2767
+ keyconsts = [ir.Const(value=x, loc=self.loc) for x in keytup]
2768
+ for kval, tmp in zip(keyconsts, keytmps):
2769
+ self.store(kval, tmp)
2770
+ items = list(zip(map(self.get, keytmps), map(self.get, values)))
2771
+
2772
+ # sort out literal values
2773
+ literal_items = []
2774
+ for v in values:
2775
+ defns = self.definitions[v]
2776
+ if len(defns) != 1:
2777
+ break
2778
+ defn = defns[0]
2779
+ if not isinstance(defn, ir.Const):
2780
+ break
2781
+ literal_items.append(defn.value)
2782
+
2783
+ def resolve_const(v):
2784
+ defns = self.definitions[v]
2785
+ if len(defns) != 1:
2786
+ return _UNKNOWN_VALUE(self.get(v).name)
2787
+ defn = defns[0]
2788
+ if not isinstance(defn, ir.Const):
2789
+ return _UNKNOWN_VALUE(self.get(v).name)
2790
+ return defn.value
2791
+
2792
+ if len(literal_items) != len(values):
2793
+ literal_dict = {x: resolve_const(y) for x, y in zip(keytup, values)}
2794
+ else:
2795
+ literal_dict = {x: y for x, y in zip(keytup, literal_items)}
2796
+
2797
+ # to deal with things like {'a': 1, 'a': 'cat', 'b': 2, 'a': 2j}
2798
+ # store the index of the actual used value for a given key, this is
2799
+ # used when lowering to pull the right value out into the tuple repr
2800
+ # of a mixed value type dictionary.
2801
+ value_indexes = {}
2802
+ for i, k in enumerate(keytup):
2803
+ value_indexes[k] = i
2804
+
2805
+ expr = ir.Expr.build_map(
2806
+ items=items,
2807
+ size=2,
2808
+ literal_value=literal_dict,
2809
+ value_indexes=value_indexes,
2810
+ loc=self.loc,
2811
+ )
2812
+
2813
+ self.store(expr, res)
2814
+
2815
+ def op_GET_ITER(self, inst, value, res):
2816
+ expr = ir.Expr.getiter(value=self.get(value), loc=self.loc)
2817
+ self.store(expr, res)
2818
+
2819
+ def op_FOR_ITER(self, inst, iterator, pair, indval, pred):
2820
+ """
2821
+ Assign new block other this instruction.
2822
+ """
2823
+ assert inst.offset in self.blocks, "FOR_ITER must be block head"
2824
+
2825
+ # Emit code
2826
+ val = self.get(iterator)
2827
+
2828
+ pairval = ir.Expr.iternext(value=val, loc=self.loc)
2829
+ self.store(pairval, pair)
2830
+
2831
+ iternext = ir.Expr.pair_first(value=self.get(pair), loc=self.loc)
2832
+ self.store(iternext, indval)
2833
+
2834
+ isvalid = ir.Expr.pair_second(value=self.get(pair), loc=self.loc)
2835
+ self.store(isvalid, pred)
2836
+
2837
+ # Conditional jump
2838
+ br = ir.Branch(
2839
+ cond=self.get(pred),
2840
+ truebr=inst.next,
2841
+ falsebr=inst.get_jump_target(),
2842
+ loc=self.loc,
2843
+ )
2844
+ self.current_block.append(br)
2845
+
2846
+ def op_BINARY_SUBSCR(self, inst, target, index, res):
2847
+ index = self.get(index)
2848
+ target = self.get(target)
2849
+ expr = ir.Expr.getitem(target, index=index, loc=self.loc)
2850
+ self.store(expr, res)
2851
+
2852
+ def op_STORE_SUBSCR(self, inst, target, index, value):
2853
+ index = self.get(index)
2854
+ target = self.get(target)
2855
+ value = self.get(value)
2856
+ stmt = ir.SetItem(target=target, index=index, value=value, loc=self.loc)
2857
+ self.current_block.append(stmt)
2858
+
2859
+ def op_DELETE_SUBSCR(self, inst, target, index):
2860
+ index = self.get(index)
2861
+ target = self.get(target)
2862
+ stmt = ir.DelItem(target=target, index=index, loc=self.loc)
2863
+ self.current_block.append(stmt)
2864
+
2865
+ def op_BUILD_TUPLE(self, inst, items, res):
2866
+ expr = ir.Expr.build_tuple(
2867
+ items=[self.get(x) for x in items], loc=self.loc
2868
+ )
2869
+ self.store(expr, res)
2870
+
2871
+ def op_BUILD_LIST(self, inst, items, res):
2872
+ expr = ir.Expr.build_list(
2873
+ items=[self.get(x) for x in items], loc=self.loc
2874
+ )
2875
+ self.store(expr, res)
2876
+
2877
+ def op_BUILD_SET(self, inst, items, res):
2878
+ expr = ir.Expr.build_set(
2879
+ items=[self.get(x) for x in items], loc=self.loc
2880
+ )
2881
+ self.store(expr, res)
2882
+
2883
+ def op_SET_UPDATE(self, inst, target, value, updatevar, res):
2884
+ target = self.get(target)
2885
+ value = self.get(value)
2886
+ updateattr = ir.Expr.getattr(target, "update", loc=self.loc)
2887
+ self.store(value=updateattr, name=updatevar)
2888
+ updateinst = ir.Expr.call(
2889
+ self.get(updatevar), (value,), (), loc=self.loc
2890
+ )
2891
+ self.store(value=updateinst, name=res)
2892
+
2893
+ def op_DICT_UPDATE(self, inst, target, value, updatevar, res):
2894
+ target = self.get(target)
2895
+ value = self.get(value)
2896
+ # We generate _update_from_bytecode instead of update so we can
2897
+ # differentiate between user .update() calls and those from the
2898
+ # bytecode. This is then used to recombine dictionaries in peephole
2899
+ # optimizations. See the dicussion in this PR about why:
2900
+ # https://github.com/numba/numba/pull/7964/files#r868229306
2901
+ updateattr = ir.Expr.getattr(
2902
+ target, "_update_from_bytecode", loc=self.loc
2903
+ )
2904
+ self.store(value=updateattr, name=updatevar)
2905
+ updateinst = ir.Expr.call(
2906
+ self.get(updatevar), (value,), (), loc=self.loc
2907
+ )
2908
+ self.store(value=updateinst, name=res)
2909
+
2910
+ def op_BUILD_MAP(self, inst, items, size, res):
2911
+ got_items = [(self.get(k), self.get(v)) for k, v in items]
2912
+
2913
+ # sort out literal values, this is a bit contrived but is to handle
2914
+ # situations like `{1: 10, 1: 10}` where the size of the literal dict
2915
+ # is smaller than the definition
2916
+ def get_literals(target):
2917
+ literal_items = []
2918
+ values = [self.get(v.name) for v in target]
2919
+ for v in values:
2920
+ defns = self.definitions[v.name]
2921
+ if len(defns) != 1:
2922
+ break
2923
+ defn = defns[0]
2924
+ if not isinstance(defn, ir.Const):
2925
+ break
2926
+ literal_items.append(defn.value)
2927
+ return literal_items
2928
+
2929
+ literal_keys = get_literals(x[0] for x in got_items)
2930
+ literal_values = get_literals(x[1] for x in got_items)
2931
+
2932
+ has_literal_keys = len(literal_keys) == len(got_items)
2933
+ has_literal_values = len(literal_values) == len(got_items)
2934
+
2935
+ value_indexes = {}
2936
+ if not has_literal_keys and not has_literal_values:
2937
+ literal_dict = None
2938
+ elif has_literal_keys and not has_literal_values:
2939
+ literal_dict = {
2940
+ x: _UNKNOWN_VALUE(y[1]) for x, y in zip(literal_keys, got_items)
2941
+ }
2942
+ for i, k in enumerate(literal_keys):
2943
+ value_indexes[k] = i
2944
+ else:
2945
+ literal_dict = {x: y for x, y in zip(literal_keys, literal_values)}
2946
+ for i, k in enumerate(literal_keys):
2947
+ value_indexes[k] = i
2948
+
2949
+ expr = ir.Expr.build_map(
2950
+ items=got_items,
2951
+ size=size,
2952
+ literal_value=literal_dict,
2953
+ value_indexes=value_indexes,
2954
+ loc=self.loc,
2955
+ )
2956
+ self.store(expr, res)
2957
+
2958
+ def op_STORE_MAP(self, inst, dct, key, value):
2959
+ stmt = ir.StoreMap(
2960
+ dct=self.get(dct),
2961
+ key=self.get(key),
2962
+ value=self.get(value),
2963
+ loc=self.loc,
2964
+ )
2965
+ self.current_block.append(stmt)
2966
+
2967
+ def op_UNARY_NEGATIVE(self, inst, value, res):
2968
+ value = self.get(value)
2969
+ expr = ir.Expr.unary("-", value=value, loc=self.loc)
2970
+ return self.store(expr, res)
2971
+
2972
+ def op_UNARY_POSITIVE(self, inst, value, res):
2973
+ value = self.get(value)
2974
+ expr = ir.Expr.unary("+", value=value, loc=self.loc)
2975
+ return self.store(expr, res)
2976
+
2977
+ def op_UNARY_INVERT(self, inst, value, res):
2978
+ value = self.get(value)
2979
+ expr = ir.Expr.unary("~", value=value, loc=self.loc)
2980
+ return self.store(expr, res)
2981
+
2982
+ def op_UNARY_NOT(self, inst, value, res):
2983
+ value = self.get(value)
2984
+ expr = ir.Expr.unary("not", value=value, loc=self.loc)
2985
+ return self.store(expr, res)
2986
+
2987
+ def _binop(self, op, lhs, rhs, res):
2988
+ op = BINOPS_TO_OPERATORS[op]
2989
+ lhs = self.get(lhs)
2990
+ rhs = self.get(rhs)
2991
+ expr = ir.Expr.binop(op, lhs=lhs, rhs=rhs, loc=self.loc)
2992
+ self.store(expr, res)
2993
+
2994
+ def _inplace_binop(self, op, lhs, rhs, res):
2995
+ immuop = BINOPS_TO_OPERATORS[op]
2996
+ op = INPLACE_BINOPS_TO_OPERATORS[op + "="]
2997
+ lhs = self.get(lhs)
2998
+ rhs = self.get(rhs)
2999
+ expr = ir.Expr.inplace_binop(op, immuop, lhs=lhs, rhs=rhs, loc=self.loc)
3000
+ self.store(expr, res)
3001
+
3002
+ def op_BINARY_OP(self, inst, op, lhs, rhs, res):
3003
+ if "=" in op:
3004
+ self._inplace_binop(op[:-1], lhs, rhs, res)
3005
+ else:
3006
+ self._binop(op, lhs, rhs, res)
3007
+
3008
+ def op_BINARY_ADD(self, inst, lhs, rhs, res):
3009
+ self._binop("+", lhs, rhs, res)
3010
+
3011
+ def op_BINARY_SUBTRACT(self, inst, lhs, rhs, res):
3012
+ self._binop("-", lhs, rhs, res)
3013
+
3014
+ def op_BINARY_MULTIPLY(self, inst, lhs, rhs, res):
3015
+ self._binop("*", lhs, rhs, res)
3016
+
3017
+ def op_BINARY_DIVIDE(self, inst, lhs, rhs, res):
3018
+ self._binop("/?", lhs, rhs, res)
3019
+
3020
+ def op_BINARY_TRUE_DIVIDE(self, inst, lhs, rhs, res):
3021
+ self._binop("/", lhs, rhs, res)
3022
+
3023
+ def op_BINARY_FLOOR_DIVIDE(self, inst, lhs, rhs, res):
3024
+ self._binop("//", lhs, rhs, res)
3025
+
3026
+ def op_BINARY_MODULO(self, inst, lhs, rhs, res):
3027
+ self._binop("%", lhs, rhs, res)
3028
+
3029
+ def op_BINARY_POWER(self, inst, lhs, rhs, res):
3030
+ self._binop("**", lhs, rhs, res)
3031
+
3032
+ def op_BINARY_MATRIX_MULTIPLY(self, inst, lhs, rhs, res):
3033
+ self._binop("@", lhs, rhs, res)
3034
+
3035
+ def op_BINARY_LSHIFT(self, inst, lhs, rhs, res):
3036
+ self._binop("<<", lhs, rhs, res)
3037
+
3038
+ def op_BINARY_RSHIFT(self, inst, lhs, rhs, res):
3039
+ self._binop(">>", lhs, rhs, res)
3040
+
3041
+ def op_BINARY_AND(self, inst, lhs, rhs, res):
3042
+ self._binop("&", lhs, rhs, res)
3043
+
3044
+ def op_BINARY_OR(self, inst, lhs, rhs, res):
3045
+ self._binop("|", lhs, rhs, res)
3046
+
3047
+ def op_BINARY_XOR(self, inst, lhs, rhs, res):
3048
+ self._binop("^", lhs, rhs, res)
3049
+
3050
+ def op_INPLACE_ADD(self, inst, lhs, rhs, res):
3051
+ self._inplace_binop("+", lhs, rhs, res)
3052
+
3053
+ def op_INPLACE_SUBTRACT(self, inst, lhs, rhs, res):
3054
+ self._inplace_binop("-", lhs, rhs, res)
3055
+
3056
+ def op_INPLACE_MULTIPLY(self, inst, lhs, rhs, res):
3057
+ self._inplace_binop("*", lhs, rhs, res)
3058
+
3059
+ def op_INPLACE_DIVIDE(self, inst, lhs, rhs, res):
3060
+ self._inplace_binop("/?", lhs, rhs, res)
3061
+
3062
+ def op_INPLACE_TRUE_DIVIDE(self, inst, lhs, rhs, res):
3063
+ self._inplace_binop("/", lhs, rhs, res)
3064
+
3065
+ def op_INPLACE_FLOOR_DIVIDE(self, inst, lhs, rhs, res):
3066
+ self._inplace_binop("//", lhs, rhs, res)
3067
+
3068
+ def op_INPLACE_MODULO(self, inst, lhs, rhs, res):
3069
+ self._inplace_binop("%", lhs, rhs, res)
3070
+
3071
+ def op_INPLACE_POWER(self, inst, lhs, rhs, res):
3072
+ self._inplace_binop("**", lhs, rhs, res)
3073
+
3074
+ def op_INPLACE_MATRIX_MULTIPLY(self, inst, lhs, rhs, res):
3075
+ self._inplace_binop("@", lhs, rhs, res)
3076
+
3077
+ def op_INPLACE_LSHIFT(self, inst, lhs, rhs, res):
3078
+ self._inplace_binop("<<", lhs, rhs, res)
3079
+
3080
+ def op_INPLACE_RSHIFT(self, inst, lhs, rhs, res):
3081
+ self._inplace_binop(">>", lhs, rhs, res)
3082
+
3083
+ def op_INPLACE_AND(self, inst, lhs, rhs, res):
3084
+ self._inplace_binop("&", lhs, rhs, res)
3085
+
3086
+ def op_INPLACE_OR(self, inst, lhs, rhs, res):
3087
+ self._inplace_binop("|", lhs, rhs, res)
3088
+
3089
+ def op_INPLACE_XOR(self, inst, lhs, rhs, res):
3090
+ self._inplace_binop("^", lhs, rhs, res)
3091
+
3092
+ def op_JUMP_ABSOLUTE(self, inst):
3093
+ jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
3094
+ self.current_block.append(jmp)
3095
+
3096
+ def op_JUMP_FORWARD(self, inst):
3097
+ jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
3098
+ self.current_block.append(jmp)
3099
+
3100
+ def op_JUMP_BACKWARD(self, inst):
3101
+ jmp = ir.Jump(inst.get_jump_target(), loc=self.loc)
3102
+ self.current_block.append(jmp)
3103
+
3104
+ op_JUMP_BACKWARD_NO_INTERRUPT = op_JUMP_BACKWARD
3105
+
3106
+ def op_POP_BLOCK(self, inst, kind=None):
3107
+ if kind is None:
3108
+ self.syntax_blocks.pop()
3109
+ elif kind == "with":
3110
+ d = ir.PopBlock(loc=self.loc)
3111
+ self.current_block.append(d)
3112
+ elif kind == "try":
3113
+ self._insert_try_block_end()
3114
+
3115
+ def op_RETURN_VALUE(self, inst, retval, castval):
3116
+ self.store(ir.Expr.cast(self.get(retval), loc=self.loc), castval)
3117
+ ret = ir.Return(self.get(castval), loc=self.loc)
3118
+ self.current_block.append(ret)
3119
+
3120
+ if PYVERSION in ((3, 12), (3, 13)):
3121
+
3122
+ def op_RETURN_CONST(self, inst, retval, castval):
3123
+ value = self.code_consts[inst.arg]
3124
+ const = ir.Const(value, loc=self.loc)
3125
+ self.store(const, retval)
3126
+ self.store(ir.Expr.cast(self.get(retval), loc=self.loc), castval)
3127
+ ret = ir.Return(self.get(castval), loc=self.loc)
3128
+ self.current_block.append(ret)
3129
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
3130
+ pass
3131
+ else:
3132
+ raise NotImplementedError(PYVERSION)
3133
+
3134
+ if PYVERSION in ((3, 13),):
3135
+
3136
+ def op_TO_BOOL(self, inst, val, res):
3137
+ self.store(self.get(val), res) # TODO: just a lazy hack
3138
+
3139
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11), (3, 12)):
3140
+ pass
3141
+ else:
3142
+ raise NotImplementedError(PYVERSION)
3143
+
3144
+ def op_COMPARE_OP(self, inst, lhs, rhs, res):
3145
+ if PYVERSION in ((3, 13),):
3146
+ op = dis.cmp_op[inst.arg >> 5]
3147
+ # TODO: fifth lowest bit now indicates a forced version to bool.
3148
+ elif PYVERSION in ((3, 12),):
3149
+ op = dis.cmp_op[inst.arg >> 4]
3150
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
3151
+ op = dis.cmp_op[inst.arg]
3152
+ else:
3153
+ raise NotImplementedError(PYVERSION)
3154
+ if op == "in" or op == "not in":
3155
+ lhs, rhs = rhs, lhs
3156
+
3157
+ if op == "not in":
3158
+ self._binop("in", lhs, rhs, res)
3159
+ tmp = self.get(res)
3160
+ out = ir.Expr.unary("not", value=tmp, loc=self.loc)
3161
+ self.store(out, res)
3162
+ elif op == "exception match":
3163
+ gv_fn = ir.Global(
3164
+ "exception_match",
3165
+ eh.exception_match,
3166
+ loc=self.loc,
3167
+ )
3168
+ exc_match_name = "$exc_match"
3169
+ self.store(value=gv_fn, name=exc_match_name, redefine=True)
3170
+ lhs = self.get(lhs)
3171
+ rhs = self.get(rhs)
3172
+ exc = ir.Expr.call(
3173
+ self.get(exc_match_name),
3174
+ args=(lhs, rhs),
3175
+ kws=(),
3176
+ loc=self.loc,
3177
+ )
3178
+ self.store(exc, res)
3179
+ else:
3180
+ self._binop(op, lhs, rhs, res)
3181
+
3182
+ def op_IS_OP(self, inst, lhs, rhs, res):
3183
+ # invert if op case is 1
3184
+ op = "is not" if inst.arg == 1 else "is"
3185
+ self._binop(op, lhs, rhs, res)
3186
+
3187
+ def op_CONTAINS_OP(self, inst, lhs, rhs, res):
3188
+ lhs, rhs = rhs, lhs
3189
+ self._binop("in", lhs, rhs, res)
3190
+ # invert if op case is 1
3191
+ if inst.arg == 1:
3192
+ tmp = self.get(res)
3193
+ out = ir.Expr.unary("not", value=tmp, loc=self.loc)
3194
+ self.store(out, res)
3195
+
3196
+ def op_BREAK_LOOP(self, inst, end=None):
3197
+ if end is None:
3198
+ loop = self.syntax_blocks[-1]
3199
+ assert isinstance(loop, ir.Loop)
3200
+ end = loop.exit
3201
+ jmp = ir.Jump(target=end, loc=self.loc)
3202
+ self.current_block.append(jmp)
3203
+
3204
+ def _op_JUMP_IF(self, inst, pred, iftrue):
3205
+ brs = {
3206
+ True: inst.get_jump_target(),
3207
+ False: inst.next,
3208
+ }
3209
+ truebr = brs[iftrue]
3210
+ falsebr = brs[not iftrue]
3211
+
3212
+ name = "$bool%s" % (inst.offset)
3213
+ gv_fn = ir.Global("bool", bool, loc=self.loc)
3214
+ self.store(value=gv_fn, name=name)
3215
+
3216
+ callres = ir.Expr.call(
3217
+ self.get(name), (self.get(pred),), (), loc=self.loc
3218
+ )
3219
+
3220
+ pname = "$%spred" % (inst.offset)
3221
+ predicate = self.store(value=callres, name=pname)
3222
+ bra = ir.Branch(
3223
+ cond=predicate, truebr=truebr, falsebr=falsebr, loc=self.loc
3224
+ )
3225
+ self.current_block.append(bra)
3226
+
3227
+ def op_JUMP_IF_FALSE(self, inst, pred):
3228
+ self._op_JUMP_IF(inst, pred=pred, iftrue=False)
3229
+
3230
+ def op_JUMP_IF_TRUE(self, inst, pred):
3231
+ self._op_JUMP_IF(inst, pred=pred, iftrue=True)
3232
+
3233
+ def _jump_if_none(self, inst, pred, iftrue):
3234
+ # branch pruning assumes true falls through and false is jump
3235
+ truebr = inst.next
3236
+ falsebr = inst.get_jump_target()
3237
+
3238
+ # this seems strange
3239
+ if not iftrue:
3240
+ op = BINOPS_TO_OPERATORS["is"]
3241
+ else:
3242
+ op = BINOPS_TO_OPERATORS["is not"]
3243
+
3244
+ rhs = self.store(
3245
+ value=ir.Const(None, loc=self.loc), name=f"$constNone{inst.offset}"
3246
+ )
3247
+ lhs = self.get(pred)
3248
+ isnone = ir.Expr.binop(op, lhs=lhs, rhs=rhs, loc=self.loc)
3249
+
3250
+ maybeNone = f"$maybeNone{inst.offset}"
3251
+ self.store(value=isnone, name=maybeNone)
3252
+
3253
+ name = f"$bool{inst.offset}"
3254
+ gv_fn = ir.Global("bool", bool, loc=self.loc)
3255
+ self.store(value=gv_fn, name=name)
3256
+
3257
+ callres = ir.Expr.call(
3258
+ self.get(name), (self.get(maybeNone),), (), loc=self.loc
3259
+ )
3260
+
3261
+ pname = f"$pred{inst.offset}"
3262
+ predicate = self.store(value=callres, name=pname)
3263
+ branch = ir.Branch(
3264
+ cond=predicate, truebr=truebr, falsebr=falsebr, loc=self.loc
3265
+ )
3266
+ self.current_block.append(branch)
3267
+
3268
+ def op_POP_JUMP_FORWARD_IF_NONE(self, inst, pred):
3269
+ self._jump_if_none(inst, pred, True)
3270
+
3271
+ def op_POP_JUMP_FORWARD_IF_NOT_NONE(self, inst, pred):
3272
+ self._jump_if_none(inst, pred, False)
3273
+
3274
+ if PYVERSION in ((3, 12), (3, 13)):
3275
+
3276
+ def op_POP_JUMP_IF_NONE(self, inst, pred):
3277
+ self._jump_if_none(inst, pred, True)
3278
+
3279
+ def op_POP_JUMP_IF_NOT_NONE(self, inst, pred):
3280
+ self._jump_if_none(inst, pred, False)
3281
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
3282
+ pass
3283
+ else:
3284
+ raise NotImplementedError(PYVERSION)
3285
+
3286
+ def op_POP_JUMP_BACKWARD_IF_NONE(self, inst, pred):
3287
+ self._jump_if_none(inst, pred, True)
3288
+
3289
+ def op_POP_JUMP_BACKWARD_IF_NOT_NONE(self, inst, pred):
3290
+ self._jump_if_none(inst, pred, False)
3291
+
3292
+ def op_POP_JUMP_FORWARD_IF_FALSE(self, inst, pred):
3293
+ self._op_JUMP_IF(inst, pred=pred, iftrue=False)
3294
+
3295
+ def op_POP_JUMP_FORWARD_IF_TRUE(self, inst, pred):
3296
+ self._op_JUMP_IF(inst, pred=pred, iftrue=True)
3297
+
3298
+ def op_POP_JUMP_BACKWARD_IF_FALSE(self, inst, pred):
3299
+ self._op_JUMP_IF(inst, pred=pred, iftrue=False)
3300
+
3301
+ def op_POP_JUMP_BACKWARD_IF_TRUE(self, inst, pred):
3302
+ self._op_JUMP_IF(inst, pred=pred, iftrue=True)
3303
+
3304
+ def op_POP_JUMP_IF_FALSE(self, inst, pred):
3305
+ self._op_JUMP_IF(inst, pred=pred, iftrue=False)
3306
+
3307
+ def op_POP_JUMP_IF_TRUE(self, inst, pred):
3308
+ self._op_JUMP_IF(inst, pred=pred, iftrue=True)
3309
+
3310
+ def op_JUMP_IF_FALSE_OR_POP(self, inst, pred):
3311
+ self._op_JUMP_IF(inst, pred=pred, iftrue=False)
3312
+
3313
+ def op_JUMP_IF_TRUE_OR_POP(self, inst, pred):
3314
+ self._op_JUMP_IF(inst, pred=pred, iftrue=True)
3315
+
3316
+ def op_CHECK_EXC_MATCH(self, inst, pred, tos, tos1):
3317
+ gv_fn = ir.Global(
3318
+ "exception_match",
3319
+ eh.exception_match,
3320
+ loc=self.loc,
3321
+ )
3322
+ exc_match_name = "$exc_match"
3323
+ self.store(value=gv_fn, name=exc_match_name, redefine=True)
3324
+ lhs = self.get(tos1)
3325
+ rhs = self.get(tos)
3326
+ exc = ir.Expr.call(
3327
+ self.get(exc_match_name),
3328
+ args=(lhs, rhs),
3329
+ kws=(),
3330
+ loc=self.loc,
3331
+ )
3332
+ self.store(exc, pred)
3333
+
3334
+ def op_JUMP_IF_NOT_EXC_MATCH(self, inst, pred, tos, tos1):
3335
+ truebr = inst.next
3336
+ falsebr = inst.get_jump_target()
3337
+ gv_fn = ir.Global(
3338
+ "exception_match",
3339
+ eh.exception_match,
3340
+ loc=self.loc,
3341
+ )
3342
+ exc_match_name = "$exc_match"
3343
+ self.store(value=gv_fn, name=exc_match_name, redefine=True)
3344
+ lhs = self.get(tos1)
3345
+ rhs = self.get(tos)
3346
+ exc = ir.Expr.call(
3347
+ self.get(exc_match_name),
3348
+ args=(lhs, rhs),
3349
+ kws=(),
3350
+ loc=self.loc,
3351
+ )
3352
+ predicate = self.store(exc, pred)
3353
+ bra = ir.Branch(
3354
+ cond=predicate, truebr=truebr, falsebr=falsebr, loc=self.loc
3355
+ )
3356
+ self.current_block.append(bra)
3357
+
3358
+ def op_RERAISE(self, inst, exc):
3359
+ tryblk = self.dfainfo.active_try_block
3360
+ if tryblk is not None:
3361
+ stmt = ir.TryRaise(exception=None, loc=self.loc)
3362
+ self.current_block.append(stmt)
3363
+ self._insert_try_block_end()
3364
+ self.current_block.append(ir.Jump(tryblk["end"], loc=self.loc))
3365
+ else:
3366
+ # Numba can't handle this case and it's caught else where, this is a
3367
+ # runtime guard in case this is reached by unknown means.
3368
+ msg = (
3369
+ f"Unreachable condition reached (op code RERAISE executed)"
3370
+ f"{error_extras['reportable']}"
3371
+ )
3372
+ stmt = ir.StaticRaise(AssertionError, (msg,), self.loc)
3373
+ self.current_block.append(stmt)
3374
+
3375
+ def op_RAISE_VARARGS(self, inst, exc):
3376
+ if exc is not None:
3377
+ exc = self.get(exc)
3378
+ tryblk = self.dfainfo.active_try_block
3379
+ if tryblk is not None:
3380
+ # In a try block
3381
+ stmt = ir.TryRaise(exception=exc, loc=self.loc)
3382
+ self.current_block.append(stmt)
3383
+ self._insert_try_block_end()
3384
+ self.current_block.append(ir.Jump(tryblk["end"], loc=self.loc))
3385
+ else:
3386
+ # Not in a try block
3387
+ stmt = ir.Raise(exception=exc, loc=self.loc)
3388
+ self.current_block.append(stmt)
3389
+
3390
+ def op_YIELD_VALUE(self, inst, value, res):
3391
+ # initialize index to None. it's being set later in post-processing
3392
+ index = None
3393
+ inst = ir.Yield(value=self.get(value), index=index, loc=self.loc)
3394
+ return self.store(inst, res)
3395
+
3396
+ def op_MAKE_FUNCTION(
3397
+ self, inst, name, code, closure, annotations, kwdefaults, defaults, res
3398
+ ):
3399
+ # annotations are ignored by numba but useful for static analysis
3400
+ # re. https://github.com/numba/numba/issues/7269
3401
+ if kwdefaults is not None:
3402
+ msg = "op_MAKE_FUNCTION with kwdefaults is not implemented"
3403
+ raise NotImplementedError(msg)
3404
+ if defaults:
3405
+ if isinstance(defaults, tuple):
3406
+ defaults = tuple([self.get(name) for name in defaults])
3407
+ else:
3408
+ defaults = self.get(defaults)
3409
+
3410
+ assume_code_const = self.definitions[code][0]
3411
+ if not isinstance(assume_code_const, ir.Const):
3412
+ msg = (
3413
+ "Unsupported use of closure. "
3414
+ "Probably caused by complex control-flow constructs; "
3415
+ "e.g. try-except"
3416
+ )
3417
+ raise errors.UnsupportedBytecodeError(msg, loc=self.loc)
3418
+ fcode = assume_code_const.value
3419
+ if name:
3420
+ name = self.get(name)
3421
+ if closure:
3422
+ closure = self.get(closure)
3423
+ expr = ir.Expr.make_function(name, fcode, closure, defaults, self.loc)
3424
+ self.store(expr, res)
3425
+
3426
+ def op_MAKE_CLOSURE(
3427
+ self, inst, name, code, closure, annotations, kwdefaults, defaults, res
3428
+ ):
3429
+ self.op_MAKE_FUNCTION(
3430
+ inst, name, code, closure, annotations, kwdefaults, defaults, res
3431
+ )
3432
+
3433
+ if PYVERSION in ((3, 11), (3, 12), (3, 13)):
3434
+
3435
+ def op_LOAD_CLOSURE(self, inst, res):
3436
+ name = self.func_id.func.__code__._varname_from_oparg(inst.arg)
3437
+ if name in self.code_cellvars:
3438
+ try:
3439
+ gl = self.get(name)
3440
+ except NotDefinedError:
3441
+ msg = "Unsupported use of cell variable encountered"
3442
+ raise NotImplementedError(msg)
3443
+ elif name in self.code_freevars:
3444
+ idx = self.code_freevars.index(name)
3445
+ value = self.get_closure_value(idx)
3446
+ gl = ir.FreeVar(idx, name, value, loc=self.loc)
3447
+ else:
3448
+ assert 0, "unreachable"
3449
+ self.store(gl, res)
3450
+
3451
+ elif PYVERSION in (
3452
+ (3, 9),
3453
+ (3, 10),
3454
+ ):
3455
+
3456
+ def op_LOAD_CLOSURE(self, inst, res):
3457
+ n_cellvars = len(self.code_cellvars)
3458
+ if inst.arg < n_cellvars:
3459
+ name = self.code_cellvars[inst.arg]
3460
+ try:
3461
+ gl = self.get(name)
3462
+ except NotDefinedError:
3463
+ msg = "Unsupported use of cell variable encountered"
3464
+ raise NotImplementedError(msg)
3465
+ else:
3466
+ idx = inst.arg - n_cellvars
3467
+ name = self.code_freevars[idx]
3468
+ value = self.get_closure_value(idx)
3469
+ gl = ir.FreeVar(idx, name, value, loc=self.loc)
3470
+ self.store(gl, res)
3471
+ else:
3472
+ raise NotImplementedError(PYVERSION)
3473
+
3474
+ def op_LIST_APPEND(self, inst, target, value, appendvar, res):
3475
+ target = self.get(target)
3476
+ value = self.get(value)
3477
+ appendattr = ir.Expr.getattr(target, "append", loc=self.loc)
3478
+ self.store(value=appendattr, name=appendvar)
3479
+ appendinst = ir.Expr.call(
3480
+ self.get(appendvar), (value,), (), loc=self.loc
3481
+ )
3482
+ self.store(value=appendinst, name=res)
3483
+
3484
+ def op_LIST_EXTEND(self, inst, target, value, extendvar, res):
3485
+ target = self.get(target)
3486
+ value = self.get(value)
3487
+ # If the statements between the current instruction and the target
3488
+ # are N * consts followed by build_tuple AND the target has no items,
3489
+ # it's a situation where a list is being statically initialised, rewrite
3490
+ # the build_tuple as a build_list, drop the extend, and wire up the
3491
+ # target as the result from the build_tuple that's been rewritten.
3492
+
3493
+ # See if this is the first statement in a block, if so its probably from
3494
+ # control flow in a tuple unpack like:
3495
+ # `(*(1, (2,) if predicate else (3,)))`
3496
+ # this cannot be handled as present so raise
3497
+ msg = (
3498
+ "An unsupported bytecode sequence has been encountered: "
3499
+ "op_LIST_EXTEND at the start of a block.\n\nThis could be "
3500
+ "due to the use of a branch in a tuple unpacking statement."
3501
+ )
3502
+ if not self.current_block.body:
3503
+ raise errors.UnsupportedBytecodeError(msg)
3504
+
3505
+ # is last emitted statement a build_tuple?
3506
+ stmt = self.current_block.body[-1]
3507
+ ok = isinstance(stmt.value, ir.Expr) and stmt.value.op == "build_tuple"
3508
+ # check statements from self.current_block.body[-1] through to target,
3509
+ # make sure they are consts
3510
+ build_empty_list = None
3511
+ if ok:
3512
+ for stmt in reversed(self.current_block.body[:-1]):
3513
+ if not isinstance(stmt, ir.Assign):
3514
+ ok = False
3515
+ break
3516
+ # if its not a const, it needs to be the `build_list` for the
3517
+ # target, else it's something else we don't know about so just
3518
+ # bail
3519
+ if isinstance(stmt.value, ir.Const):
3520
+ continue
3521
+
3522
+ # it's not a const, check for target
3523
+ elif isinstance(stmt.value, ir.Expr) and stmt.target == target:
3524
+ build_empty_list = stmt
3525
+ # it's only ok to do this if the target has no initializer
3526
+ # already
3527
+ ok = not stmt.value.items
3528
+ break
3529
+ else:
3530
+ ok = False
3531
+ break
3532
+ if ok and build_empty_list is None:
3533
+ raise errors.UnsupportedBytecodeError(msg)
3534
+ if ok:
3535
+ stmts = self.current_block.body
3536
+ build_tuple_asgn = self.current_block.body[-1]
3537
+ # move build list to last issued statement
3538
+ stmts.append(stmts.pop(stmts.index(build_empty_list)))
3539
+ # fix the build list
3540
+ build_tuple = build_tuple_asgn.value
3541
+ build_list = build_empty_list.value
3542
+ build_list.items = build_tuple.items
3543
+ else:
3544
+ # it's just a list extend with no static init, let it be
3545
+ extendattr = ir.Expr.getattr(target, "extend", loc=self.loc)
3546
+ self.store(value=extendattr, name=extendvar)
3547
+ extendinst = ir.Expr.call(
3548
+ self.get(extendvar), (value,), (), loc=self.loc
3549
+ )
3550
+ self.store(value=extendinst, name=res)
3551
+
3552
+ def op_MAP_ADD(self, inst, target, key, value, setitemvar, res):
3553
+ target = self.get(target)
3554
+ key = self.get(key)
3555
+ value = self.get(value)
3556
+ setitemattr = ir.Expr.getattr(target, "__setitem__", loc=self.loc)
3557
+ self.store(value=setitemattr, name=setitemvar)
3558
+ appendinst = ir.Expr.call(
3559
+ self.get(setitemvar),
3560
+ (
3561
+ key,
3562
+ value,
3563
+ ),
3564
+ (),
3565
+ loc=self.loc,
3566
+ )
3567
+ self.store(value=appendinst, name=res)
3568
+
3569
+ def op_LOAD_ASSERTION_ERROR(self, inst, res):
3570
+ gv_fn = ir.Global("AssertionError", AssertionError, loc=self.loc)
3571
+ self.store(value=gv_fn, name=res)
3572
+
3573
+ # NOTE: The LOAD_METHOD opcode is implemented as a LOAD_ATTR for ease,
3574
+ # however this means a new object (the bound-method instance) could be
3575
+ # created. Conversely, using a pure LOAD_METHOD no intermediary is present
3576
+ # and it is essentially like a pointer grab and forward to CALL_METHOD. The
3577
+ # net outcome is that the implementation in Numba produces the same result,
3578
+ # but in object mode it may be that it runs more slowly than it would if
3579
+ # run in CPython.
3580
+
3581
+ def op_LOAD_METHOD(self, *args, **kws):
3582
+ self.op_LOAD_ATTR(*args, **kws)
3583
+
3584
+ def op_CALL_METHOD(self, *args, **kws):
3585
+ self.op_CALL_FUNCTION(*args, **kws)
3586
+
3587
+ if PYVERSION in ((3, 12), (3, 13)):
3588
+
3589
+ def op_CALL_INTRINSIC_1(self, inst, operand, **kwargs):
3590
+ if operand == ci1op.INTRINSIC_STOPITERATION_ERROR:
3591
+ stmt = ir.StaticRaise(
3592
+ INTRINSIC_STOPITERATION_ERROR, (), self.loc
3593
+ )
3594
+ self.current_block.append(stmt)
3595
+ return
3596
+ elif operand == ci1op.UNARY_POSITIVE:
3597
+ self.op_UNARY_POSITIVE(inst, **kwargs)
3598
+ return
3599
+ elif operand == ci1op.INTRINSIC_LIST_TO_TUPLE:
3600
+ self.op_LIST_TO_TUPLE(inst, **kwargs)
3601
+ return
3602
+ else:
3603
+ raise NotImplementedError(operand)
3604
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
3605
+ pass
3606
+ else:
3607
+ raise NotImplementedError(PYVERSION)
3608
+
3609
+
3610
+ if PYVERSION in ((3, 12), (3, 13)):
3611
+
3612
+ class INTRINSIC_STOPITERATION_ERROR(AssertionError):
3613
+ pass
3614
+ elif PYVERSION in ((3, 9), (3, 10), (3, 11)):
3615
+ pass
3616
+ else:
3617
+ raise NotImplementedError(PYVERSION)