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
offload/engine/fuzz.py ADDED
@@ -0,0 +1,2455 @@
1
+ """Csmith-style random OpenMP 5.2 Fortran target-offload programs.
2
+
3
+ ``generate(seed)`` returns a ``FuzzProgram``: a legal-by-construction
4
+ deterministic free-form Fortran program whose output ends with
5
+ ``RESULT checksum=<int> ran_on_host=<0|1>``. The seed and ``GEN_VERSION``
6
+ (both in the header) determine the program.
7
+ A program holds 1 to 4 kernels (target regions) of kind ``loop``, ``guard``,
8
+ ``phase`` or ``inred``. A loop kernel's construct nest is a chain taken from
9
+ a compound directive in ``catalog/omp/skeleton.yaml``, with clauses from
10
+ ``FILLABLE``. Bodies use bounded
11
+ integer arithmetic without races. ``FuzzProgram.expected`` comes from a
12
+ Python model of sequential execution.
13
+ ``check(program)`` runs ``check_scope``, ``offload.engine.rules``, the AFAR flang
14
+ frontend and gfortran ``-std=f2008``; a failing program is a
15
+ ``generator_reject`` and is never run."""
16
+ from __future__ import annotations
17
+
18
+ import random
19
+ import re
20
+ import shutil
21
+ import subprocess
22
+ import tempfile
23
+ from dataclasses import dataclass, field
24
+ from functools import lru_cache
25
+ from pathlib import Path
26
+ from typing import Callable
27
+
28
+ from offload.engine.catalog import (default_grammar, default_skeleton,
29
+ rule_valid, slice_directives, spelling_valid)
30
+ from offload.engine.fuzz_base import (ALL_GROUPS, BASE_GROUPS, TYPES, BaseMixin,
31
+ Overflow,
32
+ checksum_terms, contributions,
33
+ red_apply_typed, zero)
34
+
35
+ # Generator versions. A seed replays only with its version (in the
36
+ # program header and every campaign result row).
37
+ # fuzz-1: the first campaign (results/fuzz/c1).
38
+ # fuzz-2: defaultmap on the scalar and all categories draws only default,
39
+ # tofrom, to or firstprivate (Ruling below: a loop iteration variable
40
+ # referenced only inside a loop construct nested in the target region;
41
+ # CCE applies defaultmap(present: all) to it).
42
+ # fuzz-3: the base-language axis (offload.engine.fuzz_base): base
43
+ # groups chosen per campaign; without any group a fuzz-3 program is the
44
+ # fuzz-2 program of its seed (only the header differs).
45
+ # fuzz-4: fuzz-3 with generator defect G1 fixed: default(none)
46
+ # on a combined construct also lists the variables of its if(<leaf>:)
47
+ # clauses whose leaf is nested inside the default's leaf (those
48
+ # expressions are evaluated inside that region, 5.2 §17.2 p.340,
49
+ # §5.4.1 p.109); every other line, and the model, is fuzz-3's.
50
+ # fuzz-4s50: the fuzz-4 program of the seed with the OpenMP
51
+ # 5.0/5.1 spelling of each construct whose 5.2 spelling has an exact
52
+ # 5.0/5.1 equivalent (``spell50``); the model, every random decision and
53
+ # every other line are fuzz-4's, and the program is still a legal 5.2
54
+ # program (each 5.0 spelling is valid, if deprecated, at 5.2), checked by
55
+ # the same checkers. For compilers that reject the 5.2 spellings (NVHPC).
56
+ # fuzz-5 (fortran-oop): fuzz-4 plus the base group ``oop`` (type extension,
57
+ # type-bound procedures, dispatch, SELECT TYPE, CLASS(*) in declare target
58
+ # functions, offload.engine.fuzz_base.setup_oop); without that group a fuzz-5
59
+ # program is the fuzz-4 program of its seed (only the header differs), and
60
+ # no older version's program changes.
61
+ GEN_VERSIONS = ("fuzz-1", "fuzz-2", "fuzz-3", "fuzz-4", "fuzz-4s50",
62
+ "fuzz-5")
63
+ GEN_VERSION = "fuzz-4"
64
+ # the generator behaviour (self.v) of a spelling variant
65
+ _SPELL_OF = {"fuzz-4s50": "fuzz-4"}
66
+
67
+
68
+ def spell50(source: str) -> str:
69
+ """The OpenMP 5.0/5.1 spellings of a fuzz program's directives. The
70
+ first two have the same meaning at 5.2; the third does not:
71
+
72
+ * ``declare target enter(list)`` -> ``to(list)``: 5.2 §5.8.4, p.157
73
+ ("to ... is a deprecated synonym of enter"; enter is new in 5.2,
74
+ 5.2 §B.2 p.627);
75
+ * ``defaultmap(behavior: all)`` -> ``defaultmap(behavior)``: without a
76
+ variable-category the clause applies to all variables (5.2 §5.8.7,
77
+ p.162; 5.0 §2.19.7.2, p.325), and 5.0 has no all category;
78
+ * ``order(unconstrained: concurrent)`` -> ``order(concurrent)``: NOT
79
+ the same meaning. 5.0 has only ``order(concurrent)``: the iterations
80
+ may run in any order, including concurrently (5.0 §2.9.2 p.104,
81
+ §2.9.5 p.130). At 5.2 the iterations may still run in any order
82
+ (§10.3 p.234), but the modifier decides reproducibility: with
83
+ unconstrained "the loop schedule is not reproducible"; without a
84
+ modifier the clause does not affect it (5.2 §B.2 p.628: order with
85
+ concurrent "only affects whether a loop schedule is reproducible if a
86
+ modifier is explicitly specified"), so a schedule(static) worksharing
87
+ loop, a dist_schedule(static) distribute or a loop construct stays
88
+ reproducible (§11.5 p.248, §11.6 p.254, §11.7 p.257). The 5.0 spelling
89
+ therefore asks more of the compiler than fuzz-4's program (a reproducible
90
+ schedule); every fuzz-4 program stays legal and its checksum, which
91
+ no schedule decides, is unchanged.
92
+
93
+ ``order(reproducible: ...)``, ``thread_limit`` on target and the other
94
+ 5.1/5.2 features have no 5.0 equivalent and are kept."""
95
+ out = []
96
+ for line in source.split("\n"):
97
+ if line.lstrip().lower().startswith("!$omp"):
98
+ line = re.sub(r"\benter\s*\(", "to(", line)
99
+ line = re.sub(r"\bdefaultmap\(\s*(\w+)\s*:\s*all\s*\)",
100
+ r"defaultmap(\1)", line)
101
+ line = re.sub(r"\border\(\s*unconstrained\s*:\s*concurrent\s*\)",
102
+ "order(concurrent)", line)
103
+ out.append(line)
104
+ return "\n".join(out)
105
+ VERSION = 52
106
+ LIMIT = 2 ** 30 # |every intermediate value| stays below this
107
+ CHECK_MOD = 2147483629 # checksum modulus (a prime below 2**31)
108
+
109
+ LOOP_LEAVES = ("distribute", "do", "simd", "loop")
110
+ BLOCK_LEAVES = ("target", "teams", "parallel")
111
+
112
+ # Clauses the generator fills without changing the result.
113
+ FILLABLE = frozenset({
114
+ "map", "firstprivate", "private", "shared", "default", "reduction",
115
+ "lastprivate", "collapse", "schedule", "dist_schedule", "order",
116
+ "num_teams", "thread_limit", "num_threads", "proc_bind", "if", "device",
117
+ "defaultmap", "nowait", "depend", "in_reduction", "simdlen", "safelen",
118
+ "bind", "nontemporal"})
119
+
120
+ RED_OPS = ("+", "*", "max", "min", "iand", "ior", "ieor")
121
+
122
+ # Legal 5.2 forms AFAR flang's frontend rejects (its semantic check is one
123
+ # of the three legality checks, so a program using one would only be a
124
+ # generator reject). The generator avoids them; each has a reproducer in
125
+ # data/findings/ (afar-flang-*.f90) and the spec text that allows it.
126
+ FLANG_FALSE_REJECTS = {
127
+ "task_reduction_intrinsic_identifier":
128
+ "task_reduction/in_reduction with max, min, iand, ior or ieor "
129
+ "(5.2 §5.5.1: intrinsic procedure names are reduction identifiers; "
130
+ "flang: 'Internal: no symbol found for max')",
131
+ "loop_bind_teams_reduction":
132
+ "reduction on a loop construct bound to an enclosing teams "
133
+ "construct (5.2 §11.7.1 only makes it unspecified when the loop is "
134
+ "not nested in a teams construct; flang: 'REDUCTION clause not "
135
+ "allowed with !$OMP LOOP BIND(TEAMS)')",
136
+ "thread_limit_target_parallel_do":
137
+ "thread_limit on target parallel do [simd] (5.2 §13.8: target "
138
+ "takes thread_limit; §17.2 applies it to every leaf that takes it; "
139
+ "flang: 'THREAD_LIMIT clause is not allowed on TARGET PARALLEL DO')",
140
+ "firstprivate_and_map_on_different_targets":
141
+ "a variable firstprivate on one target construct and mapped on "
142
+ "another (5.2 §13.8 forbids both only on the same construct; "
143
+ "flang: 'may not appear on both MAP and FIRSTPRIVATE clauses on a "
144
+ "TARGET construct')",
145
+ }
146
+
147
+ # Optional features, each enabled for a random half of the programs.
148
+ SWARM = ("device", "if_target", "thread_limit", "split", "order", "atomic",
149
+ "critical", "lastprivate", "conditional", "inner_loop", "num_teams",
150
+ "num_threads", "proc_bind", "if_parallel", "if_simd", "schedule",
151
+ "dist_schedule", "simdlen", "safelen", "bind", "default", "shared",
152
+ "firstprivate", "nontemporal", "defaultmap", "nowait", "temp",
153
+ "map_always", "map_close", "map_present", "map_section", "guard",
154
+ "phase", "inred", "wrapper", "functions", "two_d", "reduction")
155
+
156
+
157
+ # --- the catalog view ---------------------------------------------------------
158
+
159
+ @lru_cache(maxsize=None)
160
+ def _cat():
161
+ return default_skeleton(), default_grammar()
162
+
163
+
164
+ def directive_valid(key: str) -> bool:
165
+ sk, g = _cat()
166
+ return key in sk.directives and spelling_valid(sk, g, key, key, VERSION)
167
+
168
+
169
+ @lru_cache(maxsize=None)
170
+ def allowed_clauses(key: str) -> frozenset:
171
+ """Clauses of directive `key` valid at 5.2 (after the spec overrides)."""
172
+ sk, g = _cat()
173
+ return frozenset(c for c, r in g.allowed(sk, key).items()
174
+ if rule_valid(r, VERSION) and not c.startswith("ompx_"))
175
+
176
+
177
+ def leaves_of(key: str) -> tuple:
178
+ sk, _ = _cat()
179
+ return tuple(sk.directive(key).leaves or [key])
180
+
181
+
182
+ @lru_cache(maxsize=None)
183
+ def target_chains() -> tuple:
184
+ """Leaf chains of the slice's compound directives that start with
185
+ target and are valid at 5.2, except the data-motion directives (and
186
+ 6.0's workdistribute)."""
187
+ sk, _ = _cat()
188
+ out = set()
189
+ for key in slice_directives(sk):
190
+ lv = leaves_of(key)
191
+ if lv[0] != "target" or not directive_valid(key):
192
+ continue
193
+ if all(x in LOOP_LEAVES + BLOCK_LEAVES for x in lv):
194
+ out.add(lv)
195
+ return tuple(sorted(out))
196
+
197
+
198
+ @lru_cache(maxsize=None)
199
+ def partitions(chain: tuple) -> tuple:
200
+ """Every split of `chain` into consecutive groups that are directives
201
+ valid at 5.2 (each group a tuple of leaves)."""
202
+ if not chain:
203
+ return ((),)
204
+ out = []
205
+ for k in range(1, len(chain) + 1):
206
+ head = chain[:k]
207
+ if directive_valid(" ".join(head)):
208
+ out += [(head,) + rest for rest in partitions(chain[k:])]
209
+ return tuple(out)
210
+
211
+
212
+ def catalog_coverage() -> dict:
213
+ """Per target chain: its allowed 5.2 clauses the generator fills and
214
+ those it does not."""
215
+ out = {}
216
+ for chain in target_chains():
217
+ key = " ".join(chain)
218
+ al = allowed_clauses(key)
219
+ out[key] = {"filled": sorted(al & FILLABLE),
220
+ "not_filled": sorted(al - FILLABLE)}
221
+ return out
222
+
223
+
224
+ # --- expressions --------------------------------------------------------------
225
+
226
+ def _chk(v: int) -> int:
227
+ if abs(v) >= LIMIT:
228
+ raise Overflow(v)
229
+ return v
230
+
231
+
232
+ def fmod(a: int, p: int) -> int:
233
+ """Fortran MOD (the sign of the first argument)."""
234
+ r = abs(a) % abs(p)
235
+ return r if a >= 0 else -r
236
+
237
+
238
+ def fdiv(a: int, b: int) -> int:
239
+ """Fortran integer division (truncates toward zero)."""
240
+ q = abs(a) // abs(b)
241
+ return q if (a >= 0) == (b > 0) else -q
242
+
243
+
244
+ class Ex:
245
+ def f(self) -> str:
246
+ """Fortran text."""
247
+ raise NotImplementedError
248
+
249
+ def ev(self, env: dict, arrs: dict) -> int:
250
+ raise NotImplementedError
251
+
252
+
253
+ @dataclass(frozen=True)
254
+ class Const(Ex):
255
+ v: int
256
+
257
+ def f(self):
258
+ return str(self.v) if self.v >= 0 else f"({self.v})"
259
+
260
+ def ev(self, env, arrs):
261
+ return self.v
262
+
263
+
264
+ @dataclass(frozen=True)
265
+ class Var(Ex):
266
+ name: str
267
+
268
+ def f(self):
269
+ return self.name
270
+
271
+ def ev(self, env, arrs):
272
+ return env[self.name]
273
+
274
+
275
+ @dataclass(frozen=True)
276
+ class ARef(Ex):
277
+ arr: str
278
+ idx: tuple
279
+
280
+ def f(self):
281
+ if not self.idx: # a scalar component (fuzz-3)
282
+ return self.arr
283
+ sub = ", ".join(x.f() for x in self.idx)
284
+ if "(@)" in self.arr: # a component of an array of structures
285
+ return self.arr.replace("@", sub)
286
+ return f"{self.arr}({sub})"
287
+
288
+ def ev(self, env, arrs):
289
+ return arrs[self.arr][tuple(x.ev(env, arrs) for x in self.idx)]
290
+
291
+
292
+ @dataclass(frozen=True)
293
+ class Bin(Ex):
294
+ op: str
295
+ a: Ex
296
+ b: Ex
297
+
298
+ def f(self):
299
+ return f"({self.a.f()} {self.op} {self.b.f()})"
300
+
301
+ def ev(self, env, arrs):
302
+ x, y = self.a.ev(env, arrs), self.b.ev(env, arrs)
303
+ if self.op == "+":
304
+ return _chk(x + y)
305
+ if self.op == "-":
306
+ return _chk(x - y)
307
+ if self.op == "*":
308
+ return _chk(x * y)
309
+ return fdiv(x, y) # "/" by a positive constant
310
+
311
+
312
+ @dataclass(frozen=True)
313
+ class Intr(Ex):
314
+ name: str
315
+ args: tuple
316
+
317
+ def f(self):
318
+ return f"{self.name}({', '.join(a.f() for a in self.args)})"
319
+
320
+ def ev(self, env, arrs):
321
+ v = [a.ev(env, arrs) for a in self.args]
322
+ n = self.name
323
+ if n == "mod":
324
+ return fmod(v[0], v[1])
325
+ if n == "max":
326
+ return max(v)
327
+ if n == "min":
328
+ return min(v)
329
+ if n == "iand":
330
+ return v[0] & v[1]
331
+ if n == "ior":
332
+ return v[0] | v[1]
333
+ if n == "ieor":
334
+ return v[0] ^ v[1]
335
+ if n == "abs":
336
+ return abs(v[0])
337
+ if n == "ishft": # applied to iand(x, 1023) only: never negative
338
+ return _chk(v[0] << v[1] if v[1] >= 0 else v[0] >> -v[1])
339
+ raise ValueError(n)
340
+
341
+
342
+ @dataclass(frozen=True)
343
+ class Cond:
344
+ op: str
345
+ a: Ex
346
+ b: Ex
347
+
348
+ def f(self):
349
+ return f"{self.a.f()} {self.op} {self.b.f()}"
350
+
351
+ def ev(self, env, arrs) -> bool:
352
+ x, y = self.a.ev(env, arrs), self.b.ev(env, arrs)
353
+ return {"<": x < y, "<=": x <= y, ">": x > y, ">=": x >= y,
354
+ "==": x == y, "/=": x != y}[self.op]
355
+
356
+
357
+ @dataclass(frozen=True)
358
+ class Merge(Ex):
359
+ a: Ex
360
+ b: Ex
361
+ c: Cond
362
+
363
+ def f(self):
364
+ return f"merge({self.a.f()}, {self.b.f()}, {self.c.f()})"
365
+
366
+ def ev(self, env, arrs):
367
+ # Fortran evaluates both; both are in range by construction
368
+ x, y = self.a.ev(env, arrs), self.b.ev(env, arrs)
369
+ return x if self.c.ev(env, arrs) else y
370
+
371
+
372
+ @dataclass(frozen=True)
373
+ class Func:
374
+ name: str
375
+ params: tuple
376
+ body: Ex
377
+
378
+
379
+ @dataclass(frozen=True)
380
+ class Call(Ex):
381
+ """A call of a declare-target module function."""
382
+ fn: Func
383
+ args: tuple
384
+
385
+ def f(self):
386
+ return f"{self.fn.name}({', '.join(a.f() for a in self.args)})"
387
+
388
+ def ev(self, env, arrs):
389
+ vals = [a.ev(env, arrs) for a in self.args]
390
+ return self.fn.body.ev(dict(zip(self.fn.params, vals)), arrs)
391
+
392
+
393
+ def red_apply(op: str, acc: int, v: int) -> int:
394
+ if op == "+":
395
+ return _chk(acc + v)
396
+ if op == "*":
397
+ return _chk(acc * v)
398
+ if op == "max":
399
+ return max(acc, v)
400
+ if op == "min":
401
+ return min(acc, v)
402
+ if op == "iand":
403
+ return acc & v
404
+ if op == "ior":
405
+ return acc | v
406
+ return acc ^ v
407
+
408
+
409
+ # --- text helpers ---------------------------------------------------------------
410
+
411
+ def wrap_directive(indent: str, name: str, clauses: list,
412
+ width: int = 96) -> list[str]:
413
+ """`!$omp name clauses...` with free-form continuation lines."""
414
+ lines, cur = [], f"{indent}!$omp {name}"
415
+ first = True
416
+ for c in clauses:
417
+ if len(cur) + 1 + len(c) > width and not first:
418
+ lines.append(cur + " &")
419
+ cur = f"{indent}!$omp& {c}"
420
+ else:
421
+ cur += " " + c
422
+ first = False
423
+ lines.append(cur)
424
+ return lines
425
+
426
+
427
+ def wrap_stmt(indent: str, text: str, width: int = 100) -> list[str]:
428
+ """A statement split with `&` continuations at spaces (generated
429
+ statements have spaces only between tokens, never in strings)."""
430
+ out = []
431
+ line = indent + text
432
+ while len(line) > width:
433
+ k = line.rfind(" ", len(indent) + 12, width)
434
+ if k < 0:
435
+ break
436
+ out.append(line[:k] + " &")
437
+ line = indent + " & " + line[k + 1:]
438
+ out.append(line)
439
+ return out
440
+
441
+
442
+ def add_clauses(lines: list[str], extra: list[str]) -> list[str]:
443
+ """`lines` (a directive, maybe continued, then more lines) with
444
+ `extra` clauses appended to the directive as continuation lines."""
445
+ if not extra:
446
+ return list(lines)
447
+ last = 0
448
+ while lines[last].rstrip().endswith("&"):
449
+ last += 1
450
+ ind = re.match(r"\s*", lines[0]).group()
451
+ cont = [f"{ind}!$omp& {x} &" for x in extra[:-1]] + \
452
+ [f"{ind}!$omp& {extra[-1]}"]
453
+ return lines[:last] + [lines[last] + " &"] + cont + lines[last + 1:]
454
+
455
+
456
+ # --- the program model ------------------------------------------------------------
457
+
458
+ @dataclass
459
+ class Arr:
460
+ name: str
461
+ rank: int # 1: (n), 2: (n, m)
462
+ alloc: bool # allocatable, else explicit shape
463
+ role: str # input | output | scratch
464
+ type: str = "integer" # a key of fuzz_base.TYPES (fuzz-3)
465
+ var: str = "" # the structure of a component (fuzz-3)
466
+
467
+
468
+ @dataclass
469
+ class Group:
470
+ leaves: tuple
471
+ levels: int = 0
472
+ clauses: list = field(default_factory=list)
473
+ vars: tuple = () # loop variables of the associated levels
474
+
475
+ @property
476
+ def key(self) -> str:
477
+ return " ".join(self.leaves)
478
+
479
+ @property
480
+ def is_loop(self) -> bool:
481
+ return self.leaves[-1] in LOOP_LEAVES
482
+
483
+ def has(self, leaf: str) -> bool:
484
+ return leaf in self.leaves
485
+
486
+ def allows(self, clause: str) -> bool:
487
+ return clause in allowed_clauses(self.key)
488
+
489
+
490
+ @dataclass
491
+ class Level:
492
+ var: str
493
+ extent: str # "n" or "m"
494
+ form: str # up | down | step2
495
+
496
+ def header(self) -> str:
497
+ return {"up": f"do {self.var} = 1, {self.extent}",
498
+ "down": f"do {self.var} = {self.extent}, 1, -1",
499
+ "step2": f"do {self.var} = 1, {self.extent}, 2"}[self.form]
500
+
501
+ def values(self, size: int) -> range:
502
+ return {"up": range(1, size + 1), "down": range(size, 0, -1),
503
+ "step2": range(1, size + 1, 2)}[self.form]
504
+
505
+ def first(self) -> str:
506
+ return self.extent if self.form == "down" else "1"
507
+
508
+
509
+ @dataclass
510
+ class Red:
511
+ var: str
512
+ op: str
513
+ method: str # clause | atomic | critical | plain
514
+ init: object
515
+ type: str = "integer" # a key of fuzz_base.TYPES (fuzz-3)
516
+
517
+
518
+ @dataclass
519
+ class Kern:
520
+ lines: list
521
+ reads: set
522
+ writes: set
523
+ target_line: int = 0 # index of the target directive's first line
524
+ host: bool = False # host statements (not a kernel)
525
+
526
+
527
+ @dataclass(frozen=True)
528
+ class FuzzProgram:
529
+ seed: int
530
+ source: str
531
+ expected: int
532
+ features: frozenset
533
+ kernels: tuple # one description per kernel
534
+ flags: int # kernels with a host-execution flag
535
+ gen_version: str = GEN_VERSION
536
+ base: tuple = () # base-language groups (fuzz-3)
537
+
538
+ @property
539
+ def id(self) -> str:
540
+ return f"fuzz-{self.seed}"
541
+
542
+ @property
543
+ def base_features(self) -> tuple:
544
+ """The program's base-language feature set (sorted)."""
545
+ return tuple(sorted(f for f in self.features
546
+ if f.startswith("base:")))
547
+
548
+
549
+ class _Gen(BaseMixin):
550
+ """One program. Every random decision goes through self.r in a fixed
551
+ order (base-language decisions through self.rb), so the program is a
552
+ function of the seed, the generator version and the base groups."""
553
+
554
+ def __init__(self, seed: int, gen_version: str = GEN_VERSION,
555
+ base: tuple = ()):
556
+ if gen_version not in GEN_VERSIONS:
557
+ raise ValueError(f"unknown generator version {gen_version!r}")
558
+ self.gen_version = gen_version
559
+ self.v = GEN_VERSIONS.index(_SPELL_OF.get(gen_version,
560
+ gen_version)) + 1
561
+ self.seed = seed
562
+ self.r = random.Random(seed)
563
+ self.n = self.r.choice((16, 24, 32, 48, 64, 100, 128, 200))
564
+ self.m = self.r.choice((2, 3, 4, 5, 8))
565
+ self.arrays: dict[str, Arr] = {}
566
+ self.scalars: dict[str, int] = {} # integer scalars: initial value
567
+ self.logicals: dict[str, bool] = {}
568
+ self.inits: dict[str, str] = {}
569
+ self.funcs: list[Func] = []
570
+ self.api: set[str] = set()
571
+ self.features: set[str] = set()
572
+ self.kdesc: list[str] = []
573
+ self.flags: list[str] = []
574
+ self.temps: set[str] = set()
575
+ self.check_items: list[str] = []
576
+ self.arrs: dict[str, dict] = {} # model: array values
577
+ self.env: dict[str, int] = {"n": self.n, "m": self.m} # scalars
578
+ self.k = 0
579
+ self.uses_dev = False
580
+ self.in_data = False
581
+ self.pmode: dict[str, str] = {} # param -> "fp" | "map" (targets)
582
+ # swarm testing (Groce et al., ISSTA 2012): each program enables a
583
+ # random half of the optional features, so many programs avoid any
584
+ # one feature a compiler rejects
585
+ self.swarm = {f: self.coin(0.5) for f in SWARM}
586
+ self.features.update(f"swarm:{f}" for f, on in self.swarm.items()
587
+ if on)
588
+ self.cur_out = ""
589
+ self.race_redraws = 0
590
+ self.base_init(tuple(base))
591
+
592
+ # -- helpers --
593
+
594
+ def feat(self, *names: str) -> None:
595
+ self.features.update(names)
596
+
597
+ def coin(self, p: float) -> bool:
598
+ return self.r.random() < p
599
+
600
+ def on(self, name: str) -> bool:
601
+ return self.swarm[name]
602
+
603
+ def sw(self, name: str, p: float) -> bool:
604
+ """An optional feature: enabled in this program's swarm, then
605
+ drawn with probability p at this site."""
606
+ return self.swarm[name] and self.coin(p)
607
+
608
+ def size(self, extent: str) -> int:
609
+ return self.n if extent == "n" else self.m
610
+
611
+ def points(self, a: Arr) -> list[tuple]:
612
+ if a.rank == 0:
613
+ return [()]
614
+ if a.rank == 1:
615
+ return [(i,) for i in range(1, self.n + 1)]
616
+ return [(i, j) for j in range(1, self.m + 1)
617
+ for i in range(1, self.n + 1)]
618
+
619
+ def new_array(self, name: str, rank: int, role: str,
620
+ typ: str = "integer", var: str = "") -> Arr:
621
+ if var:
622
+ a = Arr(name, rank, False, role, typ, var)
623
+ elif typ == "integer":
624
+ a = Arr(name, rank, self.coin(0.6), role)
625
+ else:
626
+ # typed arrays (fuzz-3) draw from the base stream
627
+ a = Arr(name, rank, rank > 0 and self.rb.random() < 0.4, role,
628
+ typ)
629
+ if typ != "integer" and role == "output":
630
+ base, kind = TYPES[typ]
631
+ from offload.engine.fuzz_base import INT_MAX, real_limit
632
+ self.tbound[name] = real_limit(kind) if base in (
633
+ "real", "complex") else INT_MAX.get(kind, 0) \
634
+ if base == "integer" else 0
635
+ self.arrays[name] = a
636
+ self.arrs[name] = {t: zero(typ) for t in self.points(a)}
637
+ if role == "output":
638
+ self.cur_out = name
639
+ if var:
640
+ pass
641
+ elif typ == "integer":
642
+ self.feat(f"decl:{'allocatable' if a.alloc else 'explicit'}"
643
+ f"_rank{rank}")
644
+ elif rank:
645
+ self.feat(f"base:decl:{'allocatable' if a.alloc else 'explicit'}"
646
+ f"_{typ}")
647
+ return a
648
+
649
+ def new_scalar(self, name: str, value: int) -> str:
650
+ self.scalars[name] = value
651
+ self.env[name] = value
652
+ return name
653
+
654
+ def params(self) -> list[str]:
655
+ return [p for p in self.scalars if re.fullmatch(r"p\d", p)]
656
+
657
+ # -- inputs and functions --
658
+
659
+ def setup(self) -> None:
660
+ r = self.r
661
+ for name, rank in (("ia", 1), ("ib", 1), ("ic", 2)):
662
+ a = self.new_array(name, rank, "input")
663
+ c1, c2 = r.randint(3, 61), r.randint(0, 50)
664
+ p = r.choice((97, 101, 211, 1009, 30011))
665
+ off = r.randint(0, p // 2)
666
+ cj = r.randint(1, 9)
667
+ for t in self.points(a):
668
+ lin = t[0] if rank == 1 else t[0] + cj * t[1]
669
+ self.arrs[name][t] = fmod(lin * c1 + c2, p) - off
670
+ lin = "i" if rank == 1 else f"(i + {cj} * j)"
671
+ idx = "i" if rank == 1 else "i, j"
672
+ self.inits[name] = (f"{name}({idx}) = mod({lin} * {c1} + {c2}, "
673
+ f"{p}) - {off}")
674
+ for k in range(r.choice((1, 1, 2))):
675
+ self.new_scalar(f"p{k + 1}", r.randint(-9, 9))
676
+ for k in range(r.choice((1, 2)) if self.on("functions") else 0):
677
+ params = ("x",) if self.coin(0.5) else ("x", "y")
678
+ leaves = [Var(p) for p in params] + [Const(r.randint(1, 13))]
679
+ body = Intr("mod", (self.expr(2, leaves, calls=False),
680
+ Const(r.choice((97, 1009, 9973)))))
681
+ self.funcs.append(Func(f"g{k + 1}", params, body))
682
+ if "types" in self.base:
683
+ self.setup_types()
684
+ if "derived" in self.base:
685
+ self.setup_derived()
686
+ if "alloc" in self.base:
687
+ self.setup_alloc()
688
+ if "declare" in self.base:
689
+ self.setup_declare()
690
+ if "multitu" in self.base:
691
+ self.setup_multitu()
692
+ if "oop" in self.base:
693
+ self.setup_oop()
694
+
695
+ # -- expressions --
696
+
697
+ def expr(self, depth: int, leaves: list, calls: bool = True) -> Ex:
698
+ r = self.r
699
+ if depth <= 0 or self.coin(0.25):
700
+ return r.choice(leaves)
701
+ kind = r.choices(
702
+ ("add", "sub", "mul", "mod", "mm", "bit", "merge", "div", "call",
703
+ "ishft"),
704
+ (5, 3, 3, 3, 2, 2, 2, 1,
705
+ (6 if self.ofuncs else 2) if (calls and (
706
+ self.funcs or self.dfuncs or self.mfuncs or self.xfuncs or
707
+ self.ofuncs)) else 0, 1))[0]
708
+
709
+ def sub():
710
+ return self.expr(depth - 1, leaves, calls)
711
+ if kind == "add":
712
+ return Bin("+", sub(), sub())
713
+ if kind == "sub":
714
+ return Bin("-", sub(), sub())
715
+ if kind == "mul":
716
+ small = Const(r.choice((-3, -2, 2, 3, 5, 7))) if self.coin(0.6) \
717
+ else Intr("mod", (sub(), Const(r.randint(3, 15))))
718
+ return Bin("*", sub(), small)
719
+ if kind == "mod":
720
+ return Intr("mod", (sub(), Const(r.choice((7, 13, 97, 1000)))))
721
+ if kind == "mm":
722
+ return Intr(r.choice(("max", "min")), (sub(), sub()))
723
+ if kind == "bit":
724
+ return Intr(r.choice(("iand", "ior", "ieor")), (sub(), sub()))
725
+ if kind == "merge":
726
+ c = Cond(r.choice(("<", "<=", ">", ">=", "==", "/=")), sub(),
727
+ sub())
728
+ return Merge(sub(), sub(), c)
729
+ if kind == "div":
730
+ return Bin("/", sub(), Const(r.randint(2, 9)))
731
+ if kind == "ishft":
732
+ return Intr("ishft", (Intr("iand", (sub(), Const(1023))),
733
+ Const(r.randint(-4, 4))))
734
+ fn = r.choice(self.funcs + self.dfuncs + self.mfuncs + self.xfuncs
735
+ + self.ofuncs)
736
+ self.feat("body:call_declare_target")
737
+ if fn in self.ofuncs:
738
+ self.feat(f"base:oop:call:{fn.name}")
739
+ elif fn not in self.funcs:
740
+ self.feat(f"base:dc:call:{fn.name}")
741
+ return Call(fn, tuple(sub() for _ in fn.params))
742
+
743
+ def index(self, extent: str, ivars: dict) -> Ex:
744
+ """A subscript in 1..extent built from the loop variables."""
745
+ r = self.r
746
+ same = [v for v, e in ivars.items() if e == extent]
747
+ if same and self.coin(0.6):
748
+ v = r.choice(same)
749
+ if self.coin(0.75):
750
+ return Var(v)
751
+ return Bin("-", Const(self.size(extent) + 1), Var(v))
752
+ if ivars and self.coin(0.8):
753
+ v = r.choice(sorted(ivars))
754
+ return Bin("+", Intr("mod", (Bin("+", Bin("*", Var(v), Const(
755
+ r.randint(1, 7))), Const(r.randint(0, 9))), Var(extent))),
756
+ Const(1))
757
+ return Const(r.randint(1, self.size(extent)))
758
+
759
+ def leaves(self, ivars: dict, readable: list[str]) -> list[Ex]:
760
+ out: list[Ex] = [Var(v) for v in ivars]
761
+ out += [Var(p) for p in self.params()]
762
+ out += [Const(self.r.randint(-20, 40)) for _ in range(2)]
763
+ for name in readable:
764
+ if self.arrays[name].rank == 0: # a scalar component
765
+ out.append(ARef(name, ()))
766
+ continue
767
+ dims = ("n",) if self.arrays[name].rank == 1 else ("n", "m")
768
+ for _ in range(2):
769
+ out.append(ARef(name, tuple(self.index(d, ivars)
770
+ for d in dims)))
771
+ if self.bsw:
772
+ out += self.typed_leaves(ivars, self.cur_out)
773
+ return out
774
+
775
+ def bounded(self, e: Ex) -> Ex:
776
+ """A kernel result wrapped so later kernels read small values."""
777
+ r = self.r
778
+ kind = r.choice(("mod", "mod", "iand", "none"))
779
+ if kind == "mod":
780
+ return Intr("mod", (e, Const(r.choice((97, 1009, 9973, 30011)))))
781
+ if kind == "iand":
782
+ return Intr("iand", (e, Const(r.choice((255, 4095, 65535)))))
783
+ return e
784
+
785
+ def readable(self, but: str) -> list[str]:
786
+ """Integer arrays an integer expression may read."""
787
+ return [a.name for a in self.arrays.values()
788
+ if a.role in ("input", "output") and a.name != but
789
+ and a.type == "integer"]
790
+
791
+ def read_in(self, text: str, but: str = "") -> set:
792
+ """Arrays (any type) the kernel text reads."""
793
+ return {a.name for a in self.arrays.values()
794
+ if a.role in ("input", "output") and a.name != but
795
+ and re.search(self.ref_re(a.name), text)}
796
+
797
+ # -- reductions, lastprivate, flags --
798
+
799
+ def new_red(self, idx: int, method: str, ops=RED_OPS,
800
+ typed: bool = False) -> Red:
801
+ r = self.r
802
+ t = self.typed_red_type() if typed else None
803
+ if t is not None:
804
+ from offload.engine.fuzz_base import RED_OPS_TYPED
805
+ base = TYPES[t][0]
806
+ if method == "atomic" and base == "complex":
807
+ method = "clause" # no atomic update of complex items
808
+ op = self.rb.choice(RED_OPS_TYPED[self.red_key(t)])
809
+ init = self.typed_red_init(t, op)
810
+ name = f"r{self.k}{'ab'[idx]}"
811
+ self.tscalars[name] = (t, init)
812
+ self.env[name] = init
813
+ self.check_items.append(name)
814
+ self.feat(f"base:red:{t}:{op}", f"base:red:{t}:{method}")
815
+ return Red(name, op, method, init, t)
816
+ op = r.choice(ops)
817
+ init = {"+": r.randint(-50, 50), "*": r.choice((1, 2, -1)),
818
+ "max": r.randint(-100, 0), "min": r.randint(0, 100),
819
+ "iand": r.choice((-1, 65535, 1048575)),
820
+ "ior": r.randint(0, 8), "ieor": r.randint(0, 255)}[op]
821
+ red = Red(self.new_scalar(f"r{self.k}{'ab'[idx]}", init), op, method,
822
+ init)
823
+ self.check_items.append(red.var)
824
+ return red
825
+
826
+ def red_term(self, op: str, lv: list) -> Ex:
827
+ r = self.r
828
+ if op == "*":
829
+ c = Cond("==", Intr("mod", (r.choice(lv), Const(r.choice(
830
+ (11, 13, 17))))), Const(0))
831
+ return Merge(Const(r.choice((2, -1, 3))), Const(1), c)
832
+ e = self.expr(2, lv)
833
+ if op in ("iand", "ior", "ieor"):
834
+ return Intr("iand", (e, Const(r.choice((255, 65535, 1048575)))))
835
+ return e
836
+
837
+ def red_lines(self, red: Red, ce: Ex) -> list[str]:
838
+ v = red.var
839
+ if red.type != "integer":
840
+ upd = self.typed_red_update(v, red.type, red.op, ce)
841
+ else:
842
+ upd = (f"{v} = {v} {red.op} {ce.f()}" if red.op in ("+", "*")
843
+ else f"{v} = {red.op}({v}, {ce.f()})")
844
+ if red.method == "atomic":
845
+ return [f"!$omp atomic{self.r.choice(('', ' update'))}"] + \
846
+ wrap_stmt("", upd)
847
+ if red.method == "critical":
848
+ return ["!$omp critical"] + wrap_stmt("", upd) + \
849
+ ["!$omp end critical"]
850
+ return wrap_stmt("", upd)
851
+
852
+ def new_flag(self) -> str:
853
+ self.api.add("omp_is_initial_device")
854
+ name = self.new_scalar(f"hf{self.k}", 0)
855
+ self.flags.append(name)
856
+ return name
857
+
858
+ @staticmethod
859
+ def flag_stmt(flag: str) -> str:
860
+ return f"{flag} = merge(1, 0, omp_is_initial_device())"
861
+
862
+ # -- the body of one iteration point --
863
+
864
+ def point(self, ivars: dict, out: Arr, outidx: tuple, reds: list,
865
+ lps: list, temps: list, seq_inner: bool, readable: list
866
+ ) -> tuple[list[str], Callable]:
867
+ """(lines, model step) of one iteration point: a temporary, an
868
+ optional sequential inner loop, the output element, reduction
869
+ updates and lastprivate assignments."""
870
+ lines: list[str] = []
871
+ steps: list[Callable] = []
872
+ lv = self.leaves(ivars, readable)
873
+ if self.sw("temp", 0.5):
874
+ t = f"t{self.k}"
875
+ temps.append(t)
876
+ te = self.expr(2, lv)
877
+ lines += wrap_stmt("", f"{t} = {te.f()}")
878
+ steps.append(lambda env, a, te=te, t=t:
879
+ env.__setitem__(t, te.ev(env, a)))
880
+ lv = lv + [Var(t)]
881
+ self.feat("body:temp")
882
+ if seq_inner:
883
+ acc = f"acc{self.k}"
884
+ temps += [acc, "jj"]
885
+ ie = self.expr(2, self.leaves(dict(ivars, jj="m"), readable)
886
+ + [x for x in lv if isinstance(x, Var)
887
+ and x.name.startswith("t")])
888
+ lines += [f"{acc} = 0", "do jj = 1, m"] + \
889
+ wrap_stmt(" ", f"{acc} = {acc} + {ie.f()}") + ["end do"]
890
+
891
+ def inner(env, a, ie=ie, acc=acc):
892
+ s = 0
893
+ for v in range(1, self.m + 1):
894
+ env["jj"] = v
895
+ s = _chk(s + ie.ev(env, a))
896
+ env[acc] = s
897
+ steps.append(inner)
898
+ lv = lv + [Var(acc)]
899
+ self.feat("body:inner_seq_loop")
900
+ if out.type != "integer":
901
+ oe = self.typed_store(out.type, lv, ivars, out.name)
902
+ else:
903
+ oe = self.bounded(self.expr(3, lv))
904
+ tgt = ARef(out.name, outidx)
905
+ lines += wrap_stmt("", f"{tgt.f()} = {oe.f()}")
906
+ steps.append(lambda env, a, oe=oe, tgt=tgt: a[tgt.arr].__setitem__(
907
+ tuple(x.ev(env, a) for x in tgt.idx), oe.ev(env, a)))
908
+ for red in reds:
909
+ if red.type == "pair":
910
+ ex, ey = self.udr_term(lv)
911
+ lines += wrap_stmt("", f"{red.var} = pair_t({red.var}%x + "
912
+ f"{ex.f()}, {red.var}%y + {ey.f()})")
913
+
914
+ def pupd(env, a, ex=ex, ey=ey, red=red):
915
+ x, y = env[red.var]
916
+ env[red.var] = (_chk(x + ex.ev(env, a)),
917
+ _chk(y + ey.ev(env, a)))
918
+ steps.append(pupd)
919
+ continue
920
+ if red.type != "integer":
921
+ ce = self.typed_red_term(red.type, red.op, lv, ivars,
922
+ self.n * self.m, red.init)
923
+ lines += self.red_lines(red, ce)
924
+
925
+ def tupd(env, a, ce=ce, red=red):
926
+ env[red.var] = red_apply_typed(
927
+ TYPES[red.type][0], red.op, env[red.var],
928
+ ce.ev(env, a))
929
+ steps.append(tupd)
930
+ continue
931
+ ce = self.red_term(red.op, lv)
932
+ lines += self.red_lines(red, ce)
933
+
934
+ def upd(env, a, ce=ce, red=red):
935
+ v = ce.ev(env, a)
936
+ env[red.var] = red_apply(red.op, env[red.var], v)
937
+ # any combination order stays in range
938
+ key = "_abs_" + red.var
939
+ env[key] = _chk(env.get(key, abs(red.init)) + abs(v)) \
940
+ if red.op == "+" else _chk(env.get(key, max(1, abs(
941
+ red.init))) * max(1, abs(v))) if red.op == "*" else 0
942
+ steps.append(upd)
943
+ for name, cond in lps:
944
+ le = self.expr(2, lv)
945
+ if cond is None:
946
+ lines += wrap_stmt("", f"{name} = {le.f()}")
947
+ steps.append(lambda env, a, le=le, name=name:
948
+ env.__setitem__(name, le.ev(env, a)))
949
+ else:
950
+ lines += wrap_stmt("", f"if ({cond.f()}) {name} = {le.f()}")
951
+
952
+ def cl(env, a, le=le, name=name, cond=cond):
953
+ if cond.ev(env, a):
954
+ env[name] = le.ev(env, a)
955
+ env["_set_" + name] = 1
956
+ steps.append(cl)
957
+
958
+ def run(env, a):
959
+ for s in steps:
960
+ s(env, a)
961
+ return lines, run
962
+
963
+ def run_points(self, levels: list[Level], step: Callable,
964
+ parallel: bool = True) -> None:
965
+ """Run `step` at every iteration point. From fuzz-3 the points of
966
+ a parallel loop are checked for races (``_Tracked``): an array
967
+ element one point writes is neither written nor read by another
968
+ point (the reductions live in the scalars, not here)."""
969
+ env = self.env
970
+ arrs = _Tracked(self.arrs) if self.v >= 3 and parallel \
971
+ else self.arrs
972
+ if len(levels) == 1:
973
+ for i in levels[0].values(self.size(levels[0].extent)):
974
+ env[levels[0].var] = i
975
+ if arrs is not self.arrs:
976
+ arrs.point = (i,)
977
+ step(env, arrs)
978
+ else:
979
+ for i in levels[0].values(self.size(levels[0].extent)):
980
+ for j in levels[1].values(self.size(levels[1].extent)):
981
+ env[levels[0].var], env[levels[1].var] = i, j
982
+ if arrs is not self.arrs:
983
+ arrs.point = (i, j)
984
+ step(env, arrs)
985
+ if arrs is not self.arrs:
986
+ race = arrs.race()
987
+ if race:
988
+ self.race_redraws += 1
989
+ raise Overflow(f"race: {race}")
990
+
991
+ def new_levels(self, count: int) -> list[Level]:
992
+ out = []
993
+ for d in range(count):
994
+ form = self.r.choices(("up", "down", "step2"), (6, 2, 1))[0]
995
+ out.append(Level("ij"[d], "nm"[d], form))
996
+ self.feat(f"loop:{form}")
997
+ return out
998
+
999
+ # -- clauses of the target group --
1000
+
1001
+ def map_clauses(self, reads: set, writes: dict, scal_reads: set,
1002
+ scal_writes: set, implied: set) -> tuple[list, set]:
1003
+ """Map/firstprivate clauses of a target group and the variables
1004
+ left implicit. `writes`: array -> full | partial | scratch;
1005
+ `implied`: scalars a clause on the combined target already maps
1006
+ tofrom (5.2 §17.2)."""
1007
+ r = self.r
1008
+ by_type: dict[str, list[str]] = {}
1009
+ implicit: set = set()
1010
+ fp: list[str] = []
1011
+ handled: set = set()
1012
+ if self.dvars:
1013
+ pairs, implicit, handled = self.struct_maps(
1014
+ reads | set(writes), reads, writes)
1015
+ for key, item in pairs:
1016
+ by_type.setdefault(key, []).append(item)
1017
+ for name in sorted((reads | set(writes)) - handled):
1018
+ kind = writes.get(name)
1019
+ if self.arrays[name].rank == 0:
1020
+ # a character or allocatable scalar: always mapped
1021
+ # explicitly (offload.engine.fuzz_base)
1022
+ opts = ("to", "tofrom")
1023
+ elif name in self.ptrs and kind == "full" and name not in reads:
1024
+ opts = ("from", "tofrom") # a pointer: always explicit
1025
+ elif name in self.ptrs:
1026
+ opts = ("tofrom",) if kind else ("to", "tofrom")
1027
+ elif kind == "scratch":
1028
+ opts = ("alloc", "tofrom", "implicit")
1029
+ elif kind == "full" and name not in reads:
1030
+ opts = ("from", "tofrom", "implicit")
1031
+ elif kind:
1032
+ opts = ("tofrom", "implicit")
1033
+ else:
1034
+ opts = ("to", "tofrom", "implicit")
1035
+ t = r.choice(opts)
1036
+ self.feat(f"map:{t}")
1037
+ if t == "implicit":
1038
+ implicit.add(name)
1039
+ continue
1040
+ mods = [m for m, p in (("always", 0.25), ("close", 0.2))
1041
+ if self.sw("map_" + m, p)]
1042
+ # in a data region the host copy of an earlier kernel's output
1043
+ # is stale: always would copy it over the device copy
1044
+ if self.in_data and "always" in mods and kind is None and \
1045
+ self.arrays[name].role == "output":
1046
+ mods.remove("always")
1047
+ if self.in_data and self.sw("map_present", 0.3) and \
1048
+ self.arrays[name].role in ("input", "output"):
1049
+ mods.append("present")
1050
+ for mm in mods:
1051
+ self.feat(f"map:mod:{mm}")
1052
+ item = name
1053
+ if self.sw("map_section", 0.3) and self.arrays[name].rank:
1054
+ self.feat("map:section")
1055
+ item = f"{name}(1:n)" if self.arrays[name].rank == 1 else \
1056
+ r.choice((f"{name}(:, 1:m)", f"{name}(:, :)"))
1057
+ by_type.setdefault(", ".join(mods + [t]), []).append(item)
1058
+ for name in sorted(scal_reads):
1059
+ # FLANG_FALSE_REJECTS: one program never both firstprivates
1060
+ # and maps the same variable on target constructs
1061
+ opts = [x for x in ("implicit", "implicit", "firstprivate", "to",
1062
+ "tofrom")
1063
+ if self.pmode.get(name) is None or x == "implicit"
1064
+ or (x == "firstprivate") == (self.pmode[name] == "fp")]
1065
+ t = r.choice(opts)
1066
+ if t != "implicit":
1067
+ self.pmode[name] = "fp" if t == "firstprivate" else "map"
1068
+ self.feat(f"scalar:{t}")
1069
+ if t == "implicit":
1070
+ implicit.add(name)
1071
+ elif t == "firstprivate":
1072
+ fp.append(name)
1073
+ else:
1074
+ by_type.setdefault(t, []).append(name)
1075
+ for name in sorted(scal_writes):
1076
+ if name in implied:
1077
+ # 5.2 §17.2: the reduction/lastprivate clause on the
1078
+ # combined target maps it tofrom (flang rejects an
1079
+ # explicit map of it as well)
1080
+ self.feat("scalar:implied_tofrom")
1081
+ continue
1082
+ by_type.setdefault("always, tofrom" if self.sw("map_always", 0.2)
1083
+ else "tofrom", []).append(name)
1084
+ out = []
1085
+ groups = sorted(by_type.items())
1086
+ if self.coin(0.4):
1087
+ out += [f"map({key}: {x})" for key, items in groups
1088
+ for x in items]
1089
+ else:
1090
+ out += [f"map({key}: {', '.join(items)})"
1091
+ for key, items in groups]
1092
+ if fp:
1093
+ out.append(f"firstprivate({', '.join(fp)})")
1094
+ return out, implicit
1095
+
1096
+ def defaultmap(self, implicit: set, writes: dict, cl: list = ()
1097
+ ) -> str | None:
1098
+ """A defaultmap clause that keeps the result for every implicitly
1099
+ mapped variable of its category (see the Ruling), or None."""
1100
+ r = self.r
1101
+ if not self.sw("defaultmap", 0.5):
1102
+ return None
1103
+ cat = r.choice(("scalar", "aggregate", "allocatable", "all"))
1104
+ members = []
1105
+ for name in sorted(implicit):
1106
+ if name in self.dvars: # a structure (fuzz-3)
1107
+ if cat in ("aggregate", "all"):
1108
+ members.append(name)
1109
+ elif name in self.arrays:
1110
+ cats = {"aggregate", "all"} | (
1111
+ {"allocatable"} if self.arrays[name].alloc else set())
1112
+ if cat in cats:
1113
+ members.append(name)
1114
+ elif cat in ("scalar", "all"):
1115
+ members.append(name)
1116
+ safe = {"default", "tofrom"}
1117
+ for name in members:
1118
+ if name in self.dvars:
1119
+ # from/alloc of a whole structure would clobber the
1120
+ # components the kernel does not write
1121
+ safe &= {"default", "tofrom"} if self.dvar_written(
1122
+ name, writes) else {"default", "tofrom", "to",
1123
+ "firstprivate"}
1124
+ elif name not in self.arrays:
1125
+ safe &= {"default", "tofrom", "to", "firstprivate"}
1126
+ elif writes.get(name) == "full":
1127
+ safe &= {"default", "tofrom", "from"}
1128
+ elif writes.get(name) == "scratch":
1129
+ safe &= {"default", "tofrom", "alloc"}
1130
+ elif writes.get(name):
1131
+ safe &= {"default", "tofrom"}
1132
+ else:
1133
+ safe &= {"default", "tofrom", "to", "firstprivate"}
1134
+ if not members:
1135
+ safe = {"default", "tofrom", "to", "from", "firstprivate",
1136
+ "alloc"}
1137
+ # none only for arrays: scalars such as the logical of an if
1138
+ # clause on an inner construct may be referenced implicitly
1139
+ if cat in ("aggregate", "allocatable"):
1140
+ safe.add("none")
1141
+ if any("(" in c.split(":", 1)[-1] for c in cl if c.startswith("map(")):
1142
+ safe.discard("none") # flang: a section does not list the array
1143
+ if self.in_data and members and all(
1144
+ x in self.dvars or (x in self.arrays and
1145
+ self.arrays[x].role != "scratch")
1146
+ for x in members):
1147
+ safe.add("present")
1148
+ if self.v >= 2 and cat in ("scalar", "all"):
1149
+ safe &= {"default", "tofrom", "to", "firstprivate"}
1150
+ beh = r.choice(sorted(safe))
1151
+ self.feat(f"defaultmap:{beh}:{cat}")
1152
+ return f"defaultmap({beh}: {cat})"
1153
+
1154
+ def target_extras(self, g: Group) -> list[str]:
1155
+ r = self.r
1156
+ out = []
1157
+ if g.allows("device") and self.sw("device", 0.25):
1158
+ self.uses_dev = True
1159
+ self.api.add("omp_get_default_device")
1160
+ out.append("device(dev)" if self.coin(0.5)
1161
+ else "device(device_num: dev)")
1162
+ self.feat("clause:device")
1163
+ if g.allows("if") and self.sw("if_target", 0.25):
1164
+ self.logicals["lt"] = True
1165
+ out.append("if(target: lt)" if self.coin(0.6) else "if(lt)")
1166
+ self.feat("clause:if:target")
1167
+ if g.allows("thread_limit") and not (g.has("parallel") and
1168
+ g.has("do")) and \
1169
+ self.sw("thread_limit", 0.3): # FLANG_FALSE_REJECTS
1170
+ out.append(f"thread_limit({r.choice((1, 8, 32, 64, 256))})")
1171
+ self.feat("clause:thread_limit")
1172
+ return out
1173
+
1174
+ def target_clauses(self, g: Group, reads, writes, scal_reads,
1175
+ scal_writes, implied, temps=()) -> list[str]:
1176
+ if self.bsw and self.dtv:
1177
+ # declare target variables: never in a map clause (fuzz_base)
1178
+ reads = {x for x in reads if self.var_of(x) not in self.dtv}
1179
+ writes = {x: v for x, v in writes.items()
1180
+ if self.var_of(x) not in self.dtv}
1181
+ cl, implicit = self.map_clauses(reads, writes, scal_reads,
1182
+ scal_writes, implied)
1183
+ # temporaries are implicitly firstprivate scalars of the region
1184
+ implicit |= set(temps)
1185
+ dm = self.defaultmap(implicit, writes, cl) if \
1186
+ g.allows("defaultmap") else None
1187
+ return cl + ([dm] if dm else []) + self.target_extras(g)
1188
+
1189
+ # -- the loop kernel --
1190
+
1191
+ def k_loop(self, ind: str) -> Kern:
1192
+ r = self.r
1193
+ chain = r.choice([c for c in target_chains()
1194
+ if c[-1] in LOOP_LEAVES])
1195
+ parts = [p for p in partitions(chain)
1196
+ if sum(g[-1] in LOOP_LEAVES for g in p) <= 2]
1197
+ part = parts[0] if len(parts) == 1 or not self.sw("split", 0.8) else \
1198
+ r.choice(parts[1:])
1199
+ groups = [Group(g) for g in part]
1200
+ loops = [g for g in groups if g.is_loop]
1201
+ nlev = 2 if len(loops) == 2 else (2 if self.sw("two_d", 0.5) else 1)
1202
+ for g in loops:
1203
+ g.levels = 1
1204
+ if nlev == 2 and len(loops) == 1:
1205
+ loops[0].levels = 2
1206
+ levels = self.new_levels(nlev)
1207
+ li = 0
1208
+ for g in loops:
1209
+ g.vars = tuple(lvl.var for lvl in levels[li:li + g.levels])
1210
+ li += g.levels
1211
+ otyp = self.out_type(nlev) if self.bsw else "integer"
1212
+ out = (self.modvar_output(nlev) if self.bsw else None) or (
1213
+ self.component_output(nlev, otyp) if self.dvars else None) \
1214
+ or self.new_array(f"o{self.k}", nlev, "output", otyp)
1215
+ if "alloc" in self.base:
1216
+ self.pointer_output(out)
1217
+ full = all(lvl.form != "step2" for lvl in levels)
1218
+ ivars = {lvl.var: lvl.extent for lvl in levels}
1219
+ readable = self.readable(out.name)
1220
+ teams = any(g.has("teams") for g in groups)
1221
+ concurrent = any(g.has("simd") or g.has("loop") for g in groups)
1222
+ if not concurrent and self.sw("order", 0.4):
1223
+ # innermost only: an order(concurrent) region may hold only
1224
+ # loop, parallel and simd constructs (5.2 §10.3)
1225
+ cands = [g for g in loops[-1:] if g.allows("order")]
1226
+ if cands:
1227
+ g = r.choice(cands)
1228
+ g.clauses.append(r.choice((
1229
+ "order(concurrent)", "order(reproducible: concurrent)",
1230
+ "order(unconstrained: concurrent)")))
1231
+ self.feat("clause:order")
1232
+ concurrent = True
1233
+ reds = []
1234
+ # FLANG_FALSE_REJECTS: no reduction when a loop group is closely
1235
+ # nested in a teams group
1236
+ loop_in_teams = any(g.leaves[0] == "loop" and gi and
1237
+ groups[gi - 1].leaves[-1] == "teams"
1238
+ for gi, g in enumerate(groups))
1239
+ for idx in range(r.choice((1, 1, 2)) if self.on("reduction")
1240
+ and not loop_in_teams else 0):
1241
+ method = "clause"
1242
+ if not concurrent and (self.sw("atomic", 0.5) or self.sw(
1243
+ "critical", 0.4)):
1244
+ method = "atomic" if teams or not self.on("critical") or \
1245
+ (self.on("atomic") and self.coin(0.5)) else "critical"
1246
+ udr = self.udr_red(idx) if self.bsw and method == "clause" \
1247
+ else None
1248
+ reds.append(udr or self.new_red(idx, method,
1249
+ typed=bool(self.bsw)))
1250
+ self.feat(f"red:{method}", f"red:{method}:{reds[-1].op}")
1251
+ lps = []
1252
+ # lastprivate on a loop construct takes only its iteration variable
1253
+ # (5.2 §11.7.1 loop-dsa-001); conditional is not allowed on
1254
+ # distribute (§11.6 distribute-clause-001)
1255
+ if self.sw("lastprivate", 0.5) and all(g.allows("lastprivate") and
1256
+ not g.has("loop") for g in loops):
1257
+ name = self.new_scalar(f"lp{self.k}", 0)
1258
+ self.check_items.append(name)
1259
+ cond = None
1260
+ if self.sw("conditional", 0.5) and not any(g.has("distribute")
1261
+ for g in loops):
1262
+ cond = Cond("==", Intr("mod", (Var(levels[0].var), Const(
1263
+ r.randint(2, 5)))), Const(r.randint(0, 1)))
1264
+ self.feat("clause:lastprivate:conditional")
1265
+ lps.append((name, cond))
1266
+ self.feat("clause:lastprivate")
1267
+ temps: list[str] = []
1268
+ body, step = self.point(ivars, out, tuple(Var(v) for v in ivars),
1269
+ reds, lps, temps, nlev == 1 and
1270
+ self.sw("inner_loop", 0.5), readable)
1271
+ self.run_points(levels, step)
1272
+ for name, cond in lps:
1273
+ if cond is not None and not self.env.pop("_set_" + name, 0):
1274
+ raise Overflow("conditional lastprivate never assigned")
1275
+ text = "\n".join(body)
1276
+ reads = {n for n in readable if re.search(rf"\b{n}\(", text)}
1277
+ if self.bsw:
1278
+ reads |= self.read_in(text, out.name)
1279
+ writes = {out.name: "full" if full else "partial"}
1280
+ self.full_out[out.name] = full
1281
+ scal_reads = {p for p in self.params()
1282
+ if re.search(rf"\b{p}\b", text)}
1283
+ # clauses that do not depend on the target's maps
1284
+ for gi, g in enumerate(groups):
1285
+ if g.levels == 2:
1286
+ g.clauses.append("collapse(2)")
1287
+ self.feat("clause:collapse")
1288
+ nxt = groups[gi + 1] if gi + 1 < len(groups) else None
1289
+ # a worksharing (or loop) construct's reduction needs the item
1290
+ # shared in the binding parallel/teams region (5.2 §5.5.8
1291
+ # reduction-dsa-001): the enclosing block group has none
1292
+ binds = (not g.is_loop and nxt is not None
1293
+ and nxt.leaves[0] in ("do", "loop"))
1294
+ for red in reds:
1295
+ if red.method == "clause" and g.allows("reduction") and (
1296
+ set(g.leaves) - {"target", "distribute"}) and \
1297
+ not binds:
1298
+ g.clauses.append(f"reduction({red.op}: {red.var})")
1299
+ for name, cond in lps:
1300
+ if g.is_loop and g.allows("lastprivate"):
1301
+ mod = "conditional: " if cond is not None else ""
1302
+ g.clauses.append(f"lastprivate({mod}{name})")
1303
+ if temps:
1304
+ groups[-1].clauses.append(f"private({', '.join(temps)})")
1305
+ flag_at = self.flag_position(groups)
1306
+ flag = self.new_flag() if flag_at else None
1307
+ scal_writes = {red.var for red in reds} | {n for n, _ in lps} | (
1308
+ {flag} if flag else set())
1309
+ tgt = groups[0]
1310
+ implied = {v for v in scal_writes if any(
1311
+ re.search(rf"\b(reduction|lastprivate)\([^)]*\b{v}\b", c)
1312
+ for c in tgt.clauses)} if len(tgt.leaves) > 1 else set()
1313
+ # innermost first: default(none) lists what the inner groups use
1314
+ for gi in range(len(groups) - 1, 0, -1):
1315
+ self.group_extras(groups[gi], gi, groups, text, temps, reds, lps,
1316
+ flag)
1317
+ tgt.clauses = self.target_clauses(
1318
+ tgt, reads, writes, scal_reads, scal_writes, implied,
1319
+ temps) + tgt.clauses
1320
+ self.group_extras(tgt, 0, groups, text, temps, reds, lps, flag)
1321
+ lines = self.nest(ind, groups, 0, levels, 0, body, flag, flag_at, [])
1322
+ self.kdesc.append("loop: " + " / ".join(g.key for g in groups)
1323
+ + f" ({nlev}D)")
1324
+ self.feat("kernel:loop", "chain:" + " ".join(chain),
1325
+ "split:" + " | ".join(g.key for g in groups))
1326
+ for g in groups:
1327
+ self.feat(f"dir:{g.key}")
1328
+ self.check_items.append(out.name)
1329
+ return Kern(lines, reads | scal_reads, set(writes) | scal_writes)
1330
+
1331
+ def flag_position(self, groups: list[Group]):
1332
+ """(group index, "loop"|"block") of the outermost place where a
1333
+ statement may call omp_is_initial_device: outside every simd, loop
1334
+ and order(concurrent) region (5.2 §10.3, §10.4, §11.7.1), not in
1335
+ a target that contains teams (§10.2), not in a teams body outside
1336
+ a nested construct (Ruling); None if there is no such place."""
1337
+ for gi, g in enumerate(groups):
1338
+ if g.has("simd") or g.has("loop") or any(
1339
+ c.startswith("order(") for c in g.clauses):
1340
+ return None
1341
+ if g.is_loop:
1342
+ return gi, "loop"
1343
+ nxt = groups[gi + 1] if gi + 1 < len(groups) else None
1344
+ if nxt is None:
1345
+ return None
1346
+ if g.leaves[-1] == "teams" or (g.leaves[-1] == "target"
1347
+ and nxt.leaves[0] == "teams"):
1348
+ continue
1349
+ return gi, "block"
1350
+ return None
1351
+
1352
+ def group_extras(self, g: Group, gi: int, groups: list[Group], text: str,
1353
+ temps: list, reds: list, lps: list, flag) -> None:
1354
+ r = self.r
1355
+ if g.has("teams") and g.allows("num_teams") and self.sw("num_teams", 0.5):
1356
+ if self.coin(0.2):
1357
+ g.clauses.append(f"num_teams({r.randint(1, 2)}: "
1358
+ f"{r.randint(2, 16)})")
1359
+ self.feat("clause:num_teams:lower_bound")
1360
+ else:
1361
+ g.clauses.append(f"num_teams({r.choice((1, 2, 4, 7, 64))})")
1362
+ self.feat("clause:num_teams")
1363
+ if g.has("teams") and not g.has("target") and \
1364
+ g.allows("thread_limit") and self.sw("thread_limit", 0.3):
1365
+ g.clauses.append(f"thread_limit({r.choice((1, 16, 64))})")
1366
+ self.feat("clause:thread_limit")
1367
+ if g.has("parallel") and g.allows("num_threads") and \
1368
+ self.sw("num_threads", 0.5):
1369
+ g.clauses.append(f"num_threads({r.choice((1, 2, 3, 8, 64))})")
1370
+ self.feat("clause:num_threads")
1371
+ if g.has("parallel") and g.allows("proc_bind") and \
1372
+ self.sw("proc_bind", 0.3):
1373
+ g.clauses.append("proc_bind("
1374
+ f"{r.choice(('spread', 'close', 'primary'))})")
1375
+ self.feat("clause:proc_bind")
1376
+ # one if clause without a directive-name modifier applies to every
1377
+ # leaf: no second if clause then (5.2 §3.4 if-clause-001)
1378
+ bare_if = any(re.match(r"if\([^:]*\)$", c) for c in g.clauses)
1379
+ if g.has("parallel") and g.allows("if") and not bare_if and \
1380
+ self.sw("if_parallel", 0.3):
1381
+ self.logicals.setdefault("lpar", self.coin(0.5))
1382
+ g.clauses.append("if(parallel: lpar)")
1383
+ self.feat("clause:if:parallel")
1384
+ if g.has("simd") and g.allows("if") and not bare_if and \
1385
+ self.sw("if_simd", 0.3):
1386
+ self.logicals.setdefault("lsimd", self.coin(0.5))
1387
+ g.clauses.append("if(simd: lsimd)")
1388
+ self.feat("clause:if:simd")
1389
+ if g.has("do") and g.allows("schedule") and \
1390
+ self.sw("schedule", 0.6):
1391
+ kind = r.choice(("static", "dynamic", "guided", "auto",
1392
+ "runtime"))
1393
+ text_ = kind
1394
+ if kind in ("static", "dynamic", "guided") and self.coin(0.5):
1395
+ text_ += f", {r.choice((1, 2, 3, 7, 16))}"
1396
+ mods = []
1397
+ if self.coin(0.3):
1398
+ mods.append("monotonic" if kind not in ("dynamic", "guided")
1399
+ or self.coin(0.5) else "nonmonotonic")
1400
+ if g.has("simd") and self.coin(0.3):
1401
+ mods.append("simd")
1402
+ g.clauses.append(f"schedule({', '.join(mods) + ': ' if mods else ''}"
1403
+ f"{text_})")
1404
+ self.feat("clause:schedule", f"clause:schedule:{kind}")
1405
+ if g.has("distribute") and g.allows("dist_schedule") and \
1406
+ self.sw("dist_schedule", 0.5):
1407
+ g.clauses.append("dist_schedule(static" + (
1408
+ f", {r.choice((1, 2, 5, 16))})" if self.coin(0.6) else ")"))
1409
+ self.feat("clause:dist_schedule")
1410
+ if g.has("simd") and g.allows("simdlen") and \
1411
+ self.sw("simdlen", 0.5):
1412
+ sl = r.choice((1, 2, 4, 8, 16))
1413
+ g.clauses.append(f"simdlen({sl})")
1414
+ self.feat("clause:simdlen")
1415
+ if g.allows("safelen") and self.coin(0.5):
1416
+ g.clauses.append(f"safelen({sl * r.choice((1, 2))})")
1417
+ self.feat("clause:safelen")
1418
+ elif g.has("simd") and g.allows("safelen") and \
1419
+ self.sw("safelen", 0.4):
1420
+ g.clauses.append(f"safelen({r.choice((1, 4, 16))})")
1421
+ self.feat("clause:safelen")
1422
+ if g.leaves[-1] == "loop" and g.allows("bind") and \
1423
+ self.sw("bind", 0.6):
1424
+ prev = groups[gi - 1] if gi else None
1425
+ if len(g.leaves) > 1:
1426
+ outer = g.leaves[-2]
1427
+ elif prev is not None and not prev.is_loop:
1428
+ outer = prev.leaves[-1]
1429
+ else:
1430
+ outer = None
1431
+ bind = {"teams": "teams", "parallel": "parallel"}.get(outer,
1432
+ "thread")
1433
+ g.clauses.append(f"bind({bind})")
1434
+ self.feat(f"clause:bind:{bind}")
1435
+ inner = text + "\n" + "\n".join(c for h in groups[gi + 1:]
1436
+ for c in h.clauses)
1437
+ if (g.has("teams") or g.has("parallel")) and not g.has("target") \
1438
+ and g.allows("default") and self.sw("default", 0.5):
1439
+ if self.coin(0.5):
1440
+ g.clauses.append("default(shared)")
1441
+ self.feat("clause:default:shared")
1442
+ else:
1443
+ outer = {v for h in groups[:gi] for v in h.vars}
1444
+ if self.v >= 4:
1445
+ # G1: the group's if clauses of leaves
1446
+ # nested inside the default's leaf are evaluated
1447
+ # inside its region
1448
+ inner += "\n" + "\n".join(nested_if_clauses(
1449
+ g.leaves, g.clauses))
1450
+ self.default_none(g, inner, temps, reds, lps, flag, outer)
1451
+ elif (g.has("teams") or g.has("parallel")) and g.allows("shared") \
1452
+ and self.sw("shared", 0.3):
1453
+ arrs = sorted(a for a in self.arrays
1454
+ if re.search(rf"\b{a}\(", inner)) if not \
1455
+ self.dvars else sorted({self.var_of(a) for a in self.arrays
1456
+ if re.search(self.ref_re(a), inner)})
1457
+ if arrs:
1458
+ g.clauses.append(f"shared({', '.join(arrs)})")
1459
+ self.feat("clause:shared")
1460
+ # firstprivate only on teams/parallel: on a worksharing or
1461
+ # distribute construct it would name an item private in the
1462
+ # binding region (5.2 §5.4.4 firstprivate-dsa-001/002)
1463
+ if g.allows("firstprivate") and self.sw("firstprivate", 0.3) and \
1464
+ not g.is_loop and "default(none)" not in g.clauses:
1465
+ ps = [p for p in self.params() if re.search(rf"\b{p}\b", inner)
1466
+ and not any(re.search(rf"\b{p}\b", c) for c in g.clauses)
1467
+ and self.pmode.get(p, "fp") == "fp"]
1468
+ for p in ps:
1469
+ self.pmode[p] = "fp"
1470
+ if ps:
1471
+ g.clauses.append(f"firstprivate({', '.join(ps)})")
1472
+ self.feat("clause:firstprivate")
1473
+ if g.has("simd") and g.allows("nontemporal") and \
1474
+ self.sw("nontemporal", 0.3):
1475
+ m = re.search(r"(?<![%\w])(o\d+)\(", text)
1476
+ if m:
1477
+ g.clauses.append(f"nontemporal({m.group(1)})")
1478
+ self.feat("clause:nontemporal")
1479
+
1480
+ def default_none(self, g: Group, inner: str, temps, reds, lps,
1481
+ flag, outer: set = frozenset()) -> None:
1482
+ """default(none) with every variable referenced in the construct
1483
+ listed (5.2 §5.4.1); the group's own associated loop variables are
1484
+ predetermined and not listed; the loop variables of enclosing loop
1485
+ groups (`outer`) keep their values: firstprivate."""
1486
+ names = set(re.findall(r"\b([a-z]\w*)\b", inner))
1487
+ own = set(g.vars)
1488
+ listed = {x for c in g.clauses for x in re.findall(r"\b\w+\b", c)}
1489
+ private = sorted((set(temps) | ({"i", "j", "jj"} & names)) - own
1490
+ - listed - set(outer))
1491
+ shared = {self.var_of(a) for a in self.arrays
1492
+ if self.var_of(a) in names}
1493
+ shared |= {red.var for red in reds if red.var not in listed}
1494
+ shared |= {n for n, _ in lps if n not in listed}
1495
+ if flag:
1496
+ shared.add(flag)
1497
+ fp = sorted(v for v in self.params() + list(self.logicals)
1498
+ if v in names) + sorted(set(outer) & names)
1499
+ g.clauses.append("default(none)")
1500
+ if shared:
1501
+ g.clauses.append(f"shared({', '.join(sorted(shared))})")
1502
+ if private:
1503
+ g.clauses.append(f"private({', '.join(private)})")
1504
+ if fp:
1505
+ g.clauses.append(f"firstprivate({', '.join(fp)})")
1506
+ self.feat("clause:default:none")
1507
+
1508
+ def nest(self, ind, groups, gi, levels, li, body, flag, flag_at,
1509
+ outer: list) -> list[str]:
1510
+ g = groups[gi]
1511
+ lines = wrap_directive(ind, g.key, g.clauses)
1512
+ if g.is_loop:
1513
+ used = levels[li:li + g.levels]
1514
+ cur = ind
1515
+ for lvl in used:
1516
+ lines.append(cur + lvl.header())
1517
+ cur += " "
1518
+ seen = outer + used
1519
+ if flag_at == (gi, "loop"):
1520
+ cond = " .and. ".join(f"{lvl.var} == {lvl.first()}"
1521
+ for lvl in seen)
1522
+ lines.append(f"{cur}if ({cond}) {self.flag_stmt(flag)}")
1523
+ if gi + 1 < len(groups):
1524
+ lines += self.nest(cur, groups, gi + 1, levels,
1525
+ li + g.levels, body, flag, flag_at, seen)
1526
+ else:
1527
+ lines += [cur + s for s in body]
1528
+ for _ in used:
1529
+ cur = cur[:-2]
1530
+ lines.append(cur + "end do")
1531
+ if self.coin(0.5):
1532
+ lines.append(f"{ind}!$omp end {g.key}")
1533
+ return lines
1534
+ inner = ind + " "
1535
+ if flag_at == (gi, "block"):
1536
+ conds = [f"{lvl.var} == {lvl.first()}" for lvl in outer]
1537
+ if g.has("parallel"):
1538
+ conds.append("omp_get_thread_num() == 0")
1539
+ self.api.add("omp_get_thread_num")
1540
+ stmt = self.flag_stmt(flag)
1541
+ lines.append(f"{inner}if ({' .and. '.join(conds)}) {stmt}"
1542
+ if conds else inner + stmt)
1543
+ lines += self.nest(inner, groups, gi + 1, levels, li, body, flag,
1544
+ flag_at, outer)
1545
+ lines.append(f"{ind}!$omp end {g.key}")
1546
+ return lines
1547
+
1548
+ # -- the guard kernel --
1549
+
1550
+ def k_guard(self, ind: str) -> Kern:
1551
+ r = self.r
1552
+ shape = r.choice(("par_thread0", "par_thread0", "single", "masked",
1553
+ "teams_team0", "target_seq", "split_par_thread0",
1554
+ "teams_team0_pardo"))
1555
+ otyp = self.out_type(1) if self.bsw else "integer"
1556
+ out = (self.modvar_output(1) if self.bsw else None) or (
1557
+ self.component_output(1, otyp) if self.dvars else None) \
1558
+ or self.new_array(f"o{self.k}", 1, "output", otyp)
1559
+ if "alloc" in self.base:
1560
+ self.pointer_output(out)
1561
+ lvl = self.new_levels(1)[0]
1562
+ readable = self.readable(out.name)
1563
+ pardo = shape == "teams_team0_pardo"
1564
+ reds = [self.new_red(idx, "clause" if pardo else "plain",
1565
+ typed=bool(self.bsw))
1566
+ for idx in range(r.choice((0, 1, 1)))]
1567
+ temps: list[str] = []
1568
+ body, step = self.point({"i": "n"}, out, (Var("i"),), reds, [],
1569
+ temps, self.coin(0.2), readable)
1570
+ self.run_points([lvl], step, parallel=pardo)
1571
+ flag = self.new_flag()
1572
+ text = "\n".join(body)
1573
+ reads = {n for n in readable if re.search(rf"\b{n}\(", text)}
1574
+ if self.bsw:
1575
+ reads |= self.read_in(text, out.name)
1576
+ writes = {out.name: "partial" if lvl.form == "step2" else "full"}
1577
+ self.full_out[out.name] = lvl.form != "step2"
1578
+ scal_reads = {p for p in self.params()
1579
+ if re.search(rf"\b{p}\b", text)}
1580
+ scal_writes = {red.var for red in reds} | {flag}
1581
+ head = Group({"par_thread0": ("target", "parallel"),
1582
+ "single": ("target", "parallel"),
1583
+ "masked": ("target", "parallel"),
1584
+ "teams_team0": ("target", "teams"),
1585
+ "teams_team0_pardo": ("target", "teams")}.get(
1586
+ shape, ("target",)))
1587
+ tcl = self.target_clauses(head, reads, writes, scal_reads,
1588
+ scal_writes, set(), temps)
1589
+ if head.has("parallel") and self.coin(0.3):
1590
+ tcl.append(f"num_threads({r.choice((1, 4, 64, 256))})")
1591
+ self.feat("clause:num_threads")
1592
+ if head.has("teams") and self.coin(0.3):
1593
+ tcl.append(f"num_teams({r.choice((1, 3, 8))})")
1594
+ self.feat("clause:num_teams")
1595
+ if head.has("parallel") and temps and self.coin(0.5):
1596
+ tcl.append(f"private({', '.join(temps)})")
1597
+ temps = []
1598
+ if head.has("parallel") and self.coin(0.2):
1599
+ tcl.append("private(i)")
1600
+ self.feat("clause:private:loop_variable")
1601
+ b, c = ind + " ", ind + " "
1602
+ seq = [lvl.header()] + [" " + s for s in body] + ["end do"]
1603
+ fl = self.flag_stmt(flag)
1604
+ lines = wrap_directive(ind, head.key, tcl)
1605
+ if shape == "par_thread0":
1606
+ self.api.add("omp_get_thread_num")
1607
+ lines += [f"{b}if (omp_get_thread_num() == 0) then", c + fl]
1608
+ lines += [c + s for s in seq] + [f"{b}end if"]
1609
+ elif shape == "single":
1610
+ lines += [f"{b}!$omp single", c + fl] + [c + s for s in seq]
1611
+ lines.append(f"{b}!$omp end single"
1612
+ + (" nowait" if self.coin(0.3) else ""))
1613
+ elif shape == "masked":
1614
+ lines.append(f"{b}!$omp masked"
1615
+ + (" filter(0)" if self.coin(0.4) else ""))
1616
+ lines += [c + fl] + [c + s for s in seq] + [f"{b}!$omp end masked"]
1617
+ elif shape == "split_par_thread0":
1618
+ self.api.add("omp_get_thread_num")
1619
+ pcl = []
1620
+ if self.coin(0.3):
1621
+ pcl.append(f"num_threads({r.choice((2, 8, 64))})")
1622
+ if temps and self.coin(0.5):
1623
+ pcl.append(f"private({', '.join(temps)})")
1624
+ lines += wrap_directive(b, "parallel", pcl)
1625
+ lines += [f"{c}if (omp_get_thread_num() == 0) then",
1626
+ c + " " + fl] + [c + " " + s for s in seq]
1627
+ lines += [f"{c}end if", f"{b}!$omp end parallel"]
1628
+ elif shape == "teams_team0":
1629
+ self.api |= {"omp_get_team_num", "omp_get_thread_num"}
1630
+ lines += [f"{b}if (omp_get_team_num() == 0) then",
1631
+ f"{c}!$omp parallel",
1632
+ f"{c} if (omp_get_thread_num() == 0) {fl}",
1633
+ f"{c}!$omp end parallel"]
1634
+ lines += [c + s for s in seq] + [f"{b}end if"]
1635
+ elif shape == "teams_team0_pardo":
1636
+ self.api.add("omp_get_team_num")
1637
+ lines.append(f"{b}if (omp_get_team_num() == 0) then")
1638
+ pcl = [f"reduction({red.op}: {red.var})" for red in reds]
1639
+ if temps:
1640
+ pcl.append(f"private({', '.join(temps)})")
1641
+ lines += wrap_directive(c, "parallel do", pcl)
1642
+ first = lvl.first()
1643
+ lines += [c + seq[0], f"{c} if (i == {first}) {fl}"]
1644
+ lines += [c + s for s in seq[1:]] + [f"{b}end if"]
1645
+ self.feat("dir:parallel do")
1646
+ else: # target_seq
1647
+ lines += [b + fl] + [b + s for s in seq]
1648
+ lines.append(f"{ind}!$omp end {head.key}")
1649
+ self.kdesc.append(f"guard: {shape}")
1650
+ self.feat("kernel:guard", f"guard:{shape}", f"dir:{head.key}")
1651
+ self.check_items.append(out.name)
1652
+ return Kern(lines, reads | scal_reads, set(writes) | scal_writes)
1653
+
1654
+ # -- the phase kernel --
1655
+
1656
+ def k_phase(self, ind: str) -> Kern:
1657
+ r = self.r
1658
+ out = self.new_array(f"o{self.k}", 1, "output")
1659
+ scr = self.new_array(f"s{self.k}", 1, "scratch")
1660
+ readable = self.readable(out.name)
1661
+ iv = {"i": "n"}
1662
+ e1 = self.bounded(self.expr(3, self.leaves(iv, readable)))
1663
+ for i in range(1, self.n + 1):
1664
+ self.env["i"] = i
1665
+ self.arrs[scr.name][(i,)] = e1.ev(self.env, self.arrs)
1666
+ lv2 = self.leaves(iv, readable) + [
1667
+ ARef(scr.name, (self.index("n", iv),)) for _ in range(3)]
1668
+ e2 = self.bounded(self.expr(3, lv2))
1669
+ if scr.name not in e2.f():
1670
+ e2 = Bin("+", e2, ARef(scr.name, (self.index("n", iv),)))
1671
+ reds = [self.new_red(0, "clause")] if self.coin(0.4) else []
1672
+ terms = [self.red_term(red.op, lv2) for red in reds]
1673
+ for i in range(1, self.n + 1):
1674
+ self.env["i"] = i
1675
+ self.arrs[out.name][(i,)] = e2.ev(self.env, self.arrs)
1676
+ for red, ce in zip(reds, terms):
1677
+ self.env[red.var] = red_apply(red.op, self.env[red.var],
1678
+ ce.ev(self.env, self.arrs))
1679
+ flag = self.new_flag()
1680
+ text = "\n".join([e1.f(), e2.f()] + [t.f() for t in terms])
1681
+ reads = {n for n in readable if re.search(rf"\b{n}\(", text)}
1682
+ if self.bsw:
1683
+ reads |= self.read_in(text, out.name)
1684
+ writes = {out.name: "full", scr.name: "scratch"}
1685
+ scal_reads = {p for p in self.params()
1686
+ if re.search(rf"\b{p}\b", text)}
1687
+ scal_writes = {red.var for red in reds} | {flag}
1688
+ split = self.coin(0.3)
1689
+ head = Group(("target",) if split else ("target", "parallel"))
1690
+ tcl = self.target_clauses(head, reads, writes, scal_reads,
1691
+ scal_writes, set())
1692
+ pcl = []
1693
+ if self.coin(0.3):
1694
+ pcl.append(f"num_threads({r.choice((1, 2, 4, 64))})")
1695
+ self.feat("clause:num_threads")
1696
+ if split:
1697
+ lines = wrap_directive(ind, "target", tcl)
1698
+ lines += wrap_directive(ind + " ", "parallel", pcl)
1699
+ b = ind + " "
1700
+ else:
1701
+ lines = wrap_directive(ind, "target parallel", tcl + pcl)
1702
+ b = ind + " "
1703
+ nowait = self.coin(0.4)
1704
+ d1 = r.choice(("do", "do", "do simd"))
1705
+ c1 = ([f"schedule(static, {r.choice((1, 4))})"]
1706
+ if self.coin(0.4) else [])
1707
+ lines += wrap_directive(b, d1, c1)
1708
+ lines += [f"{b}do i = 1, n"] + wrap_stmt(b + " ",
1709
+ f"{scr.name}(i) = {e1.f()}")
1710
+ lines += [f"{b}end do", f"{b}!$omp end {d1}"
1711
+ + (" nowait" if nowait else "")]
1712
+ if nowait:
1713
+ lines.append(f"{b}!$omp barrier")
1714
+ self.feat("phase:nowait_barrier")
1715
+ d2 = r.choice(("do", "do", "loop", "do simd"))
1716
+ c2 = [f"reduction({red.op}: {red.var})" for red in reds]
1717
+ if d2 == "loop" and self.coin(0.5):
1718
+ c2.append("bind(parallel)")
1719
+ elif d2 != "loop" and self.coin(0.3):
1720
+ c2.append(f"schedule({r.choice(('dynamic', 'guided', 'static'))}"
1721
+ ", 3)")
1722
+ lines += wrap_directive(b, d2, c2) + [f"{b}do i = 1, n"]
1723
+ lines += wrap_stmt(b + " ", f"{out.name}(i) = {e2.f()}")
1724
+ for red, ce in zip(reds, terms):
1725
+ lines += [b + " " + s for s in self.red_lines(red, ce)]
1726
+ lines += [f"{b}end do", f"{b}!$omp end {d2}"]
1727
+ mark = r.choice(("masked", "single"))
1728
+ lines += [f"{b}!$omp {mark}", f"{b} {self.flag_stmt(flag)}",
1729
+ f"{b}!$omp end {mark}"]
1730
+ if split:
1731
+ lines += [f"{ind} !$omp end parallel", f"{ind}!$omp end target"]
1732
+ else:
1733
+ lines.append(f"{ind}!$omp end target parallel")
1734
+ self.kdesc.append(f"phase: {head.key}{' / parallel' if split else ''}"
1735
+ f" {d1} / {d2}")
1736
+ self.feat("kernel:phase", f"dir:{head.key}", f"phase:{d1}",
1737
+ f"phase:{d2}", f"phase:{mark}")
1738
+ self.check_items.append(out.name)
1739
+ return Kern(lines, reads | scal_reads, set(writes) | scal_writes)
1740
+
1741
+ # -- the in_reduction kernel --
1742
+
1743
+ def k_inred(self, ind: str) -> Kern:
1744
+ out = self.new_array(f"o{self.k}", 1, "output")
1745
+ readable = self.readable(out.name)
1746
+ inner_par = self.coin(0.4)
1747
+ red = self.new_red(0, "clause" if inner_par else "plain",
1748
+ ops=("+", "*")) # FLANG_FALSE_REJECTS
1749
+ temps: list[str] = []
1750
+ body, step = self.point({"i": "n"}, out, (Var("i"),), [red], [],
1751
+ temps, False, readable)
1752
+ self.run_points([Level("i", "n", "up")], step, parallel=inner_par)
1753
+ flag = self.new_flag()
1754
+ text = "\n".join(body)
1755
+ reads = {n for n in readable if re.search(rf"\b{n}\(", text)}
1756
+ if self.bsw:
1757
+ reads |= self.read_in(text, out.name)
1758
+ scal_reads = {p for p in self.params()
1759
+ if re.search(rf"\b{p}\b", text)}
1760
+ g = Group(("target",))
1761
+ tcl = self.target_clauses(g, reads, {out.name: "full"}, scal_reads,
1762
+ {flag}, set(), temps)
1763
+ tcl.append(f"in_reduction({red.op}: {red.var})")
1764
+ b = ind + " "
1765
+ lines = [f"{ind}!$omp taskgroup task_reduction({red.op}: {red.var})"]
1766
+ lines += wrap_directive(b, "target", tcl)
1767
+ lines.append(f"{b} {self.flag_stmt(flag)}")
1768
+ if inner_par:
1769
+ pcl = [f"reduction({red.op}: {red.var})"]
1770
+ if temps:
1771
+ pcl.append(f"private({', '.join(temps)})")
1772
+ lines += wrap_directive(b + " ", "parallel do", pcl)
1773
+ self.feat("dir:parallel do")
1774
+ lines += [f"{b} do i = 1, n"] + [f"{b} {s}" for s in body]
1775
+ lines += [f"{b} end do", f"{b}!$omp end target",
1776
+ f"{ind}!$omp end taskgroup"]
1777
+ self.kdesc.append("inred: taskgroup task_reduction / target "
1778
+ "in_reduction" + (" / parallel do" if inner_par
1779
+ else ""))
1780
+ self.feat("kernel:inred", "clause:in_reduction",
1781
+ f"red:in_reduction:{red.op}", "dir:target",
1782
+ "dir:taskgroup")
1783
+ self.check_items.append(out.name)
1784
+ return Kern(lines, reads | scal_reads, {out.name, red.var, flag})
1785
+
1786
+ # -- the whole program --
1787
+
1788
+ def kernel(self, flavor: str, ind: str) -> Kern:
1789
+ """One kernel, redrawn (from the same stream) until its model stays
1790
+ in range."""
1791
+ snap = self.snapshot()
1792
+ for _ in range(60):
1793
+ try:
1794
+ kern = getattr(self, f"k_{flavor}")(ind)
1795
+ for name in kern.writes:
1796
+ if self.env.get("_abs_" + name, 0) >= LIMIT:
1797
+ raise Overflow(name)
1798
+ a = self.arrays.get(name)
1799
+ if a is not None and a.type != "integer":
1800
+ for v in self.arrs[name].values():
1801
+ contributions(a.type, v)
1802
+ elif name in self.tscalars:
1803
+ contributions(self.tscalars[name][0],
1804
+ self.env[name])
1805
+ return kern
1806
+ except Overflow:
1807
+ self.restore(snap)
1808
+ raise RuntimeError(f"seed {self.seed}: no in-range kernel")
1809
+
1810
+ def snapshot(self):
1811
+ return ({k: dict(v) for k, v in self.arrs.items()}, dict(self.env),
1812
+ dict(self.arrays), set(self.features), list(self.flags),
1813
+ list(self.check_items), set(self.api), dict(self.scalars),
1814
+ dict(self.logicals), self.uses_dev, list(self.kdesc),
1815
+ dict(self.pmode), dict(self.tscalars), dict(self.tbound),
1816
+ dict(self.spell), self.cur_out, dict(self.ptrs),
1817
+ dict(self.full_out))
1818
+
1819
+ def restore(self, snap) -> None:
1820
+ (arrs, env, arrays, feats, flags, items, api, scal, logi, dev,
1821
+ kd, pm, tsc, tb, sp, co, pt, fo) = snap
1822
+ self.ptrs, self.full_out = dict(pt), dict(fo)
1823
+ self.tscalars, self.tbound, self.spell = dict(tsc), dict(tb), dict(sp)
1824
+ self.cur_out = co
1825
+ self.pmode = dict(pm)
1826
+ self.arrs = {k: dict(v) for k, v in arrs.items()}
1827
+ self.env, self.arrays = dict(env), dict(arrays)
1828
+ self.features, self.flags = set(feats), list(flags)
1829
+ self.check_items, self.api = list(items), set(api)
1830
+ self.scalars, self.logicals = dict(scal), dict(logi)
1831
+ self.uses_dev, self.kdesc = dev, list(kd)
1832
+
1833
+ def build(self) -> FuzzProgram:
1834
+ r = self.r
1835
+ self.setup()
1836
+ nk = r.choice((1, 1, 2, 2, 3, 4))
1837
+ flavors = r.choices(("loop", "guard", "phase", "inred"),
1838
+ (10, 4 * self.on("guard"), 2 * self.on("phase"),
1839
+ 2 * self.on("inred")), k=nk)
1840
+ wrapper = r.choice(("data", "enter")) if self.sw("wrapper", 0.7) \
1841
+ else "none"
1842
+ nowait = nk >= 2 and self.sw("nowait", 0.5)
1843
+ self.in_data = wrapper != "none"
1844
+ ind = " " if wrapper == "data" else " "
1845
+ kerns: list[Kern] = []
1846
+ updated = False
1847
+ for flavor in flavors:
1848
+ self.k += 1
1849
+ if wrapper != "none" and not updated and self.k > 1 and \
1850
+ self.coin(0.4):
1851
+ kerns.append(self.host_update(ind))
1852
+ updated = True
1853
+ kerns.append(self.kernel(flavor, ind))
1854
+ if self.bon("al_proc") and not nowait:
1855
+ for kern in kerns:
1856
+ if not kern.host and self.rb.random() < 0.6:
1857
+ kern.lines = self.wrap_in_procedure(kern, ind)
1858
+ body: list[str] = []
1859
+ pending = False
1860
+ for kern in kerns:
1861
+ plain = kern.host or kern.lines[0].lstrip().startswith(
1862
+ "!$omp taskgroup")
1863
+ if nowait and not plain:
1864
+ body += self.with_nowait(kern)
1865
+ pending = True
1866
+ continue
1867
+ if pending:
1868
+ body.append(f"{ind}!$omp taskwait")
1869
+ pending = False
1870
+ body += kern.lines
1871
+ if pending:
1872
+ body.append(f"{ind}!$omp taskwait")
1873
+ arrs = sorted(a.name for a in self.arrays.values()
1874
+ if a.role in ("input", "output"))
1875
+ ins = [a for a in arrs if self.arrays[a].role == "input"]
1876
+ outs = [a for a in arrs if a not in ins]
1877
+ if self.dvars: # structures are mapped whole by the wrapper
1878
+ outs = sorted({self.var_of(a) for a in outs})
1879
+ ins = sorted({self.var_of(a) for a in ins} - set(outs))
1880
+ if self.bsw and self.dtv:
1881
+ outs = [a for a in outs if a not in self.dtv]
1882
+ ins = [a for a in ins if a not in self.dtv]
1883
+ if wrapper == "data":
1884
+ cl = [f"map(to: {', '.join(ins)})"] + (
1885
+ [f"map(tofrom: {', '.join(outs)})"] if outs else [])
1886
+ body = wrap_directive(" ", "target data", cl) + body + \
1887
+ [" !$omp end target data"]
1888
+ self.feat("wrap:target_data")
1889
+ elif wrapper == "enter":
1890
+ enter = [f"map(to: {', '.join(ins + outs)})"]
1891
+ ex = ([f"map(from: {', '.join(outs)})"] if outs else []) + [
1892
+ f"map({r.choice(('release', 'delete'))}: {', '.join(ins)})"]
1893
+ body = wrap_directive(" ", "target enter data", enter) + body \
1894
+ + wrap_directive(" ", "target exit data", ex)
1895
+ self.feat("wrap:enter_exit_data")
1896
+ expected = self.checksum()
1897
+ src = self.source(body, expected)
1898
+ if self.gen_version == "fuzz-4s50":
1899
+ src = spell50(src)
1900
+ return FuzzProgram(self.seed, src, expected,
1901
+ frozenset(self.features), tuple(self.kdesc),
1902
+ len(self.flags), self.gen_version, self.base)
1903
+
1904
+ def host_update(self, ind: str) -> Kern:
1905
+ """The host changes an input inside the data region and updates
1906
+ the device copy (5.2 §13.9)."""
1907
+ name = self.r.choice(("ia", "ib"))
1908
+ if self.dvars:
1909
+ name = self.rb.choice([name] + [
1910
+ a.name for a in self.arrays.values() if a.var and
1911
+ a.role == "input" and a.rank and a.type == "integer"
1912
+ and "(@)" not in a.name])
1913
+ if name != "ia" and name != "ib":
1914
+ self.feat("base:dt:target_update_component")
1915
+ c = self.r.randint(1, 9)
1916
+ if self.bon("al_stride_update") and self.rb.random() < 0.6:
1917
+ # only the odd elements change: a strided section is enough
1918
+ for t in self.arrs[name]:
1919
+ if t[0] % 2 == 1:
1920
+ self.arrs[name][t] += c
1921
+ self.feat("wrap:host_update_to", "base:al:strided_update")
1922
+ return Kern([f"{ind}do i = 1, n, 2",
1923
+ f"{ind} {name}(i) = {name}(i) + {c}",
1924
+ f"{ind}end do",
1925
+ f"{ind}!$omp target update to({name}(1:n:2))"],
1926
+ set(), set(), host=True)
1927
+ for t in self.arrs[name]:
1928
+ self.arrs[name][t] += c
1929
+ self.feat("wrap:host_update_to")
1930
+ return Kern([f"{ind}do i = 1, n", f"{ind} {name}(i) = {name}(i) + {c}",
1931
+ f"{ind}end do", f"{ind}!$omp target update to({name})"],
1932
+ set(), set(), host=True)
1933
+
1934
+ def with_nowait(self, kern: Kern) -> list[str]:
1935
+ """The kernel's target directive with nowait and depend clauses
1936
+ (5.2 §13.8, §15.9.5); a taskwait follows the sequence. A variable
1937
+ the kernel only reads is depend(in) when the target maps it to or
1938
+ firstprivate; else (an implicit or tofrom map copies it back) it is
1939
+ depend(inout), so no two tasks touch it concurrently."""
1940
+ text = []
1941
+ for line in kern.lines:
1942
+ text.append(line)
1943
+ if not line.rstrip().endswith("&"):
1944
+ break
1945
+ head = " ".join(text)
1946
+ only_in = set(map_items(head, ("to",))) | set(
1947
+ x for c in re.findall(r"firstprivate\(([^)]*)\)", head)
1948
+ for x in re.split(r"\s*,\s*", c.strip()))
1949
+ ro = kern.reads - kern.writes
1950
+ ins = sorted(ro & only_in)
1951
+ outs = sorted(kern.writes | (ro - only_in))
1952
+ if self.dvars:
1953
+ ins, outs = self.struct_depend(set(kern.reads), set(kern.writes),
1954
+ head)
1955
+ extra = ["nowait"]
1956
+ if self.bon("al_depend_section"):
1957
+ def sec(x):
1958
+ a = self.arrays.get(x)
1959
+ if a is not None and not a.var and a.rank == 1 and \
1960
+ self.rb.random() < 0.5:
1961
+ self.feat("base:al:depend_section")
1962
+ return f"{x}(1:n)" if self.rb.random() < 0.5 else \
1963
+ f"{x}(:)"
1964
+ return x
1965
+ ins, outs = [sec(x) for x in ins], [sec(x) for x in outs]
1966
+ if ins:
1967
+ extra.append(f"depend(in: {', '.join(ins)})")
1968
+ if outs:
1969
+ extra.append(f"depend({self.r.choice(('out', 'inout'))}: "
1970
+ f"{', '.join(outs)})")
1971
+ self.feat("tasking:nowait_depend")
1972
+ return add_clauses(kern.lines, extra)
1973
+
1974
+ def checksum(self) -> int:
1975
+ cs = 0
1976
+ for item in self.check_items:
1977
+ if item in self.arrays:
1978
+ typ = self.arrays[item].type
1979
+ for t in self.points(self.arrays[item]):
1980
+ for c in contributions(typ, self.arrs[item][t]):
1981
+ cs = (cs * 31 + c) % CHECK_MOD
1982
+ elif item in self.tscalars:
1983
+ for c in contributions(self.tscalars[item][0],
1984
+ self.env[item]):
1985
+ cs = (cs * 31 + c) % CHECK_MOD
1986
+ else:
1987
+ cs = (cs * 31 + self.env[item]) % CHECK_MOD
1988
+ return cs
1989
+
1990
+ def source(self, body: list[str], expected: int) -> str:
1991
+ L = ["! Generated by compliance.fuzz (OpenMP 5.2, free-form "
1992
+ "Fortran). Do not edit.",
1993
+ f"! generator: {self.gen_version}",
1994
+ f"! seed: {self.seed}",
1995
+ f"! expected checksum: {expected}",
1996
+ f"! host-execution flags: {', '.join(self.flags) or 'none'}"]
1997
+ if self.v >= 3:
1998
+ bf = sorted(f[5:] for f in self.features
1999
+ if f.startswith("base:") and
2000
+ not f.startswith("base:group:"))
2001
+ L.append(f"! base groups: {', '.join(self.base) or 'none'}")
2002
+ L += [f"! base features: {x}" for x in _chunks(bf, 90)] or \
2003
+ ["! base features: none"]
2004
+ L += [f"! kernel {k + 1}: {d}" for k, d in enumerate(self.kdesc)]
2005
+ if self.bsw:
2006
+ L += self.dc_module_lines()
2007
+ if self.ofuncs:
2008
+ L += self.oop_module_lines()
2009
+ if self.funcs:
2010
+ L += ["module fuzz_mod", " implicit none", "contains"]
2011
+ for fn in self.funcs:
2012
+ args = ", ".join(fn.params)
2013
+ L += [f" integer function {fn.name}({args})",
2014
+ " !$omp declare target",
2015
+ f" integer, intent(in) :: {args}"]
2016
+ L += wrap_stmt(" ", f"{fn.name} = {fn.body.f()}")
2017
+ L.append(f" end function {fn.name}")
2018
+ L.append("end module fuzz_mod")
2019
+ self.feat("declare_target_function")
2020
+ L.append("program fuzz_prog")
2021
+ if self.api:
2022
+ L.append(f" use omp_lib, only: {', '.join(sorted(self.api))}")
2023
+ if self.funcs:
2024
+ L.append(" use fuzz_mod, only: "
2025
+ + ", ".join(f.name for f in self.funcs))
2026
+ if self.bsw and any(ln == "module fuzz_dmod" for ln in L):
2027
+ L.append(" use fuzz_dmod")
2028
+ if self.bsw and self.dfuncs:
2029
+ L.append(" use fuzz_dfun, only: "
2030
+ + ", ".join(f.name for f in self.dfuncs))
2031
+ if self.ofuncs:
2032
+ L.append(" use fuzz_omod, only: "
2033
+ + ", ".join(f.name for f in self.ofuncs))
2034
+ if self.bsw and self.mt_funcs:
2035
+ L += self.mt_use_lines()
2036
+ L += [" implicit none"]
2037
+ if self.bsw and self.mt_funcs:
2038
+ L += self.mt_interface_lines()
2039
+ L += [f" integer, parameter :: n = {self.n}, m = {self.m}"]
2040
+ L += self.dt_decl_lines()
2041
+ for a in self.arrays.values():
2042
+ if a.type != "integer" or a.var or (self.bsw and
2043
+ a.name in self.dtv):
2044
+ continue
2045
+ tgt = self.decl_attrs(a.name) if self.bsw else ""
2046
+ if a.rank == 0: # an allocatable scalar (fuzz-3)
2047
+ L.append(f" integer{', allocatable' if a.alloc else ''}"
2048
+ f" :: {a.name}")
2049
+ elif self.bsw and a.name in self.ptrs:
2050
+ L.append(f" integer, pointer :: {a.name}"
2051
+ f"({':' if a.rank == 1 else ':, :'})")
2052
+ elif a.alloc:
2053
+ L.append(f" integer, allocatable{tgt} :: {a.name}"
2054
+ f"({':' if a.rank == 1 else ':, :'})")
2055
+ else:
2056
+ L.append(f" integer{tgt} :: {a.name}"
2057
+ f"({'n' if a.rank == 1 else 'n, m'})")
2058
+ L += self.typed_decl_lines()
2059
+ if self.bsw:
2060
+ L += self.alloc_decl_lines()
2061
+ text = "\n".join(body)
2062
+ temps = sorted(set(re.findall(r"\b((?:t|acc)\d+)\b", text)))
2063
+ names = ["i", "j", "jj"] + list(self.scalars) + temps + (
2064
+ ["dev"] if self.uses_dev else [])
2065
+ L.append(f" integer :: {', '.join(names)}")
2066
+ if self.logicals:
2067
+ L.append(f" logical :: {', '.join(self.logicals)}")
2068
+ L.append(" integer(8) :: cs")
2069
+ for a in self.arrays.values():
2070
+ if a.alloc and not a.var and a.rank:
2071
+ L.append(f" allocate({a.name}"
2072
+ f"({'n' if a.rank == 1 else 'n, m'}))")
2073
+ if self.bsw:
2074
+ L += self.alloc_setup_lines()
2075
+ for name in ("ia", "ib"):
2076
+ L += [" do i = 1, n", f" {self.inits[name]}", " end do"]
2077
+ L += [" do j = 1, m", " do i = 1, n", f" {self.inits['ic']}",
2078
+ " end do", " end do"]
2079
+ typed_in = [a.name for a in self.arrays.values()
2080
+ if a.name not in ("ia", "ib", "ic") and a.role == "input"
2081
+ and a.name in self.inits]
2082
+ if typed_in:
2083
+ arr = [x for x in typed_in if self.arrays[x].rank]
2084
+ if arr:
2085
+ L.append(" do i = 1, n")
2086
+ for name in arr:
2087
+ L += wrap_stmt(" ", self.inits[name])
2088
+ L.append(" end do")
2089
+ L += [f" {self.inits[x]}" for x in typed_in
2090
+ if not self.arrays[x].rank]
2091
+ L += [f" {self.whole_text(a.name)} = "
2092
+ f"{self.typed_zero_text(a.type) if a.type != 'integer' else 0}"
2093
+ for a in self.arrays.values() if a.role != "input"]
2094
+ L += [f" {k} = {v}" for k, v in self.scalars.items()]
2095
+ L += [f" {k} = {self.typed_value_text(t, v)}"
2096
+ for k, (t, v) in self.tscalars.items()]
2097
+ L += [f" {k} = {'.true.' if v else '.false.'}"
2098
+ for k, v in self.logicals.items()]
2099
+ if self.uses_dev:
2100
+ L.append(" dev = omp_get_default_device()")
2101
+ if self.bsw:
2102
+ L += self.dc_setup_lines()
2103
+ body = body + self.dc_final_lines()
2104
+ L += [" ! fuzz: kernels"] + body + [" ! fuzz: checksum", " cs = 0"]
2105
+ for item in self.check_items:
2106
+ add = (f"cs = modulo(cs * 31_8 + int({{}}, 8), {CHECK_MOD}_8)")
2107
+ typ = self.arrays[item].type if item in self.arrays else \
2108
+ self.tscalars[item][0] if item in self.tscalars else \
2109
+ "integer"
2110
+ if typ != "integer":
2111
+ addt = f"cs = modulo(cs * 31_8 + {{}}, {CHECK_MOD}_8)"
2112
+ if item not in self.arrays:
2113
+ L += [" " + addt.format(x)
2114
+ for x in checksum_terms(typ, item)]
2115
+ elif self.arrays[item].rank == 1:
2116
+ L += [" do i = 1, n"] + [
2117
+ " " + addt.format(x)
2118
+ for x in checksum_terms(typ, self.check_ref(item, "i"))
2119
+ ] + [" end do"]
2120
+ else:
2121
+ L += [" do j = 1, m", " do i = 1, n"] + [
2122
+ " " + addt.format(x)
2123
+ for x in checksum_terms(
2124
+ typ, self.check_ref(item, "i, j"))] + \
2125
+ [" end do", " end do"]
2126
+ elif item not in self.arrays:
2127
+ L.append(" " + add.format(item))
2128
+ elif self.arrays[item].rank == 1:
2129
+ L += [" do i = 1, n",
2130
+ " " + add.format(self.check_ref(item, "i")),
2131
+ " end do"]
2132
+ else:
2133
+ L += [" do j = 1, m", " do i = 1, n",
2134
+ " " + add.format(self.check_ref(item, "i, j")),
2135
+ " end do", " end do"]
2136
+ host = f"max({', '.join(self.flags)}, 0)" if self.flags else "0"
2137
+ L += [f" print '(a,i0,a,i0)', 'RESULT checksum=', cs, "
2138
+ f"' ran_on_host=', {host}"]
2139
+ if self.bsw and self.procs:
2140
+ L.append("contains")
2141
+ for proc in self.procs:
2142
+ L += proc.split("\n")
2143
+ L.append("end program fuzz_prog")
2144
+ if self.bsw and "multitu" in self.base:
2145
+ L = self.as_bundle(L)
2146
+ return "\n".join(L) + "\n"
2147
+
2148
+ def as_bundle(self, L: list[str]) -> list[str]:
2149
+ """The single-file program L as a bundle of files (stage 5): the
2150
+ stage-5 units before the main program, a FILE_MARK line before
2151
+ every program unit."""
2152
+ from offload.engine.fuzz_base import FILE_MARK
2153
+ k = L.index("program fuzz_prog")
2154
+ units = []
2155
+ for name, lines in self.mt_unit_lines():
2156
+ units += [FILE_MARK + name] + lines
2157
+ out = []
2158
+ for i, ln in enumerate(L[:k]):
2159
+ m = re.match(r"(?:module|submodule \(\w+\)) (\w+)$", ln)
2160
+ if m and not ln.startswith("module procedure"):
2161
+ out.append(f"{FILE_MARK}{m.group(1)}.f90")
2162
+ out.append(ln)
2163
+ return out + units + [FILE_MARK + "fuzz_prog.f90"] + L[k:]
2164
+
2165
+
2166
+ def map_items(text: str, types: tuple) -> list[str]:
2167
+ """Base names of the list items of map clauses in `text` whose map
2168
+ type is one of `types`."""
2169
+ out = []
2170
+ for m in re.finditer(r"\bmap\(", text):
2171
+ depth, k = 1, m.end()
2172
+ while depth and k < len(text):
2173
+ depth += {"(": 1, ")": -1}.get(text[k], 0)
2174
+ k += 1
2175
+ inner = text[m.end():k - 1]
2176
+ top = re.sub(r"\([^()]*\)", "", inner)
2177
+ if ":" not in top:
2178
+ continue
2179
+ mods, items = top.rsplit(":", 1)
2180
+ mtype = mods.split(",")[-1].strip()
2181
+ if mtype in types:
2182
+ out += [x.strip() for x in items.split(",") if x.strip()]
2183
+ return out
2184
+
2185
+
2186
+ def generate(seed: int, gen_version: str = GEN_VERSION,
2187
+ base: tuple = ()) -> FuzzProgram:
2188
+ """The program of `seed` (deterministic for one generator version and
2189
+ set of base-language groups, offload.engine.fuzz_base; groups need
2190
+ fuzz-3)."""
2191
+ return _Gen(seed, gen_version, tuple(base)).build()
2192
+
2193
+
2194
+ def _chunks(words: list[str], width: int) -> list[str]:
2195
+ out, cur = [], ""
2196
+ for w in words:
2197
+ if cur and len(cur) + 2 + len(w) > width:
2198
+ out.append(cur)
2199
+ cur = w
2200
+ else:
2201
+ cur = f"{cur}, {w}" if cur else w
2202
+ if cur:
2203
+ out.append(cur)
2204
+ return out
2205
+
2206
+
2207
+ class _TrackedArr:
2208
+ def __init__(self, owner, name, data):
2209
+ self.owner, self.name, self.data = owner, name, data
2210
+
2211
+ def __getitem__(self, idx):
2212
+ self.owner.log.setdefault((self.name, idx), set()).add(
2213
+ ("r", self.owner.point))
2214
+ return self.data[idx]
2215
+
2216
+ def __setitem__(self, idx, v):
2217
+ self.owner.log.setdefault((self.name, idx), set()).add(
2218
+ ("w", self.owner.point))
2219
+ self.data[idx] = v
2220
+
2221
+
2222
+ class _Tracked:
2223
+ """The model's arrays with every element access logged by iteration
2224
+ point (fuzz-3 race check of a parallel loop)."""
2225
+
2226
+ def __init__(self, arrs: dict):
2227
+ self.arrs, self.point, self.log = arrs, None, {}
2228
+
2229
+ def __getitem__(self, name):
2230
+ return _TrackedArr(self, name, self.arrs[name])
2231
+
2232
+ def race(self) -> str | None:
2233
+ for (name, idx), acc in sorted(self.log.items(), key=str):
2234
+ writers = {p for k, p in acc if k == "w"}
2235
+ if not writers:
2236
+ continue
2237
+ others = {p for _, p in acc} - writers
2238
+ if len(writers) > 1 or others:
2239
+ return f"{name}{list(idx)} written by {sorted(writers)[:2]}"
2240
+ return None
2241
+
2242
+
2243
+ # --- legality checks ----------------------------------------------------------------
2244
+
2245
+ GFORTRAN = shutil.which("gfortran") or "/usr/tce/bin/gfortran"
2246
+
2247
+
2248
+ @dataclass(frozen=True)
2249
+ class CheckResult:
2250
+ """`stage`: "ok", or the first checker that said no ("scope",
2251
+ "rules", "gfortran", "flang", "defined"), or "error" (a checker could not be run: neither
2252
+ a pass nor a reject)."""
2253
+ stage: str
2254
+ detail: str = ""
2255
+
2256
+ @property
2257
+ def ok(self) -> bool:
2258
+ return self.stage == "ok"
2259
+
2260
+
2261
+ def check_scope(source: str) -> str | None:
2262
+ """None, or why the program is outside the device-offload scope (Task
2263
+ 24, offload.engine.offload_scope): an OpenMP construct outside a target
2264
+ region that is not offload machinery, or a target region sent to the
2265
+ host by a clause. Every generated program is device offload by
2266
+ construction; this keeps it so."""
2267
+ from offload.engine.grammar import GrammarError
2268
+ from offload.engine.offload_scope import host_constructs, host_execution
2269
+ from offload.engine.rules import ProgramError
2270
+ try:
2271
+ found = host_constructs(source, VERSION, "f90")
2272
+ except (GrammarError, ProgramError):
2273
+ return None # check_rules reports the parse error
2274
+ sent = host_execution(source)
2275
+ if not found and not sent:
2276
+ return None
2277
+ return "; ".join(
2278
+ [f"{h.directive} at line {h.line} ({h.why})" for h in found] + sent)
2279
+
2280
+
2281
+ def check_rules(source: str) -> str | None:
2282
+ """None, or why offload.engine.rules rejects the program at 5.2 (a parse
2283
+ error of the grammar or the scanner, or the violated rule ids)."""
2284
+ from offload.engine.grammar import GrammarError
2285
+ from offload.engine.rules import ProgramError, parse_program, violations
2286
+ try:
2287
+ found = violations(parse_program(source, VERSION), VERSION)
2288
+ except (GrammarError, ProgramError) as e:
2289
+ return f"{type(e).__name__}: {str(e).splitlines()[0]}"
2290
+ # The known generator defects are rule violations too
2291
+ found = list(found) + generator_defects(source)
2292
+ return ", ".join(found) or None
2293
+
2294
+
2295
+ @lru_cache(maxsize=None)
2296
+ def _stub_dir() -> str:
2297
+ """A per-process directory with omp_lib.mod built from
2298
+ gen.OMP_LIB_STUB (declarations only; base-language checking)."""
2299
+ from offload.engine.gen import OMP_LIB_STUB
2300
+ d = tempfile.mkdtemp(prefix="fuzz_stub_")
2301
+ (Path(d) / "omp_lib_stub.f90").write_text(OMP_LIB_STUB)
2302
+ subprocess.run([GFORTRAN, "-std=f2008", "-fsyntax-only",
2303
+ "omp_lib_stub.f90"], cwd=d, check=True,
2304
+ capture_output=True, timeout=120)
2305
+ return d
2306
+
2307
+
2308
+ def check_gfortran(source: str) -> str | None:
2309
+ """None, or gfortran's first error for `-std=f2008 -fsyntax-only`
2310
+ without -fopenmp (OpenMP directives are comments)."""
2311
+ with tempfile.TemporaryDirectory(prefix="fuzz_gf_") as d:
2312
+ (Path(d) / "t.f90").write_text(source)
2313
+ res = subprocess.run([GFORTRAN, "-std=f2008", "-fsyntax-only",
2314
+ f"-I{_stub_dir()}", "-J", d, "t.f90"],
2315
+ cwd=d, capture_output=True, text=True,
2316
+ timeout=120)
2317
+ if res.returncode == 0:
2318
+ return None
2319
+ lines = [ln for ln in res.stderr.splitlines() if "Error" in ln]
2320
+ return (lines[0] if lines else res.stderr.strip()[:300]) or \
2321
+ f"rc={res.returncode}"
2322
+
2323
+
2324
+ class CheckerError(Exception):
2325
+ """A checker could not be run (not a verdict on the program)."""
2326
+
2327
+
2328
+ def check_flang(source: str) -> str | None:
2329
+ """None, or AFAR flang's frontend diagnostic (parse + semantic checks
2330
+ at -fopenmp-version=52, the offload.engine.flang_oracle invocation)."""
2331
+ from offload.engine.flang_oracle import MODULE_FLAGS, FlangError, _dump
2332
+ try:
2333
+ _dump(source, VERSION, sema=True, extra_flags=MODULE_FLAGS)
2334
+ except FlangError as e:
2335
+ if e.stage in ("run", "map"):
2336
+ raise CheckerError(str(e))
2337
+ errs = [ln for ln in e.message.splitlines()
2338
+ if re.search(r":\d+:\d+: error:", ln)] or \
2339
+ [ln for ln in e.message.splitlines() if "error:" in ln]
2340
+ return f"{e.stage}: " + (errs[0] if errs else
2341
+ e.message.splitlines()[0])
2342
+ return None
2343
+
2344
+
2345
+ # The definedness check (fuzz-3): the program without OpenMP (sequential
2346
+ # elision's build, offload.engine.expected.run_elided) built by gfortran with
2347
+ # run-time checks, twice with different fills of uninitialised storage
2348
+ # (-finit-* for variables, MALLOC_PERTURB_ for allocated memory). Both
2349
+ # builds must run to a RESULT line (no bounds, pointer, allocation,
2350
+ # floating-point or signed-overflow trap) and print the same value: a
2351
+ # read of undefined storage would differ. With `expected` given, the value
2352
+ # must also be the model's (a self-check of the model).
2353
+ DEFINED_RUNS = (
2354
+ (("-fcheck=all", "-ftrapv", "-ffpe-trap=invalid,zero,overflow",
2355
+ "-finit-integer=-31415", "-finit-real=snan", "-finit-logical=true",
2356
+ "-finit-character=35", "-finit-derived"), {"MALLOC_PERTURB_": "165"}),
2357
+ (("-fcheck=all", "-finit-integer=27182", "-finit-real=zero",
2358
+ "-finit-logical=false", "-finit-character=64", "-finit-derived"),
2359
+ {"MALLOC_PERTURB_": "90"}),
2360
+ )
2361
+
2362
+
2363
+ def check_defined(source: str, expected: int | None = None) -> str | None:
2364
+ """None, or why the definedness check fails (see DEFINED_RUNS)."""
2365
+ from offload.engine import expected as E
2366
+ vals = []
2367
+ for extra, env in DEFINED_RUNS:
2368
+ v, note = E.run_elided(source, "gfortran", extra, env)
2369
+ if v is None:
2370
+ if "build failed" in note:
2371
+ raise CheckerError(note)
2372
+ return f"definedness: {note}"
2373
+ vals.append(v)
2374
+ if len(set(vals)) > 1:
2375
+ return f"definedness: undefined value read ({' vs '.join(vals)})"
2376
+ if expected is not None and vals[0] != f"checksum={expected}":
2377
+ return (f"definedness: the sequential program prints {vals[0]}, "
2378
+ f"the model {expected}")
2379
+ return None
2380
+
2381
+
2382
+ DEFAULT_LEAVES = ("parallel", "teams")
2383
+
2384
+
2385
+ def nested_if_clauses(leaves, clauses) -> list[str]:
2386
+ """The if(<leaf>: x) clauses of a combined construct whose leaf comes
2387
+ after (is nested inside) a leaf that takes a default clause."""
2388
+ leaves = list(leaves)
2389
+ out = []
2390
+ for c in clauses:
2391
+ m = re.match(r"if\((\w+):", c)
2392
+ if not m or m.group(1) not in leaves:
2393
+ continue
2394
+ k = leaves.index(m.group(1))
2395
+ if any(x in DEFAULT_LEAVES for x in leaves[:k]):
2396
+ out.append(c)
2397
+ return out
2398
+
2399
+
2400
+ def generator_defects(source: str) -> list[str]:
2401
+ """Known generator defects of a program, found statically:
2402
+ G1, a default(none) combined construct whose if(<leaf>: x) clause
2403
+ names a leaf nested inside the leaf with default, without x in a
2404
+ data-sharing clause (fuzz-3; fixed in fuzz-4)."""
2405
+ out = []
2406
+ for st in re.findall(r"^[ \t]*!\$omp (?!end\b)[^\n]*(?:\n[ \t]*"
2407
+ r"!\$omp&[^\n]*)*", source, re.M | re.I):
2408
+ st = re.sub(r"&?[ \t]*\n[ \t]*!\$omp&", " ", st).strip()
2409
+ if "default(none)" not in st.lower():
2410
+ continue
2411
+ head = st[6:].lower()
2412
+ leaves = []
2413
+ for w in head.split():
2414
+ if "(" in w:
2415
+ break
2416
+ leaves.append(w)
2417
+ clauses = re.findall(r"\w+\([^()]*(?:\([^()]*\)[^()]*)*\)", head)
2418
+ for c in nested_if_clauses(leaves, clauses):
2419
+ x = re.match(r"if\(\w+:\s*(\w+)\)", c)
2420
+ if x and not re.search(rf"\b(shared|firstprivate|private)\("
2421
+ rf"[^)]*\b{x.group(1)}\b", head):
2422
+ out.append(f"G1: {x.group(1)} in {c} under default(none) of "
2423
+ f"'{' '.join(leaves)}' is not in a data-sharing "
2424
+ "clause (5.2 §17.2 p.340, §5.4.1 p.109)")
2425
+ return out
2426
+
2427
+
2428
+ def is_fuzz3(source: str) -> bool:
2429
+ return re.search(r"^! generator: fuzz-(\d+)", source, re.M) is not None \
2430
+ and int(re.search(r"^! generator: fuzz-(\d+)", source,
2431
+ re.M).group(1)) >= 3
2432
+
2433
+
2434
+ def check(source: str, defined: bool | None = None,
2435
+ expected: int | None = None, scope: bool = True) -> CheckResult:
2436
+ """The scope check (unless `scope` is False: a host-execution rewrite
2437
+ that serves as a reference, offload.engine.expected), the three legality
2438
+ checks, cheapest first, then (fuzz-3: `defined` None means "the header
2439
+ says fuzz-3") the definedness check; the first "no" wins."""
2440
+ if defined is None:
2441
+ defined = is_fuzz3(source)
2442
+ stages = ([("scope", check_scope)] if scope else []) + [
2443
+ ("rules", check_rules), ("gfortran", check_gfortran),
2444
+ ("flang", check_flang)]
2445
+ if defined:
2446
+ stages.append(("defined",
2447
+ lambda src: check_defined(src, expected)))
2448
+ try:
2449
+ for stage, fn in stages:
2450
+ why = fn(source)
2451
+ if why:
2452
+ return CheckResult(stage, why)
2453
+ except (CheckerError, subprocess.SubprocessError, OSError) as e:
2454
+ return CheckResult("error", str(e)[:500])
2455
+ return CheckResult("ok")