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,1433 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: BSD-2-Clause
3
+
4
+ import itertools
5
+
6
+ import unittest
7
+ from numba.cuda import jit
8
+ from numba.cuda.core.controlflow import CFGraph, ControlFlowAnalysis
9
+ from numba.cuda import types
10
+ from numba.cuda.core.bytecode import (
11
+ FunctionIdentity,
12
+ ByteCode,
13
+ _fix_LOAD_GLOBAL_arg,
14
+ )
15
+ from numba.cuda.tests.support import TestCase
16
+ from numba.cuda import utils
17
+ from numba.cuda.core import config
18
+
19
+ if config.ENABLE_CUDASIM:
20
+ raise unittest.SkipTest("Analysis passes not done in simulator")
21
+
22
+
23
+ def for_loop_usecase1(x, y, res1, res2):
24
+ result = 0
25
+ for i in range(x):
26
+ result += i
27
+ res1 = result # noqa: F841
28
+
29
+
30
+ def for_loop_usecase2(x, y, res1, res2):
31
+ result = 0
32
+ for i, j in enumerate(range(x, y, -1)):
33
+ result += i * j
34
+ res1 = result # noqa: F841
35
+
36
+
37
+ def for_loop_usecase4(x, y, res1, res2):
38
+ result = 0
39
+ for i in range(10):
40
+ for j in range(10):
41
+ result += 1
42
+ res1 = result # noqa: F841
43
+
44
+
45
+ def for_loop_usecase5(x, y, res1, res2):
46
+ result = 0
47
+ for i in range(x):
48
+ result += 1
49
+ if result > y:
50
+ break
51
+ res1 = result # noqa: F841
52
+
53
+
54
+ def for_loop_usecase6(x, y, res1, res2):
55
+ result = 0
56
+ for i in range(x):
57
+ if i > y:
58
+ continue
59
+ result += 1
60
+ res1 = result # noqa: F841
61
+
62
+
63
+ def for_loop_usecase7(x, y, res1, res2):
64
+ for i in range(x):
65
+ x = 0
66
+ for j in range(x):
67
+ res1 = 1 # noqa: F841
68
+ else:
69
+ pass
70
+ res1 = 0 # noqa: F841
71
+
72
+
73
+ def for_loop_usecase8(x, y, res1, res2):
74
+ result = 0
75
+ for i in range(x, y, y - x + 1):
76
+ result += 1
77
+ res1 = result # noqa: F841
78
+
79
+
80
+ def for_loop_usecase9(x, y, res1, res2):
81
+ z = 0
82
+ for i in range(x):
83
+ x = 0
84
+ for j in range(x):
85
+ if j == x / 2:
86
+ z += j
87
+ break
88
+ else:
89
+ z += y
90
+
91
+ res1 = z # noqa: F841
92
+
93
+
94
+ def for_loop_usecase10(x, y, res1, res2):
95
+ for i in range(x):
96
+ if i == y:
97
+ z = y
98
+ break
99
+ else:
100
+ z = i * 2
101
+ res1 = z # noqa: F841
102
+
103
+
104
+ def while_loop_usecase1(x, y, res1, res2):
105
+ result = 0
106
+ i = 0
107
+ while i < x:
108
+ result += i
109
+ i += 1
110
+ res1 = result # noqa: F841
111
+
112
+
113
+ def while_loop_usecase2(x, y, res1, res2):
114
+ result = 0
115
+ while result != x:
116
+ result += 1
117
+ res1 = result # noqa: F841
118
+
119
+
120
+ def while_loop_usecase3(x, y, res1, res2):
121
+ result = 0
122
+ i = 0
123
+ j = 0
124
+ while i < x:
125
+ while j < y:
126
+ result += i + j
127
+ i += 1
128
+ j += 1
129
+ res1 = result # noqa: F841
130
+
131
+
132
+ def while_loop_usecase4(x, y, res1, res2):
133
+ result = 0
134
+ while True:
135
+ result += 1
136
+ if result > x:
137
+ break
138
+ res1 = result # noqa: F841
139
+
140
+
141
+ def while_loop_usecase5(x, y, res1, res2):
142
+ result = 0
143
+ while result < x:
144
+ if result > y:
145
+ result += 2
146
+ continue
147
+ result += 1
148
+ res1 = result # noqa: F841
149
+
150
+
151
+ def ifelse_usecase1(x, y, res1, res2):
152
+ if x > 0:
153
+ pass
154
+ elif y > 0:
155
+ pass
156
+ else:
157
+ pass
158
+ res1 = True # noqa: F841
159
+
160
+
161
+ def ifelse_usecase2(x, y, res1, res2):
162
+ if x > y:
163
+ res1 = 1 # noqa: F841
164
+ elif x == 0 or y == 0:
165
+ res1 = 2 # noqa: F841
166
+ else:
167
+ res1 = 3 # noqa: F841
168
+
169
+
170
+ def ifelse_usecase3(x, y, res1, res2):
171
+ if x > 0:
172
+ if y > 0:
173
+ res1 = 1 # noqa: F841
174
+ elif y < 0:
175
+ res1 = 1 # noqa: F841
176
+ else:
177
+ res1 = 0 # noqa: F841
178
+ elif x < 0:
179
+ res1 = 1 # noqa: F841
180
+ else:
181
+ res1 = 0 # noqa: F841
182
+
183
+
184
+ def ifelse_usecase4(x, y, res1, res2):
185
+ if x == y:
186
+ res1 = 1 # noqa: F841
187
+
188
+
189
+ def ternary_ifelse_usecase1(x, y, res1, res2):
190
+ res1 = True if x > y else False # noqa: F841
191
+
192
+
193
+ def double_infinite_loop(x, y, res1, res2):
194
+ L = x
195
+ i = y
196
+
197
+ while True:
198
+ while True:
199
+ if i == L - 1:
200
+ break
201
+ i += 1
202
+ i += 1
203
+ if i >= L:
204
+ break
205
+
206
+ res1 = i # noqa: F841
207
+ res2 = L # noqa: F841
208
+
209
+
210
+ def try_except_usecase():
211
+ try:
212
+ pass
213
+ except Exception:
214
+ pass
215
+
216
+
217
+ class TestFlowControl(TestCase):
218
+ def run_test(
219
+ self,
220
+ pyfunc,
221
+ x_operands,
222
+ y_operands,
223
+ res1_operands,
224
+ res2_operands,
225
+ ):
226
+ cfunc = jit((types.intp, types.intp, types.intp, types.intp))(pyfunc)
227
+ for x, y, res1, res2 in itertools.product(
228
+ x_operands, y_operands, res1_operands, res2_operands
229
+ ):
230
+ pyerr = None
231
+ cerr = None
232
+ try:
233
+ pyfunc(x, y, res1, res2)
234
+ except Exception as e:
235
+ pyerr = e
236
+
237
+ cres1 = 0
238
+ cres2 = 0
239
+ try:
240
+ cfunc[1, 1](x, y, cres1, cres2)
241
+ except Exception as e:
242
+ if pyerr is None:
243
+ raise
244
+ cerr = e
245
+ self.assertEqual(type(pyerr), type(cerr))
246
+ else:
247
+ if pyerr is not None:
248
+ self.fail(
249
+ "Invalid for pure-python but numba-cuda works\n"
250
+ + str(pyerr)
251
+ )
252
+ self.assertEqual(res1, cres1)
253
+ self.assertEqual(res2, cres2)
254
+
255
+ def test_for_loop1(self):
256
+ self.run_test(for_loop_usecase1, [-10, 0, 10], [0], [0], [0])
257
+
258
+ def test_for_loop1_npm(self):
259
+ self.test_for_loop1()
260
+
261
+ def test_for_loop2(self):
262
+ self.run_test(for_loop_usecase2, [-10, 0, 10], [-10, 0, 10], [0], [0])
263
+
264
+ def test_for_loop2_npm(self):
265
+ self.test_for_loop2()
266
+
267
+ def test_for_loop4(self):
268
+ self.run_test(for_loop_usecase4, [10], [10], [0], [0])
269
+
270
+ def test_for_loop4_npm(self):
271
+ self.test_for_loop4()
272
+
273
+ def test_for_loop5(self):
274
+ self.run_test(for_loop_usecase5, [100], [50], [0], [0])
275
+
276
+ def test_for_loop5_npm(self):
277
+ self.test_for_loop5()
278
+
279
+ def test_for_loop6(self):
280
+ self.run_test(for_loop_usecase6, [100], [50], [0], [0])
281
+
282
+ def test_for_loop6_npm(self):
283
+ self.test_for_loop6()
284
+
285
+ def test_for_loop7(self):
286
+ self.run_test(for_loop_usecase7, [5], [0], [0], [0])
287
+
288
+ def test_for_loop7_npm(self):
289
+ self.test_for_loop7()
290
+
291
+ @unittest.expectedFailure
292
+ def test_for_loop8(self):
293
+ self.run_test(for_loop_usecase8, [0, 1], [0, 2, 10], [0], [0])
294
+
295
+ @unittest.expectedFailure
296
+ def test_for_loop8_npm(self):
297
+ self.test_for_loop8()
298
+
299
+ def test_for_loop9(self):
300
+ self.run_test(for_loop_usecase9, [0, 1], [0, 2, 10], [0], [0])
301
+
302
+ def test_for_loop9_npm(self):
303
+ self.test_for_loop9()
304
+
305
+ def test_for_loop10(self):
306
+ self.run_test(for_loop_usecase10, [5], [2, 7], [0], [0])
307
+
308
+ def test_for_loop10_npm(self):
309
+ self.test_for_loop10()
310
+
311
+ def test_while_loop1(self):
312
+ self.run_test(while_loop_usecase1, [10], [0], [0], [0])
313
+
314
+ def test_while_loop1_npm(self):
315
+ self.test_while_loop1()
316
+
317
+ def test_while_loop2(self):
318
+ self.run_test(while_loop_usecase2, [10], [0], [0], [0])
319
+
320
+ def test_while_loop2_npm(self):
321
+ self.test_while_loop2()
322
+
323
+ def test_while_loop3(self):
324
+ self.run_test(while_loop_usecase3, [10], [10], [0], [0])
325
+
326
+ def test_while_loop3_npm(self):
327
+ self.test_while_loop3()
328
+
329
+ def test_while_loop4(self):
330
+ self.run_test(while_loop_usecase4, [10], [0], [0], [0])
331
+
332
+ def test_while_loop4_npm(self):
333
+ self.test_while_loop4()
334
+
335
+ def test_while_loop5(self):
336
+ self.run_test(while_loop_usecase5, [0, 5, 10], [0, 5, 10], [0], [0])
337
+
338
+ def test_while_loop5_npm(self):
339
+ self.test_while_loop5()
340
+
341
+ def test_ifelse1(self):
342
+ self.run_test(ifelse_usecase1, [-1, 0, 1], [-1, 0, 1], [0], [0])
343
+
344
+ def test_ifelse1_npm(self):
345
+ self.test_ifelse1()
346
+
347
+ def test_ifelse2(self):
348
+ self.run_test(ifelse_usecase2, [-1, 0, 1], [-1, 0, 1], [0], [0])
349
+
350
+ def test_ifelse2_npm(self):
351
+ self.test_ifelse2()
352
+
353
+ def test_ifelse3(self):
354
+ self.run_test(ifelse_usecase3, [-1, 0, 1], [-1, 0, 1], [0], [0])
355
+
356
+ def test_ifelse3_npm(self):
357
+ self.test_ifelse3()
358
+
359
+ def test_ifelse4(self):
360
+ self.run_test(ifelse_usecase4, [-1, 0, 1], [-1, 0, 1], [0], [0])
361
+
362
+ def test_ifelse4_npm(self):
363
+ self.test_ifelse4()
364
+
365
+ def test_ternary_ifelse1(self):
366
+ self.run_test(
367
+ ternary_ifelse_usecase1,
368
+ [-1, 0, 1],
369
+ [-1, 0, 1],
370
+ [0],
371
+ [0],
372
+ )
373
+
374
+ def test_ternary_ifelse1_npm(self):
375
+ self.test_ternary_ifelse1()
376
+
377
+ def test_double_infinite_loop(self):
378
+ self.run_test(double_infinite_loop, [10], [0], [0], [0])
379
+
380
+ def test_double_infinite_loop_npm(self):
381
+ self.test_double_infinite_loop()
382
+
383
+
384
+ class TestCFGraph(TestCase):
385
+ """
386
+ Test the numba.controlflow.CFGraph class.
387
+ """
388
+
389
+ def from_adj_list(self, d, entry_point=0):
390
+ """
391
+ Build a CFGraph class from a dict of adjacency lists.
392
+ """
393
+ g = CFGraph()
394
+ # Need to add all nodes before adding edges
395
+ for node in d:
396
+ g.add_node(node)
397
+ for node, dests in d.items():
398
+ for dest in dests:
399
+ g.add_edge(node, dest)
400
+ return g
401
+
402
+ def loopless1(self):
403
+ """
404
+ A simple CFG corresponding to the following code structure:
405
+
406
+ c = (... if ... else ...) + ...
407
+ return b + c
408
+ """
409
+ g = self.from_adj_list({0: [18, 12], 12: [21], 18: [21], 21: []})
410
+ g.set_entry_point(0)
411
+ g.process()
412
+ return g
413
+
414
+ def loopless1_dead_nodes(self):
415
+ """
416
+ Same as loopless1(), but with added dead blocks (some of them
417
+ in a loop).
418
+ """
419
+ g = self.from_adj_list(
420
+ {
421
+ 0: [18, 12],
422
+ 12: [21],
423
+ 18: [21],
424
+ 21: [],
425
+ 91: [12, 0],
426
+ 92: [91, 93],
427
+ 93: [92],
428
+ 94: [],
429
+ }
430
+ )
431
+ g.set_entry_point(0)
432
+ g.process()
433
+ return g
434
+
435
+ def loopless2(self):
436
+ """
437
+ A loopless CFG corresponding to the following code structure:
438
+
439
+ c = (... if ... else ...) + ...
440
+ if c:
441
+ return ...
442
+ else:
443
+ return ...
444
+
445
+ Note there are two exit points, and the entry point has been
446
+ changed to a non-zero value.
447
+ """
448
+ g = self.from_adj_list(
449
+ {99: [18, 12], 12: [21], 18: [21], 21: [42, 34], 34: [], 42: []}
450
+ )
451
+ g.set_entry_point(99)
452
+ g.process()
453
+ return g
454
+
455
+ def multiple_loops(self):
456
+ """
457
+ A CFG with multiple nested loops:
458
+
459
+ for y in b:
460
+ for x in a:
461
+ # This loop has two back edges
462
+ if b:
463
+ continue
464
+ else:
465
+ continue
466
+ for z in c:
467
+ if z:
468
+ return ...
469
+ """
470
+ g = self.from_adj_list(
471
+ {
472
+ 0: [7],
473
+ 7: [10, 60],
474
+ 10: [13],
475
+ 13: [20],
476
+ 20: [56, 23],
477
+ 23: [32, 44],
478
+ 32: [20],
479
+ 44: [20],
480
+ 56: [57],
481
+ 57: [7],
482
+ 60: [61],
483
+ 61: [68],
484
+ 68: [87, 71],
485
+ 71: [80, 68],
486
+ 80: [],
487
+ 87: [88],
488
+ 88: [],
489
+ }
490
+ )
491
+ g.set_entry_point(0)
492
+ g.process()
493
+ return g
494
+
495
+ def multiple_exits(self):
496
+ """
497
+ A CFG with three loop exits, one of which is also a function
498
+ exit point, and another function exit point:
499
+
500
+ for x in a:
501
+ if a:
502
+ return b
503
+ elif b:
504
+ break
505
+ return c
506
+ """
507
+ g = self.from_adj_list(
508
+ {
509
+ 0: [7],
510
+ 7: [10, 36],
511
+ 10: [19, 23],
512
+ 19: [],
513
+ 23: [29, 7],
514
+ 29: [37],
515
+ 36: [37],
516
+ 37: [],
517
+ }
518
+ )
519
+ g.set_entry_point(0)
520
+ g.process()
521
+ return g
522
+
523
+ def infinite_loop1(self):
524
+ """
525
+ A CFG with a infinite loop and an alternate exit point:
526
+
527
+ if c:
528
+ return
529
+ while True:
530
+ if a:
531
+ ...
532
+ else:
533
+ ...
534
+ """
535
+ g = self.from_adj_list(
536
+ {0: [10, 6], 6: [], 10: [13], 13: [26, 19], 19: [13], 26: [13]}
537
+ )
538
+ g.set_entry_point(0)
539
+ g.process()
540
+ return g
541
+
542
+ def infinite_loop2(self):
543
+ """
544
+ A CFG with no exit point at all:
545
+
546
+ while True:
547
+ if a:
548
+ ...
549
+ else:
550
+ ...
551
+ """
552
+ g = self.from_adj_list({0: [3], 3: [16, 9], 9: [3], 16: [3]})
553
+ g.set_entry_point(0)
554
+ g.process()
555
+ return g
556
+
557
+ def test_simple_properties(self):
558
+ g = self.loopless1()
559
+ self.assertEqual(sorted(g.successors(0)), [(12, None), (18, None)])
560
+ self.assertEqual(sorted(g.successors(21)), [])
561
+ self.assertEqual(sorted(g.predecessors(0)), [])
562
+ self.assertEqual(sorted(g.predecessors(21)), [(12, None), (18, None)])
563
+
564
+ def test_exit_points(self):
565
+ g = self.loopless1()
566
+ self.assertEqual(sorted(g.exit_points()), [21])
567
+ g = self.loopless1_dead_nodes()
568
+ self.assertEqual(sorted(g.exit_points()), [21])
569
+ g = self.loopless2()
570
+ self.assertEqual(sorted(g.exit_points()), [34, 42])
571
+ g = self.multiple_loops()
572
+ self.assertEqual(sorted(g.exit_points()), [80, 88])
573
+ g = self.infinite_loop1()
574
+ self.assertEqual(sorted(g.exit_points()), [6])
575
+ g = self.infinite_loop2()
576
+ self.assertEqual(sorted(g.exit_points()), [])
577
+ g = self.multiple_exits()
578
+ self.assertEqual(sorted(g.exit_points()), [19, 37])
579
+
580
+ def test_dead_nodes(self):
581
+ g = self.loopless1()
582
+ self.assertEqual(len(g.dead_nodes()), 0)
583
+ self.assertEqual(sorted(g.nodes()), [0, 12, 18, 21])
584
+ g = self.loopless2()
585
+ self.assertEqual(len(g.dead_nodes()), 0)
586
+ self.assertEqual(sorted(g.nodes()), [12, 18, 21, 34, 42, 99])
587
+ g = self.multiple_loops()
588
+ self.assertEqual(len(g.dead_nodes()), 0)
589
+ g = self.infinite_loop1()
590
+ self.assertEqual(len(g.dead_nodes()), 0)
591
+ g = self.multiple_exits()
592
+ self.assertEqual(len(g.dead_nodes()), 0)
593
+ # Only this example has dead nodes
594
+ g = self.loopless1_dead_nodes()
595
+ self.assertEqual(sorted(g.dead_nodes()), [91, 92, 93, 94])
596
+ self.assertEqual(sorted(g.nodes()), [0, 12, 18, 21])
597
+
598
+ def test_descendents(self):
599
+ g = self.loopless2()
600
+ d = g.descendents(34)
601
+ self.assertEqual(sorted(d), [])
602
+ d = g.descendents(42)
603
+ self.assertEqual(sorted(d), [])
604
+ d = g.descendents(21)
605
+ self.assertEqual(sorted(d), [34, 42])
606
+ d = g.descendents(99)
607
+ self.assertEqual(sorted(d), [12, 18, 21, 34, 42])
608
+ g = self.infinite_loop1()
609
+ d = g.descendents(26)
610
+ self.assertEqual(sorted(d), [])
611
+ d = g.descendents(19)
612
+ self.assertEqual(sorted(d), [])
613
+ d = g.descendents(13)
614
+ self.assertEqual(sorted(d), [19, 26])
615
+ d = g.descendents(10)
616
+ self.assertEqual(sorted(d), [13, 19, 26])
617
+ d = g.descendents(6)
618
+ self.assertEqual(sorted(d), [])
619
+ d = g.descendents(0)
620
+ self.assertEqual(sorted(d), [6, 10, 13, 19, 26])
621
+
622
+ def test_topo_order(self):
623
+ g = self.loopless1()
624
+ self.assertIn(g.topo_order(), ([0, 12, 18, 21], [0, 18, 12, 21]))
625
+ g = self.loopless2()
626
+ self.assertIn(
627
+ g.topo_order(), ([99, 18, 12, 21, 34, 42], [99, 12, 18, 21, 34, 42])
628
+ )
629
+ g = self.infinite_loop2()
630
+ self.assertIn(g.topo_order(), ([0, 3, 9, 16], [0, 3, 16, 9]))
631
+ g = self.infinite_loop1()
632
+ self.assertIn(
633
+ g.topo_order(),
634
+ (
635
+ [0, 6, 10, 13, 19, 26],
636
+ [0, 6, 10, 13, 26, 19],
637
+ [0, 10, 13, 19, 26, 6],
638
+ [0, 10, 13, 26, 19, 6],
639
+ ),
640
+ )
641
+
642
+ def test_topo_sort(self):
643
+ def check_topo_sort(nodes, expected):
644
+ self.assertIn(list(g.topo_sort(nodes)), expected)
645
+ self.assertIn(list(g.topo_sort(nodes[::-1])), expected)
646
+ self.assertIn(
647
+ list(g.topo_sort(nodes, reverse=True))[::-1], expected
648
+ )
649
+ self.assertIn(
650
+ list(g.topo_sort(nodes[::-1], reverse=True))[::-1], expected
651
+ )
652
+ self.random.shuffle(nodes)
653
+ self.assertIn(list(g.topo_sort(nodes)), expected)
654
+ self.assertIn(
655
+ list(g.topo_sort(nodes, reverse=True))[::-1], expected
656
+ )
657
+
658
+ g = self.loopless2()
659
+ check_topo_sort([21, 99, 12, 34], ([99, 12, 21, 34],))
660
+ # NOTE: topo_sort() is not stable
661
+ check_topo_sort([18, 12, 42, 99], ([99, 12, 18, 42], [99, 18, 12, 42]))
662
+ g = self.multiple_exits()
663
+ check_topo_sort(
664
+ [19, 10, 7, 36], ([7, 10, 19, 36], [7, 10, 36, 19], [7, 36, 10, 19])
665
+ )
666
+
667
+ def check_dominators(self, got, expected):
668
+ self.assertEqual(sorted(got), sorted(expected))
669
+ for node in sorted(got):
670
+ self.assertEqual(
671
+ sorted(got[node]),
672
+ sorted(expected[node]),
673
+ "mismatch for %r" % (node,),
674
+ )
675
+
676
+ def test_dominators_loopless(self):
677
+ def eq_(d, l):
678
+ self.assertEqual(sorted(doms[d]), l)
679
+
680
+ for g in [self.loopless1(), self.loopless1_dead_nodes()]:
681
+ doms = g.dominators()
682
+ eq_(0, [0])
683
+ eq_(12, [0, 12])
684
+ eq_(18, [0, 18])
685
+ eq_(21, [0, 21])
686
+ g = self.loopless2()
687
+ doms = g.dominators()
688
+ eq_(99, [99])
689
+ eq_(12, [12, 99])
690
+ eq_(18, [18, 99])
691
+ eq_(21, [21, 99])
692
+ eq_(34, [21, 34, 99])
693
+ eq_(42, [21, 42, 99])
694
+
695
+ def test_dominators_loops(self):
696
+ g = self.multiple_exits()
697
+ doms = g.dominators()
698
+ self.check_dominators(
699
+ doms,
700
+ {
701
+ 0: [0],
702
+ 7: [0, 7],
703
+ 10: [0, 7, 10],
704
+ 19: [0, 7, 10, 19],
705
+ 23: [0, 7, 10, 23],
706
+ 29: [0, 7, 10, 23, 29],
707
+ 36: [0, 7, 36],
708
+ 37: [0, 7, 37],
709
+ },
710
+ )
711
+ g = self.multiple_loops()
712
+ doms = g.dominators()
713
+ self.check_dominators(
714
+ doms,
715
+ {
716
+ 0: [0],
717
+ 7: [0, 7],
718
+ 10: [0, 10, 7],
719
+ 13: [0, 10, 13, 7],
720
+ 20: [0, 10, 20, 13, 7],
721
+ 23: [0, 20, 23, 7, 10, 13],
722
+ 32: [32, 0, 20, 23, 7, 10, 13],
723
+ 44: [0, 20, 23, 7, 10, 44, 13],
724
+ 56: [0, 20, 7, 56, 10, 13],
725
+ 57: [0, 20, 7, 56, 57, 10, 13],
726
+ 60: [0, 60, 7],
727
+ 61: [0, 60, 61, 7],
728
+ 68: [0, 68, 60, 61, 7],
729
+ 71: [0, 68, 71, 7, 60, 61],
730
+ 80: [80, 0, 68, 71, 7, 60, 61],
731
+ 87: [0, 68, 87, 7, 60, 61],
732
+ 88: [0, 68, 87, 88, 7, 60, 61],
733
+ },
734
+ )
735
+ g = self.infinite_loop1()
736
+ doms = g.dominators()
737
+ self.check_dominators(
738
+ doms,
739
+ {
740
+ 0: [0],
741
+ 6: [0, 6],
742
+ 10: [0, 10],
743
+ 13: [0, 10, 13],
744
+ 19: [0, 10, 19, 13],
745
+ 26: [0, 10, 13, 26],
746
+ },
747
+ )
748
+
749
+ def test_post_dominators_loopless(self):
750
+ def eq_(d, l):
751
+ self.assertEqual(sorted(doms[d]), l)
752
+
753
+ for g in [self.loopless1(), self.loopless1_dead_nodes()]:
754
+ doms = g.post_dominators()
755
+ eq_(0, [0, 21])
756
+ eq_(12, [12, 21])
757
+ eq_(18, [18, 21])
758
+ eq_(21, [21])
759
+ g = self.loopless2()
760
+ doms = g.post_dominators()
761
+ eq_(34, [34])
762
+ eq_(42, [42])
763
+ eq_(21, [21])
764
+ eq_(18, [18, 21])
765
+ eq_(12, [12, 21])
766
+ eq_(99, [21, 99])
767
+
768
+ def test_post_dominators_loops(self):
769
+ g = self.multiple_exits()
770
+ doms = g.post_dominators()
771
+ self.check_dominators(
772
+ doms,
773
+ {
774
+ 0: [0, 7],
775
+ 7: [7],
776
+ 10: [10],
777
+ 19: [19],
778
+ 23: [23],
779
+ 29: [29, 37],
780
+ 36: [36, 37],
781
+ 37: [37],
782
+ },
783
+ )
784
+ g = self.multiple_loops()
785
+ doms = g.post_dominators()
786
+ self.check_dominators(
787
+ doms,
788
+ {
789
+ 0: [0, 60, 68, 61, 7],
790
+ 7: [60, 68, 61, 7],
791
+ 10: [68, 7, 10, 13, 20, 56, 57, 60, 61],
792
+ 13: [68, 7, 13, 20, 56, 57, 60, 61],
793
+ 20: [20, 68, 7, 56, 57, 60, 61],
794
+ 23: [68, 7, 20, 23, 56, 57, 60, 61],
795
+ 32: [32, 68, 7, 20, 56, 57, 60, 61],
796
+ 44: [68, 7, 44, 20, 56, 57, 60, 61],
797
+ 56: [68, 7, 56, 57, 60, 61],
798
+ 57: [57, 60, 68, 61, 7],
799
+ 60: [60, 68, 61],
800
+ 61: [68, 61],
801
+ 68: [68],
802
+ 71: [71],
803
+ 80: [80],
804
+ 87: [88, 87],
805
+ 88: [88],
806
+ },
807
+ )
808
+
809
+ def test_post_dominators_infinite_loops(self):
810
+ # Post-dominators with infinite loops need special care
811
+ # (the ordinary algorithm won't work).
812
+ g = self.infinite_loop1()
813
+ doms = g.post_dominators()
814
+ self.check_dominators(
815
+ doms,
816
+ {
817
+ 0: [0],
818
+ 6: [6],
819
+ 10: [10, 13],
820
+ 13: [13],
821
+ 19: [19],
822
+ 26: [26],
823
+ },
824
+ )
825
+ g = self.infinite_loop2()
826
+ doms = g.post_dominators()
827
+ self.check_dominators(
828
+ doms,
829
+ {
830
+ 0: [0, 3],
831
+ 3: [3],
832
+ 9: [9],
833
+ 16: [16],
834
+ },
835
+ )
836
+
837
+ def test_dominator_tree(self):
838
+ def check(graph, expected):
839
+ domtree = graph.dominator_tree()
840
+ self.assertEqual(domtree, expected)
841
+
842
+ check(
843
+ self.loopless1(), {0: {12, 18, 21}, 12: set(), 18: set(), 21: set()}
844
+ )
845
+ check(
846
+ self.loopless2(),
847
+ {
848
+ 12: set(),
849
+ 18: set(),
850
+ 21: {34, 42},
851
+ 34: set(),
852
+ 42: set(),
853
+ 99: {18, 12, 21},
854
+ },
855
+ )
856
+ check(
857
+ self.loopless1_dead_nodes(),
858
+ {0: {12, 18, 21}, 12: set(), 18: set(), 21: set()},
859
+ )
860
+ check(
861
+ self.multiple_loops(),
862
+ {
863
+ 0: {7},
864
+ 7: {10, 60},
865
+ 60: {61},
866
+ 61: {68},
867
+ 68: {71, 87},
868
+ 87: {88},
869
+ 88: set(),
870
+ 71: {80},
871
+ 80: set(),
872
+ 10: {13},
873
+ 13: {20},
874
+ 20: {56, 23},
875
+ 23: {32, 44},
876
+ 44: set(),
877
+ 32: set(),
878
+ 56: {57},
879
+ 57: set(),
880
+ },
881
+ )
882
+ check(
883
+ self.multiple_exits(),
884
+ {
885
+ 0: {7},
886
+ 7: {10, 36, 37},
887
+ 36: set(),
888
+ 10: {19, 23},
889
+ 23: {29},
890
+ 29: set(),
891
+ 37: set(),
892
+ 19: set(),
893
+ },
894
+ )
895
+ check(
896
+ self.infinite_loop1(),
897
+ {
898
+ 0: {10, 6},
899
+ 6: set(),
900
+ 10: {13},
901
+ 13: {26, 19},
902
+ 19: set(),
903
+ 26: set(),
904
+ },
905
+ )
906
+ check(self.infinite_loop2(), {0: {3}, 3: {16, 9}, 9: set(), 16: set()})
907
+
908
+ def test_immediate_dominators(self):
909
+ def check(graph, expected):
910
+ idoms = graph.immediate_dominators()
911
+ self.assertEqual(idoms, expected)
912
+
913
+ check(self.loopless1(), {0: 0, 12: 0, 18: 0, 21: 0})
914
+ check(
915
+ self.loopless2(), {18: 99, 12: 99, 21: 99, 42: 21, 34: 21, 99: 99}
916
+ )
917
+ check(self.loopless1_dead_nodes(), {0: 0, 12: 0, 18: 0, 21: 0})
918
+ check(
919
+ self.multiple_loops(),
920
+ {
921
+ 0: 0,
922
+ 7: 0,
923
+ 10: 7,
924
+ 13: 10,
925
+ 20: 13,
926
+ 23: 20,
927
+ 32: 23,
928
+ 44: 23,
929
+ 56: 20,
930
+ 57: 56,
931
+ 60: 7,
932
+ 61: 60,
933
+ 68: 61,
934
+ 71: 68,
935
+ 80: 71,
936
+ 87: 68,
937
+ 88: 87,
938
+ },
939
+ )
940
+ check(
941
+ self.multiple_exits(),
942
+ {0: 0, 7: 0, 10: 7, 19: 10, 23: 10, 29: 23, 36: 7, 37: 7},
943
+ )
944
+ check(
945
+ self.infinite_loop1(), {0: 0, 6: 0, 10: 0, 13: 10, 19: 13, 26: 13}
946
+ )
947
+ check(self.infinite_loop2(), {0: 0, 3: 0, 9: 3, 16: 3})
948
+
949
+ def test_dominance_frontier(self):
950
+ def check(graph, expected):
951
+ df = graph.dominance_frontier()
952
+ self.assertEqual(df, expected)
953
+
954
+ check(self.loopless1(), {0: set(), 12: {21}, 18: {21}, 21: set()})
955
+ check(
956
+ self.loopless2(),
957
+ {18: {21}, 12: {21}, 21: set(), 42: set(), 34: set(), 99: set()},
958
+ )
959
+ check(
960
+ self.loopless1_dead_nodes(),
961
+ {0: set(), 12: {21}, 18: {21}, 21: set()},
962
+ )
963
+ check(
964
+ self.multiple_loops(),
965
+ {
966
+ 0: set(),
967
+ 7: {7},
968
+ 10: {7},
969
+ 13: {7},
970
+ 20: {20, 7},
971
+ 23: {20},
972
+ 32: {20},
973
+ 44: {20},
974
+ 56: {7},
975
+ 57: {7},
976
+ 60: set(),
977
+ 61: set(),
978
+ 68: {68},
979
+ 71: {68},
980
+ 80: set(),
981
+ 87: set(),
982
+ 88: set(),
983
+ },
984
+ )
985
+ check(
986
+ self.multiple_exits(),
987
+ {
988
+ 0: set(),
989
+ 7: {7},
990
+ 10: {37, 7},
991
+ 19: set(),
992
+ 23: {37, 7},
993
+ 29: {37},
994
+ 36: {37},
995
+ 37: set(),
996
+ },
997
+ )
998
+ check(
999
+ self.infinite_loop1(),
1000
+ {0: set(), 6: set(), 10: set(), 13: {13}, 19: {13}, 26: {13}},
1001
+ )
1002
+ check(self.infinite_loop2(), {0: set(), 3: {3}, 9: {3}, 16: {3}})
1003
+
1004
+ def test_backbone_loopless(self):
1005
+ for g in [self.loopless1(), self.loopless1_dead_nodes()]:
1006
+ self.assertEqual(sorted(g.backbone()), [0, 21])
1007
+ g = self.loopless2()
1008
+ self.assertEqual(sorted(g.backbone()), [21, 99])
1009
+
1010
+ def test_backbone_loops(self):
1011
+ g = self.multiple_loops()
1012
+ self.assertEqual(sorted(g.backbone()), [0, 7, 60, 61, 68])
1013
+ g = self.infinite_loop1()
1014
+ self.assertEqual(sorted(g.backbone()), [0])
1015
+ g = self.infinite_loop2()
1016
+ self.assertEqual(sorted(g.backbone()), [0, 3])
1017
+
1018
+ def test_loops(self):
1019
+ for g in [
1020
+ self.loopless1(),
1021
+ self.loopless1_dead_nodes(),
1022
+ self.loopless2(),
1023
+ ]:
1024
+ self.assertEqual(len(g.loops()), 0)
1025
+
1026
+ g = self.multiple_loops()
1027
+ # Loop headers
1028
+ self.assertEqual(sorted(g.loops()), [7, 20, 68])
1029
+ outer1 = g.loops()[7]
1030
+ inner1 = g.loops()[20]
1031
+ outer2 = g.loops()[68]
1032
+ self.assertEqual(outer1.header, 7)
1033
+ self.assertEqual(sorted(outer1.entries), [0])
1034
+ self.assertEqual(sorted(outer1.exits), [60])
1035
+ self.assertEqual(
1036
+ sorted(outer1.body), [7, 10, 13, 20, 23, 32, 44, 56, 57]
1037
+ )
1038
+ self.assertEqual(inner1.header, 20)
1039
+ self.assertEqual(sorted(inner1.entries), [13])
1040
+ self.assertEqual(sorted(inner1.exits), [56])
1041
+ self.assertEqual(sorted(inner1.body), [20, 23, 32, 44])
1042
+ self.assertEqual(outer2.header, 68)
1043
+ self.assertEqual(sorted(outer2.entries), [61])
1044
+ self.assertEqual(sorted(outer2.exits), [80, 87])
1045
+ self.assertEqual(sorted(outer2.body), [68, 71])
1046
+ for node in [0, 60, 61, 80, 87, 88]:
1047
+ self.assertEqual(g.in_loops(node), [])
1048
+ for node in [7, 10, 13, 56, 57]:
1049
+ self.assertEqual(g.in_loops(node), [outer1])
1050
+ for node in [20, 23, 32, 44]:
1051
+ self.assertEqual(g.in_loops(node), [inner1, outer1])
1052
+ for node in [68, 71]:
1053
+ self.assertEqual(g.in_loops(node), [outer2])
1054
+
1055
+ g = self.infinite_loop1()
1056
+ # Loop headers
1057
+ self.assertEqual(sorted(g.loops()), [13])
1058
+ loop = g.loops()[13]
1059
+ self.assertEqual(loop.header, 13)
1060
+ self.assertEqual(sorted(loop.entries), [10])
1061
+ self.assertEqual(sorted(loop.exits), [])
1062
+ self.assertEqual(sorted(loop.body), [13, 19, 26])
1063
+ for node in [0, 6, 10]:
1064
+ self.assertEqual(g.in_loops(node), [])
1065
+ for node in [13, 19, 26]:
1066
+ self.assertEqual(g.in_loops(node), [loop])
1067
+
1068
+ g = self.infinite_loop2()
1069
+ # Loop headers
1070
+ self.assertEqual(sorted(g.loops()), [3])
1071
+ loop = g.loops()[3]
1072
+ self.assertEqual(loop.header, 3)
1073
+ self.assertEqual(sorted(loop.entries), [0])
1074
+ self.assertEqual(sorted(loop.exits), [])
1075
+ self.assertEqual(sorted(loop.body), [3, 9, 16])
1076
+ for node in [0]:
1077
+ self.assertEqual(g.in_loops(node), [])
1078
+ for node in [3, 9, 16]:
1079
+ self.assertEqual(g.in_loops(node), [loop])
1080
+
1081
+ g = self.multiple_exits()
1082
+ # Loop headers
1083
+ self.assertEqual(sorted(g.loops()), [7])
1084
+ loop = g.loops()[7]
1085
+ self.assertEqual(loop.header, 7)
1086
+ self.assertEqual(sorted(loop.entries), [0])
1087
+ self.assertEqual(sorted(loop.exits), [19, 29, 36])
1088
+ self.assertEqual(sorted(loop.body), [7, 10, 23])
1089
+ for node in [0, 19, 29, 36]:
1090
+ self.assertEqual(g.in_loops(node), [])
1091
+ for node in [7, 10, 23]:
1092
+ self.assertEqual(g.in_loops(node), [loop])
1093
+
1094
+ def test_loop_dfs_pathological(self):
1095
+ # The follow adjlist is an export from the reproducer in #6186
1096
+ g = self.from_adj_list(
1097
+ {
1098
+ 0: {38, 14},
1099
+ 14: {38, 22},
1100
+ 22: {38, 30},
1101
+ 30: {42, 38},
1102
+ 38: {42},
1103
+ 42: {64, 50},
1104
+ 50: {64, 58},
1105
+ 58: {128},
1106
+ 64: {72, 86},
1107
+ 72: {80, 86},
1108
+ 80: {128},
1109
+ 86: {108, 94},
1110
+ 94: {108, 102},
1111
+ 102: {128},
1112
+ 108: {128, 116},
1113
+ 116: {128, 124},
1114
+ 124: {128},
1115
+ 128: {178, 174},
1116
+ 174: {178},
1117
+ 178: {210, 206},
1118
+ 206: {210},
1119
+ 210: {248, 252},
1120
+ 248: {252},
1121
+ 252: {282, 286},
1122
+ 282: {286},
1123
+ 286: {296, 326},
1124
+ 296: {330},
1125
+ 326: {330},
1126
+ 330: {370, 340},
1127
+ 340: {374},
1128
+ 370: {374},
1129
+ 374: {380, 382},
1130
+ 380: {382},
1131
+ 382: {818, 390},
1132
+ 390: {456, 458},
1133
+ 456: {458},
1134
+ 458: {538, 566},
1135
+ 538: {548, 566},
1136
+ 548: set(),
1137
+ 566: {586, 572},
1138
+ 572: {586},
1139
+ 586: {708, 596},
1140
+ 596: {608},
1141
+ 608: {610},
1142
+ 610: {704, 620},
1143
+ 620: {666, 630},
1144
+ 630: {636, 646},
1145
+ 636: {666, 646},
1146
+ 646: {666},
1147
+ 666: {610},
1148
+ 704: {706},
1149
+ 706: {818},
1150
+ 708: {720},
1151
+ 720: {722},
1152
+ 722: {816, 732},
1153
+ 732: {778, 742},
1154
+ 742: {748, 758},
1155
+ 748: {778, 758},
1156
+ 758: {778},
1157
+ 778: {722},
1158
+ 816: {818},
1159
+ 818: set(),
1160
+ }
1161
+ )
1162
+ g.set_entry_point(0)
1163
+ g.process()
1164
+ stats = {}
1165
+ # Compute backedges and store the iteration count for testing
1166
+ back_edges = g._find_back_edges(stats=stats)
1167
+ self.assertEqual(back_edges, {(666, 610), (778, 722)})
1168
+ self.assertEqual(stats["iteration_count"], 155)
1169
+
1170
+ def test_equals(self):
1171
+ def get_new():
1172
+ g = self.from_adj_list({0: [18, 12], 12: [21], 18: [21], 21: []})
1173
+ g.set_entry_point(0)
1174
+ g.process()
1175
+ return g
1176
+
1177
+ x = get_new()
1178
+ y = get_new()
1179
+
1180
+ # identical
1181
+ self.assertEqual(x, y)
1182
+
1183
+ # identical but defined in a different order
1184
+ g = self.from_adj_list({0: [12, 18], 18: [21], 21: [], 12: [21]})
1185
+ g.set_entry_point(0)
1186
+ g.process()
1187
+ self.assertEqual(x, g)
1188
+
1189
+ # different entry point
1190
+ z = get_new()
1191
+ z.set_entry_point(18)
1192
+ z.process()
1193
+ self.assertNotEqual(x, z)
1194
+
1195
+ # extra node/edge, same entry point
1196
+ z = self.from_adj_list(
1197
+ {0: [18, 12], 12: [21], 18: [21], 21: [22], 22: []}
1198
+ )
1199
+ z.set_entry_point(0)
1200
+ z.process()
1201
+ self.assertNotEqual(x, z)
1202
+
1203
+ # same nodes, different edges
1204
+ a = self.from_adj_list({0: [18, 12], 12: [0], 18: []})
1205
+ a.set_entry_point(0)
1206
+ a.process()
1207
+ z = self.from_adj_list({0: [18, 12], 12: [18], 18: []})
1208
+ z.set_entry_point(0)
1209
+ z.process()
1210
+ self.assertNotEqual(a, z)
1211
+
1212
+
1213
+ class TestRealCodeDomFront(TestCase):
1214
+ """Test IDOM and DOMFRONT computation on real python bytecode.
1215
+ Note: there will be less testing on IDOM (esp in loop) because of
1216
+ the extra blocks inserted by the interpreter. But, testing on DOMFRONT
1217
+ (which depends on IDOM) is easier.
1218
+
1219
+ Testing is done by associating names to basicblock by using globals of
1220
+ the pattern "SET_BLOCK_<name>", which are scanned by
1221
+ `.get_cfa_and_namedblocks` into *namedblocks* dictionary. That way, we
1222
+ can check that a block of a certain name is a IDOM or DOMFRONT of another
1223
+ named block.
1224
+ """
1225
+
1226
+ def cfa(self, bc):
1227
+ cfa = ControlFlowAnalysis(bc)
1228
+ cfa.run()
1229
+ return cfa
1230
+
1231
+ def get_cfa_and_namedblocks(self, fn):
1232
+ fid = FunctionIdentity.from_function(fn)
1233
+ bc = ByteCode(func_id=fid)
1234
+ cfa = self.cfa(bc)
1235
+ namedblocks = self._scan_namedblocks(bc, cfa)
1236
+
1237
+ #### To debug, uncomment below
1238
+ # print(bc.dump())
1239
+ # print("IDOMS")
1240
+ # for k, v in sorted(cfa.graph.immediate_dominators().items()):
1241
+ # print('{} -> {}'.format(k, v))
1242
+ # print("DOMFRONT")
1243
+ # for k, vs in sorted(cfa.graph.dominance_frontier().items()):
1244
+ # print('{} -> {}'.format(k, vs))
1245
+ # print(namedblocks)
1246
+ # cfa.graph.render_dot().view()
1247
+
1248
+ return cfa, namedblocks
1249
+
1250
+ def _scan_namedblocks(self, bc, cfa):
1251
+ """Scan namedblocks as denoted by a LOAD_GLOBAL bytecode referring
1252
+ to global variables with the pattern "SET_BLOCK_<name>", where "<name>"
1253
+ would be the name for the current block.
1254
+ """
1255
+ namedblocks = {}
1256
+ blocks = sorted([x.offset for x in cfa.iterblocks()])
1257
+ prefix = "SET_BLOCK_"
1258
+
1259
+ for inst in bc:
1260
+ # Find LOAD_GLOBAL that refers to "SET_BLOCK_<name>"
1261
+ if inst.opname == "LOAD_GLOBAL":
1262
+ gv = bc.co_names[_fix_LOAD_GLOBAL_arg(inst.arg)]
1263
+ if gv.startswith(prefix):
1264
+ name = gv[len(prefix) :]
1265
+ # Find the block where this instruction resides
1266
+ for s, e in zip(blocks, blocks[1:] + [blocks[-1] + 1]):
1267
+ if s <= inst.offset < e:
1268
+ break
1269
+ else:
1270
+ raise AssertionError("unreachable loop")
1271
+ blkno = s
1272
+ namedblocks[name] = blkno
1273
+ return namedblocks
1274
+
1275
+ def test_loop(self):
1276
+ def foo(n):
1277
+ c = 0
1278
+ SET_BLOCK_A # noqa: F821
1279
+ i = 0
1280
+ while SET_BLOCK_B0: # noqa: F821
1281
+ SET_BLOCK_B1 # noqa: F821
1282
+ c += 1
1283
+ i += 1
1284
+ SET_BLOCK_C # noqa: F821
1285
+ return c
1286
+
1287
+ cfa, blkpts = self.get_cfa_and_namedblocks(foo)
1288
+
1289
+ # Py3.10 turns while loop into if(...) { do {...} while(...) }.
1290
+ # Also, `SET_BLOCK_B0` is duplicated. As a result, the second B0
1291
+ # is picked up by `blkpts`.
1292
+ domfront = cfa.graph.dominance_frontier()
1293
+ self.assertFalse(domfront[blkpts["A"]])
1294
+ self.assertFalse(domfront[blkpts["C"]])
1295
+
1296
+ def test_loop_nested_and_break(self):
1297
+ def foo(n):
1298
+ SET_BLOCK_A # noqa: F821
1299
+ while SET_BLOCK_B0: # noqa: F821
1300
+ SET_BLOCK_B1 # noqa: F821
1301
+ while SET_BLOCK_C0: # noqa: F821
1302
+ SET_BLOCK_C1 # noqa: F821
1303
+ if SET_BLOCK_D0: # noqa: F821
1304
+ SET_BLOCK_D1 # noqa: F821
1305
+ break
1306
+ elif n:
1307
+ SET_BLOCK_D2 # noqa: F821
1308
+ SET_BLOCK_E # noqa: F821
1309
+ SET_BLOCK_F # noqa: F821
1310
+ SET_BLOCK_G # noqa: F821
1311
+
1312
+ cfa, blkpts = self.get_cfa_and_namedblocks(foo)
1313
+ self.assertEqual(blkpts["D0"], blkpts["C1"])
1314
+
1315
+ # Py3.10 changes while loop into if-do-while
1316
+ domfront = cfa.graph.dominance_frontier()
1317
+ self.assertFalse(domfront[blkpts["A"]])
1318
+ self.assertFalse(domfront[blkpts["G"]])
1319
+ # 2 domfront members for C1
1320
+ # C0 because of the loop; F because of the break.
1321
+ self.assertEqual({blkpts["F"]}, domfront[blkpts["D1"]])
1322
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["D2"]])
1323
+
1324
+ def test_if_else(self):
1325
+ def foo(a, b):
1326
+ c = 0
1327
+ SET_BLOCK_A # noqa: F821
1328
+ if a < b:
1329
+ SET_BLOCK_B # noqa: F821
1330
+ c = 1
1331
+ elif SET_BLOCK_C0: # noqa: F821
1332
+ SET_BLOCK_C1 # noqa: F821
1333
+ c = 2
1334
+ else:
1335
+ SET_BLOCK_D # noqa: F821
1336
+ c = 3
1337
+
1338
+ SET_BLOCK_E # noqa: F821
1339
+ if a % b == 0:
1340
+ SET_BLOCK_F # noqa: F821
1341
+ c += 1
1342
+ SET_BLOCK_G # noqa: F821
1343
+ return c
1344
+
1345
+ cfa, blkpts = self.get_cfa_and_namedblocks(foo)
1346
+
1347
+ idoms = cfa.graph.immediate_dominators()
1348
+ self.assertEqual(blkpts["A"], idoms[blkpts["B"]])
1349
+ self.assertEqual(blkpts["A"], idoms[blkpts["C0"]])
1350
+ self.assertEqual(blkpts["C0"], idoms[blkpts["C1"]])
1351
+ self.assertEqual(blkpts["C0"], idoms[blkpts["D"]])
1352
+ self.assertEqual(blkpts["A"], idoms[blkpts["E"]])
1353
+ self.assertEqual(blkpts["E"], idoms[blkpts["F"]])
1354
+ self.assertEqual(blkpts["E"], idoms[blkpts["G"]])
1355
+
1356
+ domfront = cfa.graph.dominance_frontier()
1357
+ self.assertFalse(domfront[blkpts["A"]])
1358
+ self.assertFalse(domfront[blkpts["E"]])
1359
+ self.assertFalse(domfront[blkpts["G"]])
1360
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["B"]])
1361
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["C0"]])
1362
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["C1"]])
1363
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["D"]])
1364
+ self.assertEqual({blkpts["G"]}, domfront[blkpts["F"]])
1365
+
1366
+ def test_if_else_nested(self):
1367
+ def foo():
1368
+ if SET_BLOCK_A0: # noqa: F821
1369
+ SET_BLOCK_A1 # noqa: F821
1370
+ if SET_BLOCK_B0: # noqa: F821
1371
+ SET_BLOCK_B1 # noqa: F821
1372
+ a = 0
1373
+ else:
1374
+ if SET_BLOCK_C0: # noqa: F821
1375
+ SET_BLOCK_C1 # noqa: F821
1376
+ a = 1
1377
+ else:
1378
+ SET_BLOCK_C2 # noqa: F821
1379
+ a = 2
1380
+ SET_BLOCK_D # noqa: F821
1381
+ SET_BLOCK_E # noqa: F821
1382
+ SET_BLOCK_F # noqa: F821
1383
+ return a
1384
+
1385
+ cfa, blkpts = self.get_cfa_and_namedblocks(foo)
1386
+
1387
+ idoms = cfa.graph.immediate_dominators()
1388
+ self.assertEqual(blkpts["A0"], idoms[blkpts["A1"]])
1389
+ self.assertEqual(blkpts["A1"], idoms[blkpts["B1"]])
1390
+ self.assertEqual(blkpts["A1"], idoms[blkpts["C0"]])
1391
+ self.assertEqual(blkpts["C0"], idoms[blkpts["D"]])
1392
+ self.assertEqual(blkpts["A1"], idoms[blkpts["E"]])
1393
+ self.assertEqual(blkpts["A0"], idoms[blkpts["F"]])
1394
+
1395
+ domfront = cfa.graph.dominance_frontier()
1396
+ self.assertFalse(domfront[blkpts["A0"]])
1397
+ self.assertFalse(domfront[blkpts["F"]])
1398
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["B1"]])
1399
+ self.assertEqual({blkpts["D"]}, domfront[blkpts["C1"]])
1400
+ self.assertEqual({blkpts["E"]}, domfront[blkpts["D"]])
1401
+ self.assertEqual({blkpts["F"]}, domfront[blkpts["E"]])
1402
+
1403
+ def test_infinite_loop(self):
1404
+ def foo():
1405
+ SET_BLOCK_A # noqa: F821
1406
+ while True: # infinite loop
1407
+ if SET_BLOCK_B: # noqa: F821
1408
+ SET_BLOCK_C # noqa: F821
1409
+ return
1410
+ SET_BLOCK_D # noqa: F821
1411
+ SET_BLOCK_E # noqa: F821
1412
+
1413
+ cfa, blkpts = self.get_cfa_and_namedblocks(foo)
1414
+
1415
+ idoms = cfa.graph.immediate_dominators()
1416
+ if utils.PYVERSION >= (3, 10):
1417
+ self.assertNotIn("E", blkpts)
1418
+ else:
1419
+ self.assertNotIn(blkpts["E"], idoms)
1420
+ self.assertEqual(blkpts["B"], idoms[blkpts["C"]])
1421
+ self.assertEqual(blkpts["B"], idoms[blkpts["D"]])
1422
+
1423
+ domfront = cfa.graph.dominance_frontier()
1424
+ if utils.PYVERSION < (3, 10):
1425
+ self.assertNotIn(blkpts["E"], domfront)
1426
+ self.assertFalse(domfront[blkpts["A"]])
1427
+ self.assertFalse(domfront[blkpts["C"]])
1428
+ self.assertEqual({blkpts["B"]}, domfront[blkpts["B"]])
1429
+ self.assertEqual({blkpts["B"]}, domfront[blkpts["D"]])
1430
+
1431
+
1432
+ if __name__ == "__main__":
1433
+ unittest.main()