offtarget 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (886) hide show
  1. offload/__init__.py +10 -0
  2. offload/__main__.py +5 -0
  3. offload/_bundle.py +74 -0
  4. offload/_root/catalog/acc/claims.yaml +197 -0
  5. offload/_root/catalog/acc/clauses.yaml +391 -0
  6. offload/_root/catalog/acc/no_oracle.yaml +89 -0
  7. offload/_root/catalog/acc/out_of_scope.yaml +17 -0
  8. offload/_root/catalog/acc/rules.yaml +433 -0
  9. offload/_root/catalog/acc/semantic_atoms.yaml +27 -0
  10. offload/_root/catalog/acc/skeleton.yaml +1567 -0
  11. offload/_root/catalog/acc/spec_overrides.yaml +72 -0
  12. offload/_root/catalog/later_forms.yaml +76 -0
  13. offload/_root/catalog/machines.yaml +218 -0
  14. offload/_root/catalog/omp/claims.yaml +2047 -0
  15. offload/_root/catalog/omp/clauses.yaml +914 -0
  16. offload/_root/catalog/omp/derivations.yaml +177 -0
  17. offload/_root/catalog/omp/memory_modes.yaml +40 -0
  18. offload/_root/catalog/omp/no_oracle.yaml +373 -0
  19. offload/_root/catalog/omp/omp50_delta.yaml +377 -0
  20. offload/_root/catalog/omp/out_of_scope.yaml +64 -0
  21. offload/_root/catalog/omp/port_equivalence.yaml +352 -0
  22. offload/_root/catalog/omp/rules.yaml +3131 -0
  23. offload/_root/catalog/omp/rules_coverage.yaml +9939 -0
  24. offload/_root/catalog/omp/semantic_atoms.yaml +34 -0
  25. offload/_root/catalog/omp/skeleton.yaml +9181 -0
  26. offload/_root/catalog/omp/spec_overrides.yaml +932 -0
  27. offload/_root/catalog/toolchains.yaml +472 -0
  28. offload/_root/catalog/vendor_claims_generic.yaml +40925 -0
  29. offload/_root/data/canuse/b.json +1 -0
  30. offload/_root/data/canuse/c.json +1 -0
  31. offload/_root/data/canuse/columns.json +1 -0
  32. offload/_root/data/canuse/d.json +1 -0
  33. offload/_root/data/canuse/f.json +1 -0
  34. offload/_root/data/canuse/index.json +1 -0
  35. offload/_root/data/canuse/p.json +1 -0
  36. offload/_root/data/compilers/afar.json +1 -0
  37. offload/_root/data/compilers/cce19.json +1 -0
  38. offload/_root/data/compilers/cce20.json +1 -0
  39. offload/_root/data/compilers/cce21.json +1 -0
  40. offload/_root/data/compilers/cce21_4.json +1 -0
  41. offload/_root/data/compilers/gcc.json +1 -0
  42. offload/_root/data/compilers/gcc_sm80.json +1 -0
  43. offload/_root/data/compilers/nvhpc.json +1 -0
  44. offload/_root/data/compilers/nvhpc269.json +1 -0
  45. offload/_root/data/findings/AUTHORING.md +107 -0
  46. offload/_root/data/findings/README.md +33 -0
  47. offload/_root/data/findings/afar-c-error-directive-in-target-link.c +37 -0
  48. offload/_root/data/findings/afar-c-lastprivate-distribute-parallel-for-small-type.c +56 -0
  49. offload/_root/data/findings/afar-c-teams-distribute-reduction-first-team.c +59 -0
  50. offload/_root/data/findings/afar-c-update-iterator-copy-mode.c +45 -0
  51. offload/_root/data/findings/afar-c-xnack1-target-is-present.c +31 -0
  52. offload/_root/data/findings/afar-cce19-character-defaultmap.f90 +27 -0
  53. offload/_root/data/findings/afar-cce19-task-in-target-ice.f90 +23 -0
  54. offload/_root/data/findings/afar-clang-requires-device-safesync-hang.c +24 -0
  55. offload/_root/data/findings/afar-flang-firstprivate-map-two-targets.f90 +34 -0
  56. offload/_root/data/findings/afar-flang-loop-bind-teams-reduction.f90 +27 -0
  57. offload/_root/data/findings/afar-flang-task-reduction-max.f90 +31 -0
  58. offload/_root/data/findings/afar-flang-thread-limit-target-parallel-do.f90 +22 -0
  59. offload/_root/data/findings/afar-linear-ref-omp50.f90 +29 -0
  60. offload/_root/data/findings/afar-loop-bind-thread-in-teams.f90 +44 -0
  61. offload/_root/data/findings/afar-nontemporal-assumed-shape-ice.f90 +38 -0
  62. offload/_root/data/findings/afar-udr-derived-type-link.f90 +41 -0
  63. offload/_root/data/findings/afar-xnack1-atomic-min-nested-parallel.f90 +53 -0
  64. offload/_root/data/findings/afar-xnack1-present-not-enforced.f90 +36 -0
  65. offload/_root/data/findings/afar-xnack1-target-is-present.f90 +47 -0
  66. offload/_root/data/findings/apps/afar-cce-teams-private-array-nested-parallel-wrong.f90 +100 -0
  67. offload/_root/data/findings/apps/cce20-device-link-infer-address-spaces-crash.f90 +159 -0
  68. offload/_root/data/findings/apps/cce21-device-link-agpr-copy-mfma-assert.f90 +343 -0
  69. offload/_root/data/findings/apps/cce21-private-array-loaded-subscript-wrong.f90 +113 -0
  70. offload/_root/data/findings/apps/controls/bubble-simple-rddot.f90 +284 -0
  71. offload/_root/data/findings/apps/controls/bubble-two-substeps.f90 +287 -0
  72. offload/_root/data/findings/apps/controls/cbc-inline.f90 +97 -0
  73. offload/_root/data/findings/apps/controls/cbc-integers.f90 +91 -0
  74. offload/_root/data/findings/apps/controls/cbc-only-density.f90 +97 -0
  75. offload/_root/data/findings/apps/controls/cbc-only-velocity.f90 +97 -0
  76. offload/_root/data/findings/apps/controls/gcc-acc-c-tile-control.c +26 -0
  77. offload/_root/data/findings/apps/controls/gcc-acc-tile-control.f90 +29 -0
  78. offload/_root/data/findings/apps/controls/private-array-subscript-probes.f90 +45 -0
  79. offload/_root/data/findings/apps/controls/teams-private-array-read-par.f90 +31 -0
  80. offload/_root/data/findings/apps/controls/teams-private-array-seq.f90 +30 -0
  81. offload/_root/data/findings/apps/controls/teams-private-array-shared.f90 +34 -0
  82. offload/_root/data/findings/apps/controls/teams-private-array-split.f90 +36 -0
  83. offload/_root/data/findings/apps/controls/teams-private-array-write-par.f90 +31 -0
  84. offload/_root/data/findings/apps/gcc-acc-c-tile-partial-tiles-wrong.c +60 -0
  85. offload/_root/data/findings/apps/gcc-acc-tile-partial-tiles-wrong.f90 +64 -0
  86. offload/_root/data/findings/catalog/afar-c-complex-reduction-link.c +66 -0
  87. offload/_root/data/findings/catalog/afar-c-critical-hint-link.c +68 -0
  88. offload/_root/data/findings/catalog/afar-c-ordered-doacross-link.c +62 -0
  89. offload/_root/data/findings/catalog/afar-c-reduction-task-link.c +81 -0
  90. offload/_root/data/findings/catalog/afar-flang-absent-optional-target-crash.f90 +76 -0
  91. offload/_root/data/findings/catalog/afar-flang-critical-target-parallel-wrong.f90 +74 -0
  92. offload/_root/data/findings/catalog/afar-flang-dist-schedule-chunk.f90 +80 -0
  93. offload/_root/data/findings/catalog/afar-flang-linear-parallel-ice.f90 +68 -0
  94. offload/_root/data/findings/catalog/afar-flang-named-critical-link.f90 +67 -0
  95. offload/_root/data/findings/catalog/afar-flang-ordered-wrong.f90 +78 -0
  96. offload/_root/data/findings/catalog/afar-flang-reduction-minus-rejected.f90 +77 -0
  97. offload/_root/data/findings/catalog/afar-flang-reduction-task-ice.f90 +68 -0
  98. offload/_root/data/findings/catalog/afar-flang-sections-in-target-ice.f90 +67 -0
  99. offload/_root/data/findings/catalog/afar-flang-workdistribute-ice.f90 +71 -0
  100. offload/_root/data/findings/catalog/c-allocate-const-mem-firstprivate-wrong.c +79 -0
  101. offload/_root/data/findings/catalog/cce-acc-allocate-in-compute-crash.f90 +65 -0
  102. offload/_root/data/findings/catalog/cce-acc-character-dummy-routine-ice.f90 +81 -0
  103. offload/_root/data/findings/catalog/cce-acc-loop-seq-in-routine-wrong.f90 +81 -0
  104. offload/_root/data/findings/catalog/cce-acc-stop-in-compute-crash.f90 +62 -0
  105. offload/_root/data/findings/catalog/cce-allocators-stack-ice.f90 +81 -0
  106. offload/_root/data/findings/catalog/cce-atomic-default-mem-order-acquire-release-rejected.f90 +61 -0
  107. offload/_root/data/findings/catalog/cce-c-allocate-align-link.c +83 -0
  108. offload/_root/data/findings/catalog/cce-c-allocate-allocator-modifier-rejected.c +77 -0
  109. offload/_root/data/findings/catalog/cce-c-device-type-directive-name-ice.c +70 -0
  110. offload/_root/data/findings/catalog/cce-c-dist-schedule-chunk.c +81 -0
  111. offload/_root/data/findings/catalog/cce-c-f-pointer-device-link.f90 +70 -0
  112. offload/_root/data/findings/catalog/cce-c-lastprivate-parallel-in-seq-loop-wrong.c +64 -0
  113. offload/_root/data/findings/catalog/cce-c-long-double-ice.c +61 -0
  114. offload/_root/data/findings/catalog/cce-c-map-iterator-ice.c +92 -0
  115. offload/_root/data/findings/catalog/cce-c-motion-iterator-rejected.c +68 -0
  116. offload/_root/data/findings/catalog/cce-c-ordered-doacross-link.c +64 -0
  117. offload/_root/data/findings/catalog/cce-c-ordered-link.c +77 -0
  118. offload/_root/data/findings/catalog/cce-c-recursive-function-ice.c +62 -0
  119. offload/_root/data/findings/catalog/cce-c-reduction-inscan-ice.c +67 -0
  120. offload/_root/data/findings/catalog/cce-c-reduction-task-link.c +73 -0
  121. offload/_root/data/findings/catalog/cce-c-sections-in-target-wrong.c +70 -0
  122. offload/_root/data/findings/catalog/cce-c-single-masked-task-link.c +66 -0
  123. offload/_root/data/findings/catalog/cce-c-task-in-target-link.c +75 -0
  124. offload/_root/data/findings/catalog/cce-c-uses-allocators-traits-rejected.c +71 -0
  125. offload/_root/data/findings/catalog/cce-flang-allocate-const-mem-ice.f90 +67 -0
  126. offload/_root/data/findings/catalog/cce-flang-allocate-in-target-crash.f90 +68 -0
  127. offload/_root/data/findings/catalog/cce-flang-lastprivate-parallel-in-seq-loop-wrong.f90 +83 -0
  128. offload/_root/data/findings/catalog/cce-flang-stop-in-target-crash.f90 +64 -0
  129. offload/_root/data/findings/catalog/cce-iterator-link.f90 +67 -0
  130. offload/_root/data/findings/catalog/cce-linear-lastprivate-ice.f90 +69 -0
  131. offload/_root/data/findings/catalog/cce-nohost-link.f90 +90 -0
  132. offload/_root/data/findings/catalog/cce-reduction-inscan-ice.f90 +66 -0
  133. offload/_root/data/findings/catalog/cce-reduction-task-link.f90 +76 -0
  134. offload/_root/data/findings/catalog/cce19-reduction-task-addrspacecast-ice.f90 +77 -0
  135. offload/_root/data/findings/catalog/cce20-c-defaultmap-private-storage-rejected.c +85 -0
  136. offload/_root/data/findings/catalog/cce20-map-self-rejected.f90 +64 -0
  137. offload/_root/data/findings/catalog/cce21-c-declare-target-local-rejected.c +73 -0
  138. offload/_root/data/findings/catalog/cce21-c-target-loop-ice.c +77 -0
  139. offload/_root/data/findings/catalog/defaultmap-present-private-array-abort.f90 +73 -0
  140. offload/_root/data/findings/catalog/nvhpc-acc-associate-illegal-address.f90 +66 -0
  141. offload/_root/data/findings/catalog/nvhpc-c-function-pointer-kernel-missing.c +68 -0
  142. offload/_root/data/findings/catalog/nvhpc-c-long-double-kernel-missing.c +64 -0
  143. offload/_root/data/findings/catalog/nvhpc-c-static-local-kernel-missing.c +73 -0
  144. offload/_root/data/findings/catalog/nvhpc-c-vla-kernel-missing.c +63 -0
  145. offload/_root/data/findings/catalog/nvhpc-flang-type-bound-kernel-missing.f90 +86 -0
  146. offload/_root/data/findings/cce-acc-init-set-runtime-assert.f90 +35 -0
  147. offload/_root/data/findings/cce-acc-reduction-200-int8-scalars-wrong.f90 +1278 -0
  148. offload/_root/data/findings/cce-acc-routine-bind-module-ice.f90 +35 -0
  149. offload/_root/data/findings/cce-acc-self-condition-ignored.f90 +17 -0
  150. offload/_root/data/findings/cce-c-dist-schedule-segv.c +34 -0
  151. offload/_root/data/findings/cce-c-map-delete-refcount.c +47 -0
  152. offload/_root/data/findings/cce-c-map-present-assert.c +45 -0
  153. offload/_root/data/findings/cce-c-openmp45-device-link.c +34 -0
  154. offload/_root/data/findings/cce-c-parallel-for-in-target.c +73 -0
  155. offload/_root/data/findings/cce-defaultmap-tofrom-explicit-map.f90 +92 -0
  156. offload/_root/data/findings/cce-mapper-next-map-copy-back.f90 +48 -0
  157. offload/_root/data/findings/cce-trim-merge-output-one-character.f90 +40 -0
  158. offload/_root/data/findings/cce-uses-allocators-traits-omp50.f90 +28 -0
  159. offload/_root/data/findings/cce19-acc-if-false-link.f90 +17 -0
  160. offload/_root/data/findings/cce19-c-reduction-63-scalars-one-wrong.c +235 -0
  161. offload/_root/data/findings/cce19-target-parallel-guarded-loop.f90 +35 -0
  162. offload/_root/data/findings/cce19-target-parallel-single-ice.f90 +38 -0
  163. offload/_root/data/findings/cce21-alloc-2e32-sum-wrong.f90 +68 -0
  164. offload/_root/data/findings/cce21-defaultmap-aggregate-flag.f90 +52 -0
  165. offload/_root/data/findings/cce21-in-reduction-assumed-shape-write-lost.f90 +61 -0
  166. offload/_root/data/findings/cce21-in-reduction-taskwait-link.f90 +59 -0
  167. offload/_root/data/findings/cce21-linear-modifier-default-none.f90 +59 -0
  168. offload/_root/data/findings/clang-c-declare-target-to-omp52.c +50 -0
  169. offload/_root/data/findings/clang-c-linear-directive-name-hang.c +30 -0
  170. offload/_root/data/findings/clang-c-map-iterator-omp51.c +51 -0
  171. offload/_root/data/findings/clang-c-shared-declare-target-combined.c +58 -0
  172. offload/_root/data/findings/dataenv/cce-value-dummy-target-write-visible.f90 +74 -0
  173. offload/_root/data/findings/defaultmap-none-loop-variable.f90 +69 -0
  174. offload/_root/data/findings/fortran-loop-bind-thread-in-parallel.f90 +53 -0
  175. offload/_root/data/findings/fortran-schedule-static-in-target.f90 +55 -0
  176. offload/_root/data/findings/fresh/cce-common-block-name-in-map-rejected.f90 +47 -0
  177. offload/_root/data/findings/fresh/cce-if-stop-in-target-ice-one-condition.f90 +38 -0
  178. offload/_root/data/findings/fresh/cce-if-stop-in-target-ice.f90 +43 -0
  179. offload/_root/data/findings/fresh/cce-list-directed-print-in-target-copy-crash.f90 +40 -0
  180. offload/_root/data/findings/fresh/cce19-acc-automatic-array-copyout-copy-crash.f90 +56 -0
  181. offload/_root/data/findings/fresh/cce21-combined-if-runtime-expr-loop-skipped.f90 +57 -0
  182. offload/_root/data/findings/fresh/nvhpc-acc-gang-worker-collapse-nested-vector-reduction-lost.f90 +67 -0
  183. offload/_root/data/findings/fresh/nvhpc-teams-loop-module-allocatable-assign-fort2-crash.f90 +73 -0
  184. offload/_root/data/findings/fuzz/1131-afar.f90 +48 -0
  185. offload/_root/data/findings/fuzz/1391-cce20.f90 +40 -0
  186. offload/_root/data/findings/fuzz/14-cce20.f90 +36 -0
  187. offload/_root/data/findings/fuzz/1505-cce20.f90 +88 -0
  188. offload/_root/data/findings/fuzz/1540-afar.f90 +44 -0
  189. offload/_root/data/findings/fuzz/158-afar.f90 +63 -0
  190. offload/_root/data/findings/fuzz/16-cce20.f90 +39 -0
  191. offload/_root/data/findings/fuzz/1644-cce21.f90 +31 -0
  192. offload/_root/data/findings/fuzz/165-cce19.f90 +52 -0
  193. offload/_root/data/findings/fuzz/1749-cce20.f90 +34 -0
  194. offload/_root/data/findings/fuzz/1936-afar.f90 +61 -0
  195. offload/_root/data/findings/fuzz/1978-cce19.f90 +41 -0
  196. offload/_root/data/findings/fuzz/2014-cce19.f90 +46 -0
  197. offload/_root/data/findings/fuzz/2224-cce19.f90 +30 -0
  198. offload/_root/data/findings/fuzz/2334-cce19.f90 +57 -0
  199. offload/_root/data/findings/fuzz/536-cce19.f90 +38 -0
  200. offload/_root/data/findings/fuzz/591-cce19.f90 +54 -0
  201. offload/_root/data/findings/fuzz/650-afar.f90 +58 -0
  202. offload/_root/data/findings/fuzz/698-afar.f90 +68 -0
  203. offload/_root/data/findings/fuzz/700-afar.f90 +46 -0
  204. offload/_root/data/findings/fuzz/775-cce21.f90 +33 -0
  205. offload/_root/data/findings/fuzz/87-afar.f90 +47 -0
  206. offload/_root/data/findings/fuzz/916-afar.f90 +67 -0
  207. offload/_root/data/findings/fuzz/958-cce20.f90 +44 -0
  208. offload/_root/data/findings/fuzz/98-cce19.f90 +40 -0
  209. offload/_root/data/findings/fuzz/README.md +236 -0
  210. offload/_root/data/findings/fuzz/b1-121-afar.f90 +47 -0
  211. offload/_root/data/findings/fuzz/b1-183-afar.f90 +55 -0
  212. offload/_root/data/findings/fuzz/b1-22-cce20.f90 +38 -0
  213. offload/_root/data/findings/fuzz/b1-231-afar.f90 +56 -0
  214. offload/_root/data/findings/fuzz/b1-268-afar.f90 +46 -0
  215. offload/_root/data/findings/fuzz/b2-183-afar.f90 +57 -0
  216. offload/_root/data/findings/fuzz/b2-209-cce19.f90 +51 -0
  217. offload/_root/data/findings/fuzz/b2-213-afar.f90 +63 -0
  218. offload/_root/data/findings/fuzz/b2-52-afar.f90 +56 -0
  219. offload/_root/data/findings/fuzz/b2-68-afar.f90 +54 -0
  220. offload/_root/data/findings/fuzz/b2-85-cce20.f90 +55 -0
  221. offload/_root/data/findings/fuzz/b3-188-cce19.f90 +90 -0
  222. offload/_root/data/findings/fuzz/b3-190-cce21.f90 +88 -0
  223. offload/_root/data/findings/fuzz/b3-197-cce19.f90 +77 -0
  224. offload/_root/data/findings/fuzz/b3-250-cce20.f90 +89 -0
  225. offload/_root/data/findings/fuzz/b3-278-cce19.f90 +70 -0
  226. offload/_root/data/findings/fuzz/b3-45-cce21.f90 +83 -0
  227. offload/_root/data/findings/fuzz/b3-54-afar.f90 +67 -0
  228. offload/_root/data/findings/fuzz/b3-61-cce20.f90 +100 -0
  229. offload/_root/data/findings/fuzz/b3-9-afar.f90 +100 -0
  230. offload/_root/data/findings/fuzz/b3-9-cce21.f90 +103 -0
  231. offload/_root/data/findings/fuzz/b3-94-afar.f90 +80 -0
  232. offload/_root/data/findings/fuzz/b4-39-afar.f90 +141 -0
  233. offload/_root/data/findings/fuzz/b4-86-cce19.f90 +71 -0
  234. offload/_root/data/findings/fuzz/controls/gcc-complex-pointer-store-control.f90 +28 -0
  235. offload/_root/data/findings/fuzz/controls/gcc-declare-reduction-module-control.f90 +29 -0
  236. offload/_root/data/findings/fuzz/controls/gcc-target-simd-map-nontemporal-control.f90 +21 -0
  237. offload/_root/data/findings/fuzz/controls/nvhpc-allocatable-component-mapped-control.f90 +22 -0
  238. offload/_root/data/findings/fuzz/controls/nvhpc-allocatable-component-unreferenced-control.f90 +22 -0
  239. offload/_root/data/findings/fuzz/controls/nvhpc-default-none-removed-control.f90 +18 -0
  240. offload/_root/data/findings/fuzz/controls/nvhpc-default-shared-control.f90 +18 -0
  241. offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-firstprivate-removed-control.f90 +15 -0
  242. offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-to-scalar-reduction-mapped-control.f90 +17 -0
  243. offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-to-scalar-removed-control.f90 +17 -0
  244. offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-tofrom-lastprivate-control.f90 +15 -0
  245. offload/_root/data/findings/fuzz/controls/nvhpc-depend-explicit-map-control.f90 +22 -0
  246. offload/_root/data/findings/fuzz/controls/nvhpc-depend-removed-control.f90 +22 -0
  247. offload/_root/data/findings/fuzz/controls/nvhpc-distribute-end-distribute-control.f90 +16 -0
  248. offload/_root/data/findings/fuzz/controls/nvhpc-distribute-parallel-num-threads-removed-control.f90 +26 -0
  249. offload/_root/data/findings/fuzz/controls/nvhpc-distribute-parallel-removed-control.f90 +22 -0
  250. offload/_root/data/findings/fuzz/controls/nvhpc-distribute-simd-no-end-directive-control.f90 +15 -0
  251. offload/_root/data/findings/fuzz/controls/nvhpc-explicit-length-character-dummy-control.f90 +18 -0
  252. offload/_root/data/findings/fuzz/controls/nvhpc-loop-character-array-value-control.f90 +23 -0
  253. offload/_root/data/findings/fuzz/controls/nvhpc-loop-character-distribute-control.f90 +20 -0
  254. offload/_root/data/findings/fuzz/controls/nvhpc-map-always-first-control.f90 +15 -0
  255. offload/_root/data/findings/fuzz/controls/nvhpc-map-always-removed-control.f90 +15 -0
  256. offload/_root/data/findings/fuzz/controls/nvhpc-num-threads-removed-control.f90 +12 -0
  257. offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-firstprivate-dropped-control.f90 +15 -0
  258. offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-single-nowait-control.f90 +13 -0
  259. offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-split-control.f90 +15 -0
  260. offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-collapse-split-control.f90 +21 -0
  261. offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-end-directive-control.f90 +14 -0
  262. offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-no-collapse-control.f90 +19 -0
  263. offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-split-no-end-directive-control.f90 +15 -0
  264. offload/_root/data/findings/fuzz/gcc-declare-reduction-module-not-found.f90 +66 -0
  265. offload/_root/data/findings/fuzz/gcc-strided-target-update-rejected.f90 +58 -0
  266. offload/_root/data/findings/fuzz/gcc-target-simd-map-nontemporal-rejected.f90 +54 -0
  267. offload/_root/data/findings/fuzz/nvhpc-allocatable-component-implicit-map-illegal-address.f90 +84 -0
  268. offload/_root/data/findings/fuzz/nvhpc-assumed-length-character-dummy-map-ice.f90 +69 -0
  269. offload/_root/data/findings/fuzz/nvhpc-default-none-reduction-lastprivate-fort1-crash.f90 +70 -0
  270. offload/_root/data/findings/fuzz/nvhpc-defaultmap-firstprivate-lastprivate-ice.f90 +71 -0
  271. offload/_root/data/findings/fuzz/nvhpc-defaultmap-to-scalar-reduction-lost.f90 +82 -0
  272. offload/_root/data/findings/fuzz/nvhpc-depend-implicit-map-illegal-address.f90 +81 -0
  273. offload/_root/data/findings/fuzz/nvhpc-distribute-parallel-num-threads-writes-lost.f90 +79 -0
  274. offload/_root/data/findings/fuzz/nvhpc-end-distribute-simd-rejected.f90 +70 -0
  275. offload/_root/data/findings/fuzz/nvhpc-loop-character-achar-unsupported.f90 +75 -0
  276. offload/_root/data/findings/fuzz/nvhpc-map-always-after-map-to-not-copied-back.f90 +70 -0
  277. offload/_root/data/findings/fuzz/nvhpc-num-threads-reduction-identity-lost.f90 +54 -0
  278. offload/_root/data/findings/fuzz/nvhpc-target-parallel-firstprivate-translate-failure.f90 +66 -0
  279. offload/_root/data/findings/fuzz/nvhpc-target-parallel-single-hang.f90 +68 -0
  280. offload/_root/data/findings/fuzz/nvhpc-target-simd-collapse-translate-failure.f90 +73 -0
  281. offload/_root/data/findings/fuzz/nvhpc-target-simd-no-end-directive-rejected.f90 +68 -0
  282. offload/_root/data/findings/fuzz/par-s1-2082-gcc_g90.f90 +71 -0
  283. offload/_root/data/findings/fuzz/s1-2370-cce21.f90 +67 -0
  284. offload/_root/data/findings/fuzz/s1-2592-cce21.f90 +56 -0
  285. offload/_root/data/findings/fuzz/s1-3463-cce21.f90 +92 -0
  286. offload/_root/data/findings/fuzz/s1-4339-afar.f90 +79 -0
  287. offload/_root/data/findings/fuzz/s1-6085-cce21.f90 +96 -0
  288. offload/_root/data/findings/fuzz/s1-6760-cce20.f90 +65 -0
  289. offload/_root/data/findings/fuzz/s1-6888-cce21.f90 +76 -0
  290. offload/_root/data/findings/fuzz/s1-7882-cce20.f90 +63 -0
  291. offload/_root/data/findings/fuzz/s1-8634-cce21.f90 +45 -0
  292. offload/_root/data/findings/fuzz/s1-91-cce21.f90 +92 -0
  293. offload/_root/data/findings/fuzz/s1-9443-afar.f90 +59 -0
  294. offload/_root/data/findings/fuzz/s1-9914-cce19.f90 +78 -0
  295. offload/_root/data/findings/gcc/controls/gcc-acc-c-detach-control.c +34 -0
  296. offload/_root/data/findings/gcc/controls/gcc-acc-detach-control.f90 +26 -0
  297. offload/_root/data/findings/gcc/controls/gcc-defaultmap-to-pointer-control.f90 +31 -0
  298. offload/_root/data/findings/gcc/controls/gcc-target-in-task-control.c +26 -0
  299. offload/_root/data/findings/gcc/controls/gcc-target-in-task-control.f90 +21 -0
  300. offload/_root/data/findings/gcc/gcc-acc-bind-device-type-rejected.f90 +71 -0
  301. offload/_root/data/findings/gcc/gcc-acc-c-bind-device-type-rejected.c +76 -0
  302. offload/_root/data/findings/gcc/gcc-acc-c-detach-delete-attach-underflow.c +74 -0
  303. offload/_root/data/findings/gcc/gcc-acc-c-gang-dim-rejected.c +79 -0
  304. offload/_root/data/findings/gcc/gcc-acc-c-link-in-routine-rejected.c +82 -0
  305. offload/_root/data/findings/gcc/gcc-acc-detach-delete-attach-underflow.f90 +66 -0
  306. offload/_root/data/findings/gcc/gcc-acc-gang-dim-collapse-force-rejected.f90 +69 -0
  307. offload/_root/data/findings/gcc/gcc-acc-init-set-shutdown-rejected.f90 +70 -0
  308. offload/_root/data/findings/gcc/gcc-acc-link-in-routine-rejected.f90 +82 -0
  309. offload/_root/data/findings/gcc/gcc-acc-use-device-allocatable-rejected.f90 +88 -0
  310. offload/_root/data/findings/gcc/gcc-c-motion-mapper-rejected.c +110 -0
  311. offload/_root/data/findings/gcc/gcc-c-omp60-undocumented-rejected.c +76 -0
  312. offload/_root/data/findings/gcc/gcc-c-omp60-unimplemented-rejected.c +119 -0
  313. offload/_root/data/findings/gcc/gcc-c-target-in-task-mandatory-device-not-found.c +87 -0
  314. offload/_root/data/findings/gcc/gcc-c-uses-allocators-traits-unimplemented.c +85 -0
  315. offload/_root/data/findings/gcc/gcc-declare-mapper-rejected.f90 +85 -0
  316. offload/_root/data/findings/gcc/gcc-defaultmap-to-pointer-copy-back.f90 +66 -0
  317. offload/_root/data/findings/gcc/gcc-loop-bind-default-none-rejected.f90 +93 -0
  318. offload/_root/data/findings/gcc/gcc-omp60-undocumented-rejected.f90 +72 -0
  319. offload/_root/data/findings/gcc/gcc-omp60-unimplemented-rejected.f90 +112 -0
  320. offload/_root/data/findings/gcc/gcc-target-in-task-mandatory-device-not-found.f90 +83 -0
  321. offload/_root/data/findings/gcc/gcc-uses-allocators-traits-unimplemented.f90 +78 -0
  322. offload/_root/data/findings/harvest/afar-flang-strided-target-update.f90 +96 -0
  323. offload/_root/data/findings/harvest/cce-acc-declare-create-module-allocatable-xnack1-fault.f90 +58 -0
  324. offload/_root/data/findings/harvest/cce-c-implicit-struct-map-partly-present.c +100 -0
  325. offload/_root/data/findings/harvest/cce-c-strided-target-update.c +74 -0
  326. offload/_root/data/findings/harvest/cce-ftn-target-parallel-thread-query-ice.f90 +67 -0
  327. offload/_root/data/findings/harvest/cce-named-constant-array-declare-target-routine-rejected.f90 +69 -0
  328. offload/_root/data/findings/harvest/cce-use-device-ptr-c-ptr-not-converted.f90 +64 -0
  329. offload/_root/data/findings/harvest/cce21-declare-target-link-module-variable-write-lost.f90 +63 -0
  330. offload/_root/data/findings/harvest/cce21-internal-procedure-calls-internal-in-target-fault.f90 +71 -0
  331. offload/_root/data/findings/harvest/controls/cce-c-implicit-struct-map-partly-present-target-only-control.c +22 -0
  332. offload/_root/data/findings/harvest/controls/cce-c-implicit-struct-map-partly-present-whole-control.c +23 -0
  333. offload/_root/data/findings/harvest/controls/gcc-acc-declare-create-allocatable-control.f90 +34 -0
  334. offload/_root/data/findings/harvest/controls/gcc-c-same-item-two-maps-control.c +17 -0
  335. offload/_root/data/findings/harvest/controls/gcc-c-target-data-struct-pointer-section-control.c +27 -0
  336. offload/_root/data/findings/harvest/controls/gcc-c-target-data-two-maps-control.c +20 -0
  337. offload/_root/data/findings/harvest/controls/gcc-same-item-two-maps-control.f90 +16 -0
  338. offload/_root/data/findings/harvest/controls/gcc-teams-simd-matmul-allocatable-control.f90 +27 -0
  339. offload/_root/data/findings/harvest/gcc-acc-declare-create-allocatable-not-mapped.f90 +66 -0
  340. offload/_root/data/findings/harvest/gcc-c-same-item-two-maps-rejected.c +45 -0
  341. offload/_root/data/findings/harvest/gcc-c-strided-section-rejected.c +70 -0
  342. offload/_root/data/findings/harvest/gcc-c-target-data-struct-pointer-section-ice.c +78 -0
  343. offload/_root/data/findings/harvest/gcc-c-target-data-two-maps-ice.c +49 -0
  344. offload/_root/data/findings/harvest/gcc-same-item-two-maps-rejected.f90 +46 -0
  345. offload/_root/data/findings/harvest/gcc-teams-simd-matmul-allocatable-ice.f90 +53 -0
  346. offload/_root/data/findings/harvest/nvhpc-c-target-data-if-false-use-device-ptr-garbage.c +49 -0
  347. offload/_root/data/findings/harvest/nvhpc-named-constant-array-declare-target-routine-rejected.f90 +65 -0
  348. offload/_root/data/findings/harvest/nvhpc-use-device-ptr-c-ptr-not-found.f90 +60 -0
  349. offload/_root/data/findings/harvest/nvhpc2511-target-nowait-in-parallel-for-ice.c +59 -0
  350. offload/_root/data/findings/hecbench/controls/f16-ctl-float-array.c +28 -0
  351. offload/_root/data/findings/hecbench/controls/pc-ctl-builtin-popcount.c +37 -0
  352. offload/_root/data/findings/hecbench/controls/pc-ctl-shift-sum.c +43 -0
  353. offload/_root/data/findings/hecbench/gcc-c-float16-array-in-target-lto-ice.c +65 -0
  354. offload/_root/data/findings/hecbench/gcc-c-swar-popcount-assembler-error.c +80 -0
  355. offload/_root/data/findings/index.yaml +2453 -0
  356. offload/_root/data/findings/malloc/afar-device-malloc-in-kernel-corrupts-records.c +371 -0
  357. offload/_root/data/findings/malloc/controls/afar-first-use-malloc-direct.c +52 -0
  358. offload/_root/data/findings/malloc/controls/afar-first-use-malloc-fence.c +57 -0
  359. offload/_root/data/findings/malloc/controls/afar-first-use-malloc-flush.c +57 -0
  360. offload/_root/data/findings/malloc/controls/afar-first-use-malloc-stack.c +52 -0
  361. offload/_root/data/findings/multithread-allocatable-section-maps.f90 +91 -0
  362. offload/_root/data/findings/nested/afar-cce-c-call-result-member-in-target-rejected.c +69 -0
  363. offload/_root/data/findings/nested/afar-cce-c-update-struct-and-member-rejected.c +92 -0
  364. offload/_root/data/findings/nested/afar-flang-pointer-root-allocatable-component-enter-data-fault.f90 +121 -0
  365. offload/_root/data/findings/nested/cce-c-struct-and-nested-pointee-sections-ice.c +79 -0
  366. offload/_root/data/findings/nested/cce-fortran-nested-allocatable-component-copy-fault.f90 +64 -0
  367. offload/_root/data/findings/nested/cce-fortran-pointer-to-type-with-allocatable-scalar-component-typed-transfer.f90 +93 -0
  368. offload/_root/data/findings/nested/cce-fortran-update-to-pointer-root-allocatable-scalar-component-no-accelerator-object.f90 +80 -0
  369. offload/_root/data/findings/nested/controls/c3-ctl-nested-data.c +27 -0
  370. offload/_root/data/findings/nested/controls/c5-acc-serial-struct-and-array.c +26 -0
  371. offload/_root/data/findings/nested/controls/e2-ctl-two-directives.c +42 -0
  372. offload/_root/data/findings/nested/controls/e3-ctl-attach-clause.c +42 -0
  373. offload/_root/data/findings/nested/controls/f3-pointer-array-only.c +33 -0
  374. offload/_root/data/findings/nested/controls/f5-ctl-copyout-exit.c +33 -0
  375. offload/_root/data/findings/nested/controls/f6-ctl-pointer-to-struct-array.c +28 -0
  376. offload/_root/data/findings/nested/controls/g2-ctl-allocatable.f90 +34 -0
  377. offload/_root/data/findings/nested/controls/g2-ctl-entered-to.f90 +34 -0
  378. offload/_root/data/findings/nested/controls/g3-ctl-from-struct-no-element.c +27 -0
  379. offload/_root/data/findings/nested/controls/g3-ptrs-two-elements-to.c +27 -0
  380. offload/_root/data/findings/nested/controls/g3-ptrs-two-elements-tofrom.c +27 -0
  381. offload/_root/data/findings/nested/controls/g5-ctl-element-pointers-only.f90 +36 -0
  382. offload/_root/data/findings/nested/controls/g5-ctl-root-pointer-only.f90 +36 -0
  383. offload/_root/data/findings/nested/controls/gp2-ctl-no-mapper-explicit-maps.c +24 -0
  384. offload/_root/data/findings/nested/controls/gt2-ctl-no-always.c +26 -0
  385. offload/_root/data/findings/nested/controls/gt3-ctl-always-on-structure-only.c +26 -0
  386. offload/_root/data/findings/nested/controls/j1-embedded-struct-pointer-to-struct.c +24 -0
  387. offload/_root/data/findings/nested/controls/j2-ctl-pointer-instead-of-embedded.c +24 -0
  388. offload/_root/data/findings/nested/controls/j6-ctl-struct-and-one-pointee-level.c +23 -0
  389. offload/_root/data/findings/nested/controls/j7-ctl-struct-and-embedded-pointee.c +24 -0
  390. offload/_root/data/findings/nested/controls/m2-ctl-variable-root.f90 +32 -0
  391. offload/_root/data/findings/nested/controls/m3-ctl-fixed-array-component.f90 +32 -0
  392. offload/_root/data/findings/nested/controls/m5-ctl-no-enter-data.f90 +33 -0
  393. offload/_root/data/findings/nested/controls/n8-ctl-fixed-array-in-component.f90 +33 -0
  394. offload/_root/data/findings/nested/controls/n9-ctl-allocatable-in-the-variable.f90 +33 -0
  395. offload/_root/data/findings/nested/controls/ns4-ctl-two-directives-struct-then-pointee.c +27 -0
  396. offload/_root/data/findings/nested/controls/ns8-ctl-enter-together-exit-split.c +26 -0
  397. offload/_root/data/findings/nested/controls/nu3-ctl-update-pointee-only.c +28 -0
  398. offload/_root/data/findings/nested/controls/p2-ctl-pointer-variable.c +27 -0
  399. offload/_root/data/findings/nested/controls/p3-ctl-direct-member.c +26 -0
  400. offload/_root/data/findings/nested/controls/q2-ctl-fixed-array.f90 +37 -0
  401. offload/_root/data/findings/nested/controls/q3-ctl-allocatable-component-of-the-variable.f90 +38 -0
  402. offload/_root/data/findings/nested/controls/ta2-ctl-no-allocatable-component.f90 +42 -0
  403. offload/_root/data/findings/nested/controls/ta3-ctl-allocatable-scalar-in-the-variable.f90 +38 -0
  404. offload/_root/data/findings/nested/controls/ta4-ctl-pointer-component-only.f90 +42 -0
  405. offload/_root/data/findings/nested/controls/u3-ctl-update-member-only.c +24 -0
  406. offload/_root/data/findings/nested/controls/u4-ctl-two-updates.c +25 -0
  407. offload/_root/data/findings/nested/controls/u5-ctl-same-list-in-map.c +25 -0
  408. offload/_root/data/findings/nested/controls/ua2-ctl-variable-root.f90 +37 -0
  409. offload/_root/data/findings/nested/controls/ua4-ctl-to-in-place-of-alloc-and-update.f90 +37 -0
  410. offload/_root/data/findings/nested/controls/v2-ctl-parent-first.c +25 -0
  411. offload/_root/data/findings/nested/controls/v4-ctl-embedded-member.c +24 -0
  412. offload/_root/data/findings/nested/gcc-acc-c-exit-data-of-a-pointer-array-element-target-hangs.c +83 -0
  413. offload/_root/data/findings/nested/gcc-acc-c-parent-and-shared-pointee-one-directive.c +88 -0
  414. offload/_root/data/findings/nested/gcc-acc-c-struct-and-member-array-one-directive.c +84 -0
  415. offload/_root/data/findings/nested/gcc-c-always-on-pointer-member-section-ice.c +75 -0
  416. offload/_root/data/findings/nested/gcc-c-declare-mapper-pointer-member-section-gpu-fault.c +93 -0
  417. offload/_root/data/findings/nested/gcc-c-from-struct-and-pointee-section-rejected.c +83 -0
  418. offload/_root/data/findings/nested/gcc-fortran-pointer-component-alloc-bounds-lost.f90 +62 -0
  419. offload/_root/data/findings/nested/gcc-fortran-root-and-element-pointer-components-ice.f90 +77 -0
  420. offload/_root/data/findings/nested/nvhpc-c-pointee-before-parent-in-one-map-list-copy-fault.c +55 -0
  421. offload/_root/data/findings/nested/nvhpc-c-update-from-structure-overwrites-attached-pointer-segv.c +86 -0
  422. offload/_root/data/findings/nvhpc-acc-atomic-update-sum-fort2-crash.f90 +53 -0
  423. offload/_root/data/findings/nvhpc-c-acc-atomic-update-sum-ice.c +43 -0
  424. offload/_root/data/findings/nvhpc-c-dist-schedule-chunk-compile-hang.c +41 -0
  425. offload/_root/data/findings/nvhpc-c-map-present-ignored.c +42 -0
  426. offload/_root/data/findings/nvhpc-c-ordered-in-target-nvcpfe-crash.c +92 -0
  427. offload/_root/data/findings/nvhpc-c-parallel-for-firstprivate-in-target.c +62 -0
  428. offload/_root/data/findings/nvhpc-c-parallel-if-in-target-nvvm-ice.c +56 -0
  429. offload/_root/data/findings/nvhpc-defaultmap-firstprivate-explicit-map.f90 +45 -0
  430. offload/_root/data/findings/nvhpc-defaultmap-from-allocatable-indexing.f90 +60 -0
  431. offload/_root/data/findings/nvhpc-depend-inoutset-ignored.f90 +64 -0
  432. offload/_root/data/findings/nvhpc-dist-schedule-chunk-illegal-address.f90 +52 -0
  433. offload/_root/data/findings/nvhpc-managed-acc-shutdown-host-access.f90 +42 -0
  434. offload/_root/data/findings/nvhpc-parallel-if-in-target-nvvm-ice.f90 +60 -0
  435. offload/_root/data/findings/oop/afar-final-dealloc-device-link.f90 +85 -0
  436. offload/_root/data/findings/oop/afar-pdt-length-parameter-not-implemented.f90 +65 -0
  437. offload/_root/data/findings/oop/cce-class-is-device-link.f90 +86 -0
  438. offload/_root/data/findings/oop/cce-copy-alloc-component-section-fault.f90 +73 -0
  439. offload/_root/data/findings/oop/cce-copy-parent-to-component-tofrom-lost.f90 +65 -0
  440. offload/_root/data/findings/oop/cce-copy-second-member-section-lost.f90 +65 -0
  441. offload/_root/data/findings/oop/cce-element-component-map-lost.f90 +64 -0
  442. offload/_root/data/findings/oop/cce-final-dealloc-device-abort.f90 +85 -0
  443. offload/_root/data/findings/oop/cce-pdt-default-mapper-rejected.f90 +71 -0
  444. offload/_root/data/findings/oop/cce-polymorphic-dispatch-device-link.f90 +100 -0
  445. offload/_root/data/findings/oop/cce-section-of-element-component-overlap.f90 +76 -0
  446. offload/_root/data/findings/oop/cce-select-type-guard-not-taken.f90 +91 -0
  447. offload/_root/data/findings/oop/cce-udr-derived-type-unsupported.f90 +69 -0
  448. offload/_root/data/findings/oop/cce21-element-component-map-lost.f90 +62 -0
  449. offload/_root/data/findings/oop/controls/alloccomp-comp-only.f90 +44 -0
  450. offload/_root/data/findings/oop/controls/alloccomp-whole-explicit-component.f90 +50 -0
  451. offload/_root/data/findings/oop/controls/alloccomp-whole.f90 +49 -0
  452. offload/_root/data/findings/oop/controls/elemsec-element.f90 +47 -0
  453. offload/_root/data/findings/oop/controls/final-local.f90 +64 -0
  454. offload/_root/data/findings/oop/controls/host-class-star-select-type.f90 +58 -0
  455. offload/_root/data/findings/oop/controls/host-firstprivate-defined-assignment.f90 +54 -0
  456. offload/_root/data/findings/oop/controls/host-lastprivate-defined-assignment.f90 +58 -0
  457. offload/_root/data/findings/oop/controls/host-private-finalization.f90 +51 -0
  458. offload/_root/data/findings/oop/controls/host-select-type.f90 +65 -0
  459. offload/_root/data/findings/oop/controls/parent-and-comp-component-only.f90 +45 -0
  460. offload/_root/data/findings/oop/controls/pdt-kind.f90 +46 -0
  461. offload/_root/data/findings/oop/controls/pdt-len-host.f90 +43 -0
  462. offload/_root/data/findings/oop/controls/pdt-len-unparameterized.f90 +46 -0
  463. offload/_root/data/findings/oop/controls/poly-dispatch-static.f90 +75 -0
  464. offload/_root/data/findings/oop/controls/section-alloc-whole-component.f90 +49 -0
  465. offload/_root/data/findings/oop/controls/section-element-whole-array.f90 +50 -0
  466. offload/_root/data/findings/oop/controls/section-element-whole-component.f90 +50 -0
  467. offload/_root/data/findings/oop/controls/section-fixed.f90 +43 -0
  468. offload/_root/data/findings/oop/controls/tbp-override.f90 +64 -0
  469. offload/_root/data/findings/oop/gcc-acc-parent-and-member-data-rejected.f90 +63 -0
  470. offload/_root/data/findings/oop/gcc-pdt-length-parameter-abort.f90 +68 -0
  471. offload/_root/data/findings/oop/gcc-polymorphic-dispatch-abort.f90 +97 -0
  472. offload/_root/data/findings/oop/gcc-vtab-not-marked-for-offload.f90 +94 -0
  473. offload/_root/data/findings/oop/nvhpc-copy-alloc-component-illegal-address.f90 +76 -0
  474. offload/_root/data/findings/oop/nvhpc-copy-pdt-length-parameter-illegal-address.f90 +69 -0
  475. offload/_root/data/findings/oop/nvhpc-named-mapper-rejected.f90 +65 -0
  476. offload/_root/data/findings/oop/nvhpc-polymorphic-dispatch-translate-failure.f90 +90 -0
  477. offload/_root/data/findings/oop/nvhpc-polymorphism-runtime-unsupported.f90 +94 -0
  478. offload/_root/data/findings/oop/nvhpc-type-bound-call-rejected.f90 +89 -0
  479. offload/_root/data/findings/oop/nvhpc-udr-derived-type-rejected.f90 +67 -0
  480. offload/_root/data/findings/reviews/afar-c-error-directive-in-target-link.json +217 -0
  481. offload/_root/data/findings/reviews/afar-c-lastprivate-distribute-parallel-for-small-type.json +113 -0
  482. offload/_root/data/findings/reviews/afar-c-teams-distribute-reduction-first-team.json +130 -0
  483. offload/_root/data/findings/reviews/afar-c-update-iterator-copy-mode.json +113 -0
  484. offload/_root/data/findings/reviews/afar-cce19-character-defaultmap.json +292 -0
  485. offload/_root/data/findings/reviews/afar-clang-requires-device-safesync-hang.json +191 -0
  486. offload/_root/data/findings/reviews/afar-flang-firstprivate-map-two-targets.json +130 -0
  487. offload/_root/data/findings/reviews/afar-flang-loop-bind-teams-reduction.json +126 -0
  488. offload/_root/data/findings/reviews/afar-flang-task-reduction-max.json +113 -0
  489. offload/_root/data/findings/reviews/afar-flang-thread-limit-target-parallel-do.json +113 -0
  490. offload/_root/data/findings/reviews/afar-loop-bind-thread-in-teams.json +191 -0
  491. offload/_root/data/findings/reviews/afar-nontemporal-assumed-shape-ice.json +113 -0
  492. offload/_root/data/findings/reviews/afar-udr-derived-type-link.json +113 -0
  493. offload/_root/data/findings/reviews/afar-xnack1-atomic-min-nested-parallel.json +113 -0
  494. offload/_root/data/findings/reviews/afar-xnack1-target-is-present.json +113 -0
  495. offload/_root/data/findings/reviews/apps--afar-cce-teams-private-array-nested-parallel-wrong.json +113 -0
  496. offload/_root/data/findings/reviews/apps--cce20-device-link-infer-address-spaces-crash.json +113 -0
  497. offload/_root/data/findings/reviews/apps--cce21-device-link-agpr-copy-mfma-assert.json +113 -0
  498. offload/_root/data/findings/reviews/apps--cce21-private-array-loaded-subscript-wrong.json +113 -0
  499. offload/_root/data/findings/reviews/apps--gcc-acc-c-tile-partial-tiles-wrong.json +113 -0
  500. offload/_root/data/findings/reviews/catalog--afar-c-ordered-doacross-link.json +113 -0
  501. offload/_root/data/findings/reviews/catalog--afar-c-reduction-task-link.json +113 -0
  502. offload/_root/data/findings/reviews/catalog--afar-flang-absent-optional-target-crash.json +113 -0
  503. offload/_root/data/findings/reviews/catalog--afar-flang-critical-target-parallel-wrong.json +113 -0
  504. offload/_root/data/findings/reviews/catalog--afar-flang-dist-schedule-chunk.json +113 -0
  505. offload/_root/data/findings/reviews/catalog--afar-flang-linear-parallel-ice.json +113 -0
  506. offload/_root/data/findings/reviews/catalog--afar-flang-named-critical-link.json +126 -0
  507. offload/_root/data/findings/reviews/catalog--afar-flang-ordered-wrong.json +113 -0
  508. offload/_root/data/findings/reviews/catalog--afar-flang-reduction-minus-rejected.json +113 -0
  509. offload/_root/data/findings/reviews/catalog--afar-flang-sections-in-target-ice.json +113 -0
  510. offload/_root/data/findings/reviews/catalog--afar-flang-workdistribute-ice.json +113 -0
  511. offload/_root/data/findings/reviews/catalog--c-allocate-const-mem-firstprivate-wrong.json +113 -0
  512. offload/_root/data/findings/reviews/catalog--cce-acc-character-dummy-routine-ice.json +113 -0
  513. offload/_root/data/findings/reviews/catalog--cce-acc-loop-seq-in-routine-wrong.json +113 -0
  514. offload/_root/data/findings/reviews/catalog--cce-allocators-stack-ice.json +113 -0
  515. offload/_root/data/findings/reviews/catalog--cce-c-allocate-align-link.json +113 -0
  516. offload/_root/data/findings/reviews/catalog--cce-c-allocate-allocator-modifier-rejected.json +113 -0
  517. offload/_root/data/findings/reviews/catalog--cce-c-dist-schedule-chunk.json +113 -0
  518. offload/_root/data/findings/reviews/catalog--cce-c-f-pointer-device-link.json +130 -0
  519. offload/_root/data/findings/reviews/catalog--cce-c-long-double-ice.json +217 -0
  520. offload/_root/data/findings/reviews/catalog--cce-c-map-iterator-ice.json +217 -0
  521. offload/_root/data/findings/reviews/catalog--cce-c-recursive-function-ice.json +113 -0
  522. offload/_root/data/findings/reviews/catalog--cce-c-sections-in-target-wrong.json +113 -0
  523. offload/_root/data/findings/reviews/catalog--cce-flang-allocate-in-target-crash.json +113 -0
  524. offload/_root/data/findings/reviews/catalog--cce-flang-lastprivate-parallel-in-seq-loop-wrong.json +113 -0
  525. offload/_root/data/findings/reviews/catalog--cce-flang-stop-in-target-crash.json +113 -0
  526. offload/_root/data/findings/reviews/catalog--cce-iterator-link.json +113 -0
  527. offload/_root/data/findings/reviews/catalog--cce-linear-lastprivate-ice.json +113 -0
  528. offload/_root/data/findings/reviews/catalog--cce-reduction-inscan-ice.json +113 -0
  529. offload/_root/data/findings/reviews/catalog--cce-reduction-task-link.json +113 -0
  530. offload/_root/data/findings/reviews/catalog--cce19-reduction-task-addrspacecast-ice.json +113 -0
  531. offload/_root/data/findings/reviews/catalog--cce20-c-defaultmap-private-storage-rejected.json +217 -0
  532. offload/_root/data/findings/reviews/catalog--cce20-map-self-rejected.json +204 -0
  533. offload/_root/data/findings/reviews/catalog--cce21-c-target-loop-ice.json +126 -0
  534. offload/_root/data/findings/reviews/catalog--defaultmap-present-private-array-abort.json +236 -0
  535. offload/_root/data/findings/reviews/catalog--nvhpc-acc-associate-illegal-address.json +113 -0
  536. offload/_root/data/findings/reviews/catalog--nvhpc-c-function-pointer-kernel-missing.json +268 -0
  537. offload/_root/data/findings/reviews/cce-acc-init-set-runtime-assert.json +113 -0
  538. offload/_root/data/findings/reviews/cce-acc-reduction-200-int8-scalars-wrong.json +113 -0
  539. offload/_root/data/findings/reviews/cce-acc-routine-bind-module-ice.json +113 -0
  540. offload/_root/data/findings/reviews/cce-c-dist-schedule-segv.json +113 -0
  541. offload/_root/data/findings/reviews/cce-c-map-delete-refcount.json +149 -0
  542. offload/_root/data/findings/reviews/cce-c-map-present-assert.json +126 -0
  543. offload/_root/data/findings/reviews/cce-c-openmp45-device-link.json +113 -0
  544. offload/_root/data/findings/reviews/cce-c-parallel-for-in-target.json +141 -0
  545. offload/_root/data/findings/reviews/cce-mapper-next-map-copy-back.json +208 -0
  546. offload/_root/data/findings/reviews/cce-uses-allocators-traits-omp50.json +191 -0
  547. offload/_root/data/findings/reviews/cce19-c-reduction-63-scalars-one-wrong.json +113 -0
  548. offload/_root/data/findings/reviews/cce19-target-parallel-guarded-loop.json +113 -0
  549. offload/_root/data/findings/reviews/cce19-target-parallel-single-ice.json +113 -0
  550. offload/_root/data/findings/reviews/cce21-alloc-2e32-sum-wrong.json +113 -0
  551. offload/_root/data/findings/reviews/cce21-defaultmap-aggregate-flag.json +210 -0
  552. offload/_root/data/findings/reviews/cce21-in-reduction-assumed-shape-write-lost.json +113 -0
  553. offload/_root/data/findings/reviews/cce21-in-reduction-taskwait-link.json +113 -0
  554. offload/_root/data/findings/reviews/clang-c-declare-target-to-omp52.json +113 -0
  555. offload/_root/data/findings/reviews/clang-c-linear-directive-name-hang.json +113 -0
  556. offload/_root/data/findings/reviews/clang-c-shared-declare-target-combined.json +132 -0
  557. offload/_root/data/findings/reviews/dataenv--cce-value-dummy-target-write-visible.json +113 -0
  558. offload/_root/data/findings/reviews/defaultmap-none-loop-variable.json +113 -0
  559. offload/_root/data/findings/reviews/fortran-schedule-static-in-target.json +113 -0
  560. offload/_root/data/findings/reviews/fresh--cce-common-block-name-in-map-rejected.json +113 -0
  561. offload/_root/data/findings/reviews/fresh--cce-list-directed-print-in-target-copy-crash.json +217 -0
  562. offload/_root/data/findings/reviews/fresh--cce19-acc-automatic-array-copyout-copy-crash.json +113 -0
  563. offload/_root/data/findings/reviews/fresh--cce21-combined-if-runtime-expr-loop-skipped.json +113 -0
  564. offload/_root/data/findings/reviews/fresh--nvhpc-acc-gang-worker-collapse-nested-vector-reduction-lost.json +113 -0
  565. offload/_root/data/findings/reviews/fresh--nvhpc-teams-loop-module-allocatable-assign-fort2-crash.json +113 -0
  566. offload/_root/data/findings/reviews/fuzz--1505-cce20.json +113 -0
  567. offload/_root/data/findings/reviews/fuzz--1540-afar.json +113 -0
  568. offload/_root/data/findings/reviews/fuzz--1978-cce19.json +130 -0
  569. offload/_root/data/findings/reviews/fuzz--2334-cce19.json +113 -0
  570. offload/_root/data/findings/reviews/fuzz--591-cce19.json +147 -0
  571. offload/_root/data/findings/reviews/fuzz--650-afar.json +113 -0
  572. offload/_root/data/findings/reviews/fuzz--916-afar.json +130 -0
  573. offload/_root/data/findings/reviews/fuzz--98-cce19.json +113 -0
  574. offload/_root/data/findings/reviews/fuzz--b1-121-afar.json +160 -0
  575. offload/_root/data/findings/reviews/fuzz--b2-209-cce19.json +141 -0
  576. offload/_root/data/findings/reviews/fuzz--b2-68-afar.json +113 -0
  577. offload/_root/data/findings/reviews/fuzz--b2-85-cce20.json +217 -0
  578. offload/_root/data/findings/reviews/fuzz--b3-188-cce19.json +113 -0
  579. offload/_root/data/findings/reviews/fuzz--b3-278-cce19.json +212 -0
  580. offload/_root/data/findings/reviews/fuzz--b3-54-afar.json +113 -0
  581. offload/_root/data/findings/reviews/fuzz--b3-61-cce20.json +191 -0
  582. offload/_root/data/findings/reviews/fuzz--b4-86-cce19.json +113 -0
  583. offload/_root/data/findings/reviews/fuzz--gcc-declare-reduction-module-not-found.json +113 -0
  584. offload/_root/data/findings/reviews/fuzz--gcc-target-simd-map-nontemporal-rejected.json +113 -0
  585. offload/_root/data/findings/reviews/fuzz--nvhpc-allocatable-component-implicit-map-illegal-address.json +141 -0
  586. offload/_root/data/findings/reviews/fuzz--nvhpc-assumed-length-character-dummy-map-ice.json +113 -0
  587. offload/_root/data/findings/reviews/fuzz--nvhpc-default-none-reduction-lastprivate-fort1-crash.json +113 -0
  588. offload/_root/data/findings/reviews/fuzz--nvhpc-defaultmap-firstprivate-lastprivate-ice.json +113 -0
  589. offload/_root/data/findings/reviews/fuzz--nvhpc-defaultmap-to-scalar-reduction-lost.json +113 -0
  590. offload/_root/data/findings/reviews/fuzz--nvhpc-depend-implicit-map-illegal-address.json +113 -0
  591. offload/_root/data/findings/reviews/fuzz--nvhpc-distribute-parallel-num-threads-writes-lost.json +113 -0
  592. offload/_root/data/findings/reviews/fuzz--nvhpc-end-distribute-simd-rejected.json +113 -0
  593. offload/_root/data/findings/reviews/fuzz--nvhpc-loop-character-achar-unsupported.json +113 -0
  594. offload/_root/data/findings/reviews/fuzz--nvhpc-map-always-after-map-to-not-copied-back.json +113 -0
  595. offload/_root/data/findings/reviews/fuzz--nvhpc-num-threads-reduction-identity-lost.json +113 -0
  596. offload/_root/data/findings/reviews/fuzz--nvhpc-target-parallel-firstprivate-translate-failure.json +191 -0
  597. offload/_root/data/findings/reviews/fuzz--nvhpc-target-parallel-single-hang.json +113 -0
  598. offload/_root/data/findings/reviews/fuzz--nvhpc-target-simd-collapse-translate-failure.json +113 -0
  599. offload/_root/data/findings/reviews/fuzz--nvhpc-target-simd-no-end-directive-rejected.json +113 -0
  600. offload/_root/data/findings/reviews/fuzz--par-s1-2082-gcc_g90.json +126 -0
  601. offload/_root/data/findings/reviews/fuzz--s1-2370-cce21.json +113 -0
  602. offload/_root/data/findings/reviews/fuzz--s1-2592-cce21.json +113 -0
  603. offload/_root/data/findings/reviews/fuzz--s1-3463-cce21.json +113 -0
  604. offload/_root/data/findings/reviews/fuzz--s1-6760-cce20.json +130 -0
  605. offload/_root/data/findings/reviews/fuzz--s1-6888-cce21.json +113 -0
  606. offload/_root/data/findings/reviews/fuzz--s1-7882-cce20.json +113 -0
  607. offload/_root/data/findings/reviews/fuzz--s1-8634-cce21.json +113 -0
  608. offload/_root/data/findings/reviews/fuzz--s1-91-cce21.json +113 -0
  609. offload/_root/data/findings/reviews/fuzz--s1-9443-afar.json +113 -0
  610. offload/_root/data/findings/reviews/fuzz--s1-9914-cce19.json +141 -0
  611. offload/_root/data/findings/reviews/gcc--gcc-acc-bind-device-type-rejected.json +113 -0
  612. offload/_root/data/findings/reviews/gcc--gcc-acc-detach-delete-attach-underflow.json +314 -0
  613. offload/_root/data/findings/reviews/gcc--gcc-acc-gang-dim-collapse-force-rejected.json +113 -0
  614. offload/_root/data/findings/reviews/gcc--gcc-acc-init-set-shutdown-rejected.json +113 -0
  615. offload/_root/data/findings/reviews/gcc--gcc-acc-link-in-routine-rejected.json +113 -0
  616. offload/_root/data/findings/reviews/gcc--gcc-acc-use-device-allocatable-rejected.json +113 -0
  617. offload/_root/data/findings/reviews/gcc--gcc-c-motion-mapper-rejected.json +113 -0
  618. offload/_root/data/findings/reviews/gcc--gcc-c-omp60-undocumented-rejected.json +217 -0
  619. offload/_root/data/findings/reviews/gcc--gcc-c-omp60-unimplemented-rejected.json +236 -0
  620. offload/_root/data/findings/reviews/gcc--gcc-c-target-in-task-mandatory-device-not-found.json +236 -0
  621. offload/_root/data/findings/reviews/gcc--gcc-c-uses-allocators-traits-unimplemented.json +113 -0
  622. offload/_root/data/findings/reviews/gcc--gcc-declare-mapper-rejected.json +113 -0
  623. offload/_root/data/findings/reviews/gcc--gcc-defaultmap-to-pointer-copy-back.json +217 -0
  624. offload/_root/data/findings/reviews/gcc--gcc-loop-bind-default-none-rejected.json +113 -0
  625. offload/_root/data/findings/reviews/harvest--afar-flang-strided-target-update.json +141 -0
  626. offload/_root/data/findings/reviews/harvest--cce-acc-declare-create-module-allocatable-xnack1-fault.json +113 -0
  627. offload/_root/data/findings/reviews/harvest--cce-c-implicit-struct-map-partly-present.json +217 -0
  628. offload/_root/data/findings/reviews/harvest--cce-c-strided-target-update.json +141 -0
  629. offload/_root/data/findings/reviews/harvest--cce-ftn-target-parallel-thread-query-ice.json +130 -0
  630. offload/_root/data/findings/reviews/harvest--cce-named-constant-array-declare-target-routine-rejected.json +113 -0
  631. offload/_root/data/findings/reviews/harvest--cce-use-device-ptr-c-ptr-not-converted.json +113 -0
  632. offload/_root/data/findings/reviews/harvest--cce21-declare-target-link-module-variable-write-lost.json +113 -0
  633. offload/_root/data/findings/reviews/harvest--cce21-internal-procedure-calls-internal-in-target-fault.json +158 -0
  634. offload/_root/data/findings/reviews/harvest--gcc-acc-declare-create-allocatable-not-mapped.json +204 -0
  635. offload/_root/data/findings/reviews/harvest--gcc-c-same-item-two-maps-rejected.json +143 -0
  636. offload/_root/data/findings/reviews/harvest--gcc-c-strided-section-rejected.json +164 -0
  637. offload/_root/data/findings/reviews/harvest--gcc-c-target-data-struct-pointer-section-ice.json +113 -0
  638. offload/_root/data/findings/reviews/harvest--gcc-c-target-data-two-maps-ice.json +113 -0
  639. offload/_root/data/findings/reviews/harvest--gcc-teams-simd-matmul-allocatable-ice.json +113 -0
  640. offload/_root/data/findings/reviews/harvest--nvhpc-c-target-data-if-false-use-device-ptr-garbage.json +113 -0
  641. offload/_root/data/findings/reviews/harvest--nvhpc-named-constant-array-declare-target-routine-rejected.json +126 -0
  642. offload/_root/data/findings/reviews/harvest--nvhpc-use-device-ptr-c-ptr-not-found.json +113 -0
  643. offload/_root/data/findings/reviews/harvest--nvhpc2511-target-nowait-in-parallel-for-ice.json +130 -0
  644. offload/_root/data/findings/reviews/hecbench--gcc-c-float16-array-in-target-lto-ice.json +217 -0
  645. offload/_root/data/findings/reviews/hecbench--gcc-c-swar-popcount-assembler-error.json +126 -0
  646. offload/_root/data/findings/reviews/malloc--afar-device-malloc-in-kernel-corrupts-records.json +270 -0
  647. offload/_root/data/findings/reviews/multithread-allocatable-section-maps.json +191 -0
  648. offload/_root/data/findings/reviews/nested--afar-cce-c-call-result-member-in-target-rejected.json +113 -0
  649. offload/_root/data/findings/reviews/nested--afar-cce-c-update-struct-and-member-rejected.json +126 -0
  650. offload/_root/data/findings/reviews/nested--afar-flang-pointer-root-allocatable-component-enter-data-fault.json +191 -0
  651. offload/_root/data/findings/reviews/nested--cce-c-struct-and-nested-pointee-sections-ice.json +113 -0
  652. offload/_root/data/findings/reviews/nested--cce-fortran-nested-allocatable-component-copy-fault.json +214 -0
  653. offload/_root/data/findings/reviews/nested--cce-fortran-pointer-to-type-with-allocatable-scalar-component-typed-transfer.json +191 -0
  654. offload/_root/data/findings/reviews/nested--cce-fortran-update-to-pointer-root-allocatable-scalar-component-no-accelerator-object.json +297 -0
  655. offload/_root/data/findings/reviews/nested--gcc-acc-c-exit-data-of-a-pointer-array-element-target-hangs.json +204 -0
  656. offload/_root/data/findings/reviews/nested--gcc-acc-c-parent-and-shared-pointee-one-directive.json +130 -0
  657. offload/_root/data/findings/reviews/nested--gcc-acc-c-struct-and-member-array-one-directive.json +141 -0
  658. offload/_root/data/findings/reviews/nested--gcc-c-always-on-pointer-member-section-ice.json +113 -0
  659. offload/_root/data/findings/reviews/nested--gcc-c-declare-mapper-pointer-member-section-gpu-fault.json +113 -0
  660. offload/_root/data/findings/reviews/nested--gcc-c-from-struct-and-pointee-section-rejected.json +113 -0
  661. offload/_root/data/findings/reviews/nested--gcc-fortran-pointer-component-alloc-bounds-lost.json +217 -0
  662. offload/_root/data/findings/reviews/nested--gcc-fortran-root-and-element-pointer-components-ice.json +217 -0
  663. offload/_root/data/findings/reviews/nested--nvhpc-c-pointee-before-parent-in-one-map-list-copy-fault.json +204 -0
  664. offload/_root/data/findings/reviews/nested--nvhpc-c-update-from-structure-overwrites-attached-pointer-segv.json +191 -0
  665. offload/_root/data/findings/reviews/nvhpc-c-acc-atomic-update-sum-ice.json +277 -0
  666. offload/_root/data/findings/reviews/nvhpc-c-dist-schedule-chunk-compile-hang.json +113 -0
  667. offload/_root/data/findings/reviews/nvhpc-c-map-present-ignored.json +113 -0
  668. offload/_root/data/findings/reviews/nvhpc-c-ordered-in-target-nvcpfe-crash.json +113 -0
  669. offload/_root/data/findings/reviews/nvhpc-c-parallel-for-firstprivate-in-target.json +113 -0
  670. offload/_root/data/findings/reviews/nvhpc-defaultmap-firstprivate-explicit-map.json +113 -0
  671. offload/_root/data/findings/reviews/nvhpc-defaultmap-from-allocatable-indexing.json +132 -0
  672. offload/_root/data/findings/reviews/nvhpc-depend-inoutset-ignored.json +113 -0
  673. offload/_root/data/findings/reviews/nvhpc-dist-schedule-chunk-illegal-address.json +113 -0
  674. offload/_root/data/findings/reviews/nvhpc-managed-acc-shutdown-host-access.json +113 -0
  675. offload/_root/data/findings/reviews/nvhpc-parallel-if-in-target-nvvm-ice.json +113 -0
  676. offload/_root/data/findings/reviews/oop--afar-final-dealloc-device-link.json +132 -0
  677. offload/_root/data/findings/reviews/oop--afar-pdt-length-parameter-not-implemented.json +113 -0
  678. offload/_root/data/findings/reviews/oop--cce-class-is-device-link.json +130 -0
  679. offload/_root/data/findings/reviews/oop--cce-copy-alloc-component-section-fault.json +217 -0
  680. offload/_root/data/findings/reviews/oop--cce-copy-parent-to-component-tofrom-lost.json +217 -0
  681. offload/_root/data/findings/reviews/oop--cce-copy-second-member-section-lost.json +113 -0
  682. offload/_root/data/findings/reviews/oop--cce-element-component-map-lost.json +113 -0
  683. offload/_root/data/findings/reviews/oop--cce-final-dealloc-device-abort.json +208 -0
  684. offload/_root/data/findings/reviews/oop--cce-pdt-default-mapper-rejected.json +191 -0
  685. offload/_root/data/findings/reviews/oop--cce-polymorphic-dispatch-device-link.json +247 -0
  686. offload/_root/data/findings/reviews/oop--cce-section-of-element-component-overlap.json +113 -0
  687. offload/_root/data/findings/reviews/oop--cce-select-type-guard-not-taken.json +191 -0
  688. offload/_root/data/findings/reviews/oop--cce-udr-derived-type-unsupported.json +132 -0
  689. offload/_root/data/findings/reviews/oop--gcc-acc-parent-and-member-data-rejected.json +141 -0
  690. offload/_root/data/findings/reviews/oop--gcc-pdt-length-parameter-abort.json +141 -0
  691. offload/_root/data/findings/reviews/oop--gcc-polymorphic-dispatch-abort.json +217 -0
  692. offload/_root/data/findings/reviews/oop--gcc-vtab-not-marked-for-offload.json +113 -0
  693. offload/_root/data/findings/reviews/oop--nvhpc-copy-alloc-component-illegal-address.json +113 -0
  694. offload/_root/data/findings/reviews/oop--nvhpc-copy-pdt-length-parameter-illegal-address.json +236 -0
  695. offload/_root/data/findings/reviews/oop--nvhpc-named-mapper-rejected.json +113 -0
  696. offload/_root/data/findings/reviews/oop--nvhpc-polymorphic-dispatch-translate-failure.json +223 -0
  697. offload/_root/data/findings/reviews/oop--nvhpc-polymorphism-runtime-unsupported.json +126 -0
  698. offload/_root/data/findings/reviews/oop--nvhpc-type-bound-call-rejected.json +113 -0
  699. offload/_root/data/findings/reviews/oop--nvhpc-udr-derived-type-rejected.json +113 -0
  700. offload/_root/data/findings/reviews/stress--afar-c-lastprivate-combined-target-not-mapped.json +113 -0
  701. offload/_root/data/findings/reviews/stress--afar-target-scalar-implicit-firstprivate.json +175 -0
  702. offload/_root/data/findings/reviews/stress--cce-acc-declare-create-scalar-serial-firstprivate.json +113 -0
  703. offload/_root/data/findings/reviews/stress--cce-c-distribute-lastprivate-lost.json +113 -0
  704. offload/_root/data/findings/reviews/stress--cce-c-flto-offload-dropped.json +204 -0
  705. offload/_root/data/findings/reviews/stress--cce-ftn-cif-record-split-abort.json +113 -0
  706. offload/_root/data/findings/reviews/stress--cce-lastprivate-num-threads-collapse-simd.json +113 -0
  707. offload/_root/data/findings/reviews/stress--cce-teams-reduction-many-teams-wrap.json +113 -0
  708. offload/_root/data/findings/reviews/stress--cce21-declare-target-scalar-map-write-lost.json +113 -0
  709. offload/_root/data/findings/reviews/stress--gcc-declare-target-allocatable-component-ice.json +191 -0
  710. offload/_root/data/findings/reviews/stress--nvhpc-acc-derived-type-component-not-copied.json +126 -0
  711. offload/_root/data/findings/reviews/stress--nvhpc-c-lastprivate-teams-distribute-parallel-for-lost.json +113 -0
  712. offload/_root/data/findings/reviews/stress--nvhpc-declare-target-scalar-write-lost.json +113 -0
  713. offload/_root/data/findings/reviews/stress--nvhpc-lastprivate-combined-target-not-mapped.json +113 -0
  714. offload/_root/data/findings/reviews/stress--nvhpc-target-scalar-implicit-firstprivate.json +130 -0
  715. offload/_root/data/findings/reviews/target-update-sections-in-parallel.json +113 -0
  716. offload/_root/data/findings/stress/afar-c-lastprivate-combined-target-not-mapped.c +72 -0
  717. offload/_root/data/findings/stress/afar-target-scalar-implicit-firstprivate.f90 +47 -0
  718. offload/_root/data/findings/stress/cce-acc-declare-create-scalar-serial-firstprivate.f90 +43 -0
  719. offload/_root/data/findings/stress/cce-c-distribute-lastprivate-lost.c +52 -0
  720. offload/_root/data/findings/stress/cce-c-flto-offload-dropped.c +73 -0
  721. offload/_root/data/findings/stress/cce-ftn-cif-record-split-abort.f90 +109 -0
  722. offload/_root/data/findings/stress/cce-lastprivate-num-threads-collapse-simd.f90 +66 -0
  723. offload/_root/data/findings/stress/cce-teams-reduction-many-teams-wrap.f90 +55 -0
  724. offload/_root/data/findings/stress/cce21-declare-target-scalar-map-write-lost.f90 +58 -0
  725. offload/_root/data/findings/stress/controls/gcc-declare-target-allocatable-component-control.f90 +29 -0
  726. offload/_root/data/findings/stress/gcc-declare-target-allocatable-component-ice.f90 +61 -0
  727. offload/_root/data/findings/stress/nvhpc-acc-derived-type-component-not-copied.f90 +33 -0
  728. offload/_root/data/findings/stress/nvhpc-c-lastprivate-teams-distribute-parallel-for-lost.c +62 -0
  729. offload/_root/data/findings/stress/nvhpc-declare-target-scalar-write-lost.f90 +43 -0
  730. offload/_root/data/findings/stress/nvhpc-lastprivate-combined-target-not-mapped.f90 +60 -0
  731. offload/_root/data/findings/stress/nvhpc-target-scalar-implicit-firstprivate.f90 +41 -0
  732. offload/_root/data/findings/target-update-sections-in-parallel.f90 +53 -0
  733. offload/_root/data/issues.json +1 -0
  734. offload/_root/data/search.json +1 -0
  735. offload/_root/data/vendor/checks/build.py +288 -0
  736. offload/_version.py +24 -0
  737. offload/canuse.py +88 -0
  738. offload/cli.py +52 -0
  739. offload/data.py +85 -0
  740. offload/engine/__init__.py +0 -0
  741. offload/engine/acc_c_gen.py +415 -0
  742. offload/engine/acc_gen.py +1104 -0
  743. offload/engine/acc_rules.py +656 -0
  744. offload/engine/apps.py +804 -0
  745. offload/engine/baseline.py +324 -0
  746. offload/engine/c_gen.py +883 -0
  747. offload/engine/c_program.py +913 -0
  748. offload/engine/c_rules.py +503 -0
  749. offload/engine/campaign.py +1180 -0
  750. offload/engine/campaigns/__init__.py +2 -0
  751. offload/engine/campaigns/hecbench.py +153 -0
  752. offload/engine/campaigns/nested.py +76 -0
  753. offload/engine/campaigns/oop.py +61 -0
  754. offload/engine/canary.py +275 -0
  755. offload/engine/catalog.py +860 -0
  756. offload/engine/citations.py +532 -0
  757. offload/engine/clang_oracle.py +208 -0
  758. offload/engine/combos.py +234 -0
  759. offload/engine/confirm/__init__.py +2 -0
  760. offload/engine/confirm/backlog.py +159 -0
  761. offload/engine/confirm/claims.py +423 -0
  762. offload/engine/confirm/collectors.py +665 -0
  763. offload/engine/confirm/decisions.py +202 -0
  764. offload/engine/confirm/draft.py +195 -0
  765. offload/engine/confirm/engine.py +157 -0
  766. offload/engine/confirm/execute.py +382 -0
  767. offload/engine/confirm/facts.py +467 -0
  768. offload/engine/confirm/findings.py +617 -0
  769. offload/engine/confirm/forms.py +145 -0
  770. offload/engine/confirm/ingest.py +372 -0
  771. offload/engine/confirm/jobs.py +215 -0
  772. offload/engine/confirm/legality.py +323 -0
  773. offload/engine/confirm/machines.py +254 -0
  774. offload/engine/confirm/minimize.py +268 -0
  775. offload/engine/confirm/model.py +249 -0
  776. offload/engine/confirm/ports.py +107 -0
  777. offload/engine/confirm/programs.py +222 -0
  778. offload/engine/confirm/registry.py +151 -0
  779. offload/engine/confirm/regress.py +278 -0
  780. offload/engine/confirm/rules.py +565 -0
  781. offload/engine/confirm/store.py +63 -0
  782. offload/engine/confirm/triage.py +838 -0
  783. offload/engine/confirm/validate.py +607 -0
  784. offload/engine/confirm/witness.py +355 -0
  785. offload/engine/corpus_check.py +388 -0
  786. offload/engine/coverage.py +318 -0
  787. offload/engine/dataenv_gen.py +1318 -0
  788. offload/engine/dataenv_rules.py +278 -0
  789. offload/engine/devtemps.py +146 -0
  790. offload/engine/expected.py +2559 -0
  791. offload/engine/f2c.py +1783 -0
  792. offload/engine/finding_claims.py +330 -0
  793. offload/engine/finding_header.py +229 -0
  794. offload/engine/finding_rows.py +382 -0
  795. offload/engine/flang_oracle.py +299 -0
  796. offload/engine/fsource.py +620 -0
  797. offload/engine/fuzz.py +2455 -0
  798. offload/engine/fuzz_base.py +2016 -0
  799. offload/engine/fuzz_campaign.py +592 -0
  800. offload/engine/fuzz_exec.py +798 -0
  801. offload/engine/fuzz_min.py +1049 -0
  802. offload/engine/fuzz_profile.py +340 -0
  803. offload/engine/fuzz_report.py +1270 -0
  804. offload/engine/fuzz_steer.py +181 -0
  805. offload/engine/gate.py +1013 -0
  806. offload/engine/gate_report.py +711 -0
  807. offload/engine/gate_run.py +118 -0
  808. offload/engine/gate_stored.py +466 -0
  809. offload/engine/gen.py +1114 -0
  810. offload/engine/gen_templates.py +2583 -0
  811. offload/engine/grammar.py +695 -0
  812. offload/engine/harness.py +1472 -0
  813. offload/engine/harvest/__init__.py +3 -0
  814. offload/engine/harvest/c_runtime.py +465 -0
  815. offload/engine/harvest/checks.py +534 -0
  816. offload/engine/harvest/convert.py +784 -0
  817. offload/engine/harvest/f_runtime.py +668 -0
  818. offload/engine/harvest/filters.py +338 -0
  819. offload/engine/harvest/history.py +122 -0
  820. offload/engine/harvest/inventory.py +399 -0
  821. offload/engine/harvest2/__init__.py +5 -0
  822. offload/engine/harvest2/aomp.py +119 -0
  823. offload/engine/harvest2/examples.py +116 -0
  824. offload/engine/harvest2/gomp.py +679 -0
  825. offload/engine/harvest2/hand.py +150 -0
  826. offload/engine/harvest2/split.py +78 -0
  827. offload/engine/harvest_known/__init__.py +2 -0
  828. offload/engine/harvest_known/apps.py +65 -0
  829. offload/engine/harvest_known/cases.py +128 -0
  830. offload/engine/harvest_known/centres.py +184 -0
  831. offload/engine/harvest_known/forum.py +180 -0
  832. offload/engine/harvest_known/relnotes.py +42 -0
  833. offload/engine/harvest_known/textscan.py +107 -0
  834. offload/engine/hdrwrap.py +42 -0
  835. offload/engine/hecbench.py +568 -0
  836. offload/engine/hecbench_report.py +265 -0
  837. offload/engine/hecbench_run.py +483 -0
  838. offload/engine/idioms.py +1427 -0
  839. offload/engine/kbody_cites.py +81 -0
  840. offload/engine/kbody_emit.py +949 -0
  841. offload/engine/kbody_gen.py +795 -0
  842. offload/engine/legality_review.py +236 -0
  843. offload/engine/localcfg.py +58 -0
  844. offload/engine/malloc_dd.py +267 -0
  845. offload/engine/mutate.py +1933 -0
  846. offload/engine/nested_cites.py +196 -0
  847. offload/engine/nested_emit.py +789 -0
  848. offload/engine/nested_gen.py +1721 -0
  849. offload/engine/offload_scope.py +197 -0
  850. offload/engine/ompvv.py +624 -0
  851. offload/engine/oop_gen.py +2249 -0
  852. offload/engine/prerun.py +1435 -0
  853. offload/engine/program_source.py +739 -0
  854. offload/engine/provenance.py +103 -0
  855. offload/engine/reduce.py +2098 -0
  856. offload/engine/report.py +3374 -0
  857. offload/engine/root.py +33 -0
  858. offload/engine/rules.py +4256 -0
  859. offload/engine/run_matrix.py +325 -0
  860. offload/engine/site/__init__.py +1 -0
  861. offload/engine/site/columns.py +53 -0
  862. offload/engine/site/data.py +648 -0
  863. offload/engine/site/header.py +228 -0
  864. offload/engine/site/inputs.py +115 -0
  865. offload/engine/site/matrix.py +434 -0
  866. offload/engine/site/scrub.py +294 -0
  867. offload/engine/skeleton.py +121 -0
  868. offload/engine/spec_text.py +242 -0
  869. offload/engine/stress.py +4122 -0
  870. offload/engine/stress_c.py +1000 -0
  871. offload/engine/stress_exec.py +805 -0
  872. offload/engine/stress_min.py +248 -0
  873. offload/engine/stress_report.py +552 -0
  874. offload/engine/textclean.py +97 -0
  875. offload/engine/toolchains.py +1070 -0
  876. offload/engine/transforms.py +511 -0
  877. offload/engine/usage.py +1252 -0
  878. offload/engine/widen.py +673 -0
  879. offload/engine/widen_progs.py +2396 -0
  880. offload/issues.py +146 -0
  881. offtarget-0.1.0.dist-info/METADATA +86 -0
  882. offtarget-0.1.0.dist-info/RECORD +886 -0
  883. offtarget-0.1.0.dist-info/WHEEL +4 -0
  884. offtarget-0.1.0.dist-info/entry_points.txt +2 -0
  885. offtarget-0.1.0.dist-info/licenses/LICENSE +21 -0
  886. offtarget-0.1.0.dist-info/licenses/THIRD_PARTY_NOTICES.md +20 -0
@@ -0,0 +1,4122 @@
1
+ """Stress programs: very large and very complex device-offload programs that
2
+ are still legal and still checked.
3
+
4
+ A stress program is a list of kernels. Each is its own subroutine in a kernel
5
+ module with its own data and prints its own value, so a wrong answer names the
6
+ kernel. Values come from a Python model (``Kernel.value``). The program prints
7
+ ``K <name> <value>`` per kernel and ends with the fuzz line
8
+ ``RESULT checksum=<sum mod P> ran_on_host=<0|1>`` (``offload.engine.fuzz_exec``).
9
+ ``AXES`` lists the axes and ``build(axis, size, seed, ...)`` makes a program:
10
+ many kernels, deep nests and call chains, long clause lists, continuation
11
+ lines and names, derived types, many translation units, async sequences and
12
+ kernel shapes taken from real failing codes (``template``).
13
+ Each program is labelled ``legal``, ``illegal_probe`` (beyond a base-language
14
+ limit, so a rejection is right), ``unspecified`` or ``impl_defined``;
15
+ ``limits`` relabels a program that exceeds a base-language limit."""
16
+ from __future__ import annotations
17
+
18
+ import random
19
+ import re
20
+ from dataclasses import dataclass, field
21
+
22
+ P = 2147483629 # checksum modulus (offload.engine.fuzz)
23
+ LINE_MAX = 132 # F2008 3.3.2.1 / F2018 6.3.2.1
24
+ CONT_MAX = 255 # F2008 3.3.2.4 / F2018 6.3.2.4
25
+ NAME_MAX = 63 # F2008 3.2.2 / F2018 6.2.2
26
+ BOUND = 2 ** 62
27
+ FILE_MARK = "!@file " # offload.engine.fuzz_base bundle marker
28
+ WIDTH = 100 # default packing width of long lines
29
+
30
+ CITES = {
31
+ "line": "Fortran 2018 6.3.2.1: a free-form line shall contain at most "
32
+ "132 characters",
33
+ "cont": "Fortran 2018 6.3.2.4: a free-form statement shall not have "
34
+ "more than 255 continuation lines",
35
+ "name": "Fortran 2018 6.2.2: a name shall have at most 63 characters",
36
+ "xtu": "OpenMP 5.2 §13.8 p.284 (a procedure referenced in a target "
37
+ "construct is treated as if named in an enter clause) and §5.8.4 "
38
+ "p.158 (a device version is created when the enter clause is in "
39
+ "the compilation unit of the definition), §1.2.2 p.3 (for "
40
+ "Fortran a compilation unit is a program unit; OpenACC 3.4 "
41
+ "§2.15.1 p.91 likewise): a procedure of another module needs its "
42
+ "own declare target / routine directive, even in the same file",
43
+ "tbp": "OpenMP 5.0 §1.2.6 p.15 / 5.2 §1.2.6 p.18 (mappable type): all "
44
+ "type-bound procedures accessed in a target region must appear "
45
+ "in a declare target directive",
46
+ "poly": "an OpenMP 6.0 program: 6.0 §7.9.6 p.287, if a map list item "
47
+ "has polymorphic type, the behavior is unspecified (5.2 restricts "
48
+ "polymorphic allocatables only in firstprivate, lastprivate and "
49
+ "copyprivate, §5.4.4, §5.4.5, §5.7.2 p.146; it does not make "
50
+ "this map unspecified, so the program declares 6.0)",
51
+ "contig": "OpenMP 5.2 §5.8.3 p.155: a map list item that is an array "
52
+ "section must specify contiguous storage",
53
+ "stride": "OpenMP 5.2 §5.9 p.164: data-motion clause list items may "
54
+ "include array sections with stride expressions",
55
+ "share": "OpenMP 5.2 §5.8.3 p.155: two map list items on one construct "
56
+ "must not share original storage unless one contains the other",
57
+ }
58
+
59
+
60
+ class Overflow(Exception):
61
+ """A model value left the bound: the kernel is redrawn smaller."""
62
+
63
+
64
+ def chk(v: int) -> int:
65
+ if abs(v) >= BOUND:
66
+ raise Overflow(v)
67
+ return v
68
+
69
+
70
+ def fmod(a: int, p: int) -> int:
71
+ """Fortran MOD (sign of the dividend)."""
72
+ r = abs(a) % abs(p)
73
+ return r if a >= 0 else -r
74
+
75
+
76
+ def cksum(vals) -> int:
77
+ """The Fortran helper ``st_cksum``: sum of mod(v_i, P)*(mod(i,7)+1),
78
+ i from 1, mod P (every v_i >= 0)."""
79
+ cs = 0
80
+ for i, v in enumerate(vals, 1):
81
+ cs = (cs + fmod(v, P) * (i % 7 + 1)) % P
82
+ return cs
83
+
84
+
85
+ # --- text helpers -----------------------------------------------------------------------------
86
+
87
+ def pack(head: str, atoms: list[str], indent: str, sentinel: str | None,
88
+ width: int = WIDTH) -> list[str]:
89
+ """Lines of a statement (sentinel None) or directive (``!$omp``)
90
+ made of `head` and `atoms`, wrapped with ``&`` continuations at
91
+ `width` columns (an atom is never split; an atom wider than the line
92
+ gets a line of its own)."""
93
+ lead = f"{indent}{sentinel} " if sentinel else indent
94
+ cont = f"{indent}{sentinel}& " if sentinel else f"{indent} & "
95
+ lines, cur = [], lead + head
96
+ for a in atoms:
97
+ if len(cur) + len(a) + 1 + 2 > width and cur.strip() not in (
98
+ lead.strip(), cont.strip()):
99
+ lines.append(cur + " &")
100
+ cur = cont + a
101
+ else:
102
+ cur = cur + ("" if cur.endswith(("(", " ")) or a.startswith(
103
+ (")", ",")) else " ") + a
104
+ lines.append(cur)
105
+ return lines
106
+
107
+
108
+ def list_atoms(name: str, items: list[str], mod: str = "") -> list[str]:
109
+ """Atoms of a clause with a list: ``name(mod: a,`` ``b,`` ... ``z)``."""
110
+ if not items:
111
+ return []
112
+ head = f"{name}({mod}: " if mod else f"{name}("
113
+ out = []
114
+ for k, it in enumerate(items):
115
+ piece = it + ("," if k < len(items) - 1 else ")")
116
+ out.append(head + piece if k == 0 else piece)
117
+ return out
118
+
119
+
120
+ def call_lines(indent: str, name: str, args: list[str],
121
+ width: int = WIDTH) -> list[str]:
122
+ if not args:
123
+ return [f"{indent}call {name}()"]
124
+ return pack(f"call {name}(", [a + ("," if k < len(args) - 1 else ")")
125
+ for k, a in enumerate(args)],
126
+ indent, None, width)
127
+
128
+
129
+ def sum_lines(indent: str, target: str, terms: list[str],
130
+ width: int = WIDTH, chunk: int = 40) -> list[str]:
131
+ """``target = target + t1 + t2 ...`` in statements of at most `chunk`
132
+ terms (a long expression is the exprs axis' business)."""
133
+ out = []
134
+ for k in range(0, len(terms), chunk):
135
+ part = terms[k:k + chunk]
136
+ out += pack(f"{target} = {target} +",
137
+ [t + (" +" if j < len(part) - 1 else "")
138
+ for j, t in enumerate(part)], indent, None, width)
139
+ return out
140
+
141
+
142
+ def vname(prefix: str, k: int, width: int = 4) -> str:
143
+ return f"{prefix}{k:0{width}d}"
144
+
145
+
146
+ # --- directives for both models ------------------------------------------------------------------
147
+
148
+ @dataclass
149
+ class Opts:
150
+ model: str = "omp" # omp | acc
151
+ spell: int = 50 # OpenMP spelling: 50 (5.0 forms) or 52
152
+ level: str = "f2018"
153
+ width: int = WIDTH
154
+
155
+ @property
156
+ def sent(self) -> str:
157
+ return "!$omp" if self.model == "omp" else "!$acc"
158
+
159
+
160
+ # OpenMP chains (5.0 spellings; each a combined or split nest whose last
161
+ # leaf is a loop construct) and their OpenACC counterparts
162
+ OMP_CHAINS = (
163
+ ("target teams distribute parallel do",),
164
+ ("target teams distribute parallel do simd",),
165
+ ("target parallel do",),
166
+ ("target teams distribute",),
167
+ ("target teams distribute simd",),
168
+ ("target parallel do simd",),
169
+ ("target simd",),
170
+ ("target teams loop",),
171
+ ("target", "teams distribute parallel do"),
172
+ ("target teams", "distribute parallel do"),
173
+ ("target", "parallel do"),
174
+ ("target", "teams", "distribute parallel do"),
175
+ )
176
+ ACC_CHAINS = (
177
+ ("parallel loop gang vector",),
178
+ ("parallel loop",),
179
+ ("kernels loop",),
180
+ ("serial loop",),
181
+ ("parallel", "loop gang vector"),
182
+ ("kernels", "loop independent"),
183
+ )
184
+
185
+
186
+ def data_clauses(o: Opts, data: list[tuple[str, str]]) -> list[str]:
187
+ """Atoms of the data clauses: [(item, to|from|tofrom|alloc)]."""
188
+ groups: dict[str, list[str]] = {}
189
+ for item, kind in data:
190
+ groups.setdefault(kind, []).append(item)
191
+ out = []
192
+ for kind in ("to", "from", "tofrom", "alloc"):
193
+ if kind not in groups:
194
+ continue
195
+ if o.model == "omp":
196
+ out += list_atoms("map", groups[kind], kind)
197
+ else:
198
+ name = {"to": "copyin", "from": "copyout", "tofrom": "copy",
199
+ "alloc": "create"}[kind]
200
+ out += list_atoms(name, groups[kind])
201
+ return out
202
+
203
+
204
+ def region(o: Opts, chain: tuple, indent: str, data=(), private=(),
205
+ firstprivate=(), reduction=(), collapse: int = 0,
206
+ extra=(), loop_extra=()) -> tuple[list[str], list[str], str]:
207
+ """(opening lines, closing lines, inner indent) of a loop region of
208
+ `chain` (a tuple of directive texts, outermost first): data clauses on
209
+ the first directive, privatization / reduction / collapse on the last
210
+ (the loop directive), `extra` atoms on the first, `loop_extra` on the
211
+ last. Fortran OpenMP: every directive gets its end directive (a
212
+ combined loop construct's is optional; written for symmetry)."""
213
+ opens, closes = [], []
214
+ ind = indent
215
+ n = len(chain)
216
+ if n > 1 and reduction:
217
+ # OpenACC 3.4 §2.6.2 p.41: a reduction variable of a loop in a
218
+ # parallel construct must be in a data clause of the construct;
219
+ # OpenMP: a reduction on a construct nested in target (not a
220
+ # combined target construct) needs the variable mapped tofrom
221
+ # (otherwise it is firstprivate on target: 5.2 §5.8.1 p.148)
222
+ data = list(data) + [(v, "tofrom") for _, items in reduction
223
+ for v in items]
224
+ if n > 1 and o.model == "omp":
225
+ lp = [a for a in loop_extra if a.startswith("lastprivate(")]
226
+ for v in [x.strip(",)") for a in lp for x in
227
+ a[len("lastprivate("):].split()]:
228
+ data = list(data) + [(v, "tofrom")]
229
+ fp_first = o.model == "acc" and n > 1
230
+ for k, d in enumerate(chain):
231
+ atoms = []
232
+ if k == 0:
233
+ atoms += data_clauses(o, list(data)) + list(extra)
234
+ if fp_first:
235
+ # OpenACC: firstprivate is a compute-construct clause
236
+ # (3.4 §2.5.14), not a loop clause
237
+ atoms += list_atoms("firstprivate", list(firstprivate))
238
+ if k < n - 1 and "teams" in d.split() and reduction:
239
+ # the teams of a split nest would race on the shared variable:
240
+ # the reduction is on the teams construct too
241
+ for op, items in reduction:
242
+ atoms += list_atoms("reduction", list(items), op)
243
+ if k == n - 1:
244
+ if collapse > 1:
245
+ atoms.append(f"collapse({collapse})")
246
+ atoms += list_atoms("private", list(private))
247
+ if not fp_first:
248
+ atoms += list_atoms("firstprivate", list(firstprivate))
249
+ for op, items in reduction:
250
+ atoms += list_atoms("reduction", list(items), op)
251
+ atoms += list(loop_extra)
252
+ opens += pack(d, atoms, ind, o.sent, o.width)
253
+ dname = d if o.model == "omp" else " ".join(
254
+ w for w in d.split() if w in ("parallel", "kernels", "serial",
255
+ "loop"))
256
+ closes.insert(0, f"{ind}{o.sent} end {dname}")
257
+ if k < n - 1:
258
+ ind += " "
259
+ if o.model == "acc":
260
+ # an OpenACC loop construct has no end directive; a combined
261
+ # construct's is optional (written), a compute construct's required
262
+ closes = [c for c, d in zip(closes, reversed(chain))
263
+ if " loop" not in " " + d or d.split()[0] in
264
+ ("parallel", "kernels", "serial")]
265
+ return opens, closes, ind
266
+
267
+
268
+ # --- kernels -----------------------------------------------------------------------------------
269
+
270
+ @dataclass
271
+ class Module:
272
+ name: str
273
+ spec: list[str] = field(default_factory=list)
274
+ contains: list[str] = field(default_factory=list)
275
+ uses: list[str] = field(default_factory=list)
276
+
277
+
278
+ class Kernel:
279
+ """One kernel: a subroutine ``<name>(cs)`` of a kernel module. Every
280
+ random decision is made in the constructor (``self.p``), so the text
281
+ and the value are functions of ``p``; ``smaller`` returns variants for
282
+ the shrinker."""
283
+ kind = "base"
284
+ legality = "legal"
285
+ cite = ""
286
+ version = 50 # the OpenMP version whose text it needs
287
+ # whether the sequential elision computes the kernel's value (False
288
+ # where the value depends on data-sharing: a firstprivate copy's write
289
+ # is not seen by the host, the elided program writes the variable)
290
+ elision_valid = True
291
+
292
+ def __init__(self, name: str, o: Opts, rng: random.Random | None,
293
+ **p):
294
+ self.name, self.o = name, o
295
+ self.p = dict(p)
296
+ if rng is not None:
297
+ self.draw(rng)
298
+
299
+ def draw(self, rng: random.Random) -> None:
300
+ pass
301
+
302
+ def clone(self, **change) -> "Kernel":
303
+ k = type(self)(self.name, self.o, None, **{**self.p, **change})
304
+ return k
305
+
306
+ # text
307
+ def modules(self) -> list[Module]:
308
+ return []
309
+
310
+ def uses(self) -> list[str]:
311
+ return []
312
+
313
+ def decls(self) -> list[str]:
314
+ return []
315
+
316
+ def body(self) -> list[str]:
317
+ return []
318
+
319
+ def value(self) -> int:
320
+ raise NotImplementedError
321
+
322
+ def smaller(self) -> list["Kernel"]:
323
+ return []
324
+
325
+ def features(self) -> set:
326
+ return {f"kernel:{self.kind}"}
327
+
328
+ def describe(self) -> str:
329
+ def show(v):
330
+ if isinstance(v, list) and len(v) <= 6 and all(
331
+ isinstance(x, int) for x in v):
332
+ return "x".join(map(str, v))
333
+ if isinstance(v, list) and all(isinstance(x, str) for x in v):
334
+ return "+".join(v) if len(v) <= 4 else f"{len(v)}items"
335
+ return v
336
+ keys = ",".join(f"{k}={show(v)}" for k, v in sorted(self.p.items())
337
+ if (isinstance(v, (int, str)) or k in ("ext",
338
+ "routes"))
339
+ and k != "seed")
340
+ return f"{self.name}:{self.kind}({keys})"
341
+
342
+ def routine(self) -> list[str]:
343
+ ind = " "
344
+ lines = [f" subroutine {self.name}(cs)"]
345
+ for u in self.uses():
346
+ lines.append(f"{ind}use {u}")
347
+ lines += [f"{ind}implicit none", f"{ind}integer(8), intent(out) :: cs"]
348
+ lines += [ind + d if not d.startswith(" ") else d
349
+ for d in self.decls()]
350
+ lines += self.body()
351
+ lines.append(f" end subroutine {self.name}")
352
+ return lines
353
+
354
+
355
+ def _halve(n: int, lo: int = 1) -> list[int]:
356
+ out = []
357
+ for m in (lo, n // 2):
358
+ if lo <= m < n and m not in out:
359
+ out.append(m)
360
+ return out
361
+
362
+
363
+ class LoopKernel(Kernel):
364
+ """out(i) = mod(a(i)*c1 + i*c2 + c3, 1000003) over a random chain."""
365
+ kind = "loop"
366
+
367
+ def draw(self, rng):
368
+ chains = OMP_CHAINS if self.o.model == "omp" else ACC_CHAINS
369
+ self.p.setdefault("chain", rng.randrange(len(chains)))
370
+ self.p.setdefault("n", rng.choice((64, 100, 257, 1000, 4096)))
371
+ self.p.setdefault("c", [rng.randrange(1, 1000) for _ in range(3)])
372
+
373
+ def chain(self):
374
+ chains = OMP_CHAINS if self.o.model == "omp" else ACC_CHAINS
375
+ return chains[self.p["chain"] % len(chains)]
376
+
377
+ def decls(self):
378
+ n = self.p["n"]
379
+ return [f"integer(8) :: a({n}), out({n})", "integer :: i"]
380
+
381
+ def body(self):
382
+ n, (c1, c2, c3) = self.p["n"], self.p["c"]
383
+ ind = " "
384
+ lines = [f"{ind}do i = 1, {n}", f"{ind} a(i) = mod(i * 37, 1009)",
385
+ f"{ind}end do", f"{ind}out = 0"]
386
+ op, cl, ii = region(self.o, self.chain(), ind,
387
+ data=[("a", "to"), ("out", "tofrom")])
388
+ lines += op + [f"{ii}do i = 1, {n}",
389
+ f"{ii} out(i) = mod(a(i) * {c1} + i * {c2} + {c3}, "
390
+ "1000003_8)", f"{ii}end do"] + cl
391
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
392
+ return lines
393
+
394
+ def value(self):
395
+ n, (c1, c2, c3) = self.p["n"], self.p["c"]
396
+ return cksum(fmod((i * 37 % 1009) * c1 + i * c2 + c3, 1000003)
397
+ for i in range(1, n + 1))
398
+
399
+ def smaller(self):
400
+ return [self.clone(n=m) for m in _halve(self.p["n"], 8)] + (
401
+ [self.clone(chain=0)] if self.p["chain"] else [])
402
+
403
+ def features(self):
404
+ return super().features() | {"chain:" + " | ".join(self.chain())}
405
+
406
+
407
+ class NestKernel(Kernel):
408
+ """A loop nest `depth` deep; collapse(c) on the loop directive (c up
409
+ to the depth); out(lin) = sum_k idx_k * w_k + c0 where lin is the
410
+ linear index of the full nest; optional split: teams distribute over
411
+ the outermost loop, a nested parallel do (collapse) over the next, simd
412
+ on the innermost."""
413
+ kind = "nest"
414
+
415
+ def draw(self, rng):
416
+ d = self.p.setdefault("depth", 3)
417
+ # past 16 levels the extra levels run once (2**16 iterations at
418
+ # most from extents of 2): the nest depth is the stress, not the
419
+ # iteration count
420
+ ext = self.p.setdefault("ext", [rng.choice((2, 3, 4, 5)) if k < 16
421
+ else 1 for k in range(d)])
422
+ tot = 1
423
+ for e in ext:
424
+ tot *= e
425
+ while tot > 200000:
426
+ k = max(range(d), key=lambda j: ext[j])
427
+ ext[k] = max(min(2, ext[k]), ext[k] - 1)
428
+ tot = 1
429
+ for e in ext:
430
+ tot *= e
431
+ if all(e <= 2 for e in ext):
432
+ break
433
+ self.p.setdefault("collapse", rng.choice(
434
+ (d, d, max(1, d - 1), 1)) if d > 1 else 1)
435
+ self.p.setdefault("split", rng.random() < 0.4 and d >= 3)
436
+ self.p.setdefault("w", [rng.randrange(1, 50) for _ in range(d)])
437
+ self.p.setdefault("c0", rng.randrange(1000))
438
+
439
+ def total(self):
440
+ t = 1
441
+ for e in self.p["ext"]:
442
+ t *= e
443
+ return t
444
+
445
+ def decls(self):
446
+ d = self.p["depth"]
447
+ return [f"integer(8) :: out({self.total()})",
448
+ *decl_lines("integer", [f"i{k}" for k in range(1, d + 1)],
449
+ self.o.width), "integer :: lin"]
450
+
451
+ def _lin(self):
452
+ ext = self.p["ext"]
453
+ terms, stride = [], 1
454
+ for k in range(len(ext), 0, -1):
455
+ terms.append(f"(i{k} - 1) * {stride}" if stride > 1
456
+ else f"(i{k} - 1)")
457
+ stride *= ext[k - 1]
458
+ return " + ".join(reversed(terms)) + " + 1"
459
+
460
+ def _lin_lines(self, ind, expr):
461
+ lin = self._lin().split(" + ")
462
+ terms = expr.split(" + ")
463
+ return pack("lin =", [t + (" +" if k < len(lin) - 1 else "")
464
+ for k, t in enumerate(lin)], ind, None,
465
+ self.o.width) + \
466
+ pack("out(lin) =", [t + (" +" if k < len(terms) - 1 else "")
467
+ for k, t in enumerate(terms)], ind, None,
468
+ self.o.width)
469
+
470
+ def body(self):
471
+ d, ext, w, c0 = (self.p["depth"], self.p["ext"], self.p["w"],
472
+ self.p["c0"])
473
+ col = self.p["collapse"]
474
+ ind = " "
475
+ lines = [f"{ind}out = 0"]
476
+ priv = [f"i{k}" for k in range(col + 1, d + 1)] + ["lin"]
477
+ expr = " + ".join(f"i{k} * {w[k - 1]}" for k in range(1, d + 1)) + \
478
+ f" + {c0}"
479
+ if self.p["split"] and self.o.model == "omp":
480
+ # teams distribute over i1; parallel do collapse over the rest
481
+ # (up to the collapse depth); simd on nothing (bodies index out)
482
+ inner_col = max(1, min(col, d - 1))
483
+ op1, cl1, i1 = region(self.o, ("target teams distribute",), ind,
484
+ data=[("out", "tofrom")])
485
+ lines += op1 + [f"{i1}do i1 = 1, {ext[0]}"]
486
+ inner_priv = [f"i{k}" for k in range(2 + inner_col, d + 1)] + \
487
+ ["lin"]
488
+ op2, cl2, i2 = region(self.o, ("parallel do",), i1 + " ",
489
+ private=inner_priv, collapse=inner_col)
490
+ lines += op2
491
+ def at(k): # indentation, capped (deep nests stay < 132)
492
+ return i2 + " " * min(k - 2, 16)
493
+ for k in range(2, d + 1):
494
+ lines.append(f"{at(k)}do i{k} = 1, {ext[k - 1]}")
495
+ lines += self._lin_lines(at(d + 1), expr)
496
+ for k in range(d, 1, -1):
497
+ lines.append(f"{at(k)}end do")
498
+ lines += cl2 + [f"{i1}end do"] + cl1
499
+ else:
500
+ chain = ("target teams distribute parallel do",) if \
501
+ self.o.model == "omp" else ("parallel loop gang vector",)
502
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")],
503
+ private=priv, collapse=col)
504
+ lines += op
505
+
506
+ def at(k):
507
+ return ii + " " * min(k - 1, 16)
508
+ for k in range(1, d + 1):
509
+ lines.append(f"{at(k)}do i{k} = 1, {ext[k - 1]}")
510
+ lines += self._lin_lines(at(d + 1), expr)
511
+ for k in range(d, 0, -1):
512
+ lines.append(f"{at(k)}end do")
513
+ lines += cl
514
+ lines.append(f"{ind}call st_cksum(out, {self.total()}, cs)")
515
+ return lines
516
+
517
+ def value(self):
518
+ import itertools
519
+ ext, w, c0 = self.p["ext"], self.p["w"], self.p["c0"]
520
+ out = [0] * self.total()
521
+ for idx in itertools.product(*[range(1, e + 1) for e in ext]):
522
+ lin, stride = 0, 1
523
+ for k in range(len(ext) - 1, -1, -1):
524
+ lin += (idx[k] - 1) * stride
525
+ stride *= ext[k]
526
+ out[lin] = sum(i * wk for i, wk in zip(idx, w)) + c0
527
+ return cksum(out)
528
+
529
+ def smaller(self):
530
+ d = self.p["depth"]
531
+ out = []
532
+ if d > 1:
533
+ out.append(self.clone(depth=d - 1, ext=self.p["ext"][:-1],
534
+ w=self.p["w"][:-1],
535
+ collapse=min(self.p["collapse"], d - 1),
536
+ split=self.p["split"] and d - 1 >= 3))
537
+ if self.p["collapse"] > 1:
538
+ out.append(self.clone(collapse=1))
539
+ if self.p["split"]:
540
+ out.append(self.clone(split=False))
541
+ if any(e > 2 for e in self.p["ext"]):
542
+ out.append(self.clone(ext=[min(2, e) for e in self.p["ext"]]))
543
+ return out
544
+
545
+ def features(self):
546
+ f = super().features() | {f"nest:depth{self.p['depth']}",
547
+ f"nest:collapse{self.p['collapse']}"}
548
+ if self.p["collapse"] == self.p["depth"]:
549
+ f.add("nest:collapse_full")
550
+ if self.p["split"]:
551
+ f.add("nest:split")
552
+ return f
553
+
554
+
555
+ def _item_count(size: int) -> int:
556
+ return max(1, int(size))
557
+
558
+
559
+ class ListKernel(Kernel):
560
+ """Base of the list axes: `nitems` items, `n` iterations (n * items is
561
+ kept below 2e5 so the model stays fast)."""
562
+ kind = "list"
563
+
564
+ def draw(self, rng):
565
+ k = self.p.setdefault("nitems", 8)
566
+ self.p.setdefault("n", max(8, min(256, 200000 // max(1, k))))
567
+ self.p.setdefault("chain", rng.randrange(3))
568
+ self.p.setdefault("c", [rng.randrange(1, 97) for _ in range(k)])
569
+
570
+ def items(self, prefix):
571
+ return [vname(prefix, k) for k in range(1, self.p["nitems"] + 1)]
572
+
573
+ def smaller(self):
574
+ k = self.p["nitems"]
575
+ out = []
576
+ for m in _halve(k):
577
+ out.append(self.clone(nitems=m, c=self.p["c"][:m]))
578
+ if self.p["n"] > 8:
579
+ out.append(self.clone(n=8))
580
+ return out
581
+
582
+ def chain(self):
583
+ if self.o.model == "omp":
584
+ return (("target teams distribute parallel do",),
585
+ ("target parallel do",),
586
+ ("target", "teams distribute parallel do"))[
587
+ self.p["chain"] % 3]
588
+ return (("parallel loop gang vector",), ("parallel loop",),
589
+ ("parallel", "loop gang vector"))[self.p["chain"] % 3]
590
+
591
+ def features(self):
592
+ return super().features() | {
593
+ f"list:{self.kind}", f"len:{self.kind}:{self.p['nitems']}"}
594
+
595
+
596
+ class PrivateKernel(ListKernel):
597
+ """private(p0001, ..., pN): each iteration sets every p_j and sums
598
+ them (a shared p_j would race)."""
599
+ kind = "private"
600
+
601
+ def decls(self):
602
+ n = self.p["n"]
603
+ its = self.items("p")
604
+ return [f"integer(8) :: out({n})", "integer :: i", "integer(8) :: t"] \
605
+ + [ln.strip() for ln in pack("integer(8) ::",
606
+ [x + ("," if k < len(its) - 1 else "")
607
+ for k, x in enumerate(its)], "",
608
+ None, self.o.width)]
609
+
610
+ def body(self):
611
+ n, c = self.p["n"], self.p["c"]
612
+ its = self.items("p")
613
+ ind = " "
614
+ lines = [f"{ind}out = 0"]
615
+ op, cl, ii = region(self.o, self.chain(), ind,
616
+ data=[("out", "tofrom")], private=its + ["t"])
617
+ lines += op + [f"{ii}do i = 1, {n}"]
618
+ for k, x in enumerate(its):
619
+ lines.append(f"{ii} {x} = mod(i * {c[k]} + {k + 1}, 997)")
620
+ lines.append(f"{ii} t = 0")
621
+ lines += sum_lines(ii + " ", "t", its, self.o.width)
622
+ lines += [f"{ii} out(i) = t", f"{ii}end do"] + cl
623
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
624
+ return lines
625
+
626
+ def value(self):
627
+ n, c = self.p["n"], self.p["c"]
628
+ k = self.p["nitems"]
629
+ return cksum(sum((i * c[j] + j + 1) % 997 for j in range(k))
630
+ for i in range(1, n + 1))
631
+
632
+
633
+ class FirstprivateKernel(ListKernel):
634
+ """firstprivate(f0001, ..., fN) of host-initialised scalars; the device
635
+ reads each; the host values must be unchanged afterwards."""
636
+ kind = "firstprivate"
637
+
638
+ def decls(self):
639
+ n = self.p["n"]
640
+ its = self.items("f")
641
+ return [f"integer(8) :: out({n})", "integer :: i", "integer(8) :: t"] \
642
+ + [ln.strip() for ln in pack("integer(8) ::",
643
+ [x + ("," if k < len(its) - 1 else "")
644
+ for k, x in enumerate(its)], "",
645
+ None, self.o.width)]
646
+
647
+ def body(self):
648
+ n, c = self.p["n"], self.p["c"]
649
+ its = self.items("f")
650
+ ind = " "
651
+ lines = [f"{ind}{x} = {c[k] * 7 + k}" for k, x in enumerate(its)]
652
+ lines.append(f"{ind}out = 0")
653
+ op, cl, ii = region(self.o, self.chain(), ind,
654
+ data=[("out", "tofrom")], private=["t"],
655
+ firstprivate=its)
656
+ lines += op + [f"{ii}do i = 1, {n}", f"{ii} t = 0"]
657
+ terms = [f"{x} * mod(i + {k}, 3)" for k, x in enumerate(its)]
658
+ lines += sum_lines(ii + " ", "t", terms, self.o.width)
659
+ lines += [f"{ii} out(i) = t", f"{ii}end do"] + cl
660
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
661
+ lines.append(f"{ind}t = 0")
662
+ lines += sum_lines(ind, "t", its, self.o.width)
663
+ lines.append(f"{ind}cs = mod(cs + t, {P}_8)")
664
+ return lines
665
+
666
+ def value(self):
667
+ n, c = self.p["n"], self.p["c"]
668
+ k = self.p["nitems"]
669
+ f = [c[j] * 7 + j for j in range(k)]
670
+ cs = cksum(sum(f[j] * ((i + j) % 3) for j in range(k))
671
+ for i in range(1, n + 1))
672
+ return (cs + sum(f)) % P
673
+
674
+
675
+ class LastprivateKernel(ListKernel):
676
+ """lastprivate(l0001, ..., lN): after the loop l_j holds the value of
677
+ the sequentially last iteration, n * c_j + j."""
678
+ kind = "lastprivate"
679
+
680
+ def decls(self):
681
+ its = self.items("l")
682
+ return ["integer :: i", "integer(8) :: t"] + \
683
+ [ln.strip() for ln in pack("integer(8) ::",
684
+ [x + ("," if k < len(its) - 1 else "")
685
+ for k, x in enumerate(its)], "",
686
+ None, self.o.width)]
687
+
688
+ def chain(self):
689
+ if self.o.model == "omp":
690
+ # lastprivate on a combined target construct: the list item is
691
+ # treated as if it also appeared in map(tofrom) (5.0 §2.19.7.1)
692
+ return (("target teams distribute parallel do",),
693
+ ("target parallel do",),
694
+ ("target parallel do",))[self.p["chain"] % 3]
695
+ raise ValueError("OpenACC has no lastprivate clause")
696
+
697
+ def body(self):
698
+ n, c = self.p["n"], self.p["c"]
699
+ its = self.items("l")
700
+ ind = " "
701
+ lines = [f"{ind}{x} = 0" for x in its]
702
+ op, cl, ii = region(self.o, self.chain()[:1], ind,
703
+ loop_extra=list_atoms("lastprivate", its))
704
+ lines += op + [f"{ii}do i = 1, {n}"]
705
+ for k, x in enumerate(its):
706
+ lines.append(f"{ii} {x} = i * {c[k]} + {k}")
707
+ lines += [f"{ii}end do"] + cl
708
+ lines.append(f"{ind}t = 0")
709
+ lines += sum_lines(ind, "t", its, self.o.width)
710
+ lines.append(f"{ind}cs = mod(t, {P}_8)")
711
+ return lines
712
+
713
+ def value(self):
714
+ n, c = self.p["n"], self.p["c"]
715
+ return sum(n * c[j] + j for j in range(self.p["nitems"])) % P
716
+
717
+
718
+ class SharedKernel(ListKernel):
719
+ """target data region; inside, ``parallel do shared(s0001..sN, out)``
720
+ nested in a target region (shared is a parallel / teams clause): the
721
+ shared scalars are read by every thread."""
722
+ kind = "shared"
723
+
724
+ def decls(self):
725
+ n = self.p["n"]
726
+ its = self.items("s")
727
+ return [f"integer(8) :: out({n})", "integer :: i", "integer(8) :: t"] \
728
+ + [ln.strip() for ln in pack("integer(8) ::",
729
+ [x + ("," if k < len(its) - 1 else "")
730
+ for k, x in enumerate(its)], "",
731
+ None, self.o.width)]
732
+
733
+ def body(self):
734
+ n, c = self.p["n"], self.p["c"]
735
+ its = self.items("s")
736
+ ind = " "
737
+ lines = [f"{ind}{x} = {c[k] + k}" for k, x in enumerate(its)]
738
+ lines.append(f"{ind}out = 0")
739
+ if self.o.model == "omp":
740
+ op1 = pack("target", data_clauses(self.o, [(x, "to") for x in
741
+ its] +
742
+ [("out", "tofrom")]),
743
+ ind, self.o.sent, self.o.width)
744
+ op2 = pack("parallel do", list_atoms("shared", its + ["out"]) +
745
+ list_atoms("private", ["t"]), ind + " ",
746
+ self.o.sent, self.o.width)
747
+ ii = ind + " "
748
+ lines += op1 + op2 + [f"{ii}do i = 1, {n}", f"{ii} t = 0"]
749
+ terms = [f"{x} * mod(i, {k + 2})" for k, x in enumerate(its)]
750
+ lines += sum_lines(ii + " ", "t", terms, self.o.width)
751
+ lines += [f"{ii} out(i) = t", f"{ii}end do",
752
+ f"{ind} {self.o.sent} end parallel do",
753
+ f"{ind}{self.o.sent} end target"]
754
+ else:
755
+ op, cl, ii = region(self.o, ("parallel loop",), ind,
756
+ data=[(x, "to") for x in its] +
757
+ [("out", "tofrom")], private=["t"])
758
+ lines += op + [f"{ii}do i = 1, {n}", f"{ii} t = 0"]
759
+ terms = [f"{x} * mod(i, {k + 2})" for k, x in enumerate(its)]
760
+ lines += sum_lines(ii + " ", "t", terms, self.o.width)
761
+ lines += [f"{ii} out(i) = t", f"{ii}end do"] + cl
762
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
763
+ return lines
764
+
765
+ def value(self):
766
+ n, c = self.p["n"], self.p["c"]
767
+ k = self.p["nitems"]
768
+ s = [c[j] + j for j in range(k)]
769
+ return cksum(sum(s[j] * (i % (j + 2)) for j in range(k))
770
+ for i in range(1, n + 1))
771
+
772
+
773
+ class MapKernel(ListKernel):
774
+ """map(to: a0001..aN) map(tofrom: b0001..bN): N arrays of m elements;
775
+ b_j(i) = b_j(i) + a_j(i) * c_j."""
776
+ kind = "map"
777
+
778
+ def draw(self, rng):
779
+ k = self.p.setdefault("nitems", 8)
780
+ self.p.setdefault("m", max(4, min(64, 100000 // max(1, k))))
781
+ self.p.setdefault("n", self.p["m"])
782
+ self.p.setdefault("chain", rng.randrange(3))
783
+ self.p.setdefault("c", [rng.randrange(1, 97) for _ in range(k)])
784
+
785
+ def decls(self):
786
+ m = self.p["m"]
787
+ its_a, its_b = self.items("a"), self.items("b")
788
+ ents = [f"{x}({m})" for x in its_a + its_b]
789
+ return ["integer :: i", "integer(8) :: t"] + \
790
+ [ln.strip() for ln in pack("integer(8) ::",
791
+ [x + ("," if k < len(ents) - 1 else "")
792
+ for k, x in enumerate(ents)], "",
793
+ None, self.o.width)]
794
+
795
+ def body(self):
796
+ m, c = self.p["m"], self.p["c"]
797
+ A, B = self.items("a"), self.items("b")
798
+ ind = " "
799
+ lines = [f"{ind}do i = 1, {m}"]
800
+ for k in range(len(A)):
801
+ lines.append(f"{ind} {A[k]}(i) = mod(i * {k + 3}, 101)")
802
+ lines.append(f"{ind} {B[k]}(i) = {k}")
803
+ lines.append(f"{ind}end do")
804
+ op, cl, ii = region(self.o, self.chain(), ind,
805
+ data=[(x, "to") for x in A] +
806
+ [(x, "tofrom") for x in B])
807
+ lines += op + [f"{ii}do i = 1, {m}"]
808
+ for k in range(len(A)):
809
+ lines.append(f"{ii} {B[k]}(i) = {B[k]}(i) + {A[k]}(i) * {c[k]}")
810
+ lines += [f"{ii}end do"] + cl
811
+ lines.append(f"{ind}cs = 0")
812
+ for k in range(len(B)):
813
+ lines.append(f"{ind}call st_cksum({B[k]}, {m}, t)")
814
+ lines.append(f"{ind}cs = mod(cs * 31 + t, {P}_8)")
815
+ return lines
816
+
817
+ def value(self):
818
+ m, c = self.p["m"], self.p["c"]
819
+ cs = 0
820
+ for k in range(self.p["nitems"]):
821
+ t = cksum(k + ((i * (k + 3)) % 101) * c[k]
822
+ for i in range(1, m + 1))
823
+ cs = (cs * 31 + t) % P
824
+ return cs
825
+
826
+ def smaller(self):
827
+ k = self.p["nitems"]
828
+ return [self.clone(nitems=m, c=self.p["c"][:m]) for m in _halve(k)] \
829
+ + ([self.clone(m=4, n=4)] if self.p["m"] > 4 else [])
830
+
831
+
832
+ RED_OPS = ("+", "*", "max", "min", "iand", "ior", "ieor")
833
+
834
+
835
+ class ReductionKernel(ListKernel):
836
+ """reduction clauses over r0001..rN with operators cycling through
837
+ + * max min iand ior ieor (one clause per operator); * multiplies by 2
838
+ on 3 iterations only (bounded)."""
839
+ kind = "reduction"
840
+
841
+ def draw(self, rng):
842
+ super().draw(rng)
843
+ self.p.setdefault("ops", [RED_OPS[(j + rng.randrange(7)) % 7]
844
+ for j in range(self.p["nitems"])])
845
+
846
+ def decls(self):
847
+ its = self.items("r")
848
+ return ["integer :: i", "integer(8) :: t"] + \
849
+ [ln.strip() for ln in pack("integer(8) ::",
850
+ [x + ("," if k < len(its) - 1 else "")
851
+ for k, x in enumerate(its)], "",
852
+ None, self.o.width)]
853
+
854
+ def init(self, op, k):
855
+ return {"+": k, "*": 1, "max": 0, "min": 1000000, "iand": 1048575,
856
+ "ior": 0, "ieor": k}[op]
857
+
858
+ def contrib(self, op, i, k, c):
859
+ if op == "*":
860
+ return f"merge(2_8, 1_8, mod(i, {max(1, self.p['n'] // 3)}) == 0" \
861
+ f" .and. i <= {3 * max(1, self.p['n'] // 3)})"
862
+ return f"int(mod(i * {c} + {k}, 65536), 8)"
863
+
864
+ def body(self):
865
+ n, c, ops = self.p["n"], self.p["c"], self.p["ops"]
866
+ its = self.items("r")
867
+ ind = " "
868
+ lines = [f"{ind}{x} = {self.init(ops[k], k)}"
869
+ for k, x in enumerate(its)]
870
+ groups: dict[str, list[str]] = {}
871
+ for k, x in enumerate(its):
872
+ groups.setdefault(ops[k], []).append(x)
873
+ red = [(op, groups[op]) for op in RED_OPS if op in groups]
874
+ op_, cl, ii = region(self.o, self.chain(), ind, reduction=red)
875
+ lines += op_ + [f"{ii}do i = 1, {n}"]
876
+ for k, x in enumerate(its):
877
+ e = self.contrib(ops[k], None, k, c[k])
878
+ stmt = {"+": f"{x} = {x} + {e}", "*": f"{x} = {x} * {e}",
879
+ "max": f"{x} = max({x}, {e})",
880
+ "min": f"{x} = min({x}, {e})",
881
+ "iand": f"{x} = iand({x}, {e} + 1048576_8 - 65536_8)",
882
+ "ior": f"{x} = ior({x}, {e})",
883
+ "ieor": f"{x} = ieor({x}, {e})"}[ops[k]]
884
+ lines.append(f"{ii} {stmt}")
885
+ lines += [f"{ii}end do"] + cl
886
+ lines.append(f"{ind}cs = 0")
887
+ for x in its:
888
+ lines.append(f"{ind}cs = mod(cs * 31 + mod({x}, {P}_8), {P}_8)")
889
+ return lines
890
+
891
+ def value(self):
892
+ n, c, ops = self.p["n"], self.p["c"], self.p["ops"]
893
+ cs = 0
894
+ step = max(1, n // 3)
895
+ for k in range(self.p["nitems"]):
896
+ op = ops[k]
897
+ v = self.init(op, k)
898
+ for i in range(1, n + 1):
899
+ e = (i * c[k] + k) % 65536
900
+ if op == "+":
901
+ v += e
902
+ elif op == "*":
903
+ v *= 2 if (i % step == 0 and i <= 3 * step) else 1
904
+ elif op == "max":
905
+ v = max(v, e)
906
+ elif op == "min":
907
+ v = min(v, e)
908
+ elif op == "iand":
909
+ v &= e + 1048576 - 65536
910
+ elif op == "ior":
911
+ v |= e
912
+ else:
913
+ v ^= e
914
+ chk(v)
915
+ cs = (cs * 31 + v % P) % P
916
+ return cs
917
+
918
+ def smaller(self):
919
+ out = super().smaller()
920
+ for k in out:
921
+ if "ops" in k.p:
922
+ k.p["ops"] = self.p["ops"][:k.p["nitems"]]
923
+ return out
924
+
925
+ def features(self):
926
+ return super().features() | {f"red:{op}" for op in self.p["ops"]}
927
+
928
+
929
+ class DependKernel(ListKernel):
930
+ """T target tasks (nowait) each with depend(inout: d0001..dN) on N
931
+ scalars and map(tofrom: x); the dependences serialize them; taskwait.
932
+ OpenACC: the async queue chain (async(q) wait(q-1)) over N queues."""
933
+ kind = "depend"
934
+
935
+ def draw(self, rng):
936
+ super().draw(rng)
937
+ self.p.setdefault("tasks", 6)
938
+
939
+ def decls(self):
940
+ its = self.items("d")
941
+ return ["integer(8) :: x(4)", "integer :: t"] + \
942
+ [ln.strip() for ln in pack("integer(8) ::",
943
+ [x + ("," if k < len(its) - 1 else "")
944
+ for k, x in enumerate(its)], "",
945
+ None, self.o.width)]
946
+
947
+ def body(self):
948
+ its = self.items("d")
949
+ T = self.p["tasks"]
950
+ ind = " "
951
+ lines = [f"{ind}{x} = 0" for x in its] + [f"{ind}x = 1"]
952
+ if self.o.model == "omp":
953
+ lines.append(f"{ind}do t = 1, {T}")
954
+ lines += pack("target", ["map(tofrom: x)", "nowait"] +
955
+ list_atoms("depend", its, "inout"),
956
+ ind + " ", self.o.sent, self.o.width)
957
+ lines += [f"{ind} x(1) = mod(x(1) * 3 + t, 1000003_8)",
958
+ f"{ind} x(2) = x(1) + t",
959
+ f"{ind} {self.o.sent} end target", f"{ind}end do",
960
+ f"{ind}{self.o.sent} taskwait"]
961
+ else:
962
+ q = len(its)
963
+ lines += [f"{ind}{self.o.sent} enter data copyin(x)",
964
+ f"{ind}do t = 1, {T}"]
965
+ lines += [f"{ind} {self.o.sent} serial present(x) "
966
+ f"async(mod(t - 1, {q}) + 1) "
967
+ f"wait(mod(t + {q} - 2, {q}) + 1)",
968
+ f"{ind} x(1) = mod(x(1) * 3 + t, 1000003_8)",
969
+ f"{ind} x(2) = x(1) + t",
970
+ f"{ind} {self.o.sent} end serial", f"{ind}end do",
971
+ f"{ind}{self.o.sent} wait",
972
+ f"{ind}{self.o.sent} exit data copyout(x)"]
973
+ lines.append(f"{ind}call st_cksum(x, 4, cs)")
974
+ return lines
975
+
976
+ def value(self):
977
+ x = [1, 1, 1, 1]
978
+ for t in range(1, self.p["tasks"] + 1):
979
+ x[0] = (x[0] * 3 + t) % 1000003
980
+ x[1] = x[0] + t
981
+ return cksum(x)
982
+
983
+
984
+ class UDRKernel(ListKernel):
985
+ """A reduction list mixing intrinsic operators with user-defined
986
+ reductions (declare reduction, OpenMP 5.2 §5.5.11): variables cycle
987
+ through +, max, ieor and two user-defined identifiers (a sum and a
988
+ max with an initializer)."""
989
+ kind = "udr"
990
+ OPS = ("+", "max", "ieor", "st_add", "st_max")
991
+
992
+ def decls(self):
993
+ its = self.items("u")
994
+ return ["integer :: i", "integer(8) :: t",
995
+ "!$omp declare reduction(st_add: integer(8): omp_out = "
996
+ "omp_out + omp_in) initializer(omp_priv = 0_8)",
997
+ "!$omp declare reduction(st_max: integer(8): omp_out = "
998
+ "max(omp_out, omp_in)) initializer(omp_priv = -1_8)"] + \
999
+ decl_lines("integer(8)", its, self.o.width)
1000
+
1001
+ def body(self):
1002
+ n, c = self.p["n"], self.p["c"]
1003
+ its = self.items("u")
1004
+ ops = [self.OPS[j % 5] for j in range(len(its))]
1005
+ ind = " "
1006
+ lines = [f"{ind}{x} = {j}" for j, x in enumerate(its)]
1007
+ groups: dict[str, list[str]] = {}
1008
+ for x, op in zip(its, ops):
1009
+ groups.setdefault(op, []).append(x)
1010
+ red = [(op, groups[op]) for op in self.OPS if op in groups]
1011
+ op_, cl, ii = region(self.o, self.chain(), ind, reduction=red)
1012
+ lines += op_ + [f"{ii}do i = 1, {n}"]
1013
+ for j, (x, op) in enumerate(zip(its, ops)):
1014
+ e = f"int(mod(i * {c[j]} + {j}, 65536), 8)"
1015
+ lines.append(f"{ii} {x} = " + {
1016
+ "+": f"{x} + {e}", "st_add": f"{x} + {e}",
1017
+ "max": f"max({x}, {e})", "st_max": f"max({x}, {e})",
1018
+ "ieor": f"ieor({x}, {e})"}[op])
1019
+ lines += [f"{ii}end do"] + cl
1020
+ lines.append(f"{ind}cs = 0")
1021
+ for x in its:
1022
+ lines.append(f"{ind}cs = mod(cs * 31 + mod({x}, {P}_8), {P}_8)")
1023
+ return lines
1024
+
1025
+ def value(self):
1026
+ n, c = self.p["n"], self.p["c"]
1027
+ cs = 0
1028
+ for j in range(self.p["nitems"]):
1029
+ op = self.OPS[j % 5]
1030
+ v = j
1031
+ for i in range(1, n + 1):
1032
+ e = (i * c[j] + j) % 65536
1033
+ v = v + e if op in ("+", "st_add") else max(v, e) \
1034
+ if op in ("max", "st_max") else v ^ e
1035
+ cs = (cs * 31 + v % P) % P
1036
+ return cs
1037
+
1038
+ def chain(self):
1039
+ return (("target teams distribute parallel do",),
1040
+ ("target parallel do",),
1041
+ ("target teams distribute parallel do",))[
1042
+ self.p["chain"] % 3]
1043
+
1044
+
1045
+ class DeclareKernel(ListKernel):
1046
+ """N module variables made device resident (declare target / acc
1047
+ declare create) in the kernel's own module; host sets them, target
1048
+ update to, the region reads them all and writes w; update from."""
1049
+ kind = "declare"
1050
+
1051
+ def mod(self):
1052
+ return f"{self.name}_m"
1053
+
1054
+ def modules(self):
1055
+ its = self.items("v")
1056
+ spec = [ln.strip() for ln in pack(
1057
+ "integer(8) ::", [x + ("," if k < len(its) - 1 else "")
1058
+ for k, x in enumerate(its)], "", None,
1059
+ self.o.width)]
1060
+ spec.append(f"integer(8) :: w({self.p['n']})")
1061
+ if self.o.model == "omp":
1062
+ dl = pack("declare target(", [x + ("," if k < len(its) else ")")
1063
+ for k, x in enumerate(its + ["w"])],
1064
+ "", self.o.sent, self.o.width)
1065
+ else:
1066
+ dl = pack("declare", list_atoms("create", its + ["w"]), "",
1067
+ self.o.sent, self.o.width)
1068
+ return [Module(self.mod(), spec + dl)]
1069
+
1070
+ def uses(self):
1071
+ return [self.mod()]
1072
+
1073
+ def decls(self):
1074
+ return ["integer :: i", "integer(8) :: t"]
1075
+
1076
+ def body(self):
1077
+ n, c = self.p["n"], self.p["c"]
1078
+ its = self.items("v")
1079
+ ind = " "
1080
+ lines = [f"{ind}{x} = {c[k] * 3 + k}" for k, x in enumerate(its)]
1081
+ lines.append(f"{ind}w = 0")
1082
+ if self.o.model == "omp":
1083
+ lines += pack("target update", list_atoms("to", its + ["w"]),
1084
+ ind, self.o.sent, self.o.width)
1085
+ op, cl, ii = region(self.o, ("target teams distribute parallel "
1086
+ "do",), ind, private=["t"])
1087
+ else:
1088
+ lines += pack("update", list_atoms("device", its + ["w"]), ind,
1089
+ self.o.sent, self.o.width)
1090
+ op, cl, ii = region(self.o, ("parallel loop",), ind,
1091
+ private=["t"], extra=["default(present)"])
1092
+ lines += op + [f"{ii}do i = 1, {n}", f"{ii} t = 0"]
1093
+ terms = [f"{x} * mod(i, {k % 5 + 2})" for k, x in enumerate(its)]
1094
+ lines += sum_lines(ii + " ", "t", terms, self.o.width)
1095
+ lines += [f"{ii} w(i) = t", f"{ii}end do"] + cl
1096
+ if self.o.model == "omp":
1097
+ lines.append(f"{ind}{self.o.sent} target update from(w)")
1098
+ else:
1099
+ lines.append(f"{ind}{self.o.sent} update self(w)")
1100
+ lines.append(f"{ind}call st_cksum(w, {n}, cs)")
1101
+ return lines
1102
+
1103
+ def value(self):
1104
+ n, c = self.p["n"], self.p["c"]
1105
+ v = [c[k] * 3 + k for k in range(self.p["nitems"])]
1106
+ return cksum(sum(v[k] * (i % (k % 5 + 2)) for k in range(len(v)))
1107
+ for i in range(1, n + 1))
1108
+
1109
+
1110
+ class SectionsKernel(ListKernel):
1111
+ """Many array sections of one array: x is entered whole (enter data),
1112
+ then a target region maps N disjoint sections x(lo:hi) (present, so
1113
+ they refer to the same storage: 5.2 §5.8.3 p.155) and a target update
1114
+ to of a strided section x(1:m:2) (5.2 §5.9 p.164)."""
1115
+ kind = "sections"
1116
+
1117
+ def draw(self, rng):
1118
+ k = self.p.setdefault("nitems", 8)
1119
+ self.p.setdefault("w", 4) # elements per section
1120
+ self.p.setdefault("n", k * self.p["w"])
1121
+ self.p.setdefault("chain", 0)
1122
+ self.p.setdefault("c", [rng.randrange(1, 97) for _ in range(k)])
1123
+
1124
+ def decls(self):
1125
+ return [f"integer(8) :: x({self.p['n']})", "integer :: i"]
1126
+
1127
+ def body(self):
1128
+ n, w = self.p["n"], self.p["w"]
1129
+ k = self.p["nitems"]
1130
+ ind = " "
1131
+ secs = [f"x({j * w + 1}:{(j + 1) * w})" for j in range(k)]
1132
+ lines = [f"{ind}do i = 1, {n}", f"{ind} x(i) = i", f"{ind}end do"]
1133
+ if self.o.model == "omp":
1134
+ lines.append(f"{ind}{self.o.sent} target enter data map(to: x)")
1135
+ lines.append(f"{ind}do i = 1, {n}, 2")
1136
+ lines.append(f"{ind} x(i) = x(i) + 1000")
1137
+ lines.append(f"{ind}end do")
1138
+ lines.append(f"{ind}{self.o.sent} target update to(x(1:{n}:2))")
1139
+ op, cl, ii = region(self.o, ("target teams distribute parallel "
1140
+ "do",), ind,
1141
+ data=[(s, "tofrom") for s in secs])
1142
+ lines += op + [f"{ii}do i = 1, {n}",
1143
+ f"{ii} x(i) = x(i) * 3 + mod(i, 7)",
1144
+ f"{ii}end do"] + cl
1145
+ lines.append(f"{ind}{self.o.sent} target exit data map(from: x)")
1146
+ else:
1147
+ lines.append(f"{ind}{self.o.sent} enter data copyin(x)")
1148
+ lines.append(f"{ind}do i = 1, {n}, 2")
1149
+ lines.append(f"{ind} x(i) = x(i) + 1000")
1150
+ lines.append(f"{ind}end do")
1151
+ lines.append(f"{ind}{self.o.sent} update device(x(1:{n}:2))")
1152
+ op, cl, ii = region(self.o, ("parallel loop",), ind,
1153
+ extra=list_atoms("present", secs))
1154
+ lines += op + [f"{ii}do i = 1, {n}",
1155
+ f"{ii} x(i) = x(i) * 3 + mod(i, 7)",
1156
+ f"{ii}end do"] + cl
1157
+ lines.append(f"{ind}{self.o.sent} exit data copyout(x)")
1158
+ lines.append(f"{ind}call st_cksum(x, {n}, cs)")
1159
+ return lines
1160
+
1161
+ def value(self):
1162
+ n = self.p["n"]
1163
+ x = [i + (1000 if i % 2 == 1 else 0) for i in range(1, n + 1)]
1164
+ return cksum(v * 3 + (i % 7) for i, v in enumerate(x, 1))
1165
+
1166
+ def smaller(self):
1167
+ k = self.p["nitems"]
1168
+ return [self.clone(nitems=m, n=m * self.p["w"], c=self.p["c"][:m])
1169
+ for m in _halve(k)]
1170
+
1171
+
1172
+ # --- calls, clauses, continuation lines, names --------------------------------------------------
1173
+
1174
+ def _dt_line(o: Opts, ind: str = " ") -> str:
1175
+ """The device-routine marker in a procedure's specification part."""
1176
+ return f"{ind}{o.sent} declare target" if o.model == "omp" else \
1177
+ f"{ind}{o.sent} routine seq"
1178
+
1179
+
1180
+ class CallsKernel(Kernel):
1181
+ """A device call chain `depth` levels deep in the kernel's module:
1182
+ f_1(x) = f_2(mod(x*3, 1009) + 1) + 1, ..., f_D(x) = x + D; out(i) =
1183
+ f_1(i); optionally a RECURSIVE device function rsum(m) = m + rsum(m-1)
1184
+ (no specification forbids recursion in a device routine; 5.2 §7.8,
1185
+ OpenACC 3.4 §2.15.1)."""
1186
+ kind = "calls"
1187
+
1188
+ def draw(self, rng):
1189
+ self.p.setdefault("depth", 5)
1190
+ self.p.setdefault("n", 512)
1191
+ self.p.setdefault("recursive", rng.random() < 0.3)
1192
+ self.p.setdefault("rdepth", 12)
1193
+
1194
+ def fname(self, k):
1195
+ return f"{self.name}_f{k}"
1196
+
1197
+ def modules(self):
1198
+ d = self.p["depth"]
1199
+ cont = []
1200
+ for k in range(1, d + 1):
1201
+ cont += [f" function {self.fname(k)}(x) result(r)",
1202
+ _dt_line(self.o), " integer(8), intent(in) :: x",
1203
+ " integer(8) :: r"]
1204
+ if k < d:
1205
+ cont.append(f" r = {self.fname(k + 1)}(mod(x * 3, 1009_8) "
1206
+ "+ 1) + 1")
1207
+ else:
1208
+ cont.append(f" r = x + {d}")
1209
+ cont.append(f" end function {self.fname(k)}")
1210
+ if self.p["recursive"]:
1211
+ cont += [f" recursive function {self.name}_rs(m) result(r)",
1212
+ _dt_line(self.o), " integer(8), intent(in) :: m",
1213
+ " integer(8) :: r", " if (m <= 0) then",
1214
+ " r = 0", " else",
1215
+ f" r = m + {self.name}_rs(m - 1)", " end if",
1216
+ f" end function {self.name}_rs"]
1217
+ return [Module(f"{self.name}_m", [], cont)]
1218
+
1219
+ def uses(self):
1220
+ return [f"{self.name}_m"]
1221
+
1222
+ def decls(self):
1223
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i"]
1224
+
1225
+ def body(self):
1226
+ n = self.p["n"]
1227
+ ind = " "
1228
+ chain = ("target teams distribute parallel do",) if \
1229
+ self.o.model == "omp" else ("parallel loop gang vector",)
1230
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")])
1231
+ e = f"{self.fname(1)}(int(i, 8))"
1232
+ if self.p["recursive"]:
1233
+ e += f" + {self.name}_rs(int(mod(i, {self.p['rdepth']}), 8))"
1234
+ lines = [f"{ind}out = 0"] + op + [f"{ii}do i = 1, {n}",
1235
+ f"{ii} out(i) = {e}",
1236
+ f"{ii}end do"] + cl
1237
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1238
+ return lines
1239
+
1240
+ def f(self, x):
1241
+ d = self.p["depth"]
1242
+ add = 0
1243
+ for k in range(1, d):
1244
+ x = (x * 3) % 1009 + 1
1245
+ add += 1
1246
+ return x + d + add
1247
+
1248
+ def value(self):
1249
+ n, rd = self.p["n"], self.p["rdepth"]
1250
+ vals = []
1251
+ for i in range(1, n + 1):
1252
+ v = self.f(i)
1253
+ if self.p["recursive"]:
1254
+ m = i % rd
1255
+ v += m * (m + 1) // 2
1256
+ vals.append(v)
1257
+ return cksum(vals)
1258
+
1259
+ def smaller(self):
1260
+ out = [self.clone(depth=m) for m in _halve(self.p["depth"])]
1261
+ if self.p["recursive"]:
1262
+ out.append(self.clone(recursive=False))
1263
+ if self.p["n"] > 8:
1264
+ out.append(self.clone(n=8))
1265
+ return out
1266
+
1267
+ def features(self):
1268
+ f = super().features() | {f"calls:depth{self.p['depth']}"}
1269
+ if self.p["recursive"]:
1270
+ f.add("calls:recursive")
1271
+ return f
1272
+
1273
+
1274
+ # fillable clauses of target teams distribute parallel do simd (5.0
1275
+ # spellings), in the order the clauses axis adds them; each: atoms,
1276
+ # declarations, setup (host, before), teardown (host, after)
1277
+ CLAUSE_ORDER = ("map", "private", "firstprivate", "reduction", "collapse",
1278
+ "lastprivate", "shared", "default", "defaultmap", "if",
1279
+ "device", "num_teams", "thread_limit", "num_threads",
1280
+ "dist_schedule", "schedule", "proc_bind", "safelen",
1281
+ "simdlen", "nontemporal", "nowait", "depend",
1282
+ "allocate", "uses_allocators", "in_reduction",
1283
+ "is_device_ptr")
1284
+ REPEATABLE = ("map", "private", "firstprivate", "reduction", "shared")
1285
+ NOT_FILLED = {
1286
+ "aligned": "an alignment the program cannot guarantee portably "
1287
+ "(a false aligned clause is unspecified behaviour)",
1288
+ "has_device_addr": "5.1; the program keeps 5.0 spellings for NVHPC",
1289
+ "linear": "on a compound with a distribute leaf only loop iteration "
1290
+ "variables may be linear (5.0 §2.9.4.2 p.124), and with "
1291
+ "collapse(2) they are lastprivate",
1292
+ "order": "order(concurrent) excludes safelen on the simd leaf (5.2 "
1293
+ "§10.4 p.235); safelen is kept",
1294
+ }
1295
+
1296
+
1297
+ class ClausesKernel(Kernel):
1298
+ """`size` clauses on one target teams distribute parallel do simd
1299
+ directive: the catalog's allowed clauses in CLAUSE_ORDER, then repeats
1300
+ of the repeatable ones (each repeat with its own variables). The loop
1301
+ is a 2-deep nest (collapse(2)); out(lin) = i*j + fp + sh."""
1302
+ kind = "clauses"
1303
+
1304
+ def draw(self, rng):
1305
+ self.p.setdefault("nclauses", 8)
1306
+ self.p.setdefault("ni", 16)
1307
+ self.p.setdefault("nj", 8)
1308
+
1309
+ def plan(self) -> list[tuple[str, int]]:
1310
+ from offload.engine.fuzz import allowed_clauses
1311
+ allowed = allowed_clauses("target teams distribute parallel do simd")
1312
+ base = [c for c in CLAUSE_ORDER if c in allowed]
1313
+ k = self.p["nclauses"]
1314
+ out = [(c, 0) for c in base[:k]]
1315
+ r = 1
1316
+ while len(out) < k:
1317
+ for c in REPEATABLE:
1318
+ if len(out) >= k:
1319
+ break
1320
+ out.append((c, r))
1321
+ r += 1
1322
+ return out
1323
+
1324
+ def decls(self):
1325
+ ni, nj = self.p["ni"], self.p["nj"]
1326
+ n = ni * nj
1327
+ d = [f"integer(8) :: out({n}), a({n})", "integer :: i, j, lin",
1328
+ "integer(8) :: tp, fp, rs, lp, sh, lk, ir, dd",
1329
+ "logical :: lt", "integer(8) :: tq"]
1330
+ reps = [r for c, r in self.plan() if r]
1331
+ for c, r in self.plan():
1332
+ if r:
1333
+ d.append(f"integer(8) :: {c[:2]}{r:04d}")
1334
+ if any(c == "is_device_ptr" for c, _ in self.plan()):
1335
+ d += ["type(c_ptr) :: cp", "integer(8), pointer :: fpp(:)",
1336
+ "integer(8), target :: hcopy(4)", "integer :: rc"]
1337
+ del reps
1338
+ return d
1339
+
1340
+ def uses(self):
1341
+ u = []
1342
+ if self.o.model == "omp":
1343
+ u.append("omp_lib")
1344
+ if any(c == "is_device_ptr" for c, _ in self.plan()):
1345
+ u.append("iso_c_binding")
1346
+ return u
1347
+
1348
+ def body(self):
1349
+ ni, nj = self.p["ni"], self.p["nj"]
1350
+ n = ni * nj
1351
+ plan = self.plan()
1352
+ names = [c for c, _ in plan]
1353
+ ind = " "
1354
+ lines = [f"{ind}out = 0", f"{ind}do i = 1, {n}",
1355
+ f"{ind} a(i) = mod(i * 13, 101)", f"{ind}end do",
1356
+ f"{ind}fp = 7", f"{ind}sh = 5", f"{ind}rs = 0",
1357
+ f"{ind}lp = 0", f"{ind}lk = 0", f"{ind}ir = 0",
1358
+ f"{ind}dd = 0", f"{ind}lt = .true.", f"{ind}tq = 0"]
1359
+ for c, r in plan:
1360
+ if r:
1361
+ v = f"{c[:2]}{r:04d}"
1362
+ lines.append(f"{ind}{v} = {r}")
1363
+ atoms = []
1364
+ body_extra = []
1365
+ after = []
1366
+ for c, r in plan:
1367
+ v = f"{c[:2]}{r:04d}" if r else ""
1368
+ if c == "map":
1369
+ atoms += (["map(to: a)", "map(tofrom: out)"] if not r
1370
+ else [f"map(tofrom: {v})"])
1371
+ elif c == "private":
1372
+ # lin (the linear index each iteration computes) is private
1373
+ # with the first private clause (fix, F1:
1374
+ # it was shared, a data race in every clauses program)
1375
+ atoms.append(f"private({v})" if r else "private(tp, lin)")
1376
+ body_extra.append(f"{v or 'tp'} = i")
1377
+ elif c == "firstprivate":
1378
+ atoms.append(f"firstprivate({v or 'fp'})")
1379
+ elif c == "reduction":
1380
+ atoms.append(f"reduction(+: {v or 'rs'})")
1381
+ body_extra.append(f"{v or 'rs'} = {v or 'rs'} + 1")
1382
+ if r:
1383
+ after.append(v)
1384
+ elif c == "collapse":
1385
+ atoms.append("collapse(2)")
1386
+ elif c == "lastprivate":
1387
+ atoms.append("lastprivate(lp)")
1388
+ body_extra.append("lp = lin")
1389
+ elif c == "shared":
1390
+ atoms.append(f"shared({v or 'sh'})")
1391
+ elif c == "default":
1392
+ atoms.append("default(shared)")
1393
+ elif c == "defaultmap":
1394
+ atoms.append("defaultmap(tofrom: scalar)")
1395
+ elif c == "if":
1396
+ atoms += ["if(target: lt)", "if(parallel: lt)"]
1397
+ elif c == "device":
1398
+ atoms.append("device(omp_get_default_device())")
1399
+ elif c == "num_teams":
1400
+ atoms.append("num_teams(4)")
1401
+ elif c == "thread_limit":
1402
+ atoms.append("thread_limit(64)")
1403
+ elif c == "num_threads":
1404
+ atoms.append("num_threads(32)")
1405
+ elif c == "dist_schedule":
1406
+ atoms.append("dist_schedule(static, 4)")
1407
+ elif c == "schedule":
1408
+ atoms.append("schedule(static, 2)")
1409
+ elif c == "proc_bind":
1410
+ atoms.append("proc_bind(close)")
1411
+ elif c == "safelen":
1412
+ atoms.append("safelen(8)")
1413
+ elif c == "simdlen":
1414
+ atoms.append("simdlen(4)")
1415
+ elif c == "nontemporal":
1416
+ atoms.append("nontemporal(a)")
1417
+ elif c == "order":
1418
+ atoms.append("order(concurrent)")
1419
+ elif c == "nowait":
1420
+ atoms.append("nowait")
1421
+ elif c == "depend":
1422
+ atoms.append("depend(inout: dd)")
1423
+ elif c == "linear":
1424
+ atoms.append("linear(lk: 1)")
1425
+ elif c == "allocate":
1426
+ atoms.append("allocate(omp_default_mem_alloc: tp)")
1427
+ elif c == "uses_allocators":
1428
+ atoms.append("uses_allocators(omp_default_mem_alloc)")
1429
+ elif c == "in_reduction":
1430
+ atoms.append("in_reduction(+: ir)")
1431
+ body_extra.append("if (lin == 1) ir = ir + 5")
1432
+ elif c == "is_device_ptr":
1433
+ atoms.append("is_device_ptr(cp)")
1434
+ if "private" not in names:
1435
+ # lin must be private even when the private clause is not one of
1436
+ # the clauses drawn (an extra clause, not counted)
1437
+ atoms.append("private(lin)")
1438
+ if "allocate" in names and not any(x.startswith("private(tp")
1439
+ for x in atoms):
1440
+ atoms.append("private(tp)")
1441
+ body_extra.append("tp = i")
1442
+ pre, post = [], []
1443
+ if "is_device_ptr" in names:
1444
+ pre += [f"{ind}cp = omp_target_alloc(int(4 * 8, c_size_t), "
1445
+ "omp_get_default_device())"]
1446
+ body_extra.append("if (lin == 1) then")
1447
+ body_extra.append(" call c_f_pointer(cp, fpp, [4])")
1448
+ body_extra.append(" fpp(1) = 11")
1449
+ body_extra.append(" fpp(2) = 22")
1450
+ body_extra.append(" fpp(3) = 33")
1451
+ body_extra.append(" fpp(4) = 44")
1452
+ body_extra.append("end if")
1453
+ post += pack("rc = omp_target_memcpy(", [
1454
+ "c_loc(hcopy),", "cp,", "int(4 * 8, c_size_t),",
1455
+ "0_c_size_t,", "0_c_size_t,", "omp_get_initial_device(),",
1456
+ "omp_get_default_device())"], ind, None, self.o.width) + [
1457
+ f"{ind}call omp_target_free(cp, "
1458
+ "omp_get_default_device())"]
1459
+ if "in_reduction" in names:
1460
+ pre.append(f"{ind}{self.o.sent} taskgroup task_reduction(+: ir)")
1461
+ post.insert(0, f"{ind}{self.o.sent} end taskgroup")
1462
+ lines += pre
1463
+ dname = "target teams distribute parallel do simd"
1464
+ lines += pack(dname, atoms, ind, self.o.sent, self.o.width)
1465
+ lines += [f"{ind}do i = 1, {ni}", f"{ind} do j = 1, {nj}",
1466
+ f"{ind} lin = (i - 1) * {nj} + j"]
1467
+ lines += [f"{ind} {s}" for s in body_extra]
1468
+ lines += [f"{ind} out(lin) = i * j + fp + sh + a(lin)",
1469
+ f"{ind} end do", f"{ind}end do",
1470
+ f"{ind}{self.o.sent} end {dname}"]
1471
+ if "nowait" in names or "depend" in names:
1472
+ lines.append(f"{ind}{self.o.sent} taskwait")
1473
+ lines += post
1474
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1475
+ if "reduction" in names:
1476
+ lines.append(f"{ind}cs = mod(cs + rs, {P}_8)")
1477
+ for v in after:
1478
+ lines.append(f"{ind}cs = mod(cs + {v}, {P}_8)")
1479
+ if "lastprivate" in names:
1480
+ lines.append(f"{ind}cs = mod(cs + lp, {P}_8)")
1481
+ if "in_reduction" in names:
1482
+ lines.append(f"{ind}cs = mod(cs + ir, {P}_8)")
1483
+ if "is_device_ptr" in names:
1484
+ lines.append(f"{ind}cs = mod(cs + hcopy(1) + hcopy(2) + "
1485
+ f"hcopy(3) + hcopy(4), {P}_8)")
1486
+ return lines
1487
+
1488
+ def value(self):
1489
+ ni, nj = self.p["ni"], self.p["nj"]
1490
+ n = ni * nj
1491
+ plan = self.plan()
1492
+ names = [c for c, _ in plan]
1493
+ out = []
1494
+ for i in range(1, ni + 1):
1495
+ for j in range(1, nj + 1):
1496
+ lin = (i - 1) * nj + j
1497
+ out.append(i * j + 7 + 5 + (lin * 13) % 101)
1498
+ cs = cksum(out)
1499
+ if "reduction" in names:
1500
+ cs = (cs + n) % P
1501
+ for c, r in plan:
1502
+ if r and c == "reduction":
1503
+ cs = (cs + r + n) % P
1504
+ if "lastprivate" in names:
1505
+ cs = (cs + n) % P
1506
+ if "in_reduction" in names:
1507
+ cs = (cs + 5) % P
1508
+ if "is_device_ptr" in names:
1509
+ cs = (cs + 110) % P
1510
+ return cs
1511
+
1512
+ def smaller(self):
1513
+ k = self.p["nclauses"]
1514
+ return [self.clone(nclauses=m) for m in _halve(k)] + \
1515
+ ([self.clone(nclauses=k - 1)] if k > 2 else [])
1516
+
1517
+ def features(self):
1518
+ return super().features() | {f"clause:{c}" for c, _ in self.plan()} \
1519
+ | {f"len:clauses:{self.p['nclauses']}"}
1520
+
1521
+
1522
+ class ContKernel(PrivateKernel):
1523
+ """One directive spanning `nitems` continuation lines: the private list
1524
+ one item per line (PrivateKernel's program with width 1 for the
1525
+ directive)."""
1526
+ kind = "contlines"
1527
+
1528
+ def body(self):
1529
+ o = self.o
1530
+ saved = o.width
1531
+ try:
1532
+ self.o = Opts(o.model, o.spell, o.level, width=1)
1533
+ lines = super().body()
1534
+ finally:
1535
+ self.o = Opts(o.model, o.spell, o.level, width=saved)
1536
+ return lines
1537
+
1538
+
1539
+ def long_name(prefix: str, k: int, length: int) -> str:
1540
+ base = f"{prefix}{k}_"
1541
+ return (base + "x" * max(0, length - len(base)))[:max(length, len(base))]
1542
+
1543
+
1544
+ class NamesKernel(Kernel):
1545
+ """Names of exactly `length` characters: the kernel's module, a device
1546
+ function, a derived type and its component, and `count` variables in a
1547
+ private list (63 is the Fortran limit; longer: an illegal probe)."""
1548
+ kind = "names"
1549
+
1550
+ def draw(self, rng):
1551
+ self.p.setdefault("length", 63)
1552
+ self.p.setdefault("count", 4)
1553
+ self.p.setdefault("n", 64)
1554
+
1555
+ def nm(self, tag, k=0):
1556
+ return long_name(f"{tag}{self.name[1:]}", k, self.p["length"])
1557
+
1558
+ def modules(self):
1559
+ L = self.p["length"]
1560
+ t, c, f = self.nm("t"), self.nm("c"), self.nm("f")
1561
+ spec = [f"type :: {t}", f" integer(8) :: {c}", f"end type {t}"]
1562
+ cont = [f" function {f}(x) result(r)", _dt_line(self.o),
1563
+ " integer(8), intent(in) :: x", " integer(8) :: r",
1564
+ " r = x * 3 + 1", f" end function {f}"]
1565
+ del L
1566
+ return [Module(self.nm("m"), spec, cont)]
1567
+
1568
+ def uses(self):
1569
+ return [self.nm("m")]
1570
+
1571
+ def decls(self):
1572
+ n = self.p["n"]
1573
+ vs = [self.nm("v", k) for k in range(self.p["count"])]
1574
+ return [f"integer(8) :: out({n})", "integer :: i",
1575
+ f"type({self.nm('t')}) :: obj"] + \
1576
+ [f"integer(8) :: {v}" for v in vs]
1577
+
1578
+ def body(self):
1579
+ n = self.p["n"]
1580
+ vs = [self.nm("v", k) for k in range(self.p["count"])]
1581
+ ind = " "
1582
+ f, c = self.nm("f"), self.nm("c")
1583
+ lines = [f"{ind}out = 0", f"{ind}obj%{c} = 9"]
1584
+ chain = ("target teams distribute parallel do",) if \
1585
+ self.o.model == "omp" else ("parallel loop",)
1586
+ op, cl, ii = region(self.o, chain, ind,
1587
+ data=[("out", "tofrom"), ("obj", "to")],
1588
+ private=vs)
1589
+ lines += op + [f"{ii}do i = 1, {n}"]
1590
+ for k, v in enumerate(vs):
1591
+ lines += pack(f"{v} =", [f"{f}(int(i, 8))", f"+ {k}"],
1592
+ ii + " ", None, self.o.width)
1593
+ lines += sum_lines(ii + " ", "out(i)", vs + [f"obj%{c}"],
1594
+ self.o.width)
1595
+ lines += [f"{ii}end do"] + cl
1596
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1597
+ return lines
1598
+
1599
+ def value(self):
1600
+ n, cnt = self.p["n"], self.p["count"]
1601
+ return cksum(sum(i * 3 + 1 + k for k in range(cnt)) + 9
1602
+ for i in range(1, n + 1))
1603
+
1604
+ def smaller(self):
1605
+ out = []
1606
+ if self.p["count"] > 1:
1607
+ out.append(self.clone(count=1))
1608
+ if self.p["length"] > 63:
1609
+ out.append(self.clone(length=64))
1610
+ return out
1611
+
1612
+ def features(self):
1613
+ return super().features() | {f"len:names:{self.p['length']}"}
1614
+
1615
+
1616
+ # --- long variable lists ---------------------------------------------------------------------------
1617
+
1618
+ def decl_lines(typ: str, names: list[str], width: int) -> list[str]:
1619
+ return [ln.strip() for ln in pack(f"{typ} ::", [
1620
+ x + ("," if k < len(names) - 1 else "")
1621
+ for k, x in enumerate(names)], "", None, width)]
1622
+
1623
+
1624
+ class LocalsKernel(Kernel):
1625
+ """A device routine with `nlocals` local variables (scalars and, every
1626
+ eighth, a 4-element array): res = sum of q_j = mod(x*(j+1)+j, 991)."""
1627
+ kind = "locals"
1628
+
1629
+ def draw(self, rng):
1630
+ self.p.setdefault("nlocals", 64)
1631
+ self.p.setdefault("n", max(8, min(256, 100000 // max(
1632
+ 1, self.p["nlocals"]))))
1633
+
1634
+ def modules(self):
1635
+ k = self.p["nlocals"]
1636
+ sc = [vname("q", j) for j in range(1, k + 1) if j % 8]
1637
+ ar = [vname("q", j) for j in range(1, k + 1) if not j % 8]
1638
+ cont = [f" subroutine {self.name}_dr(x, res)", _dt_line(self.o),
1639
+ " integer(8), intent(in) :: x",
1640
+ " integer(8), intent(out) :: res"]
1641
+ cont += [" " + d for d in decl_lines("integer(8)", sc,
1642
+ self.o.width)]
1643
+ if ar:
1644
+ cont += [" " + d for d in decl_lines(
1645
+ "integer(8)", [f"{a}(4)" for a in ar], self.o.width)]
1646
+ for j in range(1, k + 1):
1647
+ v = vname("q", j)
1648
+ rhs = f"mod(x * {j + 1} + {j}, 991_8)"
1649
+ cont.append(f" {v} = {rhs}" if j % 8 else f" {v} = {rhs}")
1650
+ cont.append(" res = 0")
1651
+ terms = [vname("q", j) if j % 8 else f"{vname('q', j)}(3)"
1652
+ for j in range(1, k + 1)]
1653
+ cont += sum_lines(" ", "res", terms, self.o.width)
1654
+ cont.append(f" end subroutine {self.name}_dr")
1655
+ return [Module(f"{self.name}_m", [], cont)]
1656
+
1657
+ def uses(self):
1658
+ return [f"{self.name}_m"]
1659
+
1660
+ def decls(self):
1661
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i",
1662
+ "integer(8) :: r"]
1663
+
1664
+ def body(self):
1665
+ n = self.p["n"]
1666
+ ind = " "
1667
+ chain = ("target teams distribute parallel do",) if \
1668
+ self.o.model == "omp" else ("parallel loop gang vector",)
1669
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")],
1670
+ private=["r"])
1671
+ return [f"{ind}out = 0"] + op + [
1672
+ f"{ii}do i = 1, {n}",
1673
+ f"{ii} call {self.name}_dr(int(i, 8), r)",
1674
+ f"{ii} out(i) = r", f"{ii}end do"] + cl + [
1675
+ f"{ind}call st_cksum(out, {n}, cs)"]
1676
+
1677
+ def value(self):
1678
+ k, n = self.p["nlocals"], self.p["n"]
1679
+ return cksum(sum((i * (j + 1) + j) % 991 for j in range(1, k + 1))
1680
+ for i in range(1, n + 1))
1681
+
1682
+ def smaller(self):
1683
+ return [self.clone(nlocals=m) for m in _halve(self.p["nlocals"])] \
1684
+ + ([self.clone(n=8)] if self.p["n"] > 8 else [])
1685
+
1686
+ def features(self):
1687
+ return super().features() | {f"len:locals:{self.p['nlocals']}"}
1688
+
1689
+
1690
+ ARG_KINDS = ("value", "ref", "array", "derived", "optional")
1691
+
1692
+
1693
+ class ArgsKernel(Kernel):
1694
+ """A device routine with `nargs` dummy arguments, kinds cycling through
1695
+ VALUE scalar, by-reference scalar, explicit-shape array(4), a derived
1696
+ type, and (last) OPTIONAL scalars of which every other one is passed
1697
+ (by keyword after the first omitted one)."""
1698
+ kind = "args"
1699
+
1700
+ def draw(self, rng):
1701
+ self.p.setdefault("nargs", 16)
1702
+ self.p.setdefault("n", max(8, min(256, 60000 // max(
1703
+ 1, self.p["nargs"]))))
1704
+
1705
+ def kinds(self):
1706
+ k = self.p["nargs"]
1707
+ nopt = max(0, k // 5)
1708
+ req = [ARG_KINDS[j % 4] for j in range(k - nopt)]
1709
+ return req + ["optional"] * nopt
1710
+
1711
+ def modules(self):
1712
+ ks = self.kinds()
1713
+ names = [vname("a", j) for j in range(1, len(ks) + 1)]
1714
+ spec = ["type :: st_pairT", " integer(8) :: u, v", "end type"] \
1715
+ if False else []
1716
+ cont = []
1717
+ cont += pack(f"subroutine {self.name}_dr(", [
1718
+ x + ("," if j < len(names) else ")") for j, x in
1719
+ enumerate(names + ["res"])], " ", None, self.o.width)
1720
+ cont.append(_dt_line(self.o))
1721
+ # declarations grouped by kind
1722
+ groups: dict[str, list[str]] = {}
1723
+ for x, kd in zip(names, ks):
1724
+ groups.setdefault(kd, []).append(x)
1725
+ typ = {"value": "integer(8), value", "ref": "integer(8), intent(in)",
1726
+ "array": "integer(8), intent(in)",
1727
+ "derived": "type(st_pair), intent(in)",
1728
+ "optional": "integer(8), intent(in), optional"}
1729
+ for kd in ARG_KINDS:
1730
+ if kd in groups:
1731
+ ents = [f"{x}(4)" if kd == "array" else x
1732
+ for x in groups[kd]]
1733
+ cont += [" " + d for d in decl_lines(typ[kd], ents,
1734
+ self.o.width)]
1735
+ cont.append(" integer(8), intent(out) :: res")
1736
+ cont.append(" res = 0")
1737
+ for j, (x, kd) in enumerate(zip(names, ks), 1):
1738
+ if kd in ("value", "ref"):
1739
+ cont.append(f" res = res + {x} * {j % 13 + 1}")
1740
+ elif kd == "array":
1741
+ cont.append(f" res = res + {x}(1) + {x}(4) * 2")
1742
+ elif kd == "derived":
1743
+ cont.append(f" res = res + {x}%u * 3 + {x}%v")
1744
+ else:
1745
+ cont.append(f" if (present({x})) res = res + {x} * 5")
1746
+ cont.append(f" end subroutine {self.name}_dr")
1747
+ return [Module(f"{self.name}_m", spec, cont, ["st_util"])]
1748
+
1749
+ def uses(self):
1750
+ return [f"{self.name}_m", "st_util"]
1751
+
1752
+ def decls(self):
1753
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i",
1754
+ "integer(8) :: r, s", "integer(8) :: arr(4)",
1755
+ "type(st_pair) :: pr"]
1756
+
1757
+ def actuals(self):
1758
+ ks = self.kinds()
1759
+ acts, keyword = [], False
1760
+ for j, kd in enumerate(ks, 1):
1761
+ x = vname("a", j)
1762
+ if kd in ("value", "ref"):
1763
+ acts.append(f"s + {j}" if kd == "value" else "s")
1764
+ elif kd == "array":
1765
+ acts.append("arr")
1766
+ elif kd == "derived":
1767
+ acts.append("pr")
1768
+ else:
1769
+ if j % 2:
1770
+ acts.append(f"{x}=s" if keyword else "s")
1771
+ else:
1772
+ keyword = True
1773
+ acts.append("res=r" if keyword else "r")
1774
+ return acts
1775
+
1776
+ def body(self):
1777
+ n = self.p["n"]
1778
+ ind = " "
1779
+ chain = ("target teams distribute parallel do",) if \
1780
+ self.o.model == "omp" else ("parallel loop gang vector",)
1781
+ op, cl, ii = region(self.o, chain, ind,
1782
+ data=[("out", "tofrom"), ("arr", "to"),
1783
+ ("pr", "to")], private=["r", "s"])
1784
+ lines = [f"{ind}out = 0", f"{ind}arr = [3, 5, 7, 11]",
1785
+ f"{ind}pr%u = 4", f"{ind}pr%v = 9"]
1786
+ lines += op + [f"{ii}do i = 1, {n}", f"{ii} s = i"]
1787
+ lines += call_lines(ii + " ", f"{self.name}_dr", self.actuals(),
1788
+ self.o.width)
1789
+ lines += [f"{ii} out(i) = r", f"{ii}end do"] + cl
1790
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1791
+ return lines
1792
+
1793
+ def value(self):
1794
+ ks, n = self.kinds(), self.p["n"]
1795
+ vals = []
1796
+ for i in range(1, n + 1):
1797
+ res = 0
1798
+ for j, kd in enumerate(ks, 1):
1799
+ if kd == "value":
1800
+ res += (i + j) * (j % 13 + 1)
1801
+ elif kd == "ref":
1802
+ res += i * (j % 13 + 1)
1803
+ elif kd == "array":
1804
+ res += 3 + 11 * 2
1805
+ elif kd == "derived":
1806
+ res += 4 * 3 + 9
1807
+ elif j % 2:
1808
+ res += i * 5
1809
+ vals.append(res)
1810
+ return cksum(vals)
1811
+
1812
+ def smaller(self):
1813
+ return [self.clone(nargs=m) for m in _halve(self.p["nargs"])] + \
1814
+ ([self.clone(n=8)] if self.p["n"] > 8 else [])
1815
+
1816
+ def features(self):
1817
+ return super().features() | {f"len:args:{self.p['nargs']}"} | {
1818
+ f"args:{k}" for k in set(self.kinds())}
1819
+
1820
+
1821
+ class UseOnlyKernel(Kernel):
1822
+ """`use <module>, only: ...` with `nitems` names: half named constants
1823
+ (parameters), half device-resident module variables."""
1824
+ kind = "useonly"
1825
+
1826
+ def draw(self, rng):
1827
+ self.p.setdefault("nitems", 16)
1828
+ self.p.setdefault("n", max(8, min(256, 100000 // max(
1829
+ 1, self.p["nitems"]))))
1830
+
1831
+ def names(self):
1832
+ k = self.p["nitems"]
1833
+ return [vname("u", j) for j in range(1, k + 1)]
1834
+
1835
+ def modules(self):
1836
+ nm = self.names()
1837
+ spec = []
1838
+ pv = [x for j, x in enumerate(nm) if j % 2 == 0]
1839
+ dv = [x for j, x in enumerate(nm) if j % 2 == 1]
1840
+ for j, x in enumerate(nm):
1841
+ if j % 2 == 0:
1842
+ spec.append(f"integer(8), parameter :: {x} = {j * 3 + 1}")
1843
+ if dv:
1844
+ spec += decl_lines("integer(8)", dv, self.o.width)
1845
+ if self.o.model == "omp":
1846
+ spec += pack("declare target(", [
1847
+ x + ("," if k < len(dv) - 1 else ")")
1848
+ for k, x in enumerate(dv)], "", self.o.sent,
1849
+ self.o.width)
1850
+ else:
1851
+ spec += pack("declare", list_atoms("create", dv), "",
1852
+ self.o.sent, self.o.width)
1853
+ del pv
1854
+ # a decoy name the kernel does not import
1855
+ spec.append(f"integer(8) :: {self.name}_unused")
1856
+ return [Module(f"{self.name}_m", spec)]
1857
+
1858
+ def routine(self):
1859
+ lines = super().routine()
1860
+ nm = self.names()
1861
+ use = pack(f"use {self.name}_m, only:", [
1862
+ x + ("," if k < len(nm) - 1 else "")
1863
+ for k, x in enumerate(nm)], " ", None, self.o.width)
1864
+ return [lines[0]] + use + lines[1:]
1865
+
1866
+ def decls(self):
1867
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i",
1868
+ "integer(8) :: t"]
1869
+
1870
+ def body(self):
1871
+ n = self.p["n"]
1872
+ nm = self.names()
1873
+ dv = [x for j, x in enumerate(nm) if j % 2 == 1]
1874
+ ind = " "
1875
+ lines = [f"{ind}{x} = {j * 3 + 1}" for j, x in enumerate(nm)
1876
+ if j % 2 == 1]
1877
+ if dv:
1878
+ if self.o.model == "omp":
1879
+ lines += pack("target update", list_atoms("to", dv), ind,
1880
+ self.o.sent, self.o.width)
1881
+ else:
1882
+ lines += pack("update", list_atoms("device", dv), ind,
1883
+ self.o.sent, self.o.width)
1884
+ chain = ("target teams distribute parallel do",) if \
1885
+ self.o.model == "omp" else ("parallel loop gang vector",)
1886
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")],
1887
+ private=["t"])
1888
+ lines += [f"{ind}out = 0"] + op + [f"{ii}do i = 1, {n}",
1889
+ f"{ii} t = i"]
1890
+ lines += sum_lines(ii + " ", "t", nm, self.o.width)
1891
+ lines += [f"{ii} out(i) = t", f"{ii}end do"] + cl
1892
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1893
+ return lines
1894
+
1895
+ def value(self):
1896
+ k, n = self.p["nitems"], self.p["n"]
1897
+ s = sum(j * 3 + 1 for j in range(k))
1898
+ return cksum(i + s for i in range(1, n + 1))
1899
+
1900
+ def smaller(self):
1901
+ return [self.clone(nitems=m) for m in _halve(self.p["nitems"])]
1902
+
1903
+ def features(self):
1904
+ return super().features() | {f"len:useonly:{self.p['nitems']}"}
1905
+
1906
+
1907
+ class CaptureKernel(ListKernel):
1908
+ """`nitems` host scalars referenced in the region with no clause
1909
+ (implicitly firstprivate: OpenMP 5.2 §5.8.1 p.148; OpenACC 3.4 §2.6.2
1910
+ p.41 for parallel)."""
1911
+ kind = "capture"
1912
+
1913
+ def decls(self):
1914
+ n = self.p["n"]
1915
+ its = self.items("s")
1916
+ return [f"integer(8) :: out({n})", "integer :: i", "integer(8) :: t"] \
1917
+ + decl_lines("integer(8)", its, self.o.width)
1918
+
1919
+ def body(self):
1920
+ n, c = self.p["n"], self.p["c"]
1921
+ its = self.items("s")
1922
+ ind = " "
1923
+ lines = [f"{ind}{x} = {c[k] + 2 * k}" for k, x in enumerate(its)]
1924
+ lines.append(f"{ind}out = 0")
1925
+ chain = ("target teams distribute parallel do",) if \
1926
+ self.o.model == "omp" else ("parallel loop gang vector",)
1927
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")],
1928
+ private=["t"])
1929
+ lines += op + [f"{ii}do i = 1, {n}", f"{ii} t = i"]
1930
+ terms = [f"{x} * mod(i, {k % 3 + 2})" for k, x in enumerate(its)]
1931
+ lines += sum_lines(ii + " ", "t", terms, self.o.width)
1932
+ lines += [f"{ii} out(i) = t", f"{ii}end do"] + cl
1933
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
1934
+ return lines
1935
+
1936
+ def value(self):
1937
+ n, c = self.p["n"], self.p["c"]
1938
+ k = self.p["nitems"]
1939
+ s = [c[j] + 2 * j for j in range(k)]
1940
+ return cksum(i + sum(s[j] * (i % (j % 3 + 2)) for j in range(k))
1941
+ for i in range(1, n + 1))
1942
+
1943
+
1944
+ # --- nested derived types and classes ------------------------------------------------------------
1945
+
1946
+ class DTNestKernel(Kernel):
1947
+ """Derived types nested `depth` levels (t1 contains t2 ... contains tD),
1948
+ each level with a scalar s and an allocatable component v(:) (and, with
1949
+ ptr, a pointer component at the deepest level); an array x(na) of t1;
1950
+ deep copy by enter data of x then of every x(e)%c...%v (OpenMP 5.2
1951
+ §5.8.3: a list item and its containing structure may both be mapped),
1952
+ or one region mapping them all (mode 'region'); out(i) = sum over
1953
+ elements and levels of v(i) + s."""
1954
+ kind = "dtnest"
1955
+
1956
+ def draw(self, rng):
1957
+ self.p.setdefault("depth", 3)
1958
+ self.p.setdefault("na", 2)
1959
+ self.p.setdefault("m", 16)
1960
+ self.p.setdefault("mode", rng.choice(("enter", "region")))
1961
+ self.p.setdefault("ptr", rng.random() < 0.3)
1962
+
1963
+ def tname(self, d):
1964
+ return f"{self.name}_t{d}"
1965
+
1966
+ def path(self, e, d):
1967
+ return f"x({e})" + "%c" * (d - 1)
1968
+
1969
+ def modules(self):
1970
+ D = self.p["depth"]
1971
+ spec = []
1972
+ for d in range(D, 0, -1):
1973
+ spec.append(f"type :: {self.tname(d)}")
1974
+ spec.append(" integer(8) :: s")
1975
+ spec.append(" integer(8), allocatable :: v(:)")
1976
+ if d == D and self.p["ptr"]:
1977
+ spec.append(" integer(8), pointer :: pv(:) => null()")
1978
+ if d < D:
1979
+ spec.append(f" type({self.tname(d + 1)}) :: c")
1980
+ spec.append(f"end type {self.tname(d)}")
1981
+ if self.p["ptr"]:
1982
+ spec.append(f"integer(8), target :: {self.name}_tgt"
1983
+ f"({self.p['m']}, {self.p['na']})")
1984
+ return [Module(f"{self.name}_m", spec)]
1985
+
1986
+ def uses(self):
1987
+ return [f"{self.name}_m"]
1988
+
1989
+ def decls(self):
1990
+ return [f"type({self.tname(1)}) :: x({self.p['na']})",
1991
+ f"integer(8) :: out({self.p['m']})", "integer :: i, e"]
1992
+
1993
+ def items(self):
1994
+ D, na = self.p["depth"], self.p["na"]
1995
+ its = []
1996
+ for e in range(1, na + 1):
1997
+ for d in range(1, D + 1):
1998
+ its.append(self.path(e, d) + "%v")
1999
+ if self.p["ptr"]:
2000
+ its.append(self.path(e, D) + "%pv")
2001
+ return its
2002
+
2003
+ def body(self):
2004
+ D, na, m = self.p["depth"], self.p["na"], self.p["m"]
2005
+ ind = " "
2006
+ lines = []
2007
+ for e in range(1, na + 1):
2008
+ for d in range(1, D + 1):
2009
+ pth = self.path(e, d)
2010
+ lines += [f"{ind}allocate({pth}%v({m}))",
2011
+ f"{ind}{pth}%s = {d * 10 + e}",
2012
+ f"{ind}do i = 1, {m}",
2013
+ f"{ind} {pth}%v(i) = mod(i * {d} + {e}, 97)",
2014
+ f"{ind}end do"]
2015
+ if self.p["ptr"]:
2016
+ pth = self.path(e, D)
2017
+ lines += [f"{ind}do i = 1, {m}",
2018
+ f"{ind} {self.name}_tgt(i, {e}) = i + {e}",
2019
+ f"{ind}end do",
2020
+ f"{ind}{pth}%pv => {self.name}_tgt(:, {e})"]
2021
+ lines.append(f"{ind}out = 0")
2022
+ its = self.items()
2023
+ o = self.o
2024
+ terms = []
2025
+ for e in range(1, na + 1):
2026
+ for d in range(1, D + 1):
2027
+ terms.append(f"{self.path(e, d)}%v(i)")
2028
+ terms.append(f"{self.path(e, d)}%s")
2029
+ if self.p["ptr"]:
2030
+ terms.append(f"{self.path(e, D)}%pv(i)")
2031
+ if self.p["mode"] == "enter":
2032
+ if o.model == "omp":
2033
+ lines.append(f"{ind}{o.sent} target enter data map(to: x)")
2034
+ lines += pack("target enter data", list_atoms("map", its,
2035
+ "to"),
2036
+ ind, o.sent, o.width)
2037
+ else:
2038
+ lines.append(f"{ind}{o.sent} enter data copyin(x)")
2039
+ lines += pack("enter data", list_atoms("copyin", its), ind,
2040
+ o.sent, o.width)
2041
+ chain = ("target teams distribute parallel do",) if \
2042
+ o.model == "omp" else ("parallel loop",)
2043
+ op, cl, ii = region(o, chain, ind, data=[("out", "tofrom")],
2044
+ extra=["present(x)"] if o.model == "acc"
2045
+ else [])
2046
+ else:
2047
+ chain = ("target teams distribute parallel do",) if \
2048
+ o.model == "omp" else ("parallel loop",)
2049
+ op, cl, ii = region(o, chain, ind,
2050
+ data=[("x", "to")] + [(t, "to") for t in its]
2051
+ + [("out", "tofrom")])
2052
+ lines += op + [f"{ii}do i = 1, {m}"]
2053
+ lines += sum_lines(ii + " ", "out(i)", terms, o.width)
2054
+ lines += [f"{ii}end do"] + cl
2055
+ if self.p["mode"] == "enter":
2056
+ if o.model == "omp":
2057
+ lines += pack("target exit data",
2058
+ list_atoms("map", list(reversed(its)),
2059
+ "delete"), ind, o.sent, o.width)
2060
+ lines.append(f"{ind}{o.sent} target exit data "
2061
+ "map(delete: x)")
2062
+ else:
2063
+ lines += pack("exit data", list_atoms(
2064
+ "delete", list(reversed(its))), ind, o.sent, o.width)
2065
+ lines.append(f"{ind}{o.sent} exit data delete(x)")
2066
+ lines.append(f"{ind}call st_cksum(out, {m}, cs)")
2067
+ return lines
2068
+
2069
+ def value(self):
2070
+ D, na, m = self.p["depth"], self.p["na"], self.p["m"]
2071
+ vals = []
2072
+ for i in range(1, m + 1):
2073
+ t = 0
2074
+ for e in range(1, na + 1):
2075
+ for d in range(1, D + 1):
2076
+ t += (i * d + e) % 97 + d * 10 + e
2077
+ if self.p["ptr"]:
2078
+ t += i + e
2079
+ vals.append(t)
2080
+ return cksum(vals)
2081
+
2082
+ def smaller(self):
2083
+ out = []
2084
+ if self.p["depth"] > 1:
2085
+ out.append(self.clone(depth=self.p["depth"] - 1))
2086
+ out.append(self.clone(depth=1))
2087
+ if self.p["na"] > 1:
2088
+ out.append(self.clone(na=1))
2089
+ if self.p["ptr"]:
2090
+ out.append(self.clone(ptr=False))
2091
+ if self.p["mode"] == "region":
2092
+ out.append(self.clone(mode="enter"))
2093
+ return out
2094
+
2095
+ def features(self):
2096
+ f = super().features() | {f"dt:depth{self.p['depth']}",
2097
+ f"dt:mode:{self.p['mode']}",
2098
+ "base:derived", "base:allocatable"}
2099
+ if self.p["na"] > 1:
2100
+ f.add("dt:array_of_dt")
2101
+ if self.p["ptr"]:
2102
+ f.add("base:pointer")
2103
+ return f
2104
+
2105
+
2106
+ OO_VARIANTS = ("tbp", "nopass", "generic", "extends", "abstract", "class",
2107
+ "polymap", "pdt")
2108
+ OO_LEGAL = ("tbp", "nopass", "generic", "extends", "abstract", "class")
2109
+
2110
+
2111
+ class OOKernel(Kernel):
2112
+ """Object-oriented code used in a target / compute region: type-bound
2113
+ procedures (passed-object, NOPASS), generic and operator bindings, an
2114
+ EXTENDS chain `depth` deep with overriding bindings, an abstract type
2115
+ with a deferred binding, a CLASS dummy with SELECT TYPE in a device
2116
+ routine; every procedure the region reaches is a device routine
2117
+ (OpenMP 5.0/5.2 §1.2.6: type-bound procedures accessed in a target
2118
+ region must appear in a declare target directive). 'polymap' maps a
2119
+ polymorphic allocatable: unspecified (OpenMP 6.0 §7.9.6 p.287; 5.0 and
2120
+ 5.2 do not define it): portability data, never a compiler bug."""
2121
+ kind = "oo"
2122
+
2123
+ def draw(self, rng):
2124
+ self.p.setdefault("variant", rng.choice(OO_VARIANTS))
2125
+ self.p.setdefault("depth", 3)
2126
+ self.p.setdefault("n", 128)
2127
+ if self.p["variant"] == "polymap":
2128
+ self.legality = "unspecified"
2129
+ self.cite = CITES["poly"]
2130
+
2131
+ def __init__(self, name, o, rng, **p):
2132
+ super().__init__(name, o, rng, **p)
2133
+ if self.p.get("variant") == "polymap":
2134
+ self.legality = "unspecified"
2135
+ self.cite = CITES["poly"]
2136
+
2137
+ def t(self, d=0):
2138
+ return f"{self.name}_t{d}"
2139
+
2140
+ def modules(self):
2141
+ v, D = self.p["variant"], self.p["depth"]
2142
+ dt = _dt_line(self.o)
2143
+ spec, cont = [], []
2144
+ if v in ("tbp", "class", "polymap"):
2145
+ spec = [f"type :: {self.t()}", " integer(8) :: k = 3",
2146
+ "contains",
2147
+ f" procedure :: get => {self.name}_get",
2148
+ f"end type {self.t()}"]
2149
+ cont = [f" function {self.name}_get(self, i) result(r)", dt,
2150
+ f" class({self.t()}), intent(in) :: self",
2151
+ " integer(8), intent(in) :: i", " integer(8) :: r",
2152
+ " r = self%k * i + 1", f" end function {self.name}_get"]
2153
+ if v in ("class", "polymap"):
2154
+ spec += [f"type, extends({self.t()}) :: {self.t(1)}",
2155
+ " integer(8) :: extra = 5",
2156
+ "contains", f" procedure :: get => {self.name}_get1",
2157
+ f"end type {self.t(1)}"]
2158
+ cont += [f" function {self.name}_get1(self, i) result(r)",
2159
+ dt, f" class({self.t(1)}), intent(in) :: self",
2160
+ " integer(8), intent(in) :: i",
2161
+ " integer(8) :: r",
2162
+ " r = self%k * i + self%extra",
2163
+ f" end function {self.name}_get1",
2164
+ f" function {self.name}_sel(o, i) result(r)", dt,
2165
+ f" class({self.t()}), intent(in) :: o",
2166
+ " integer(8), intent(in) :: i",
2167
+ " integer(8) :: r",
2168
+ " select type (o)",
2169
+ f" type is ({self.t(1)})",
2170
+ " r = o%extra * 100 + o%get(i)",
2171
+ " class default",
2172
+ " r = o%get(i)",
2173
+ " end select",
2174
+ f" end function {self.name}_sel"]
2175
+ elif v == "nopass":
2176
+ spec = [f"type :: {self.t()}", " integer(8) :: k = 3",
2177
+ "contains",
2178
+ f" procedure, nopass :: f => {self.name}_f",
2179
+ f"end type {self.t()}"]
2180
+ cont = [f" function {self.name}_f(i) result(r)", dt,
2181
+ " integer(8), intent(in) :: i", " integer(8) :: r",
2182
+ " r = i * 7 + 2", f" end function {self.name}_f"]
2183
+ elif v == "generic":
2184
+ spec = [f"type :: {self.t()}", " integer(8) :: k = 3",
2185
+ "contains",
2186
+ f" procedure :: addi => {self.name}_addi",
2187
+ " generic :: add => addi",
2188
+ f" procedure :: plus => {self.name}_plus",
2189
+ " generic :: operator(+) => plus",
2190
+ f"end type {self.t()}"]
2191
+ cont = [f" function {self.name}_addi(self, i) result(r)", dt,
2192
+ f" class({self.t()}), intent(in) :: self",
2193
+ " integer(8), intent(in) :: i", " integer(8) :: r",
2194
+ " r = self%k + i", f" end function {self.name}_addi",
2195
+ f" function {self.name}_plus(a, b) result(r)", dt,
2196
+ f" class({self.t()}), intent(in) :: a",
2197
+ f" type({self.t()}), intent(in) :: b",
2198
+ f" type({self.t()}) :: r",
2199
+ " r%k = a%k + b%k", f" end function {self.name}_plus"]
2200
+ elif v == "extends":
2201
+ for d in range(D + 1):
2202
+ head = f"type :: {self.t(0)}" if d == 0 else \
2203
+ f"type, extends({self.t(d - 1)}) :: {self.t(d)}"
2204
+ spec += [head, f" integer(8) :: c{d} = {d + 2}", "contains",
2205
+ f" procedure :: get => {self.name}_g{d}",
2206
+ f"end type {self.t(d)}"]
2207
+ cont += [f" function {self.name}_g{d}(self, i) result(r)",
2208
+ dt, f" class({self.t(d)}), intent(in) :: self",
2209
+ " integer(8), intent(in) :: i",
2210
+ " integer(8) :: r",
2211
+ f" r = self%c{d} * i + {d}",
2212
+ f" end function {self.name}_g{d}"]
2213
+ elif v == "pdt":
2214
+ # a parameterized derived type (kind and length parameters;
2215
+ # OpenMP 5.2 §5.8.3: a corresponding list item has the type
2216
+ # parameters of the original)
2217
+ spec = [f"type :: {self.t()}(kk, nn)",
2218
+ " integer, kind :: kk = 8", " integer, len :: nn",
2219
+ " integer(kk) :: v(nn)", " integer(kk) :: s",
2220
+ f"end type {self.t()}"]
2221
+ cont = []
2222
+ elif v == "abstract":
2223
+ spec = [f"type, abstract :: {self.t(0)}", " integer(8) :: k = 4",
2224
+ "contains",
2225
+ f" procedure({self.name}_iface), deferred :: get",
2226
+ f"end type {self.t(0)}",
2227
+ "abstract interface",
2228
+ f" function {self.name}_iface(self, i) result(r)",
2229
+ f" import :: {self.t(0)}",
2230
+ f" class({self.t(0)}), intent(in) :: self",
2231
+ " integer(8), intent(in) :: i", " integer(8) :: r",
2232
+ f" end function {self.name}_iface", "end interface",
2233
+ f"type, extends({self.t(0)}) :: {self.t(1)}", "contains",
2234
+ f" procedure :: get => {self.name}_g1",
2235
+ f"end type {self.t(1)}"]
2236
+ cont = [f" function {self.name}_g1(self, i) result(r)", dt,
2237
+ f" class({self.t(1)}), intent(in) :: self",
2238
+ " integer(8), intent(in) :: i", " integer(8) :: r",
2239
+ " r = self%k * i * 2", f" end function {self.name}_g1"]
2240
+ return [Module(f"{self.name}_m", spec, cont)]
2241
+
2242
+ def uses(self):
2243
+ return [f"{self.name}_m"]
2244
+
2245
+ def decls(self):
2246
+ v = self.p["variant"]
2247
+ d = [f"integer(8) :: out({self.p['n']})", "integer :: i"]
2248
+ if v in ("tbp", "nopass", "generic"):
2249
+ d.append(f"type({self.t()}) :: obj")
2250
+ if v == "generic":
2251
+ d.append(f"type({self.t()}) :: o2")
2252
+ if v == "extends":
2253
+ d.append(f"type({self.t(self.p['depth'])}) :: obj")
2254
+ if v == "abstract":
2255
+ d.append(f"type({self.t(1)}) :: obj")
2256
+ if v == "class":
2257
+ d.append(f"type({self.t(1)}) :: obj")
2258
+ if v == "polymap":
2259
+ d.append(f"class({self.t()}), allocatable :: obj")
2260
+ if v == "pdt":
2261
+ d.append(f"type({self.t()}(8, 7)) :: obj")
2262
+ return d
2263
+
2264
+ def expr(self):
2265
+ v = self.p["variant"]
2266
+ return {"tbp": "obj%get(int(i, 8))",
2267
+ "nopass": "obj%f(int(i, 8))",
2268
+ "generic": "obj%add(int(i, 8)) + o2%k",
2269
+ "extends": "obj%get(int(i, 8)) + obj%c0",
2270
+ "abstract": "obj%get(int(i, 8))",
2271
+ "class": f"{self.name}_sel(obj, int(i, 8))",
2272
+ "polymap": "obj%get(int(i, 8))",
2273
+ "pdt": "obj%v(mod(i, obj%nn) + 1) + obj%s + obj%nn"}[v]
2274
+
2275
+ def body(self):
2276
+ v = self.p["variant"]
2277
+ n = self.p["n"]
2278
+ ind = " "
2279
+ lines = [f"{ind}out = 0"]
2280
+ if v == "generic":
2281
+ lines.append(f"{ind}o2 = obj + obj")
2282
+ if v == "polymap":
2283
+ lines.append(f"{ind}allocate({self.t(1)} :: obj)")
2284
+ if v == "pdt":
2285
+ lines += [f"{ind}do i = 1, 7", f"{ind} obj%v(i) = i * 11",
2286
+ f"{ind}end do", f"{ind}obj%s = 5"]
2287
+ chain = ("target teams distribute parallel do",) if \
2288
+ self.o.model == "omp" else ("parallel loop",)
2289
+ data = [("out", "tofrom"), ("obj", "to")]
2290
+ if v == "generic":
2291
+ data.append(("o2", "to"))
2292
+ op, cl, ii = region(self.o, chain, ind, data=data)
2293
+ lines += op + [f"{ii}do i = 1, {n}",
2294
+ f"{ii} out(i) = {self.expr()}", f"{ii}end do"] + cl
2295
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
2296
+ return lines
2297
+
2298
+ def value(self):
2299
+ v, n, D = self.p["variant"], self.p["n"], self.p["depth"]
2300
+ f = {"tbp": lambda i: 3 * i + 1,
2301
+ "nopass": lambda i: i * 7 + 2,
2302
+ "generic": lambda i: 3 + i + 6,
2303
+ "extends": lambda i: (D + 2) * i + D + 2,
2304
+ "abstract": lambda i: 4 * i * 2,
2305
+ "class": lambda i: 5 * 100 + 3 * i + 5,
2306
+ "polymap": lambda i: 3 * i + 5,
2307
+ "pdt": lambda i: (i % 7 + 1) * 11 + 5 + 7}[v]
2308
+ return cksum(f(i) for i in range(1, n + 1))
2309
+
2310
+ def smaller(self):
2311
+ out = []
2312
+ if self.p["variant"] == "extends" and self.p["depth"] > 1:
2313
+ out.append(self.clone(depth=1))
2314
+ if self.p["n"] > 8:
2315
+ out.append(self.clone(n=8))
2316
+ return out
2317
+
2318
+ def features(self):
2319
+ return super().features() | {f"oo:{self.p['variant']}",
2320
+ "base:derived"}
2321
+
2322
+
2323
+ # --- translation units ---------------------------------------------------------------------------
2324
+
2325
+ class ChainTUKernel(Kernel):
2326
+ """A device call chain across modules: module <k>_c1 uses <k>_c2 ...
2327
+ uses <k>_cD, each with function g_j(x) = g_{j+1}(mod(x*5, 1013) + j)
2328
+ + j; every module also uses <k>_glob, whose declare target variable gv
2329
+ the deepest function adds (a module DAG with a shared root). Variants:
2330
+ 'plain'; 'submodule' (the deepest function's interface in the module,
2331
+ its body in a submodule); 'bindc' (the deepest function in C, bound
2332
+ with bind(C), OpenMP only); 'implicit' (no declare target on g_2..g_D:
2333
+ legal when every g_j is in the compilation unit of the region,
2334
+ otherwise an illegal probe, OpenMP 5.2 §13.8 p.284 and §5.8.4 p.158).
2335
+ The program's layout decides the files (one per module, or
2336
+ partitions)."""
2337
+ kind = "tu"
2338
+
2339
+ def draw(self, rng):
2340
+ self.p.setdefault("depth", 5)
2341
+ self.p.setdefault("n", 256)
2342
+ self.p.setdefault("variant", "plain")
2343
+ self.p.setdefault("gv", rng.randrange(1, 100))
2344
+
2345
+ def m(self, j):
2346
+ return f"{self.name}_c{j}"
2347
+
2348
+ def g(self, j):
2349
+ return f"{self.name}_g{j}"
2350
+
2351
+ def modules(self):
2352
+ D, var = self.p["depth"], self.p["variant"]
2353
+ o = self.o
2354
+ mods = []
2355
+ glob_spec = ["integer(8) :: gv = 0"]
2356
+ glob_spec.append(f"{o.sent} declare target(gv)" if o.model == "omp"
2357
+ else f"{o.sent} declare create(gv)")
2358
+ mods.append(Module(f"{self.name}_glob", glob_spec))
2359
+ for j in range(D, 0, -1):
2360
+ uses = [f"{self.name}_glob"] + ([self.m(j + 1)] if j < D else [])
2361
+ need_dt = not (var == "implicit" and j > 1)
2362
+ dl = [_dt_line(o)] if need_dt else []
2363
+ if j == D and var == "submodule":
2364
+ spec = ["interface",
2365
+ f" module function {self.g(j)}(x) result(r)",
2366
+ f" {o.sent} declare target" if o.model == "omp"
2367
+ else f" {o.sent} routine seq",
2368
+ " integer(8), intent(in) :: x",
2369
+ " integer(8) :: r",
2370
+ f" end function {self.g(j)}", "end interface"]
2371
+ mods.append(Module(self.m(j), spec, [], uses))
2372
+ continue
2373
+ if j == D and var == "bindc":
2374
+ spec = ["interface",
2375
+ f" function {self.g(j)}(x) result(r) "
2376
+ f"bind(C, name=\"{self.g(j)}_c\")",
2377
+ " import :: c_int64_t",
2378
+ f" {o.sent} declare target",
2379
+ " integer(c_int64_t), value :: x",
2380
+ " integer(c_int64_t) :: r",
2381
+ f" end function {self.g(j)}", "end interface"]
2382
+ mods.append(Module(self.m(j), spec, [],
2383
+ uses + ["iso_c_binding"]))
2384
+ continue
2385
+ cont = [f" function {self.g(j)}(x) result(r)"] + dl + [
2386
+ " integer(8), intent(in) :: x", " integer(8) :: r"]
2387
+ if j < D:
2388
+ cont.append(f" r = {self.g(j + 1)}(mod(x * 5, 1013_8) + "
2389
+ f"{j}) + {j}")
2390
+ else:
2391
+ cont.append(" r = x + gv")
2392
+ cont.append(f" end function {self.g(j)}")
2393
+ mods.append(Module(self.m(j), [], cont, uses))
2394
+ return mods
2395
+
2396
+ def extra_files(self) -> list[tuple[str, str]]:
2397
+ """Files that are not modules of the program text: the submodule
2398
+ and the C function, each its own translation unit."""
2399
+ D, var = self.p["depth"], self.p["variant"]
2400
+ o = self.o
2401
+ if var == "submodule":
2402
+ text = [f"submodule ({self.m(D)}) {self.m(D)}_s",
2403
+ " implicit none", "contains",
2404
+ f" module function {self.g(D)}(x) result(r)",
2405
+ " use " + f"{self.name}_glob, only: gv",
2406
+ f" {o.sent} declare target" if o.model == "omp"
2407
+ else f" {o.sent} routine seq",
2408
+ " integer(8), intent(in) :: x",
2409
+ " integer(8) :: r",
2410
+ " r = x + gv", f" end function {self.g(D)}",
2411
+ f"end submodule {self.m(D)}_s"]
2412
+ return [(f"{self.m(D)}_s.f90", "\n".join(text) + "\n")]
2413
+ if var == "bindc":
2414
+ text = ["#include <stdint.h>",
2415
+ "#pragma omp declare target",
2416
+ f"int64_t {self.g(D)}_c(int64_t x) {{ return x + "
2417
+ f"{self.p['gv']}; }}",
2418
+ "#pragma omp end declare target"]
2419
+ return [(f"{self.g(D)}_c.c", "\n".join(text) + "\n")]
2420
+ return []
2421
+
2422
+ def uses(self):
2423
+ return [self.m(1), f"{self.name}_glob"]
2424
+
2425
+ def decls(self):
2426
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i"]
2427
+
2428
+ def body(self):
2429
+ n = self.p["n"]
2430
+ o = self.o
2431
+ ind = " "
2432
+ lines = [f"{ind}gv = {self.p['gv']}"]
2433
+ lines.append(f"{ind}{o.sent} target update to(gv)" if o.model ==
2434
+ "omp" else f"{ind}{o.sent} update device(gv)")
2435
+ chain = ("target teams distribute parallel do",) if \
2436
+ o.model == "omp" else ("parallel loop gang vector",)
2437
+ op, cl, ii = region(o, chain, ind, data=[("out", "tofrom")])
2438
+ lines += [f"{ind}out = 0"] + op + [
2439
+ f"{ii}do i = 1, {n}", f"{ii} out(i) = {self.g(1)}(int(i, 8))",
2440
+ f"{ii}end do"] + cl
2441
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
2442
+ return lines
2443
+
2444
+ def value(self):
2445
+ D, n, gv = self.p["depth"], self.p["n"], self.p["gv"]
2446
+ vals = []
2447
+ for i in range(1, n + 1):
2448
+ x, add = i, 0
2449
+ for j in range(1, D):
2450
+ x = (x * 5) % 1013 + j
2451
+ add += j
2452
+ vals.append(x + gv + add)
2453
+ return cksum(vals)
2454
+
2455
+ def smaller(self):
2456
+ out = [self.clone(depth=m) for m in _halve(self.p["depth"], 2)]
2457
+ if self.p["variant"] != "plain":
2458
+ out.append(self.clone(variant="plain"))
2459
+ return out
2460
+
2461
+ def features(self):
2462
+ return super().features() | {f"tu:depth{self.p['depth']}",
2463
+ f"tu:{self.p['variant']}"}
2464
+
2465
+
2466
+ # --- default scalar residency ------------------------------------------------------------------
2467
+
2468
+ # route -> (defined: device read of the host value, defined: host value
2469
+ # after the region, what the host sees after: "same" | "write")
2470
+ OMP_ROUTES = {
2471
+ "implicit": (True, True, "same"),
2472
+ "firstprivate": (True, True, "same"),
2473
+ "private": (False, True, "same"),
2474
+ "to": (True, False, None),
2475
+ "from": (False, True, "write"),
2476
+ "tofrom": (True, True, "write"),
2477
+ "dm_tofrom": (True, True, "write"),
2478
+ "dm_firstprivate": (True, True, "same"),
2479
+ "dm_to": (True, False, None),
2480
+ "target_attr": (True, True, "write"),
2481
+ "present_implicit": (True, True, "same"),
2482
+ "present_update": (True, True, "write"),
2483
+ "declare": (True, True, "write"),
2484
+ "component": (True, True, "write"),
2485
+ "byref": (True, True, "same"),
2486
+ "value": (True, True, "same"),
2487
+ "reduction": (True, True, "red"),
2488
+ }
2489
+ ACC_ROUTES = {
2490
+ "implicit_parallel": (True, True, "same"),
2491
+ "implicit_serial": (True, True, "same"),
2492
+ "implicit_kernels": (True, True, "write"),
2493
+ "copy": (True, True, "write"),
2494
+ "copyin": (True, False, None),
2495
+ "copyout": (False, True, "write"),
2496
+ "firstprivate": (True, True, "same"),
2497
+ "private": (False, True, "same"),
2498
+ "data_copy": (True, True, "write"),
2499
+ "enter_implicit": (True, True, "same"),
2500
+ "declare": (True, True, "write"),
2501
+ "component": (True, True, "write"),
2502
+ "byref": (True, True, "same"),
2503
+ "reduction": (True, True, "red"),
2504
+ }
2505
+ ROUTE_CITES = (
2506
+ "OpenMP 5.2 §5.8.1 p.147-148 (implicit data-mapping: a non-scalar or a "
2507
+ "TARGET/ALLOCATABLE/POINTER scalar is tofrom, another scalar "
2508
+ "firstprivate; the same rules in 5.0 §2.19.7 p.314 and 6.0 §7.9.3 "
2509
+ "p.276), §1.4.2 p.27 (a write to a variable whose corresponding "
2510
+ "variable does not share storage makes the other undefined); OpenACC "
2511
+ "3.4 §2.6.2 p.41 (a scalar is copy in kernels, firstprivate otherwise; "
2512
+ "a visible data clause of an enclosing data construct applies)")
2513
+
2514
+
2515
+ class ScalarsKernel(Kernel):
2516
+ """Default scalar residency against every explicit route: for each
2517
+ route, `nscal` scalars s_j (host value h_j) and an array a mixed in the
2518
+ same region; one thread on the device (target / serial) reads each s_j
2519
+ into rd(j) and writes s_j = 2*s_j + 1. The value combines only the
2520
+ observations the specification defines (a device read of the host
2521
+ value; the host value afterwards: unchanged for private copies, the
2522
+ device write for tofrom); the others print an ``OBS`` line
2523
+ (portability data)."""
2524
+ kind = "scalars"
2525
+ elision_valid = False
2526
+
2527
+ def draw(self, rng):
2528
+ self.p.setdefault("nscal", 4)
2529
+ routes = OMP_ROUTES if self.o.model == "omp" else ACC_ROUTES
2530
+ self.p.setdefault("routes", list(routes))
2531
+
2532
+ def table(self):
2533
+ return OMP_ROUTES if self.o.model == "omp" else ACC_ROUTES
2534
+
2535
+ def mod(self):
2536
+ return f"{self.name}_m"
2537
+
2538
+ def svars(self, r):
2539
+ return [f"s{r}_{j}" for j in range(1, self.p["nscal"] + 1)]
2540
+
2541
+ def modules(self):
2542
+ spec, cont = [], []
2543
+ o = self.o
2544
+ if "declare" in self.p["routes"]:
2545
+ dv = [f"g_{j}" for j in range(1, self.p["nscal"] + 1)]
2546
+ spec += decl_lines("integer(8)", dv, o.width)
2547
+ if o.model == "omp":
2548
+ spec += pack("declare target(", [
2549
+ x + ("," if k < len(dv) - 1 else ")")
2550
+ for k, x in enumerate(dv)], "", o.sent, o.width)
2551
+ else:
2552
+ spec += pack("declare", list_atoms("create", dv), "",
2553
+ o.sent, o.width)
2554
+ if "component" in self.p["routes"]:
2555
+ spec += [f"type :: {self.name}_sc",
2556
+ *[f" integer(8) :: c{j}" for j in
2557
+ range(1, self.p["nscal"] + 1)],
2558
+ f"end type {self.name}_sc"]
2559
+ cont += [f" subroutine {self.name}_upd(x)", _dt_line(o),
2560
+ " integer(8), intent(inout) :: x",
2561
+ " x = 2 * x + 1", f" end subroutine {self.name}_upd",
2562
+ f" function {self.name}_val(x) result(r)", _dt_line(o),
2563
+ " integer(8), value :: x", " integer(8) :: r",
2564
+ " x = 2 * x + 1", " r = x",
2565
+ f" end function {self.name}_val"]
2566
+ return [Module(self.mod(), spec, cont)]
2567
+
2568
+ def uses(self):
2569
+ return [self.mod()]
2570
+
2571
+ def decls(self):
2572
+ k = self.p["nscal"]
2573
+ d = [f"integer(8) :: rd({k}), a(4), hv", "integer :: j, ii"]
2574
+ for r, route in enumerate(self.p["routes"]):
2575
+ if route in ("declare", "component"):
2576
+ continue
2577
+ attr = ", target" if route == "target_attr" else ""
2578
+ d += decl_lines(f"integer(8){attr}", self.svars(r), self.o.width)
2579
+ if "component" in self.p["routes"]:
2580
+ d.append(f"type({self.name}_sc) :: xc")
2581
+ return d
2582
+
2583
+ def h(self, r, j):
2584
+ return 100 * (r + 1) + j
2585
+
2586
+ def names(self, r, route):
2587
+ k = self.p["nscal"]
2588
+ if route == "declare":
2589
+ return [f"g_{j}" for j in range(1, k + 1)]
2590
+ if route == "component":
2591
+ return [f"xc%c{j}" for j in range(1, k + 1)]
2592
+ return self.svars(r)
2593
+
2594
+ def route_lines(self, r, route) -> list[str]:
2595
+ o = self.o
2596
+ ind = " "
2597
+ S = self.names(r, route)
2598
+ k = len(S)
2599
+ lines = [f"{ind}! route {route}", f"{ind}rd = -1", f"{ind}a = 0"]
2600
+ lines += [f"{ind}{s} = {self.h(r, j)}" for j, s in enumerate(S, 1)]
2601
+ read_first = OMP_ROUTES.get(route, ACC_ROUTES.get(route))[0]
2602
+ dev = []
2603
+ if route in ("from", "copyout"):
2604
+ dev += [f"{s} = {self.h(r, j)} + 0" for j, s in enumerate(S, 1)]
2605
+ if route == "private":
2606
+ dev += [f"{s} = {j} * 5" for j, s in enumerate(S, 1)]
2607
+ if route == "byref":
2608
+ dev += [f"rd({j}) = {s}" for j, s in enumerate(S, 1)]
2609
+ dev += [f"call {self.name}_upd({s})" for s in S]
2610
+ dev += [f"a({min(4, j)}) = a({min(4, j)}) + {s}"
2611
+ for j, s in enumerate(S, 1)]
2612
+ elif route == "value":
2613
+ dev += [f"rd({j}) = {self.name}_val({s}) - {s}"
2614
+ for j, s in enumerate(S, 1)]
2615
+ dev += [f"a(1) = a(1) + {s}" for s in S]
2616
+ elif route == "reduction":
2617
+ pass
2618
+ else:
2619
+ dev += [f"rd({j}) = {s}" for j, s in enumerate(S, 1)]
2620
+ dev += [f"{s} = 2 * {s} + 1" for s in S]
2621
+ dev += ["a(1) = a(1) + 1"]
2622
+ pre, post = [], []
2623
+ atoms = []
2624
+ name = "target" if o.model == "omp" else "serial"
2625
+ data = [("rd", "tofrom"), ("a", "tofrom")]
2626
+ if o.model == "omp":
2627
+ if route in ("firstprivate", "private"):
2628
+ atoms = list_atoms(route, S)
2629
+ elif route in ("to", "from", "tofrom"):
2630
+ data = [(s, route) for s in S] + data
2631
+ elif route.startswith("dm_"):
2632
+ atoms = [f"defaultmap({route[3:]}: scalar)"]
2633
+ elif route == "present_implicit":
2634
+ pre += pack("target enter data", list_atoms("map", S, "to"),
2635
+ ind, o.sent, o.width)
2636
+ pre += [f"{ind}{s} = {self.h(r, j)} + 1000"
2637
+ for j, s in enumerate(S, 1)]
2638
+ post += pack("target exit data", list_atoms("map", S,
2639
+ "delete"),
2640
+ ind, o.sent, o.width)
2641
+ elif route == "present_update":
2642
+ pre += pack("target enter data", list_atoms("map", S, "to"),
2643
+ ind, o.sent, o.width)
2644
+ pre += [f"{ind}{s} = {self.h(r, j)} + 1000"
2645
+ for j, s in enumerate(S, 1)]
2646
+ pre += pack("target update", list_atoms("to", S), ind,
2647
+ o.sent, o.width)
2648
+ data = [(s, "tofrom") for s in S] + data
2649
+ post += pack("target update", list_atoms("from", S), ind,
2650
+ o.sent, o.width)
2651
+ post += pack("target exit data", list_atoms("map", S,
2652
+ "delete"),
2653
+ ind, o.sent, o.width)
2654
+ elif route == "declare":
2655
+ pre += pack("target update", list_atoms("to", S), ind,
2656
+ o.sent, o.width)
2657
+ post += pack("target update", list_atoms("from", S), ind,
2658
+ o.sent, o.width)
2659
+ elif route == "reduction":
2660
+ name = "target teams distribute parallel do"
2661
+ atoms = list_atoms("reduction", S, "+")
2662
+ else:
2663
+ if route == "implicit_parallel":
2664
+ name = "parallel"
2665
+ atoms = ["num_gangs(1)"]
2666
+ elif route == "implicit_kernels":
2667
+ name = "kernels"
2668
+ elif route in ("copy", "copyin", "copyout", "firstprivate",
2669
+ "private"):
2670
+ atoms = list_atoms(route, S)
2671
+ elif route == "data_copy":
2672
+ pre += pack("data", list_atoms("copy", S), ind, o.sent,
2673
+ o.width)
2674
+ post += [f"{ind}{o.sent} end data"]
2675
+ elif route == "enter_implicit":
2676
+ pre += pack("enter data", list_atoms("copyin", S), ind,
2677
+ o.sent, o.width)
2678
+ pre += [f"{ind}{s} = {self.h(r, j)} + 1000"
2679
+ for j, s in enumerate(S, 1)]
2680
+ post += pack("exit data", list_atoms("delete", S), ind,
2681
+ o.sent, o.width)
2682
+ elif route == "declare":
2683
+ pre += pack("update", list_atoms("device", S), ind, o.sent,
2684
+ o.width)
2685
+ post += pack("update", list_atoms("self", S), ind, o.sent,
2686
+ o.width)
2687
+ elif route == "reduction":
2688
+ name = "parallel loop"
2689
+ atoms = list_atoms("reduction", S, "+")
2690
+ lines += pre
2691
+ lines += pack(name, data_clauses(o, data) + atoms, ind, o.sent,
2692
+ o.width)
2693
+ if route == "reduction":
2694
+ lines += [f"{ind}do ii = 1, 4"]
2695
+ lines += [f"{ind} {s} = {s} + {j}" for j, s in enumerate(S, 1)]
2696
+ lines += [f"{ind}end do"]
2697
+ else:
2698
+ lines += [f"{ind} {x}" for x in dev]
2699
+ if not (o.model == "acc" and name == "parallel loop"):
2700
+ lines.append(f"{ind}{o.sent} end {name}")
2701
+ lines += post
2702
+ del read_first, k
2703
+ return lines
2704
+
2705
+ def expect(self, r, route):
2706
+ """(rd values or None per j, host-after values or None per j)."""
2707
+ dr, da, after = self.table()[route]
2708
+ k = self.p["nscal"]
2709
+ hs = [self.h(r, j) + (1000 if route in ("present_implicit",
2710
+ "present_update",
2711
+ "enter_implicit") else 0)
2712
+ for j in range(1, k + 1)]
2713
+ rd = [None] * k
2714
+ aft = [None] * k
2715
+ for j in range(k):
2716
+ if route == "private":
2717
+ rd[j] = (j + 1) * 5
2718
+ elif route == "from" or route == "copyout":
2719
+ rd[j] = self.h(r, j + 1)
2720
+ elif route == "value":
2721
+ rd[j] = hs[j] + 1 # 2h+1 - h
2722
+ elif route == "reduction":
2723
+ rd[j] = None
2724
+ elif dr:
2725
+ rd[j] = hs[j]
2726
+ if da:
2727
+ if after == "same":
2728
+ aft[j] = hs[j]
2729
+ elif after == "write":
2730
+ base = self.h(r, j + 1) if route in ("from", "copyout") \
2731
+ else hs[j]
2732
+ aft[j] = 2 * base + 1
2733
+ elif after == "red":
2734
+ aft[j] = hs[j] + 4 * (j + 1)
2735
+ return rd, aft
2736
+
2737
+ def body(self):
2738
+ ind = " "
2739
+ lines = [f"{ind}cs = 0"]
2740
+ for r, route in enumerate(self.p["routes"]):
2741
+ lines += self.route_lines(r, route)
2742
+ rd, aft = self.expect(r, route)
2743
+ S = self.names(r, route)
2744
+ for j, s in enumerate(S, 1):
2745
+ if rd[j - 1] is not None:
2746
+ lines.append(f"{ind}cs = mod(cs * 31 + rd({j}), {P}_8)")
2747
+ else:
2748
+ lines.append(f"{ind}print '(a,i0,a,i0)', 'OBS "
2749
+ f"{self.name} {route} rd ', {j}, ' ', "
2750
+ f"rd({j})")
2751
+ if aft[j - 1] is not None:
2752
+ lines.append(f"{ind}cs = mod(cs * 31 + {s}, {P}_8)")
2753
+ else:
2754
+ lines.append(f"{ind}hv = {s}")
2755
+ lines.append(f"{ind}print '(a,i0,a,i0)', 'OBS "
2756
+ f"{self.name} {route} host ', {j}, ' ', hv")
2757
+ return lines
2758
+
2759
+ def value(self):
2760
+ cs = 0
2761
+ for r, route in enumerate(self.p["routes"]):
2762
+ rd, aft = self.expect(r, route)
2763
+ for j in range(self.p["nscal"]):
2764
+ if rd[j] is not None:
2765
+ cs = (cs * 31 + rd[j]) % P
2766
+ if aft[j] is not None:
2767
+ cs = (cs * 31 + aft[j]) % P
2768
+ return cs
2769
+
2770
+ def smaller(self):
2771
+ rs = self.p["routes"]
2772
+ out = []
2773
+ if len(rs) > 1:
2774
+ h = len(rs) // 2
2775
+ out += [self.clone(routes=rs[:h]), self.clone(routes=rs[h:])]
2776
+ if self.p["nscal"] > 1:
2777
+ out.append(self.clone(nscal=1))
2778
+ return out
2779
+
2780
+ def features(self):
2781
+ return super().features() | {f"route:{r}" for r in self.p["routes"]}
2782
+
2783
+
2784
+ # --- reductions + atomics + criticals, expressions, async, runtime -----------------------------
2785
+
2786
+ class MixedKernel(Kernel):
2787
+ """`nred` reduction variables (cycling operators), `natom` counters
2788
+ updated by atomic update, a histogram updated in `ncrit` named critical
2789
+ sections (OpenMP: in a target parallel do, no teams: Ruling of
2790
+ offload.engine.fuzz on critical and teams), all in one loop. OpenACC: the
2791
+ reductions and atomics (OpenACC has no critical)."""
2792
+ kind = "mixed"
2793
+
2794
+ def draw(self, rng):
2795
+ self.p.setdefault("nred", 4)
2796
+ self.p.setdefault("natom", 2)
2797
+ self.p.setdefault("ncrit", 2 if self.o.model == "omp" else 0)
2798
+ self.p.setdefault("n", 512)
2799
+
2800
+ def decls(self):
2801
+ nr, na, nc = self.p["nred"], self.p["natom"], self.p["ncrit"]
2802
+ d = ["integer :: i", f"integer(8) :: hist({max(1, nc)}, 8)"]
2803
+ if nr:
2804
+ d += decl_lines("integer(8)", [vname("r", j) for j in
2805
+ range(1, nr + 1)], self.o.width)
2806
+ if na:
2807
+ d += decl_lines("integer(8)", [vname("q", j) for j in
2808
+ range(1, na + 1)], self.o.width)
2809
+ return d
2810
+
2811
+ def body(self):
2812
+ nr, na, nc, n = (self.p["nred"], self.p["natom"], self.p["ncrit"],
2813
+ self.p["n"])
2814
+ o = self.o
2815
+ ind = " "
2816
+ R = [vname("r", j) for j in range(1, nr + 1)]
2817
+ Q = [vname("q", j) for j in range(1, na + 1)]
2818
+ ops = [("+", "max", "ieor", "ior")[j % 4] for j in range(nr)]
2819
+ lines = [f"{ind}{x} = 0" for x in R + Q] + [f"{ind}hist = 0"]
2820
+ groups: dict[str, list[str]] = {}
2821
+ for x, op in zip(R, ops):
2822
+ groups.setdefault(op, []).append(x)
2823
+ red = [(op, groups[op]) for op in ("+", "max", "ieor", "ior")
2824
+ if op in groups]
2825
+ chain = ("target parallel do",) if o.model == "omp" else \
2826
+ ("parallel loop gang vector",)
2827
+ op_, cl, ii = region(o, chain, ind, reduction=red,
2828
+ data=[(x, "tofrom") for x in Q] +
2829
+ [("hist", "tofrom")])
2830
+ lines += op_ + [f"{ii}do i = 1, {n}"]
2831
+ for j, (x, op) in enumerate(zip(R, ops)):
2832
+ e = f"int(mod(i * {j + 3}, 4099), 8)"
2833
+ lines.append(f"{ii} {x} = " + {
2834
+ "+": f"{x} + {e}", "max": f"max({x}, {e})",
2835
+ "ieor": f"ieor({x}, {e})",
2836
+ "ior": f"ior({x}, {e})"}[op])
2837
+ for j, x in enumerate(Q):
2838
+ lines += [f"{ii} {o.sent} atomic update",
2839
+ f"{ii} {x} = {x} + mod(i, {j + 2})"]
2840
+ for c in range(1, nc + 1):
2841
+ lines += [f"{ii} {o.sent} critical (c{self.name}_{c})",
2842
+ f"{ii} hist({c}, mod(i, 8) + 1) = "
2843
+ f"hist({c}, mod(i, 8) + 1) + {c}",
2844
+ f"{ii} {o.sent} end critical (c{self.name}_{c})"]
2845
+ lines += [f"{ii}end do"] + cl
2846
+ lines.append(f"{ind}call st_cksum(hist, {max(1, nc) * 8}, cs)")
2847
+ for x in R + Q:
2848
+ lines.append(f"{ind}cs = mod(cs * 31 + {x}, {P}_8)")
2849
+ return lines
2850
+
2851
+ def value(self):
2852
+ nr, na, nc, n = (self.p["nred"], self.p["natom"], self.p["ncrit"],
2853
+ self.p["n"])
2854
+ hist = [[0] * 8 for _ in range(max(1, nc))]
2855
+ for c in range(1, nc + 1):
2856
+ for i in range(1, n + 1):
2857
+ hist[c - 1][i % 8] += c
2858
+ flat = [hist[c][b] for b in range(8) for c in range(max(1, nc))]
2859
+ cs = cksum(flat)
2860
+ ops = [("+", "max", "ieor", "ior")[j % 4] for j in range(nr)]
2861
+ for j, op in enumerate(ops):
2862
+ v = 0
2863
+ for i in range(1, n + 1):
2864
+ e = (i * (j + 3)) % 4099
2865
+ v = {"+": v + e, "max": max(v, e), "ieor": v ^ e,
2866
+ "ior": v | e}[op]
2867
+ cs = (cs * 31 + v) % P
2868
+ for j in range(na):
2869
+ cs = (cs * 31 + sum(i % (j + 2) for i in range(1, n + 1))) % P
2870
+ return cs
2871
+
2872
+ def smaller(self):
2873
+ out = []
2874
+ for key in ("nred", "natom", "ncrit"):
2875
+ if self.p[key] > 0:
2876
+ out.append(self.clone(**{key: self.p[key] // 2}))
2877
+ return out
2878
+
2879
+ def features(self):
2880
+ f = super().features() | {f"len:mixed:{self.p['nred']}"}
2881
+ if self.p["natom"]:
2882
+ f.add("dir:atomic")
2883
+ if self.p["ncrit"]:
2884
+ f.add("dir:critical")
2885
+ return f
2886
+
2887
+
2888
+ class ExprsKernel(Kernel):
2889
+ """Compile-time stress in device code: 'expr', one assignment of
2890
+ `size` terms (continuation lines: past 255 an illegal probe); 'select',
2891
+ a SELECT CASE of `size` cases in a device function; 'spec', `size`
2892
+ device functions (specializations) dispatched by a SELECT CASE."""
2893
+ kind = "exprs"
2894
+
2895
+ def draw(self, rng):
2896
+ self.p.setdefault("variant", rng.choice(("expr", "select", "spec")))
2897
+ self.p.setdefault("size", 64)
2898
+ self.p.setdefault("n", 256)
2899
+
2900
+ def modules(self):
2901
+ v, k = self.p["variant"], self.p["size"]
2902
+ dt = _dt_line(self.o)
2903
+ cont = []
2904
+ if v == "select":
2905
+ cont += [f" function {self.name}_sel(x) result(r)", dt,
2906
+ " integer(8), intent(in) :: x", " integer(8) :: r",
2907
+ f" select case (mod(x, {k}_8))"]
2908
+ for c in range(k):
2909
+ cont += [f" case ({c})", f" r = x * {c % 17 + 1} + "
2910
+ f"{c}"]
2911
+ cont += [" case default", " r = -1", " end select",
2912
+ f" end function {self.name}_sel"]
2913
+ if v == "spec":
2914
+ for c in range(k):
2915
+ cont += [f" function {self.name}_s{c}(x) result(r)", dt,
2916
+ " integer(8), intent(in) :: x",
2917
+ " integer(8) :: r",
2918
+ f" r = x * {c % 17 + 1} + {c}",
2919
+ f" end function {self.name}_s{c}"]
2920
+ cont += [f" function {self.name}_sel(x) result(r)", dt,
2921
+ " integer(8), intent(in) :: x", " integer(8) :: r",
2922
+ f" select case (mod(x, {k}_8))"]
2923
+ for c in range(k):
2924
+ cont += [f" case ({c})", f" r = {self.name}_s{c}(x)"]
2925
+ cont += [" case default", " r = -1", " end select",
2926
+ f" end function {self.name}_sel"]
2927
+ return [Module(f"{self.name}_m", [], cont)] if cont else []
2928
+
2929
+ def uses(self):
2930
+ return [f"{self.name}_m"] if self.p["variant"] != "expr" else []
2931
+
2932
+ def decls(self):
2933
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i"]
2934
+
2935
+ def body(self):
2936
+ v, k, n = self.p["variant"], self.p["size"], self.p["n"]
2937
+ ind = " "
2938
+ chain = ("target teams distribute parallel do",) if \
2939
+ self.o.model == "omp" else ("parallel loop gang vector",)
2940
+ op, cl, ii = region(self.o, chain, ind, data=[("out", "tofrom")])
2941
+ lines = [f"{ind}out = 0"] + op + [f"{ii}do i = 1, {n}"]
2942
+ if v == "expr":
2943
+ terms = [f"mod(i * {c % 97 + 1}, {c % 13 + 2})"
2944
+ for c in range(k)]
2945
+ lines += pack("out(i) =", [t + (" +" if c < k - 1 else "")
2946
+ for c, t in enumerate(terms)],
2947
+ ii + " ", None, self.o.width)
2948
+ else:
2949
+ lines.append(f"{ii} out(i) = {self.name}_sel(int(i, 8))")
2950
+ lines += [f"{ii}end do"] + cl
2951
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
2952
+ return lines
2953
+
2954
+ def value(self):
2955
+ v, k, n = self.p["variant"], self.p["size"], self.p["n"]
2956
+ if v == "expr":
2957
+ return cksum(sum((i * (c % 97 + 1)) % (c % 13 + 2)
2958
+ for c in range(k)) for i in range(1, n + 1))
2959
+ return cksum(i * ((i % k) % 17 + 1) + (i % k)
2960
+ for i in range(1, n + 1))
2961
+
2962
+ def smaller(self):
2963
+ return [self.clone(size=m) for m in _halve(self.p["size"])]
2964
+
2965
+ def features(self):
2966
+ return super().features() | {f"exprs:{self.p['variant']}",
2967
+ f"len:exprs:{self.p['size']}"}
2968
+
2969
+
2970
+ class AsyncKernel(Kernel):
2971
+ """`ntasks` concurrent target tasks: each enters its own array (target
2972
+ enter data nowait depend(out:)), a target nowait depend(inout:)
2973
+ computes, the host updates another array, target update from nowait
2974
+ depend(in:) brings it back; one taskwait. OpenACC: the same over
2975
+ `ntasks` async queues (enter data async, parallel loop async, update
2976
+ self async) and one wait."""
2977
+ kind = "async"
2978
+
2979
+ def draw(self, rng):
2980
+ self.p.setdefault("ntasks", 8)
2981
+ self.p.setdefault("m", 64)
2982
+
2983
+ def decls(self):
2984
+ k, m = self.p["ntasks"], self.p["m"]
2985
+ return [f"integer(8) :: x({m}, {k}), h({m}, {k})",
2986
+ "integer :: i, t", "integer(8) :: tcs"]
2987
+
2988
+ def body(self):
2989
+ k, m = self.p["ntasks"], self.p["m"]
2990
+ o = self.o
2991
+ ind = " "
2992
+ lines = [f"{ind}do t = 1, {k}", f"{ind} do i = 1, {m}",
2993
+ f"{ind} x(i, t) = i + t", f"{ind} h(i, t) = 0",
2994
+ f"{ind} end do", f"{ind}end do"]
2995
+ if o.model == "omp":
2996
+ lines += [f"{ind}do t = 1, {k}",
2997
+ f"{ind} {o.sent} target enter data map(to: x(:, t)) "
2998
+ "nowait depend(out: x(:, t))",
2999
+ f"{ind} {o.sent} target teams distribute parallel do "
3000
+ "nowait depend(inout: x(:, t))",
3001
+ f"{ind} do i = 1, {m}",
3002
+ f"{ind} x(i, t) = x(i, t) * 3 + t",
3003
+ f"{ind} end do",
3004
+ f"{ind} {o.sent} end target teams distribute parallel "
3005
+ "do",
3006
+ f"{ind} {o.sent} target exit data map(from: x(:, t)) "
3007
+ "nowait depend(inout: x(:, t))",
3008
+ f"{ind} do i = 1, {m}", f"{ind} h(i, t) = i * t",
3009
+ f"{ind} end do",
3010
+ f"{ind}end do", f"{ind}{o.sent} taskwait"]
3011
+ else:
3012
+ lines += [f"{ind}do t = 1, {k}",
3013
+ f"{ind} {o.sent} enter data copyin(x(:, t)) async(t)",
3014
+ f"{ind} {o.sent} parallel loop present(x(:, t)) "
3015
+ "async(t)",
3016
+ f"{ind} do i = 1, {m}",
3017
+ f"{ind} x(i, t) = x(i, t) * 3 + t",
3018
+ f"{ind} end do",
3019
+ f"{ind} {o.sent} exit data copyout(x(:, t)) async(t)",
3020
+ f"{ind} do i = 1, {m}", f"{ind} h(i, t) = i * t",
3021
+ f"{ind} end do",
3022
+ f"{ind}end do", f"{ind}{o.sent} wait"]
3023
+ lines += [f"{ind}cs = 0", f"{ind}do t = 1, {k}",
3024
+ f"{ind} call st_cksum(x(:, t), {m}, tcs)",
3025
+ f"{ind} cs = mod(cs * 31 + tcs, {P}_8)",
3026
+ f"{ind} call st_cksum(h(:, t), {m}, tcs)",
3027
+ f"{ind} cs = mod(cs * 31 + tcs, {P}_8)", f"{ind}end do"]
3028
+ return lines
3029
+
3030
+ def value(self):
3031
+ k, m = self.p["ntasks"], self.p["m"]
3032
+ cs = 0
3033
+ for t in range(1, k + 1):
3034
+ cs = (cs * 31 + cksum((i + t) * 3 + t for i in range(1, m + 1))) \
3035
+ % P
3036
+ cs = (cs * 31 + cksum(i * t for i in range(1, m + 1))) % P
3037
+ return cs
3038
+
3039
+ def smaller(self):
3040
+ return [self.clone(ntasks=x) for x in _halve(self.p["ntasks"])]
3041
+
3042
+ def features(self):
3043
+ return super().features() | {f"len:async:{self.p['ntasks']}"}
3044
+
3045
+
3046
+ class RuntimeKernel(Kernel):
3047
+ """Runtime stress: 'iters', a reduction over `size` iterations of
3048
+ mod(i*c, 1009) (the model uses its period); 'teams', num_teams(size)
3049
+ thread_limit(t) over `size`*t iterations; 'alloc', an allocatable of
3050
+ `size` 8-byte elements (bounded: the size is in the header) filled and
3051
+ reduced on the device."""
3052
+ kind = "runtime"
3053
+
3054
+ def draw(self, rng):
3055
+ self.p.setdefault("variant", "iters")
3056
+ self.p.setdefault("size", 1 << 20)
3057
+ self.p.setdefault("c", rng.randrange(1, 1009))
3058
+
3059
+ def decls(self):
3060
+ d = ["integer(8) :: i, nn, s"]
3061
+ if self.p["variant"] == "alloc":
3062
+ d.append("integer(8), allocatable :: big(:)")
3063
+ return d
3064
+
3065
+ def iters(self):
3066
+ if self.p["variant"] == "teams":
3067
+ return self.p["size"] * 256
3068
+ return self.p["size"]
3069
+
3070
+ def body(self):
3071
+ v, c = self.p["variant"], self.p["c"]
3072
+ o = self.o
3073
+ ind = " "
3074
+ nn = self.iters()
3075
+ lines = [f"{ind}nn = {nn}_8", f"{ind}s = 0"]
3076
+ if v == "alloc":
3077
+ lines.append(f"{ind}allocate(big(nn))")
3078
+ if o.model == "omp":
3079
+ lines += [f"{ind}{o.sent} target enter data map(alloc: big)"]
3080
+ op, cl, ii = region(o, ("target teams distribute parallel "
3081
+ "do",), ind)
3082
+ else:
3083
+ lines += [f"{ind}{o.sent} enter data create(big)"]
3084
+ op, cl, ii = region(o, ("parallel loop gang vector",), ind,
3085
+ extra=["present(big)"])
3086
+ lines += op + [f"{ii}do i = 1, nn",
3087
+ f"{ii} big(i) = mod(i * {c}, 1009_8)",
3088
+ f"{ii}end do"] + cl
3089
+ op, cl, ii = region(o, ("target teams distribute parallel do",)
3090
+ if o.model == "omp" else
3091
+ ("parallel loop gang vector",), ind,
3092
+ reduction=[("+", ["s"])],
3093
+ extra=["present(big)"] if o.model == "acc"
3094
+ else [])
3095
+ lines += op + [f"{ii}do i = 1, nn", f"{ii} s = s + big(i)",
3096
+ f"{ii}end do"] + cl
3097
+ lines.append(f"{ind}{o.sent} target exit data map(delete: big)"
3098
+ if o.model == "omp" else
3099
+ f"{ind}{o.sent} exit data delete(big)")
3100
+ lines.append(f"{ind}deallocate(big)")
3101
+ else:
3102
+ extra = []
3103
+ if v == "teams" and o.model == "omp":
3104
+ extra = [f"num_teams({self.p['size']})",
3105
+ "thread_limit(256)"]
3106
+ if v == "teams" and o.model == "acc":
3107
+ extra = [f"num_gangs({self.p['size']})", "vector_length(256)"]
3108
+ chain = ("target teams distribute parallel do",) if \
3109
+ o.model == "omp" else ("parallel loop gang vector",)
3110
+ op, cl, ii = region(o, chain, ind, reduction=[("+", ["s"])],
3111
+ extra=extra)
3112
+ lines += op + [f"{ii}do i = 1, nn",
3113
+ f"{ii} s = s + mod(i * {c}, 1009_8)",
3114
+ f"{ii}end do"] + cl
3115
+ lines.append(f"{ind}cs = mod(s, {P}_8)")
3116
+ return lines
3117
+
3118
+ def value(self):
3119
+ c, nn = self.p["c"], self.iters()
3120
+ per = sum((i * c) % 1009 for i in range(1009))
3121
+ q, r = divmod(nn, 1009)
3122
+ s = q * per + sum((i * c) % 1009 for i in range(1, r + 1))
3123
+ # i runs 1..nn: the block 1..1009 has the same sum as 0..1008
3124
+ return s % P
3125
+
3126
+ def smaller(self):
3127
+ return [self.clone(size=max(1, self.p["size"] // 16))] if \
3128
+ self.p["size"] > 16 else []
3129
+
3130
+ def features(self):
3131
+ return super().features() | {f"runtime:{self.p['variant']}"}
3132
+
3133
+ def bytes(self) -> int:
3134
+ return 8 * self.iters() if self.p["variant"] == "alloc" else 0
3135
+
3136
+
3137
+ # --- templates: shapes of failing real kernels ----------------------------------------------------
3138
+
3139
+ TEMPLATES = ("team_private", "declared_alloc", "mfc_cbc", "mfc_bubbles")
3140
+
3141
+
3142
+ class TemplateKernel(Kernel):
3143
+ """Kernel shapes of failing real kernels (structure only), varied:
3144
+
3145
+ * team_private: an array private to each team (teams distribute
3146
+ private(t)) written and read by nested parallel loops (the
3147
+ widened program teams-private-array-parallel: AFAR and every CCE
3148
+ wrong; PRK transpose tile32 has the same shape with collapse(2) and
3149
+ simd); `w` tile width, `nloops` nested loops, collapse / simd;
3150
+ * declared_alloc: a declare target module variable of a derived type
3151
+ with `ncomp` allocatable components entered by enter data (MFC under CCE at unified memory);
3152
+ * mfc_cbc: MFC's s_cbc kernel (m_cbc.fpp:597, CCE 20 device-link
3153
+ crash): collapse(2), a long private list of scalars and private
3154
+ arrays (`npriv` extra scalars), loop bounds from components of a
3155
+ device-resident module derived type, inner sequential loops, device
3156
+ routines with array arguments, a module logical branch;
3157
+ * mfc_bubbles: MFC's s_compute_bubble_EE_source (m_bubbles_EE.fpp:186,
3158
+ CCE 21 device-link crash): an array of derived type with a pointer (or
3159
+ allocatable) 3-D component indexed through integer index arrays,
3160
+ collapse(3), private arrays, a device function with an OPTIONAL
3161
+ argument passed by keyword, a counter updated atomically."""
3162
+ kind = "template"
3163
+
3164
+ def draw(self, rng):
3165
+ v = self.p.setdefault("variant", rng.choice(TEMPLATES))
3166
+ if v == "team_private":
3167
+ self.p.setdefault("w", rng.choice((4, 8, 32)))
3168
+ self.p.setdefault("nt", 16)
3169
+ self.p.setdefault("nloops", 2)
3170
+ self.p.setdefault("col2", rng.random() < 0.5)
3171
+ self.p.setdefault("simd", rng.random() < 0.5)
3172
+ elif v == "declared_alloc":
3173
+ self.p.setdefault("ncomp", 2)
3174
+ self.p.setdefault("n", 64)
3175
+ elif v == "mfc_cbc":
3176
+ self.p.setdefault("npriv", 40)
3177
+ self.p.setdefault("nf", 3)
3178
+ self.p.setdefault("nk", 6)
3179
+ self.p.setdefault("nr", 5)
3180
+ else:
3181
+ self.p.setdefault("nb", 3)
3182
+ self.p.setdefault("ext", [4, 3, 2])
3183
+ self.p.setdefault("ptr", rng.random() < 0.5)
3184
+
3185
+ # team_private ------------------------------------------------------------
3186
+ def _tp_body(self):
3187
+ w, nt, nl = self.p["w"], self.p["nt"], self.p["nloops"]
3188
+ col2, simd = self.p["col2"], self.p["simd"]
3189
+ o = self.o
3190
+ ind = " "
3191
+ n = w * nt
3192
+ lines = [f"{ind}do i = 1, {n}", f"{ind} a(i) = mod(i * 7, 61)",
3193
+ f"{ind}end do", f"{ind}b = 0"]
3194
+ inner = "parallel do simd" if simd else "parallel do"
3195
+ if o.model == "acc":
3196
+ return self._tp_body_acc(lines, n)
3197
+ if col2:
3198
+ # 2-D tiles: n = (w*nt) elements as (w, nt) blocks of a 2-D view
3199
+ head = pack("target teams distribute collapse(2)",
3200
+ ["private(t, j, jj)", "map(to: a)", "map(tofrom: b)"],
3201
+ ind, o.sent, o.width)
3202
+ lines += head + [f"{ind}do jt = 1, {nt}, 2", f"{ind} do kt = 0, 1"]
3203
+ ii = ind + " "
3204
+ lines += [f"{ii}{o.sent} {inner} collapse(2)",
3205
+ f"{ii}do j = 0, {w - 1}", f"{ii} do jj = 0, 0",
3206
+ f"{ii} t(j) = a((jt + kt - 1) * {w} + j + 1)",
3207
+ f"{ii} end do", f"{ii}end do",
3208
+ f"{ii}{o.sent} end {inner}"]
3209
+ for L in range(1, nl):
3210
+ lines += [f"{ii}{o.sent} {inner} collapse(2)",
3211
+ f"{ii}do j = 0, {w - 1}", f"{ii} do jj = 0, 0",
3212
+ f"{ii} b((jt + kt - 1) * {w} + j + 1) = "
3213
+ f"b((jt + kt - 1) * {w} + j + 1) + "
3214
+ f"{L + 1} * t({w - 1} - j) + {L}",
3215
+ f"{ii} end do", f"{ii}end do",
3216
+ f"{ii}{o.sent} end {inner}"]
3217
+ lines += [f"{ind} end do", f"{ind}end do",
3218
+ f"{ind}{o.sent} end target teams distribute"]
3219
+ else:
3220
+ head = pack("target teams distribute",
3221
+ ["private(t, j)", "map(to: a)", "map(tofrom: b)"],
3222
+ ind, o.sent, o.width)
3223
+ lines += head + [f"{ind}do jt = 1, {n}, {w}"]
3224
+ ii = ind + " "
3225
+ lines += [f"{ii}{o.sent} {inner}", f"{ii}do j = 0, {w - 1}",
3226
+ f"{ii} t(j) = a(jt + j)", f"{ii}end do",
3227
+ f"{ii}{o.sent} end {inner}"]
3228
+ for L in range(1, nl):
3229
+ lines += [f"{ii}{o.sent} {inner}", f"{ii}do j = 0, {w - 1}",
3230
+ f"{ii} b(jt + j) = b(jt + j) + {L + 1} * "
3231
+ f"t({w - 1} - j) + {L}", f"{ii}end do",
3232
+ f"{ii}{o.sent} end {inner}"]
3233
+ lines += [f"{ind}end do", f"{ind}{o.sent} end target teams "
3234
+ "distribute"]
3235
+ lines.append(f"{ind}call st_cksum(b, {n}, cs)")
3236
+ return lines
3237
+
3238
+ def _tp_body_acc(self, lines, n):
3239
+ w, nt, nl = self.p["w"], self.p["nt"], self.p["nloops"]
3240
+ o = self.o
3241
+ ind = " "
3242
+ lines += pack("parallel loop gang", ["private(t)", "copyin(a)",
3243
+ "copy(b)"], ind, o.sent, o.width)
3244
+ lines += [f"{ind}do jt = 1, {n}, {w}"]
3245
+ ii = ind + " "
3246
+ lines += [f"{ii}{o.sent} loop vector", f"{ii}do j = 0, {w - 1}",
3247
+ f"{ii} t(j) = a(jt + j)", f"{ii}end do"]
3248
+ for L in range(1, nl):
3249
+ lines += [f"{ii}{o.sent} loop vector", f"{ii}do j = 0, {w - 1}",
3250
+ f"{ii} b(jt + j) = b(jt + j) + {L + 1} * "
3251
+ f"t({w - 1} - j) + {L}", f"{ii}end do"]
3252
+ lines += [f"{ind}end do", f"{ind}{o.sent} end parallel loop"]
3253
+ lines.append(f"{ind}call st_cksum(b, {n}, cs)")
3254
+ return lines
3255
+
3256
+ def _tp_value(self):
3257
+ w, nt, nl = self.p["w"], self.p["nt"], self.p["nloops"]
3258
+ n = w * nt
3259
+ a = [0] + [(i * 7) % 61 for i in range(1, n + 1)]
3260
+ b = [0] * (n + 1)
3261
+ for blk in range(nt):
3262
+ base = blk * w
3263
+ t = [a[base + j + 1] for j in range(w)]
3264
+ for L in range(1, nl):
3265
+ for j in range(w):
3266
+ b[base + j + 1] += (L + 1) * t[w - 1 - j] + L
3267
+ return cksum(b[1:])
3268
+
3269
+ # declared_alloc -----------------------------------------------------------
3270
+ def _da_modules(self):
3271
+ k = self.p["ncomp"]
3272
+ o = self.o
3273
+ spec = [f"type :: {self.name}_rec"] + [
3274
+ f" integer(8), allocatable :: v{c}(:)" for c in range(1, k + 1)
3275
+ ] + [f"end type {self.name}_rec", f"type({self.name}_rec) :: gq"]
3276
+ spec.append(f"{o.sent} declare target(gq)" if o.model == "omp" else
3277
+ f"{o.sent} declare create(gq)")
3278
+ return [Module(f"{self.name}_m", spec)]
3279
+
3280
+ def _da_body(self):
3281
+ k, n = self.p["ncomp"], self.p["n"]
3282
+ o = self.o
3283
+ ind = " "
3284
+ lines = []
3285
+ comps = [f"gq%v{c}" for c in range(1, k + 1)]
3286
+ for c, x in enumerate(comps, 1):
3287
+ lines += [f"{ind}allocate({x}({n}))", f"{ind}do i = 1, {n}",
3288
+ f"{ind} {x}(i) = i * {c + 2}", f"{ind}end do"]
3289
+ if o.model == "omp":
3290
+ lines += pack("target enter data", list_atoms("map", comps, "to"),
3291
+ ind, o.sent, o.width)
3292
+ else:
3293
+ lines += pack("enter data", list_atoms("copyin", comps), ind,
3294
+ o.sent, o.width)
3295
+ chain = ("target teams distribute parallel do",) if \
3296
+ o.model == "omp" else ("parallel loop",)
3297
+ op, cl, ii = region(o, chain, ind, data=[("out", "tofrom")])
3298
+ lines += [f"{ind}out = 0"] + op + [f"{ii}do i = 1, {n}"]
3299
+ lines += sum_lines(ii + " ", "out(i)", [f"{x}(i)" for x in comps],
3300
+ o.width)
3301
+ lines += [f"{ii} out(i) = out(i) + 1", f"{ii}end do"] + cl
3302
+ if o.model == "omp":
3303
+ lines += pack("target exit data", list_atoms("map", comps,
3304
+ "delete"),
3305
+ ind, o.sent, o.width)
3306
+ else:
3307
+ lines += pack("exit data", list_atoms("delete", comps), ind,
3308
+ o.sent, o.width)
3309
+ lines += [f"{ind}deallocate({x})" for x in comps]
3310
+ lines.append(f"{ind}call st_cksum(out, {n}, cs)")
3311
+ return lines
3312
+
3313
+ def _da_value(self):
3314
+ k, n = self.p["ncomp"], self.p["n"]
3315
+ return cksum(sum(i * (c + 2) for c in range(1, k + 1)) + 1
3316
+ for i in range(1, n + 1))
3317
+
3318
+ # mfc_cbc -------------------------------------------------------------------
3319
+ def _cbc_dims(self):
3320
+ nf = self.p["nf"]
3321
+ e = nf + 3 + 1
3322
+ return nf, e, e + nf # nf, eqn%e, nv
3323
+
3324
+ def _cbc_modules(self):
3325
+ o = self.o
3326
+ nm = self.name
3327
+ spec = [f"type :: {nm}_bnd", " integer :: beg, end",
3328
+ f"end type {nm}_bnd", f"type :: {nm}_eqn",
3329
+ f" type({nm}_bnd) :: cont, adv", " integer :: e",
3330
+ f"end type {nm}_eqn", f"type({nm}_eqn) :: eqn",
3331
+ "integer :: ndims", "logical :: chem"]
3332
+ spec.append(f"{o.sent} declare target(eqn, ndims, chem)"
3333
+ if o.model == "omp" else
3334
+ f"{o.sent} declare create(eqn, ndims, chem)")
3335
+ dt = _dt_line(o)
3336
+ cont = [f" subroutine {nm}_mix(rho, gam, ar, al, nf)", dt,
3337
+ " integer, intent(in) :: nf",
3338
+ " integer(8), intent(in) :: ar(nf), al(nf)",
3339
+ " integer(8), intent(out) :: rho, gam", " integer :: i",
3340
+ " rho = 0", " gam = 0", " do i = 1, nf",
3341
+ " rho = rho + ar(i)",
3342
+ " gam = mod(gam + al(i) * ar(i), 1009_8)", " end do",
3343
+ f" end subroutine {nm}_mix",
3344
+ f" subroutine {nm}_snd(pres, rho, gam, c)", dt,
3345
+ " integer(8), intent(in) :: pres, rho, gam",
3346
+ " integer(8), intent(out) :: c",
3347
+ " c = mod(pres * 3 + rho + gam, 10007_8)",
3348
+ f" end subroutine {nm}_snd"]
3349
+ return [Module(f"{nm}_m", spec, cont)]
3350
+
3351
+ def _cbc_privs(self):
3352
+ return [vname("x", j) for j in range(1, self.p["npriv"] + 1)]
3353
+
3354
+ def _cbc_body(self):
3355
+ nf, e, nv = self._cbc_dims()
3356
+ nk, nr = self.p["nk"], self.p["nr"]
3357
+ o = self.o
3358
+ nm = self.name
3359
+ ind = " "
3360
+ X = self._cbc_privs()
3361
+ lines = [f"{ind}eqn%cont%beg = 1", f"{ind}eqn%cont%end = {nf}",
3362
+ f"{ind}eqn%e = {e}", f"{ind}eqn%adv%beg = {e + 1}",
3363
+ f"{ind}eqn%adv%end = {e + nf}", f"{ind}ndims = 3",
3364
+ f"{ind}chem = .true."]
3365
+ lines.append(f"{ind}{o.sent} target update to(eqn, ndims, chem)"
3366
+ if o.model == "omp" else
3367
+ f"{ind}{o.sent} update device(eqn, ndims, chem)")
3368
+ lines += [f"{ind}allocate(q(0:2, {nk}, {nr}, {nv}))",
3369
+ f"{ind}do v = 1, {nv}", f"{ind} do r = 1, {nr}",
3370
+ f"{ind} do k = 1, {nk}", f"{ind} do b = 0, 2",
3371
+ f"{ind} q(b, k, r, v) = mod(b * 7 + k * 3 + r * 5 "
3372
+ "+ v, 101)",
3373
+ f"{ind} end do", f"{ind} end do", f"{ind} end do",
3374
+ f"{ind}end do", f"{ind}flux = 0", f"{ind}dir_idx = 2"]
3375
+ priv = ["r", "k", "i", "alpha_rho", "vel", "adv", "rho", "gam",
3376
+ "pres", "c", "accum"] + X
3377
+ if o.model == "omp":
3378
+ chain = ("target teams distribute parallel do",)
3379
+ data = [("q", "to"), ("flux", "tofrom"), ("dir_idx", "to")]
3380
+ else:
3381
+ chain = ("parallel loop gang vector",)
3382
+ data = [("q", "to"), ("flux", "tofrom"), ("dir_idx", "to")]
3383
+ op, cl, ii = region(o, chain, ind, data=data, private=priv,
3384
+ collapse=2)
3385
+ seq = [f"{o.sent} loop seq"] if o.model == "acc" else []
3386
+ lines += op + [f"{ii}do r = 1, {nr}", f"{ii} do k = 1, {nk}"]
3387
+ jj = ii + " "
3388
+ lines += [jj + s for s in seq] + [
3389
+ f"{jj}do i = 1, eqn%cont%end",
3390
+ f"{jj} alpha_rho(i) = q(0, k, r, i)", f"{jj}end do"]
3391
+ lines += [jj + s for s in seq] + [
3392
+ f"{jj}do i = 1, ndims",
3393
+ f"{jj} vel(i) = q(0, k, r, eqn%cont%end + i)", f"{jj}end do",
3394
+ f"{jj}pres = q(dir_idx - 2, k, r, eqn%e)"]
3395
+ lines += [jj + s for s in seq] + [
3396
+ f"{jj}do i = 1, eqn%adv%end - eqn%e",
3397
+ f"{jj} adv(i) = q(0, k, r, eqn%e + i)", f"{jj}end do",
3398
+ f"{jj}call {nm}_mix(rho, gam, alpha_rho, adv, eqn%cont%end)",
3399
+ f"{jj}if (chem) then", f"{jj} pres = pres + 7", f"{jj}end if",
3400
+ f"{jj}call {nm}_snd(pres, rho, gam, c)", f"{jj}accum = 0"]
3401
+ for j, x in enumerate(X, 1):
3402
+ lines.append(f"{jj}{x} = mod(c + {j} * k, 97_8)")
3403
+ lines += sum_lines(jj, "accum", X, o.width)
3404
+ lines += [f"{jj}flux(k, r) = c + vel(1) + vel(2) + vel(3) + accum",
3405
+ f"{ii} end do", f"{ii}end do"] + cl
3406
+ lines += [f"{ind}call st_cksum(flux, {nk * nr}, cs)",
3407
+ f"{ind}deallocate(q)"]
3408
+ return lines
3409
+
3410
+ def _cbc_value(self):
3411
+ nf, e, nv = self._cbc_dims()
3412
+ nk, nr = self.p["nk"], self.p["nr"]
3413
+
3414
+ def q(b, k, r, v):
3415
+ return (b * 7 + k * 3 + r * 5 + v) % 101
3416
+ flux = {}
3417
+ for r in range(1, nr + 1):
3418
+ for k in range(1, nk + 1):
3419
+ ar = [q(0, k, r, i) for i in range(1, nf + 1)]
3420
+ vel = [q(0, k, r, nf + i) for i in range(1, 4)]
3421
+ pres = q(0, k, r, e) + 7
3422
+ adv = [q(0, k, r, e + i) for i in range(1, nf + 1)]
3423
+ rho = sum(ar)
3424
+ gam = 0
3425
+ for i in range(nf):
3426
+ gam = (gam + adv[i] * ar[i]) % 1009
3427
+ c = (pres * 3 + rho + gam) % 10007
3428
+ acc = sum((c + j * k) % 97 for j in
3429
+ range(1, self.p["npriv"] + 1))
3430
+ flux[(k, r)] = c + sum(vel) + acc
3431
+ return cksum(flux[(k, r)] for r in range(1, nr + 1)
3432
+ for k in range(1, nk + 1))
3433
+
3434
+ # mfc_bubbles ---------------------------------------------------------------
3435
+ def _bub_modules(self):
3436
+ o = self.o
3437
+ nm = self.name
3438
+ attr = "pointer" if self.p["ptr"] else "allocatable"
3439
+ init = " => null()" if self.p["ptr"] else ""
3440
+ spec = [f"type :: {nm}_sf",
3441
+ f" integer(8), {attr} :: sf(:, :, :){init}",
3442
+ f"end type {nm}_sf"]
3443
+ dt = _dt_line(o)
3444
+ cont = [f" function {nm}_f(a, b, scale) result(r)", dt,
3445
+ " integer(8), intent(in) :: a, b",
3446
+ " integer(8), intent(in), optional :: scale",
3447
+ " integer(8) :: r", " if (present(scale)) then",
3448
+ " r = a + b * scale", " else", " r = a + b",
3449
+ " end if", f" end function {nm}_f"]
3450
+ return [Module(f"{nm}_m", spec, cont)]
3451
+
3452
+ def _bub_body(self):
3453
+ nb = self.p["nb"]
3454
+ m, n, p_ = self.p["ext"]
3455
+ nv = 2 * nb + 1
3456
+ o = self.o
3457
+ nm = self.name
3458
+ ind = " "
3459
+ lines = []
3460
+ for v in range(1, nv + 1):
3461
+ lines += [f"{ind}allocate(qp({v})%sf(0:{m - 1}, 0:{n - 1}, "
3462
+ f"0:{p_ - 1}))",
3463
+ f"{ind}do l = 0, {p_ - 1}", f"{ind} do k = 0, {n - 1}",
3464
+ f"{ind} do j = 0, {m - 1}",
3465
+ f"{ind} qp({v})%sf(j, k, l) = mod(j * 3 + k * 5 + "
3466
+ f"l * 7 + {v}, 37)",
3467
+ f"{ind} end do", f"{ind} end do", f"{ind}end do"]
3468
+ lines += [f"{ind}do q = 1, {nb}", f"{ind} rs(q) = q + 1",
3469
+ f"{ind} vs(q) = q + 1 + {nb}", f"{ind} w(q) = q",
3470
+ f"{ind}end do", f"{ind}cnt = 0", f"{ind}src = 0"]
3471
+ comps = [f"qp({v})%sf" for v in range(1, nv + 1)]
3472
+ if o.model == "omp":
3473
+ lines.append(f"{ind}{o.sent} target enter data map(to: qp)")
3474
+ lines += pack("target enter data", list_atoms("map", comps,
3475
+ "to"),
3476
+ ind, o.sent, o.width)
3477
+ chain = ("target teams distribute parallel do",)
3478
+ extra = []
3479
+ else:
3480
+ lines.append(f"{ind}{o.sent} enter data copyin(qp)")
3481
+ lines += pack("enter data", list_atoms("copyin", comps), ind,
3482
+ o.sent, o.width)
3483
+ chain = ("parallel loop gang vector",)
3484
+ extra = ["present(qp)"]
3485
+ op, cl, ii = region(o, chain, ind,
3486
+ data=[("rs", "to"), ("vs", "to"), ("w", "to"),
3487
+ ("src", "tofrom"), ("cnt", "tofrom")],
3488
+ private=["j", "k", "l", "q", "rtmp", "vtmp",
3489
+ "r3", "nbub"], collapse=3, extra=extra)
3490
+ seq = [f"{o.sent} loop seq"] if o.model == "acc" else []
3491
+ lines += op + [f"{ii}do l = 0, {p_ - 1}", f"{ii} do k = 0, {n - 1}",
3492
+ f"{ii} do j = 0, {m - 1}"]
3493
+ jj = ii + " "
3494
+ lines += [jj + s for s in seq] + [
3495
+ f"{jj}do q = 1, {nb}",
3496
+ f"{jj} rtmp(q) = qp(rs(q))%sf(j, k, l)",
3497
+ f"{jj} vtmp(q) = qp(vs(q))%sf(j, k, l)", f"{jj}end do",
3498
+ f"{jj}r3 = 0"]
3499
+ lines += [jj + s for s in seq] + [
3500
+ f"{jj}do q = 1, {nb}", f"{jj} r3 = r3 + w(q) * rtmp(q)",
3501
+ f"{jj}end do",
3502
+ f"{jj}if (mod(j + k + l, 2) == 0) then",
3503
+ f"{jj} nbub = {nm}_f(r3, vtmp(1), scale=3_8)",
3504
+ f"{jj}else", f"{jj} nbub = {nm}_f(r3, vtmp(1))", f"{jj}end if",
3505
+ f"{jj}src(j, k, l) = nbub + qp(1)%sf(j, k, l)",
3506
+ f"{jj}if (mod(j + k + l, 5) == 0) then",
3507
+ f"{jj} {o.sent} atomic update", f"{jj} cnt = cnt + 1",
3508
+ f"{jj}end if",
3509
+ f"{ii} end do", f"{ii} end do", f"{ii}end do"] + cl
3510
+ if o.model == "omp":
3511
+ lines += pack("target exit data", list_atoms(
3512
+ "map", comps, "delete"), ind, o.sent, o.width)
3513
+ lines.append(f"{ind}{o.sent} target exit data map(delete: qp)")
3514
+ else:
3515
+ lines += pack("exit data", list_atoms("delete", comps), ind,
3516
+ o.sent, o.width)
3517
+ lines.append(f"{ind}{o.sent} exit data delete(qp)")
3518
+ lines += [f"{ind}call st_cksum(src, {m * n * p_}, cs)",
3519
+ f"{ind}cs = mod(cs * 31 + cnt, {P}_8)"]
3520
+ lines += [f"{ind}deallocate(qp({v})%sf)" for v in range(1, nv + 1)]
3521
+ return lines
3522
+
3523
+ def _bub_value(self):
3524
+ nb = self.p["nb"]
3525
+ m, n, p_ = self.p["ext"]
3526
+
3527
+ def sf(v, j, k, l):
3528
+ return (j * 3 + k * 5 + l * 7 + v) % 37
3529
+ src, cnt = [], 0
3530
+ for l in range(p_):
3531
+ for k in range(n):
3532
+ for j in range(m):
3533
+ rt = [sf(q + 1, j, k, l) for q in range(1, nb + 1)]
3534
+ vt = [sf(q + 1 + nb, j, k, l) for q in range(1, nb + 1)]
3535
+ r3 = sum(q * rt[q - 1] for q in range(1, nb + 1))
3536
+ nbub = r3 + vt[0] * (3 if (j + k + l) % 2 == 0 else 1)
3537
+ src.append(nbub + sf(1, j, k, l))
3538
+ if (j + k + l) % 5 == 0:
3539
+ cnt += 1
3540
+ return (cksum(src) * 31 + cnt) % P
3541
+
3542
+ # dispatch ------------------------------------------------------------------
3543
+ def modules(self):
3544
+ v = self.p["variant"]
3545
+ if v == "declared_alloc":
3546
+ return self._da_modules()
3547
+ if v == "mfc_cbc":
3548
+ return self._cbc_modules()
3549
+ if v == "mfc_bubbles":
3550
+ return self._bub_modules()
3551
+ return []
3552
+
3553
+ def uses(self):
3554
+ return [] if self.p["variant"] == "team_private" else \
3555
+ [f"{self.name}_m"]
3556
+
3557
+ def decls(self):
3558
+ v = self.p["variant"]
3559
+ if v == "team_private":
3560
+ n = self.p["w"] * self.p["nt"]
3561
+ return [f"integer(8) :: a({n}), b({n}), t(0:{self.p['w'] - 1})",
3562
+ "integer :: i, j, jj, jt, kt"]
3563
+ if v == "declared_alloc":
3564
+ return [f"integer(8) :: out({self.p['n']})", "integer :: i"]
3565
+ if v == "mfc_cbc":
3566
+ nf = self.p["nf"]
3567
+ return ["integer(8), allocatable :: q(:, :, :, :)",
3568
+ f"integer(8) :: flux({self.p['nk']}, {self.p['nr']})",
3569
+ "integer :: r, k, i, v, b, dir_idx",
3570
+ f"integer(8) :: alpha_rho({nf}), vel(3), adv({nf})",
3571
+ "integer(8) :: rho, gam, pres, c, accum"] + decl_lines(
3572
+ "integer(8)", self._cbc_privs(), self.o.width)
3573
+ nb = self.p["nb"]
3574
+ m, n, p_ = self.p["ext"]
3575
+ return [f"type({self.name}_sf) :: qp({2 * nb + 1})",
3576
+ f"integer :: rs({nb}), vs({nb})", f"integer(8) :: w({nb})",
3577
+ f"integer(8) :: src(0:{m - 1}, 0:{n - 1}, 0:{p_ - 1})",
3578
+ f"integer(8) :: rtmp({nb}), vtmp({nb}), r3, nbub, cnt",
3579
+ "integer :: j, k, l, q"]
3580
+
3581
+ def body(self):
3582
+ return {"team_private": self._tp_body,
3583
+ "declared_alloc": self._da_body,
3584
+ "mfc_cbc": self._cbc_body,
3585
+ "mfc_bubbles": self._bub_body}[self.p["variant"]]()
3586
+
3587
+ def value(self):
3588
+ return {"team_private": self._tp_value,
3589
+ "declared_alloc": self._da_value,
3590
+ "mfc_cbc": self._cbc_value,
3591
+ "mfc_bubbles": self._bub_value}[self.p["variant"]]()
3592
+
3593
+ def smaller(self):
3594
+ v = self.p["variant"]
3595
+ out = []
3596
+ if v == "team_private":
3597
+ if self.p["nloops"] > 2:
3598
+ out.append(self.clone(nloops=2))
3599
+ if self.p["simd"]:
3600
+ out.append(self.clone(simd=False))
3601
+ if self.p["col2"]:
3602
+ out.append(self.clone(col2=False))
3603
+ if self.p["w"] > 4:
3604
+ out.append(self.clone(w=4))
3605
+ elif v == "declared_alloc" and self.p["ncomp"] > 1:
3606
+ out.append(self.clone(ncomp=1))
3607
+ elif v == "mfc_cbc" and self.p["npriv"] > 1:
3608
+ out += [self.clone(npriv=m) for m in _halve(self.p["npriv"])]
3609
+ elif v == "mfc_bubbles" and self.p["nb"] > 1:
3610
+ out.append(self.clone(nb=1))
3611
+ return out
3612
+
3613
+ def features(self):
3614
+ return super().features() | {f"template:{self.p['variant']}"}
3615
+
3616
+
3617
+ # --- programs ------------------------------------------------------------------------------------
3618
+
3619
+ GEN = "stress-1"
3620
+ # The revision of each axis's programs. A
3621
+ # program record and a result row carry the revision they were made at
3622
+ # ("rev"); offload.engine.stress_report drops anything older than the current
3623
+ # revision (the generator changed the axis's text or its label since).
3624
+ # nest 2: deep nests wrapped and indented under 132 columns (ac364f0)
3625
+ # clauses 2: no linear / order(concurrent) (ac364f0); 3: lin private
3626
+ # random 2: the clauses change; 3: lin private
3627
+ # contlines (C) 2: one list item per continuation line (ac364f0)
3628
+ # tuimp 2: Fortran cross-module calls are cross-unit (an illegal
3629
+ # probe in every layout)
3630
+ # oo.polymap 2: an OpenMP 6.0 program
3631
+ # oo 3: the mixed axis has a polymap kernel, so its text changed too
3632
+ AXIS_REV = {"nest": 2, "clauses": 3, "random": 3, "contlines-c": 2,
3633
+ "tuimp": 2, "oo.polymap": 2, "oo": 3}
3634
+
3635
+
3636
+ def axis_rev(axis: str, lang: str = "f90") -> int:
3637
+ if lang == "c":
3638
+ return AXIS_REV.get(f"{axis}-c", 1)
3639
+ return AXIS_REV.get(axis, AXIS_REV.get(axis.split(".")[0], 1)
3640
+ if axis.split(".")[0] in ("nest", "clauses",
3641
+ "random", "tuimp")
3642
+ else 1)
3643
+ LAYOUTS = ("single", "per_unit", "partition")
3644
+
3645
+ UTIL = f"""module st_util
3646
+ implicit none
3647
+ integer(8), parameter :: st_p = {P}_8
3648
+ type :: st_pair
3649
+ integer(8) :: u, v
3650
+ end type st_pair
3651
+ contains
3652
+ subroutine st_cksum(a, n, cs)
3653
+ integer, intent(in) :: n
3654
+ integer(8), intent(in) :: a(n)
3655
+ integer(8), intent(out) :: cs
3656
+ integer :: i
3657
+ cs = 0
3658
+ do i = 1, n
3659
+ cs = mod(cs + mod(a(i), st_p) * (mod(i, 7) + 1), st_p)
3660
+ end do
3661
+ end subroutine st_cksum
3662
+ end module st_util
3663
+ """
3664
+
3665
+
3666
+ def module_text(m: Module) -> str:
3667
+ uses = []
3668
+ for u in ["st_util"] + list(m.uses):
3669
+ if u not in uses:
3670
+ uses.append(u)
3671
+ lines = [f"module {m.name}"] + [f" use {u}" for u in uses] + \
3672
+ [" implicit none"]
3673
+ lines += [" " + s if s and not s.startswith(" ") else s for s in m.spec]
3674
+ if m.contains:
3675
+ lines.append("contains")
3676
+ lines += m.contains
3677
+ lines.append(f"end module {m.name}")
3678
+ return "\n".join(lines) + "\n"
3679
+
3680
+
3681
+ @dataclass
3682
+ class StressProgram:
3683
+ id: str
3684
+ axis: str
3685
+ size: int
3686
+ seed: int
3687
+ model: str
3688
+ layout: str
3689
+ kernels: list
3690
+ files: list # [(name, text)] in compile order
3691
+ expected: int
3692
+ per_kernel: dict
3693
+ legality: str = "legal"
3694
+ cite: str = ""
3695
+ features: set = field(default_factory=set)
3696
+ alloc_bytes: int = 0
3697
+ lang: str = "f90"
3698
+ gen: str = GEN
3699
+ limits: dict = field(default_factory=dict)
3700
+ rev: int = 1
3701
+
3702
+ @property
3703
+ def source(self) -> str:
3704
+ if len(self.files) == 1:
3705
+ return self.files[0][1]
3706
+ return "".join(f"{FILE_MARK}{n}\n{t}" for n, t in self.files)
3707
+
3708
+ @property
3709
+ def lines(self) -> int:
3710
+ return sum(t.count("\n") for _, t in self.files)
3711
+
3712
+ def meta(self) -> dict:
3713
+ return {"id": self.id, "gen": self.gen, "rev": self.rev,
3714
+ "axis": self.axis,
3715
+ "size": self.size, "seed": self.seed, "model": self.model,
3716
+ "lang": self.lang, "layout": self.layout,
3717
+ "legality": self.legality, "cite": self.cite,
3718
+ "expected": self.expected, "lines": self.lines,
3719
+ "files": len(self.files), "kernels": [
3720
+ k.describe() for k in self.kernels],
3721
+ "per_kernel": self.per_kernel,
3722
+ "features": sorted(self.features),
3723
+ "alloc_bytes": self.alloc_bytes, "limits": self.limits}
3724
+
3725
+
3726
+ def main_text(kernels: list, o: Opts, kmods: list[str]) -> str:
3727
+ lines = ["program stress_main", " use st_util"]
3728
+ lines += [f" use {m}" for m in kmods]
3729
+ lines.append(" use omp_lib" if o.model == "omp" else " use openacc")
3730
+ lines += [" implicit none", " integer(8) :: cs, total",
3731
+ " integer :: onhost", " total = 0"]
3732
+ for k in kernels:
3733
+ lines += [f" call {k.name}(cs)",
3734
+ f" print '(a,i0)', 'K {k.name} ', cs",
3735
+ " total = mod(total + cs, st_p)"]
3736
+ lines.append(" onhost = 1")
3737
+ if o.model == "omp":
3738
+ lines += [" !$omp target map(tofrom: onhost)",
3739
+ " if (.not. omp_is_initial_device()) onhost = 0",
3740
+ " !$omp end target"]
3741
+ else:
3742
+ lines += [" !$acc serial copy(onhost)",
3743
+ " if (acc_on_device(acc_device_not_host)) onhost = 0",
3744
+ " !$acc end serial"]
3745
+ lines += [" print '(a,i0,a,i0)', 'RESULT checksum=', total, "
3746
+ "' ran_on_host=', onhost", "end program stress_main"]
3747
+ return "\n".join(lines) + "\n"
3748
+
3749
+
3750
+ _ID = re.compile(r"[A-Za-z][A-Za-z0-9_]*")
3751
+
3752
+
3753
+ def check_limits(files: list) -> dict:
3754
+ """Base-language limits of the rendered text (Fortran files): the
3755
+ longest line, the most continuation lines of one statement or
3756
+ directive, the longest name; with ``violations`` (keys of CITES)."""
3757
+ longest = cont_max = name_max = 0
3758
+ for name, text in files:
3759
+ if not name.endswith(".f90"):
3760
+ continue
3761
+ run = 0
3762
+ for ln in text.splitlines():
3763
+ longest = max(longest, len(ln))
3764
+ body = ln.split("!", 1)[0] if not ln.lstrip().startswith(
3765
+ "!$") else ln.lstrip()[5:]
3766
+ if ln.lstrip().startswith("!") and not ln.lstrip().startswith(
3767
+ "!$"):
3768
+ continue
3769
+ if ln.rstrip().endswith("&"):
3770
+ run += 1
3771
+ cont_max = max(cont_max, run)
3772
+ else:
3773
+ run = 0
3774
+ for t in _ID.findall(re.sub(r"'[^']*'|\"[^\"]*\"", "", body)):
3775
+ name_max = max(name_max, len(t))
3776
+ v = []
3777
+ if longest > LINE_MAX:
3778
+ v.append("line")
3779
+ if cont_max > CONT_MAX:
3780
+ v.append("cont")
3781
+ if name_max > NAME_MAX:
3782
+ v.append("name")
3783
+ return {"max_line": longest, "max_continuations": cont_max,
3784
+ "max_name": name_max, "violations": v}
3785
+
3786
+
3787
+ def assemble(axis: str, size: int, seed: int, kernels: list, o: Opts,
3788
+ layout: str = "single", rng: random.Random | None = None
3789
+ ) -> StressProgram:
3790
+ """Render `kernels` into files per `layout`; compute the value, the
3791
+ limits and the legality label."""
3792
+ rng = rng or random.Random(f"layout:{seed}")
3793
+ units: list[tuple[str, str, str]] = [("st_util", "mod", UTIL)]
3794
+ extra_after: dict[str, list] = {}
3795
+ kmods = []
3796
+ for k in kernels:
3797
+ for m in k.modules():
3798
+ units.append((m.name, "mod", module_text(m)))
3799
+ if hasattr(k, "extra_files"):
3800
+ for fname, text in k.extra_files():
3801
+ units.append((fname, "file", text))
3802
+ # the kernel subroutines: one module per kernel (per_unit / partition)
3803
+ # or one module for all (single)
3804
+ if layout == "single":
3805
+ body = ["module st_kern", " use st_util", " implicit none",
3806
+ "contains"]
3807
+ for k in kernels:
3808
+ body += k.routine()
3809
+ body.append("end module st_kern")
3810
+ units.append(("st_kern", "mod", "\n".join(body) + "\n"))
3811
+ kmods = ["st_kern"]
3812
+ else:
3813
+ for k in kernels:
3814
+ mname = f"st_k_{k.name}"
3815
+ body = [f"module {mname}", " use st_util", " implicit none",
3816
+ "contains"] + k.routine() + [f"end module {mname}"]
3817
+ units.append((mname, "mod", "\n".join(body) + "\n"))
3818
+ kmods.append(mname)
3819
+ main = main_text(kernels, o, kmods)
3820
+ omp_level = "6.0" if any(isinstance(k, OOKernel) and
3821
+ k.p.get("variant") == "polymap"
3822
+ for k in kernels) else "5.2 in 5.0 spellings"
3823
+ head = [f"! stress: axis={axis} size={size} seed={seed} model={o.model}"
3824
+ f" layout={layout}",
3825
+ f"! generator: {GEN} rev {axis_rev(axis)}",
3826
+ f"! language: Fortran 2018 free form; OpenMP {omp_level}"
3827
+ if o.model == "omp" else
3828
+ "! language: Fortran 2018 free form; OpenACC 3.4"]
3829
+ for k in kernels:
3830
+ head.append(("! kernel " + k.describe())[:120])
3831
+ header = "\n".join(head) + "\n"
3832
+ # files
3833
+ fort = [u for u in units if u[1] == "mod"]
3834
+ others = [u for u in units if u[1] == "file"]
3835
+ files: list[tuple[str, str]] = []
3836
+ if layout == "single":
3837
+ text = header + "".join(t for _, _, t in fort) + main
3838
+ files.append(("stress.f90", text))
3839
+ # a submodule must follow its ancestor module: its own file after
3840
+ files += [(n, t) for n, _, t in others]
3841
+ elif layout == "per_unit":
3842
+ files.append(("st_util.f90", header + UTIL))
3843
+ for n, kind, t in fort[1:]:
3844
+ files.append((f"{n}.f90", t))
3845
+ files += [(n, t) for n, _, t in others]
3846
+ files.append(("main.f90", main))
3847
+ else:
3848
+ # random partition into contiguous groups (module order is kept)
3849
+ nf = max(2, min(len(fort), rng.randint(2, max(2, len(fort) // 2))))
3850
+ cuts = sorted(rng.sample(range(1, len(fort)), min(nf - 1,
3851
+ len(fort) - 1)))
3852
+ groups, prev = [], 0
3853
+ for c in cuts + [len(fort)]:
3854
+ groups.append(fort[prev:c])
3855
+ prev = c
3856
+ for g_i, g in enumerate(groups):
3857
+ text = (header if g_i == 0 else "") + "".join(t for _, _, t in g)
3858
+ files.append((f"part{g_i:03d}.f90", text))
3859
+ files += [(n, t) for n, _, t in others]
3860
+ files.append(("main.f90", main))
3861
+ per = {k.name: k.value() for k in kernels}
3862
+ expected = sum(per.values()) % P
3863
+ feats = set()
3864
+ for k in kernels:
3865
+ feats |= k.features()
3866
+ lim = check_limits(files)
3867
+ legality, cite = "legal", ""
3868
+ for k in kernels:
3869
+ if k.legality == "unspecified" and legality == "legal":
3870
+ legality, cite = "unspecified", k.cite
3871
+ # implicit device procedures across compilation units (OpenMP 5.2
3872
+ # §13.8 p.284, §5.8.4 p.158). For Fortran a compilation unit is a
3873
+ # program unit (5.2 §1.2.2 p.3; OpenACC 3.4 §2.15.1 p.91: "program unit
3874
+ # being compiled"), so a chain of procedures in other modules is
3875
+ # cross-unit even in one file (F7): an illegal
3876
+ # probe in every layout
3877
+ for k in kernels:
3878
+ if isinstance(k, ChainTUKernel) and k.p["variant"] == "implicit":
3879
+ legality, cite = "illegal_probe", CITES["xtu"]
3880
+ if lim["violations"]:
3881
+ legality = "illegal_probe"
3882
+ cite = "; ".join(CITES[v] for v in lim["violations"])
3883
+ alloc = sum(k.bytes() for k in kernels if hasattr(k, "bytes"))
3884
+ pid = f"{axis}-{o.model}-{size}-{seed}" + ("" if layout == "single"
3885
+ else f"-{layout}")
3886
+ feats |= {f"axis:{axis}", f"layout:{layout}"}
3887
+ return StressProgram(pid, axis, size, seed, o.model, layout, kernels,
3888
+ files, expected, per, legality, cite, feats, alloc,
3889
+ limits=lim, rev=axis_rev(axis))
3890
+
3891
+
3892
+ # --- axes ----------------------------------------------------------------------------------------
3893
+
3894
+ def _k(i: int) -> str:
3895
+ return f"k{i:04d}"
3896
+
3897
+
3898
+ def kernel_variant(k: Kernel) -> str | None:
3899
+ """The variant (route, template, ...) a kernel instantiates."""
3900
+ if "routes" in k.p and len(k.p["routes"]) == 1:
3901
+ return k.p["routes"][0]
3902
+ return k.p.get("variant")
3903
+
3904
+
3905
+ def _kernels_for(axis: str, size: int, rng: random.Random, o: Opts) -> list:
3906
+ """The kernels of one axis at one size; ``<axis>.<variant>`` keeps the
3907
+ kernels of one variant (a scalar route, an OO feature, a template, a
3908
+ translation-unit variant, ...), so a rejection of one variant does not
3909
+ hide the others."""
3910
+ if "." in axis:
3911
+ base, var = axis.split(".", 1)
3912
+ ks = [k for k in _kernels_for(base, size, rng, o)
3913
+ if kernel_variant(k) == var]
3914
+ if not ks:
3915
+ raise ValueError(f"axis {base} has no variant {var}")
3916
+ for j, k in enumerate(ks, 1):
3917
+ k.name = _k(j)
3918
+ return ks
3919
+ ks: list[Kernel] = []
3920
+ if o.model == "acc" and axis in ACC_EXCLUDED:
3921
+ raise ValueError(f"the {axis} axis is OpenMP only")
3922
+
3923
+ def add(cls, **p):
3924
+ ks.append(cls(_k(len(ks) + 1), o, random.Random(rng.random()), **p))
3925
+ if axis == "kernels":
3926
+ for _ in range(size):
3927
+ r = rng.random()
3928
+ if r < 0.8:
3929
+ add(LoopKernel)
3930
+ elif r < 0.9:
3931
+ add(PrivateKernel, nitems=4)
3932
+ else:
3933
+ add(CallsKernel, depth=2, recursive=False, n=64)
3934
+ elif axis == "nest":
3935
+ add(NestKernel, depth=size, collapse=size)
3936
+ if size >= 3 and o.model == "omp":
3937
+ add(NestKernel, depth=size, split=True)
3938
+ add(NestKernel, depth=size, collapse=1)
3939
+ elif axis == "calls":
3940
+ add(CallsKernel, depth=size, recursive=False)
3941
+ add(CallsKernel, depth=size, recursive=True)
3942
+ elif axis in LIST_AXES:
3943
+ if axis == "lastprivate" and o.model == "acc":
3944
+ raise ValueError("OpenACC has no lastprivate")
3945
+ add(LIST_AXES[axis], nitems=size)
3946
+ elif axis == "clauses":
3947
+ if o.model == "acc":
3948
+ raise ValueError("the clauses axis is OpenMP")
3949
+ add(ClausesKernel, nclauses=size)
3950
+ elif axis == "contlines":
3951
+ add(ContKernel, nitems=size, n=8)
3952
+ elif axis == "names":
3953
+ add(NamesKernel, length=size, count=4)
3954
+ elif axis == "locals":
3955
+ add(LocalsKernel, nlocals=size)
3956
+ elif axis == "args":
3957
+ add(ArgsKernel, nargs=size)
3958
+ elif axis == "useonly":
3959
+ add(UseOnlyKernel, nitems=size)
3960
+ elif axis == "capture":
3961
+ add(CaptureKernel, nitems=size)
3962
+ elif axis == "dtnest":
3963
+ add(DTNestKernel, depth=size, mode="enter", ptr=False)
3964
+ add(DTNestKernel, depth=size, mode="region", ptr=False)
3965
+ add(DTNestKernel, depth=size, mode="enter", ptr=True)
3966
+ elif axis == "oo":
3967
+ for v in OO_LEGAL:
3968
+ add(OOKernel, variant=v, depth=size)
3969
+ add(OOKernel, variant="polymap", depth=size)
3970
+ add(OOKernel, variant="pdt", depth=size)
3971
+ elif axis == "tu":
3972
+ for v in ("plain", "submodule") + (
3973
+ ("bindc",) if o.model == "omp" else ()):
3974
+ add(ChainTUKernel, depth=size, variant=v)
3975
+ elif axis == "tuimp":
3976
+ add(ChainTUKernel, depth=size, variant="implicit")
3977
+ elif axis == "scalars":
3978
+ routes = OMP_ROUTES if o.model == "omp" else ACC_ROUTES
3979
+ for r in routes:
3980
+ add(ScalarsKernel, nscal=size, routes=[r])
3981
+ elif axis == "mixed":
3982
+ add(MixedKernel, nred=size, natom=max(1, size // 2),
3983
+ ncrit=max(1, min(size, 64) // 2) if o.model == "omp" else 0)
3984
+ elif axis == "exprs":
3985
+ for v in ("expr", "select", "spec"):
3986
+ add(ExprsKernel, variant=v, size=size)
3987
+ elif axis == "async":
3988
+ add(AsyncKernel, ntasks=size)
3989
+ elif axis == "runtime":
3990
+ for v in ("iters", "teams", "alloc"):
3991
+ sz = {"iters": size, "teams": max(1, size // 256),
3992
+ "alloc": size}[v]
3993
+ add(RuntimeKernel, variant=v, size=sz)
3994
+ elif axis == "template":
3995
+ add(TemplateKernel, variant="team_private", nloops=max(2, min(size,
3996
+ 16)))
3997
+ add(TemplateKernel, variant="declared_alloc", ncomp=max(1, min(
3998
+ size, 64)))
3999
+ add(TemplateKernel, variant="mfc_cbc", npriv=size)
4000
+ add(TemplateKernel, variant="mfc_bubbles", nb=max(1, min(size, 32)))
4001
+ elif axis == "random":
4002
+ # every axis together: `size` kernels drawn from the axes at
4003
+ # moderate sizes
4004
+ pool = [a for a in AXES if a not in ("random", "runtime", "names",
4005
+ "contlines", "tuimp",
4006
+ "oo", "scalars", "udr")]
4007
+ if o.model == "acc":
4008
+ pool = [a for a in pool if a not in ACC_EXCLUDED]
4009
+ for _ in range(size):
4010
+ a = rng.choice(pool)
4011
+ sub = _kernels_for(a, rng.choice(SMALL_SIZES.get(a, (4, 8, 16))),
4012
+ random.Random(rng.random()), o)
4013
+ for k in sub[:1]:
4014
+ k.name = _k(len(ks) + 1)
4015
+ ks.append(k)
4016
+ else:
4017
+ raise ValueError(f"unknown axis {axis}")
4018
+ return ks
4019
+
4020
+
4021
+ LIST_AXES = {"private": PrivateKernel, "firstprivate": FirstprivateKernel,
4022
+ "udr": UDRKernel,
4023
+ "lastprivate": LastprivateKernel, "shared": SharedKernel,
4024
+ "map": MapKernel, "reduction": ReductionKernel,
4025
+ "depend": DependKernel, "declare": DeclareKernel,
4026
+ "sections": SectionsKernel}
4027
+ AXES = ("kernels", "nest", "calls", *LIST_AXES, "clauses", "contlines",
4028
+ "names", "locals", "args", "useonly", "capture", "dtnest", "oo",
4029
+ "tu", "tuimp", "scalars", "mixed", "exprs", "async", "runtime", "template",
4030
+ "random")
4031
+ ACC_EXCLUDED = ("lastprivate", "clauses", "udr")
4032
+ SMALL_SIZES = {"kernels": (2, 4), "nest": (3, 4, 5), "calls": (3, 5),
4033
+ "dtnest": (2, 3), "oo": (2,), "tu": (2, 3), "scalars": (1, 2),
4034
+ "template": (4, 8), "names": (40, 63), "exprs": (16, 64),
4035
+ "async": (4, 8), "mixed": (2, 4), "clauses": (8, 16, 28)}
4036
+ # the size sweep of each axis (1, 8, 64, 256, 1024 ... and the
4037
+ # real maximum x2 to x10, set from catalog/fuzz_profile.json by
4038
+ # offload.engine.fuzz_profile.sweeps; these are the defaults)
4039
+ SWEEPS = {
4040
+ "kernels": (1, 8, 64, 256, 512),
4041
+ "nest": (1, 2, 3, 4, 5, 6, 7, 8, 10, 12),
4042
+ "calls": (1, 2, 5, 10, 20, 50),
4043
+ "private": (1, 8, 64, 159, 256, 512, 1024, 2048),
4044
+ "firstprivate": (1, 8, 64, 256, 1024),
4045
+ "lastprivate": (1, 8, 64, 256, 1024),
4046
+ "shared": (1, 8, 64, 256, 1024),
4047
+ "map": (1, 8, 64, 256, 1024),
4048
+ "reduction": (1, 8, 64, 256, 1024),
4049
+ "udr": (1, 8, 64, 256, 1024),
4050
+ "depend": (1, 8, 64, 256, 1024),
4051
+ "declare": (1, 8, 64, 113, 256, 1024),
4052
+ "sections": (1, 8, 64, 256, 1024),
4053
+ "clauses": (1, 8, 16, 28, 64, 256),
4054
+ "contlines": (1, 8, 64, 200, 255, 256, 300),
4055
+ "names": (31, 63, 64, 128),
4056
+ "locals": (1, 8, 64, 190, 512, 1024, 2048),
4057
+ "args": (1, 8, 25, 64, 128, 250),
4058
+ "useonly": (1, 16, 64, 160, 1024),
4059
+ "capture": (1, 8, 20, 64, 200, 1024),
4060
+ "dtnest": (1, 2, 3, 4, 6, 8, 12),
4061
+ "oo": (1, 3, 6),
4062
+ "tu": (2, 3, 5, 8, 16, 32),
4063
+ "tuimp": (2, 3, 5, 8),
4064
+ "scalars": (1, 4, 20, 64, 200),
4065
+ "mixed": (1, 8, 64, 256),
4066
+ "exprs": (8, 64, 256, 1024, 2048),
4067
+ "async": (1, 8, 64, 256),
4068
+ "runtime": (1 << 20, 1 << 24, 1 << 28, 1 << 30),
4069
+ "template": (8, 40, 159, 400),
4070
+ "random": (8, 32, 128),
4071
+ }
4072
+
4073
+
4074
+ def variants_of(axis: str, model: str = "omp") -> tuple:
4075
+ """The variants ``<axis>.<variant>`` of an axis (empty: no split)."""
4076
+ return {
4077
+ "oo": OO_VARIANTS,
4078
+ "scalars": tuple(OMP_ROUTES if model == "omp" else ACC_ROUTES),
4079
+ "tu": ("plain", "submodule") + (("bindc",) if model == "omp"
4080
+ else ()),
4081
+ "template": TEMPLATES,
4082
+ "exprs": ("expr", "select", "spec"),
4083
+ "runtime": ("iters", "teams", "alloc"),
4084
+ }.get(axis, ())
4085
+
4086
+
4087
+ def axis_names(model: str = "omp", split: bool = True) -> list[str]:
4088
+ """Every axis of a model, split into its variants where it has
4089
+ them."""
4090
+ out = []
4091
+ for a in AXES:
4092
+ if model == "acc" and a in ACC_EXCLUDED:
4093
+ continue
4094
+ vs = variants_of(a, model) if split else ()
4095
+ out += [f"{a}.{v}" for v in vs] if vs else [a]
4096
+ return out
4097
+
4098
+
4099
+ def build(axis: str, size: int, seed: int = 0, model: str = "omp",
4100
+ layout: str = "single", width: int = WIDTH) -> StressProgram:
4101
+ """The stress program of one axis at one size (deterministic in
4102
+ axis, size, seed, model, layout)."""
4103
+ o = Opts(model=model, width=width)
4104
+ rng = random.Random(f"{GEN}:{axis}:{size}:{seed}:{model}")
4105
+ for attempt in range(20):
4106
+ ks = _kernels_for(axis, size, rng, o)
4107
+ try:
4108
+ return assemble(axis, size, seed, ks, o, layout,
4109
+ random.Random(f"layout:{seed}:{attempt}"))
4110
+ except Overflow:
4111
+ continue
4112
+ raise RuntimeError(f"{axis} {size} {seed}: model overflow 20 times")
4113
+
4114
+
4115
+ def rebuild(prog_meta: dict, kernels: list) -> StressProgram:
4116
+ """A program of `kernels` (a subset or shrunk variants) with the
4117
+ original's axis, seed, model and layout (offload.engine.stress_min)."""
4118
+ o = Opts(model=prog_meta["model"])
4119
+ for j, k in enumerate(kernels, 1):
4120
+ k.o = o
4121
+ return assemble(prog_meta["axis"], prog_meta["size"], prog_meta["seed"],
4122
+ kernels, o, prog_meta["layout"])