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.
- offload/__init__.py +10 -0
- offload/__main__.py +5 -0
- offload/_bundle.py +74 -0
- offload/_root/catalog/acc/claims.yaml +197 -0
- offload/_root/catalog/acc/clauses.yaml +391 -0
- offload/_root/catalog/acc/no_oracle.yaml +89 -0
- offload/_root/catalog/acc/out_of_scope.yaml +17 -0
- offload/_root/catalog/acc/rules.yaml +433 -0
- offload/_root/catalog/acc/semantic_atoms.yaml +27 -0
- offload/_root/catalog/acc/skeleton.yaml +1567 -0
- offload/_root/catalog/acc/spec_overrides.yaml +72 -0
- offload/_root/catalog/later_forms.yaml +76 -0
- offload/_root/catalog/machines.yaml +218 -0
- offload/_root/catalog/omp/claims.yaml +2047 -0
- offload/_root/catalog/omp/clauses.yaml +914 -0
- offload/_root/catalog/omp/derivations.yaml +177 -0
- offload/_root/catalog/omp/memory_modes.yaml +40 -0
- offload/_root/catalog/omp/no_oracle.yaml +373 -0
- offload/_root/catalog/omp/omp50_delta.yaml +377 -0
- offload/_root/catalog/omp/out_of_scope.yaml +64 -0
- offload/_root/catalog/omp/port_equivalence.yaml +352 -0
- offload/_root/catalog/omp/rules.yaml +3131 -0
- offload/_root/catalog/omp/rules_coverage.yaml +9939 -0
- offload/_root/catalog/omp/semantic_atoms.yaml +34 -0
- offload/_root/catalog/omp/skeleton.yaml +9181 -0
- offload/_root/catalog/omp/spec_overrides.yaml +932 -0
- offload/_root/catalog/toolchains.yaml +472 -0
- offload/_root/catalog/vendor_claims_generic.yaml +40925 -0
- offload/_root/data/canuse/b.json +1 -0
- offload/_root/data/canuse/c.json +1 -0
- offload/_root/data/canuse/columns.json +1 -0
- offload/_root/data/canuse/d.json +1 -0
- offload/_root/data/canuse/f.json +1 -0
- offload/_root/data/canuse/index.json +1 -0
- offload/_root/data/canuse/p.json +1 -0
- offload/_root/data/compilers/afar.json +1 -0
- offload/_root/data/compilers/cce19.json +1 -0
- offload/_root/data/compilers/cce20.json +1 -0
- offload/_root/data/compilers/cce21.json +1 -0
- offload/_root/data/compilers/cce21_4.json +1 -0
- offload/_root/data/compilers/gcc.json +1 -0
- offload/_root/data/compilers/gcc_sm80.json +1 -0
- offload/_root/data/compilers/nvhpc.json +1 -0
- offload/_root/data/compilers/nvhpc269.json +1 -0
- offload/_root/data/findings/AUTHORING.md +107 -0
- offload/_root/data/findings/README.md +33 -0
- offload/_root/data/findings/afar-c-error-directive-in-target-link.c +37 -0
- offload/_root/data/findings/afar-c-lastprivate-distribute-parallel-for-small-type.c +56 -0
- offload/_root/data/findings/afar-c-teams-distribute-reduction-first-team.c +59 -0
- offload/_root/data/findings/afar-c-update-iterator-copy-mode.c +45 -0
- offload/_root/data/findings/afar-c-xnack1-target-is-present.c +31 -0
- offload/_root/data/findings/afar-cce19-character-defaultmap.f90 +27 -0
- offload/_root/data/findings/afar-cce19-task-in-target-ice.f90 +23 -0
- offload/_root/data/findings/afar-clang-requires-device-safesync-hang.c +24 -0
- offload/_root/data/findings/afar-flang-firstprivate-map-two-targets.f90 +34 -0
- offload/_root/data/findings/afar-flang-loop-bind-teams-reduction.f90 +27 -0
- offload/_root/data/findings/afar-flang-task-reduction-max.f90 +31 -0
- offload/_root/data/findings/afar-flang-thread-limit-target-parallel-do.f90 +22 -0
- offload/_root/data/findings/afar-linear-ref-omp50.f90 +29 -0
- offload/_root/data/findings/afar-loop-bind-thread-in-teams.f90 +44 -0
- offload/_root/data/findings/afar-nontemporal-assumed-shape-ice.f90 +38 -0
- offload/_root/data/findings/afar-udr-derived-type-link.f90 +41 -0
- offload/_root/data/findings/afar-xnack1-atomic-min-nested-parallel.f90 +53 -0
- offload/_root/data/findings/afar-xnack1-present-not-enforced.f90 +36 -0
- offload/_root/data/findings/afar-xnack1-target-is-present.f90 +47 -0
- offload/_root/data/findings/apps/afar-cce-teams-private-array-nested-parallel-wrong.f90 +100 -0
- offload/_root/data/findings/apps/cce20-device-link-infer-address-spaces-crash.f90 +159 -0
- offload/_root/data/findings/apps/cce21-device-link-agpr-copy-mfma-assert.f90 +343 -0
- offload/_root/data/findings/apps/cce21-private-array-loaded-subscript-wrong.f90 +113 -0
- offload/_root/data/findings/apps/controls/bubble-simple-rddot.f90 +284 -0
- offload/_root/data/findings/apps/controls/bubble-two-substeps.f90 +287 -0
- offload/_root/data/findings/apps/controls/cbc-inline.f90 +97 -0
- offload/_root/data/findings/apps/controls/cbc-integers.f90 +91 -0
- offload/_root/data/findings/apps/controls/cbc-only-density.f90 +97 -0
- offload/_root/data/findings/apps/controls/cbc-only-velocity.f90 +97 -0
- offload/_root/data/findings/apps/controls/gcc-acc-c-tile-control.c +26 -0
- offload/_root/data/findings/apps/controls/gcc-acc-tile-control.f90 +29 -0
- offload/_root/data/findings/apps/controls/private-array-subscript-probes.f90 +45 -0
- offload/_root/data/findings/apps/controls/teams-private-array-read-par.f90 +31 -0
- offload/_root/data/findings/apps/controls/teams-private-array-seq.f90 +30 -0
- offload/_root/data/findings/apps/controls/teams-private-array-shared.f90 +34 -0
- offload/_root/data/findings/apps/controls/teams-private-array-split.f90 +36 -0
- offload/_root/data/findings/apps/controls/teams-private-array-write-par.f90 +31 -0
- offload/_root/data/findings/apps/gcc-acc-c-tile-partial-tiles-wrong.c +60 -0
- offload/_root/data/findings/apps/gcc-acc-tile-partial-tiles-wrong.f90 +64 -0
- offload/_root/data/findings/catalog/afar-c-complex-reduction-link.c +66 -0
- offload/_root/data/findings/catalog/afar-c-critical-hint-link.c +68 -0
- offload/_root/data/findings/catalog/afar-c-ordered-doacross-link.c +62 -0
- offload/_root/data/findings/catalog/afar-c-reduction-task-link.c +81 -0
- offload/_root/data/findings/catalog/afar-flang-absent-optional-target-crash.f90 +76 -0
- offload/_root/data/findings/catalog/afar-flang-critical-target-parallel-wrong.f90 +74 -0
- offload/_root/data/findings/catalog/afar-flang-dist-schedule-chunk.f90 +80 -0
- offload/_root/data/findings/catalog/afar-flang-linear-parallel-ice.f90 +68 -0
- offload/_root/data/findings/catalog/afar-flang-named-critical-link.f90 +67 -0
- offload/_root/data/findings/catalog/afar-flang-ordered-wrong.f90 +78 -0
- offload/_root/data/findings/catalog/afar-flang-reduction-minus-rejected.f90 +77 -0
- offload/_root/data/findings/catalog/afar-flang-reduction-task-ice.f90 +68 -0
- offload/_root/data/findings/catalog/afar-flang-sections-in-target-ice.f90 +67 -0
- offload/_root/data/findings/catalog/afar-flang-workdistribute-ice.f90 +71 -0
- offload/_root/data/findings/catalog/c-allocate-const-mem-firstprivate-wrong.c +79 -0
- offload/_root/data/findings/catalog/cce-acc-allocate-in-compute-crash.f90 +65 -0
- offload/_root/data/findings/catalog/cce-acc-character-dummy-routine-ice.f90 +81 -0
- offload/_root/data/findings/catalog/cce-acc-loop-seq-in-routine-wrong.f90 +81 -0
- offload/_root/data/findings/catalog/cce-acc-stop-in-compute-crash.f90 +62 -0
- offload/_root/data/findings/catalog/cce-allocators-stack-ice.f90 +81 -0
- offload/_root/data/findings/catalog/cce-atomic-default-mem-order-acquire-release-rejected.f90 +61 -0
- offload/_root/data/findings/catalog/cce-c-allocate-align-link.c +83 -0
- offload/_root/data/findings/catalog/cce-c-allocate-allocator-modifier-rejected.c +77 -0
- offload/_root/data/findings/catalog/cce-c-device-type-directive-name-ice.c +70 -0
- offload/_root/data/findings/catalog/cce-c-dist-schedule-chunk.c +81 -0
- offload/_root/data/findings/catalog/cce-c-f-pointer-device-link.f90 +70 -0
- offload/_root/data/findings/catalog/cce-c-lastprivate-parallel-in-seq-loop-wrong.c +64 -0
- offload/_root/data/findings/catalog/cce-c-long-double-ice.c +61 -0
- offload/_root/data/findings/catalog/cce-c-map-iterator-ice.c +92 -0
- offload/_root/data/findings/catalog/cce-c-motion-iterator-rejected.c +68 -0
- offload/_root/data/findings/catalog/cce-c-ordered-doacross-link.c +64 -0
- offload/_root/data/findings/catalog/cce-c-ordered-link.c +77 -0
- offload/_root/data/findings/catalog/cce-c-recursive-function-ice.c +62 -0
- offload/_root/data/findings/catalog/cce-c-reduction-inscan-ice.c +67 -0
- offload/_root/data/findings/catalog/cce-c-reduction-task-link.c +73 -0
- offload/_root/data/findings/catalog/cce-c-sections-in-target-wrong.c +70 -0
- offload/_root/data/findings/catalog/cce-c-single-masked-task-link.c +66 -0
- offload/_root/data/findings/catalog/cce-c-task-in-target-link.c +75 -0
- offload/_root/data/findings/catalog/cce-c-uses-allocators-traits-rejected.c +71 -0
- offload/_root/data/findings/catalog/cce-flang-allocate-const-mem-ice.f90 +67 -0
- offload/_root/data/findings/catalog/cce-flang-allocate-in-target-crash.f90 +68 -0
- offload/_root/data/findings/catalog/cce-flang-lastprivate-parallel-in-seq-loop-wrong.f90 +83 -0
- offload/_root/data/findings/catalog/cce-flang-stop-in-target-crash.f90 +64 -0
- offload/_root/data/findings/catalog/cce-iterator-link.f90 +67 -0
- offload/_root/data/findings/catalog/cce-linear-lastprivate-ice.f90 +69 -0
- offload/_root/data/findings/catalog/cce-nohost-link.f90 +90 -0
- offload/_root/data/findings/catalog/cce-reduction-inscan-ice.f90 +66 -0
- offload/_root/data/findings/catalog/cce-reduction-task-link.f90 +76 -0
- offload/_root/data/findings/catalog/cce19-reduction-task-addrspacecast-ice.f90 +77 -0
- offload/_root/data/findings/catalog/cce20-c-defaultmap-private-storage-rejected.c +85 -0
- offload/_root/data/findings/catalog/cce20-map-self-rejected.f90 +64 -0
- offload/_root/data/findings/catalog/cce21-c-declare-target-local-rejected.c +73 -0
- offload/_root/data/findings/catalog/cce21-c-target-loop-ice.c +77 -0
- offload/_root/data/findings/catalog/defaultmap-present-private-array-abort.f90 +73 -0
- offload/_root/data/findings/catalog/nvhpc-acc-associate-illegal-address.f90 +66 -0
- offload/_root/data/findings/catalog/nvhpc-c-function-pointer-kernel-missing.c +68 -0
- offload/_root/data/findings/catalog/nvhpc-c-long-double-kernel-missing.c +64 -0
- offload/_root/data/findings/catalog/nvhpc-c-static-local-kernel-missing.c +73 -0
- offload/_root/data/findings/catalog/nvhpc-c-vla-kernel-missing.c +63 -0
- offload/_root/data/findings/catalog/nvhpc-flang-type-bound-kernel-missing.f90 +86 -0
- offload/_root/data/findings/cce-acc-init-set-runtime-assert.f90 +35 -0
- offload/_root/data/findings/cce-acc-reduction-200-int8-scalars-wrong.f90 +1278 -0
- offload/_root/data/findings/cce-acc-routine-bind-module-ice.f90 +35 -0
- offload/_root/data/findings/cce-acc-self-condition-ignored.f90 +17 -0
- offload/_root/data/findings/cce-c-dist-schedule-segv.c +34 -0
- offload/_root/data/findings/cce-c-map-delete-refcount.c +47 -0
- offload/_root/data/findings/cce-c-map-present-assert.c +45 -0
- offload/_root/data/findings/cce-c-openmp45-device-link.c +34 -0
- offload/_root/data/findings/cce-c-parallel-for-in-target.c +73 -0
- offload/_root/data/findings/cce-defaultmap-tofrom-explicit-map.f90 +92 -0
- offload/_root/data/findings/cce-mapper-next-map-copy-back.f90 +48 -0
- offload/_root/data/findings/cce-trim-merge-output-one-character.f90 +40 -0
- offload/_root/data/findings/cce-uses-allocators-traits-omp50.f90 +28 -0
- offload/_root/data/findings/cce19-acc-if-false-link.f90 +17 -0
- offload/_root/data/findings/cce19-c-reduction-63-scalars-one-wrong.c +235 -0
- offload/_root/data/findings/cce19-target-parallel-guarded-loop.f90 +35 -0
- offload/_root/data/findings/cce19-target-parallel-single-ice.f90 +38 -0
- offload/_root/data/findings/cce21-alloc-2e32-sum-wrong.f90 +68 -0
- offload/_root/data/findings/cce21-defaultmap-aggregate-flag.f90 +52 -0
- offload/_root/data/findings/cce21-in-reduction-assumed-shape-write-lost.f90 +61 -0
- offload/_root/data/findings/cce21-in-reduction-taskwait-link.f90 +59 -0
- offload/_root/data/findings/cce21-linear-modifier-default-none.f90 +59 -0
- offload/_root/data/findings/clang-c-declare-target-to-omp52.c +50 -0
- offload/_root/data/findings/clang-c-linear-directive-name-hang.c +30 -0
- offload/_root/data/findings/clang-c-map-iterator-omp51.c +51 -0
- offload/_root/data/findings/clang-c-shared-declare-target-combined.c +58 -0
- offload/_root/data/findings/dataenv/cce-value-dummy-target-write-visible.f90 +74 -0
- offload/_root/data/findings/defaultmap-none-loop-variable.f90 +69 -0
- offload/_root/data/findings/fortran-loop-bind-thread-in-parallel.f90 +53 -0
- offload/_root/data/findings/fortran-schedule-static-in-target.f90 +55 -0
- offload/_root/data/findings/fresh/cce-common-block-name-in-map-rejected.f90 +47 -0
- offload/_root/data/findings/fresh/cce-if-stop-in-target-ice-one-condition.f90 +38 -0
- offload/_root/data/findings/fresh/cce-if-stop-in-target-ice.f90 +43 -0
- offload/_root/data/findings/fresh/cce-list-directed-print-in-target-copy-crash.f90 +40 -0
- offload/_root/data/findings/fresh/cce19-acc-automatic-array-copyout-copy-crash.f90 +56 -0
- offload/_root/data/findings/fresh/cce21-combined-if-runtime-expr-loop-skipped.f90 +57 -0
- offload/_root/data/findings/fresh/nvhpc-acc-gang-worker-collapse-nested-vector-reduction-lost.f90 +67 -0
- offload/_root/data/findings/fresh/nvhpc-teams-loop-module-allocatable-assign-fort2-crash.f90 +73 -0
- offload/_root/data/findings/fuzz/1131-afar.f90 +48 -0
- offload/_root/data/findings/fuzz/1391-cce20.f90 +40 -0
- offload/_root/data/findings/fuzz/14-cce20.f90 +36 -0
- offload/_root/data/findings/fuzz/1505-cce20.f90 +88 -0
- offload/_root/data/findings/fuzz/1540-afar.f90 +44 -0
- offload/_root/data/findings/fuzz/158-afar.f90 +63 -0
- offload/_root/data/findings/fuzz/16-cce20.f90 +39 -0
- offload/_root/data/findings/fuzz/1644-cce21.f90 +31 -0
- offload/_root/data/findings/fuzz/165-cce19.f90 +52 -0
- offload/_root/data/findings/fuzz/1749-cce20.f90 +34 -0
- offload/_root/data/findings/fuzz/1936-afar.f90 +61 -0
- offload/_root/data/findings/fuzz/1978-cce19.f90 +41 -0
- offload/_root/data/findings/fuzz/2014-cce19.f90 +46 -0
- offload/_root/data/findings/fuzz/2224-cce19.f90 +30 -0
- offload/_root/data/findings/fuzz/2334-cce19.f90 +57 -0
- offload/_root/data/findings/fuzz/536-cce19.f90 +38 -0
- offload/_root/data/findings/fuzz/591-cce19.f90 +54 -0
- offload/_root/data/findings/fuzz/650-afar.f90 +58 -0
- offload/_root/data/findings/fuzz/698-afar.f90 +68 -0
- offload/_root/data/findings/fuzz/700-afar.f90 +46 -0
- offload/_root/data/findings/fuzz/775-cce21.f90 +33 -0
- offload/_root/data/findings/fuzz/87-afar.f90 +47 -0
- offload/_root/data/findings/fuzz/916-afar.f90 +67 -0
- offload/_root/data/findings/fuzz/958-cce20.f90 +44 -0
- offload/_root/data/findings/fuzz/98-cce19.f90 +40 -0
- offload/_root/data/findings/fuzz/README.md +236 -0
- offload/_root/data/findings/fuzz/b1-121-afar.f90 +47 -0
- offload/_root/data/findings/fuzz/b1-183-afar.f90 +55 -0
- offload/_root/data/findings/fuzz/b1-22-cce20.f90 +38 -0
- offload/_root/data/findings/fuzz/b1-231-afar.f90 +56 -0
- offload/_root/data/findings/fuzz/b1-268-afar.f90 +46 -0
- offload/_root/data/findings/fuzz/b2-183-afar.f90 +57 -0
- offload/_root/data/findings/fuzz/b2-209-cce19.f90 +51 -0
- offload/_root/data/findings/fuzz/b2-213-afar.f90 +63 -0
- offload/_root/data/findings/fuzz/b2-52-afar.f90 +56 -0
- offload/_root/data/findings/fuzz/b2-68-afar.f90 +54 -0
- offload/_root/data/findings/fuzz/b2-85-cce20.f90 +55 -0
- offload/_root/data/findings/fuzz/b3-188-cce19.f90 +90 -0
- offload/_root/data/findings/fuzz/b3-190-cce21.f90 +88 -0
- offload/_root/data/findings/fuzz/b3-197-cce19.f90 +77 -0
- offload/_root/data/findings/fuzz/b3-250-cce20.f90 +89 -0
- offload/_root/data/findings/fuzz/b3-278-cce19.f90 +70 -0
- offload/_root/data/findings/fuzz/b3-45-cce21.f90 +83 -0
- offload/_root/data/findings/fuzz/b3-54-afar.f90 +67 -0
- offload/_root/data/findings/fuzz/b3-61-cce20.f90 +100 -0
- offload/_root/data/findings/fuzz/b3-9-afar.f90 +100 -0
- offload/_root/data/findings/fuzz/b3-9-cce21.f90 +103 -0
- offload/_root/data/findings/fuzz/b3-94-afar.f90 +80 -0
- offload/_root/data/findings/fuzz/b4-39-afar.f90 +141 -0
- offload/_root/data/findings/fuzz/b4-86-cce19.f90 +71 -0
- offload/_root/data/findings/fuzz/controls/gcc-complex-pointer-store-control.f90 +28 -0
- offload/_root/data/findings/fuzz/controls/gcc-declare-reduction-module-control.f90 +29 -0
- offload/_root/data/findings/fuzz/controls/gcc-target-simd-map-nontemporal-control.f90 +21 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-allocatable-component-mapped-control.f90 +22 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-allocatable-component-unreferenced-control.f90 +22 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-default-none-removed-control.f90 +18 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-default-shared-control.f90 +18 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-firstprivate-removed-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-to-scalar-reduction-mapped-control.f90 +17 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-to-scalar-removed-control.f90 +17 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-defaultmap-tofrom-lastprivate-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-depend-explicit-map-control.f90 +22 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-depend-removed-control.f90 +22 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-distribute-end-distribute-control.f90 +16 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-distribute-parallel-num-threads-removed-control.f90 +26 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-distribute-parallel-removed-control.f90 +22 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-distribute-simd-no-end-directive-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-explicit-length-character-dummy-control.f90 +18 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-loop-character-array-value-control.f90 +23 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-loop-character-distribute-control.f90 +20 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-map-always-first-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-map-always-removed-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-num-threads-removed-control.f90 +12 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-firstprivate-dropped-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-single-nowait-control.f90 +13 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-parallel-split-control.f90 +15 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-collapse-split-control.f90 +21 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-end-directive-control.f90 +14 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-no-collapse-control.f90 +19 -0
- offload/_root/data/findings/fuzz/controls/nvhpc-target-simd-split-no-end-directive-control.f90 +15 -0
- offload/_root/data/findings/fuzz/gcc-declare-reduction-module-not-found.f90 +66 -0
- offload/_root/data/findings/fuzz/gcc-strided-target-update-rejected.f90 +58 -0
- offload/_root/data/findings/fuzz/gcc-target-simd-map-nontemporal-rejected.f90 +54 -0
- offload/_root/data/findings/fuzz/nvhpc-allocatable-component-implicit-map-illegal-address.f90 +84 -0
- offload/_root/data/findings/fuzz/nvhpc-assumed-length-character-dummy-map-ice.f90 +69 -0
- offload/_root/data/findings/fuzz/nvhpc-default-none-reduction-lastprivate-fort1-crash.f90 +70 -0
- offload/_root/data/findings/fuzz/nvhpc-defaultmap-firstprivate-lastprivate-ice.f90 +71 -0
- offload/_root/data/findings/fuzz/nvhpc-defaultmap-to-scalar-reduction-lost.f90 +82 -0
- offload/_root/data/findings/fuzz/nvhpc-depend-implicit-map-illegal-address.f90 +81 -0
- offload/_root/data/findings/fuzz/nvhpc-distribute-parallel-num-threads-writes-lost.f90 +79 -0
- offload/_root/data/findings/fuzz/nvhpc-end-distribute-simd-rejected.f90 +70 -0
- offload/_root/data/findings/fuzz/nvhpc-loop-character-achar-unsupported.f90 +75 -0
- offload/_root/data/findings/fuzz/nvhpc-map-always-after-map-to-not-copied-back.f90 +70 -0
- offload/_root/data/findings/fuzz/nvhpc-num-threads-reduction-identity-lost.f90 +54 -0
- offload/_root/data/findings/fuzz/nvhpc-target-parallel-firstprivate-translate-failure.f90 +66 -0
- offload/_root/data/findings/fuzz/nvhpc-target-parallel-single-hang.f90 +68 -0
- offload/_root/data/findings/fuzz/nvhpc-target-simd-collapse-translate-failure.f90 +73 -0
- offload/_root/data/findings/fuzz/nvhpc-target-simd-no-end-directive-rejected.f90 +68 -0
- offload/_root/data/findings/fuzz/par-s1-2082-gcc_g90.f90 +71 -0
- offload/_root/data/findings/fuzz/s1-2370-cce21.f90 +67 -0
- offload/_root/data/findings/fuzz/s1-2592-cce21.f90 +56 -0
- offload/_root/data/findings/fuzz/s1-3463-cce21.f90 +92 -0
- offload/_root/data/findings/fuzz/s1-4339-afar.f90 +79 -0
- offload/_root/data/findings/fuzz/s1-6085-cce21.f90 +96 -0
- offload/_root/data/findings/fuzz/s1-6760-cce20.f90 +65 -0
- offload/_root/data/findings/fuzz/s1-6888-cce21.f90 +76 -0
- offload/_root/data/findings/fuzz/s1-7882-cce20.f90 +63 -0
- offload/_root/data/findings/fuzz/s1-8634-cce21.f90 +45 -0
- offload/_root/data/findings/fuzz/s1-91-cce21.f90 +92 -0
- offload/_root/data/findings/fuzz/s1-9443-afar.f90 +59 -0
- offload/_root/data/findings/fuzz/s1-9914-cce19.f90 +78 -0
- offload/_root/data/findings/gcc/controls/gcc-acc-c-detach-control.c +34 -0
- offload/_root/data/findings/gcc/controls/gcc-acc-detach-control.f90 +26 -0
- offload/_root/data/findings/gcc/controls/gcc-defaultmap-to-pointer-control.f90 +31 -0
- offload/_root/data/findings/gcc/controls/gcc-target-in-task-control.c +26 -0
- offload/_root/data/findings/gcc/controls/gcc-target-in-task-control.f90 +21 -0
- offload/_root/data/findings/gcc/gcc-acc-bind-device-type-rejected.f90 +71 -0
- offload/_root/data/findings/gcc/gcc-acc-c-bind-device-type-rejected.c +76 -0
- offload/_root/data/findings/gcc/gcc-acc-c-detach-delete-attach-underflow.c +74 -0
- offload/_root/data/findings/gcc/gcc-acc-c-gang-dim-rejected.c +79 -0
- offload/_root/data/findings/gcc/gcc-acc-c-link-in-routine-rejected.c +82 -0
- offload/_root/data/findings/gcc/gcc-acc-detach-delete-attach-underflow.f90 +66 -0
- offload/_root/data/findings/gcc/gcc-acc-gang-dim-collapse-force-rejected.f90 +69 -0
- offload/_root/data/findings/gcc/gcc-acc-init-set-shutdown-rejected.f90 +70 -0
- offload/_root/data/findings/gcc/gcc-acc-link-in-routine-rejected.f90 +82 -0
- offload/_root/data/findings/gcc/gcc-acc-use-device-allocatable-rejected.f90 +88 -0
- offload/_root/data/findings/gcc/gcc-c-motion-mapper-rejected.c +110 -0
- offload/_root/data/findings/gcc/gcc-c-omp60-undocumented-rejected.c +76 -0
- offload/_root/data/findings/gcc/gcc-c-omp60-unimplemented-rejected.c +119 -0
- offload/_root/data/findings/gcc/gcc-c-target-in-task-mandatory-device-not-found.c +87 -0
- offload/_root/data/findings/gcc/gcc-c-uses-allocators-traits-unimplemented.c +85 -0
- offload/_root/data/findings/gcc/gcc-declare-mapper-rejected.f90 +85 -0
- offload/_root/data/findings/gcc/gcc-defaultmap-to-pointer-copy-back.f90 +66 -0
- offload/_root/data/findings/gcc/gcc-loop-bind-default-none-rejected.f90 +93 -0
- offload/_root/data/findings/gcc/gcc-omp60-undocumented-rejected.f90 +72 -0
- offload/_root/data/findings/gcc/gcc-omp60-unimplemented-rejected.f90 +112 -0
- offload/_root/data/findings/gcc/gcc-target-in-task-mandatory-device-not-found.f90 +83 -0
- offload/_root/data/findings/gcc/gcc-uses-allocators-traits-unimplemented.f90 +78 -0
- offload/_root/data/findings/harvest/afar-flang-strided-target-update.f90 +96 -0
- offload/_root/data/findings/harvest/cce-acc-declare-create-module-allocatable-xnack1-fault.f90 +58 -0
- offload/_root/data/findings/harvest/cce-c-implicit-struct-map-partly-present.c +100 -0
- offload/_root/data/findings/harvest/cce-c-strided-target-update.c +74 -0
- offload/_root/data/findings/harvest/cce-ftn-target-parallel-thread-query-ice.f90 +67 -0
- offload/_root/data/findings/harvest/cce-named-constant-array-declare-target-routine-rejected.f90 +69 -0
- offload/_root/data/findings/harvest/cce-use-device-ptr-c-ptr-not-converted.f90 +64 -0
- offload/_root/data/findings/harvest/cce21-declare-target-link-module-variable-write-lost.f90 +63 -0
- offload/_root/data/findings/harvest/cce21-internal-procedure-calls-internal-in-target-fault.f90 +71 -0
- offload/_root/data/findings/harvest/controls/cce-c-implicit-struct-map-partly-present-target-only-control.c +22 -0
- offload/_root/data/findings/harvest/controls/cce-c-implicit-struct-map-partly-present-whole-control.c +23 -0
- offload/_root/data/findings/harvest/controls/gcc-acc-declare-create-allocatable-control.f90 +34 -0
- offload/_root/data/findings/harvest/controls/gcc-c-same-item-two-maps-control.c +17 -0
- offload/_root/data/findings/harvest/controls/gcc-c-target-data-struct-pointer-section-control.c +27 -0
- offload/_root/data/findings/harvest/controls/gcc-c-target-data-two-maps-control.c +20 -0
- offload/_root/data/findings/harvest/controls/gcc-same-item-two-maps-control.f90 +16 -0
- offload/_root/data/findings/harvest/controls/gcc-teams-simd-matmul-allocatable-control.f90 +27 -0
- offload/_root/data/findings/harvest/gcc-acc-declare-create-allocatable-not-mapped.f90 +66 -0
- offload/_root/data/findings/harvest/gcc-c-same-item-two-maps-rejected.c +45 -0
- offload/_root/data/findings/harvest/gcc-c-strided-section-rejected.c +70 -0
- offload/_root/data/findings/harvest/gcc-c-target-data-struct-pointer-section-ice.c +78 -0
- offload/_root/data/findings/harvest/gcc-c-target-data-two-maps-ice.c +49 -0
- offload/_root/data/findings/harvest/gcc-same-item-two-maps-rejected.f90 +46 -0
- offload/_root/data/findings/harvest/gcc-teams-simd-matmul-allocatable-ice.f90 +53 -0
- offload/_root/data/findings/harvest/nvhpc-c-target-data-if-false-use-device-ptr-garbage.c +49 -0
- offload/_root/data/findings/harvest/nvhpc-named-constant-array-declare-target-routine-rejected.f90 +65 -0
- offload/_root/data/findings/harvest/nvhpc-use-device-ptr-c-ptr-not-found.f90 +60 -0
- offload/_root/data/findings/harvest/nvhpc2511-target-nowait-in-parallel-for-ice.c +59 -0
- offload/_root/data/findings/hecbench/controls/f16-ctl-float-array.c +28 -0
- offload/_root/data/findings/hecbench/controls/pc-ctl-builtin-popcount.c +37 -0
- offload/_root/data/findings/hecbench/controls/pc-ctl-shift-sum.c +43 -0
- offload/_root/data/findings/hecbench/gcc-c-float16-array-in-target-lto-ice.c +65 -0
- offload/_root/data/findings/hecbench/gcc-c-swar-popcount-assembler-error.c +80 -0
- offload/_root/data/findings/index.yaml +2453 -0
- offload/_root/data/findings/malloc/afar-device-malloc-in-kernel-corrupts-records.c +371 -0
- offload/_root/data/findings/malloc/controls/afar-first-use-malloc-direct.c +52 -0
- offload/_root/data/findings/malloc/controls/afar-first-use-malloc-fence.c +57 -0
- offload/_root/data/findings/malloc/controls/afar-first-use-malloc-flush.c +57 -0
- offload/_root/data/findings/malloc/controls/afar-first-use-malloc-stack.c +52 -0
- offload/_root/data/findings/multithread-allocatable-section-maps.f90 +91 -0
- offload/_root/data/findings/nested/afar-cce-c-call-result-member-in-target-rejected.c +69 -0
- offload/_root/data/findings/nested/afar-cce-c-update-struct-and-member-rejected.c +92 -0
- offload/_root/data/findings/nested/afar-flang-pointer-root-allocatable-component-enter-data-fault.f90 +121 -0
- offload/_root/data/findings/nested/cce-c-struct-and-nested-pointee-sections-ice.c +79 -0
- offload/_root/data/findings/nested/cce-fortran-nested-allocatable-component-copy-fault.f90 +64 -0
- offload/_root/data/findings/nested/cce-fortran-pointer-to-type-with-allocatable-scalar-component-typed-transfer.f90 +93 -0
- offload/_root/data/findings/nested/cce-fortran-update-to-pointer-root-allocatable-scalar-component-no-accelerator-object.f90 +80 -0
- offload/_root/data/findings/nested/controls/c3-ctl-nested-data.c +27 -0
- offload/_root/data/findings/nested/controls/c5-acc-serial-struct-and-array.c +26 -0
- offload/_root/data/findings/nested/controls/e2-ctl-two-directives.c +42 -0
- offload/_root/data/findings/nested/controls/e3-ctl-attach-clause.c +42 -0
- offload/_root/data/findings/nested/controls/f3-pointer-array-only.c +33 -0
- offload/_root/data/findings/nested/controls/f5-ctl-copyout-exit.c +33 -0
- offload/_root/data/findings/nested/controls/f6-ctl-pointer-to-struct-array.c +28 -0
- offload/_root/data/findings/nested/controls/g2-ctl-allocatable.f90 +34 -0
- offload/_root/data/findings/nested/controls/g2-ctl-entered-to.f90 +34 -0
- offload/_root/data/findings/nested/controls/g3-ctl-from-struct-no-element.c +27 -0
- offload/_root/data/findings/nested/controls/g3-ptrs-two-elements-to.c +27 -0
- offload/_root/data/findings/nested/controls/g3-ptrs-two-elements-tofrom.c +27 -0
- offload/_root/data/findings/nested/controls/g5-ctl-element-pointers-only.f90 +36 -0
- offload/_root/data/findings/nested/controls/g5-ctl-root-pointer-only.f90 +36 -0
- offload/_root/data/findings/nested/controls/gp2-ctl-no-mapper-explicit-maps.c +24 -0
- offload/_root/data/findings/nested/controls/gt2-ctl-no-always.c +26 -0
- offload/_root/data/findings/nested/controls/gt3-ctl-always-on-structure-only.c +26 -0
- offload/_root/data/findings/nested/controls/j1-embedded-struct-pointer-to-struct.c +24 -0
- offload/_root/data/findings/nested/controls/j2-ctl-pointer-instead-of-embedded.c +24 -0
- offload/_root/data/findings/nested/controls/j6-ctl-struct-and-one-pointee-level.c +23 -0
- offload/_root/data/findings/nested/controls/j7-ctl-struct-and-embedded-pointee.c +24 -0
- offload/_root/data/findings/nested/controls/m2-ctl-variable-root.f90 +32 -0
- offload/_root/data/findings/nested/controls/m3-ctl-fixed-array-component.f90 +32 -0
- offload/_root/data/findings/nested/controls/m5-ctl-no-enter-data.f90 +33 -0
- offload/_root/data/findings/nested/controls/n8-ctl-fixed-array-in-component.f90 +33 -0
- offload/_root/data/findings/nested/controls/n9-ctl-allocatable-in-the-variable.f90 +33 -0
- offload/_root/data/findings/nested/controls/ns4-ctl-two-directives-struct-then-pointee.c +27 -0
- offload/_root/data/findings/nested/controls/ns8-ctl-enter-together-exit-split.c +26 -0
- offload/_root/data/findings/nested/controls/nu3-ctl-update-pointee-only.c +28 -0
- offload/_root/data/findings/nested/controls/p2-ctl-pointer-variable.c +27 -0
- offload/_root/data/findings/nested/controls/p3-ctl-direct-member.c +26 -0
- offload/_root/data/findings/nested/controls/q2-ctl-fixed-array.f90 +37 -0
- offload/_root/data/findings/nested/controls/q3-ctl-allocatable-component-of-the-variable.f90 +38 -0
- offload/_root/data/findings/nested/controls/ta2-ctl-no-allocatable-component.f90 +42 -0
- offload/_root/data/findings/nested/controls/ta3-ctl-allocatable-scalar-in-the-variable.f90 +38 -0
- offload/_root/data/findings/nested/controls/ta4-ctl-pointer-component-only.f90 +42 -0
- offload/_root/data/findings/nested/controls/u3-ctl-update-member-only.c +24 -0
- offload/_root/data/findings/nested/controls/u4-ctl-two-updates.c +25 -0
- offload/_root/data/findings/nested/controls/u5-ctl-same-list-in-map.c +25 -0
- offload/_root/data/findings/nested/controls/ua2-ctl-variable-root.f90 +37 -0
- offload/_root/data/findings/nested/controls/ua4-ctl-to-in-place-of-alloc-and-update.f90 +37 -0
- offload/_root/data/findings/nested/controls/v2-ctl-parent-first.c +25 -0
- offload/_root/data/findings/nested/controls/v4-ctl-embedded-member.c +24 -0
- offload/_root/data/findings/nested/gcc-acc-c-exit-data-of-a-pointer-array-element-target-hangs.c +83 -0
- offload/_root/data/findings/nested/gcc-acc-c-parent-and-shared-pointee-one-directive.c +88 -0
- offload/_root/data/findings/nested/gcc-acc-c-struct-and-member-array-one-directive.c +84 -0
- offload/_root/data/findings/nested/gcc-c-always-on-pointer-member-section-ice.c +75 -0
- offload/_root/data/findings/nested/gcc-c-declare-mapper-pointer-member-section-gpu-fault.c +93 -0
- offload/_root/data/findings/nested/gcc-c-from-struct-and-pointee-section-rejected.c +83 -0
- offload/_root/data/findings/nested/gcc-fortran-pointer-component-alloc-bounds-lost.f90 +62 -0
- offload/_root/data/findings/nested/gcc-fortran-root-and-element-pointer-components-ice.f90 +77 -0
- offload/_root/data/findings/nested/nvhpc-c-pointee-before-parent-in-one-map-list-copy-fault.c +55 -0
- offload/_root/data/findings/nested/nvhpc-c-update-from-structure-overwrites-attached-pointer-segv.c +86 -0
- offload/_root/data/findings/nvhpc-acc-atomic-update-sum-fort2-crash.f90 +53 -0
- offload/_root/data/findings/nvhpc-c-acc-atomic-update-sum-ice.c +43 -0
- offload/_root/data/findings/nvhpc-c-dist-schedule-chunk-compile-hang.c +41 -0
- offload/_root/data/findings/nvhpc-c-map-present-ignored.c +42 -0
- offload/_root/data/findings/nvhpc-c-ordered-in-target-nvcpfe-crash.c +92 -0
- offload/_root/data/findings/nvhpc-c-parallel-for-firstprivate-in-target.c +62 -0
- offload/_root/data/findings/nvhpc-c-parallel-if-in-target-nvvm-ice.c +56 -0
- offload/_root/data/findings/nvhpc-defaultmap-firstprivate-explicit-map.f90 +45 -0
- offload/_root/data/findings/nvhpc-defaultmap-from-allocatable-indexing.f90 +60 -0
- offload/_root/data/findings/nvhpc-depend-inoutset-ignored.f90 +64 -0
- offload/_root/data/findings/nvhpc-dist-schedule-chunk-illegal-address.f90 +52 -0
- offload/_root/data/findings/nvhpc-managed-acc-shutdown-host-access.f90 +42 -0
- offload/_root/data/findings/nvhpc-parallel-if-in-target-nvvm-ice.f90 +60 -0
- offload/_root/data/findings/oop/afar-final-dealloc-device-link.f90 +85 -0
- offload/_root/data/findings/oop/afar-pdt-length-parameter-not-implemented.f90 +65 -0
- offload/_root/data/findings/oop/cce-class-is-device-link.f90 +86 -0
- offload/_root/data/findings/oop/cce-copy-alloc-component-section-fault.f90 +73 -0
- offload/_root/data/findings/oop/cce-copy-parent-to-component-tofrom-lost.f90 +65 -0
- offload/_root/data/findings/oop/cce-copy-second-member-section-lost.f90 +65 -0
- offload/_root/data/findings/oop/cce-element-component-map-lost.f90 +64 -0
- offload/_root/data/findings/oop/cce-final-dealloc-device-abort.f90 +85 -0
- offload/_root/data/findings/oop/cce-pdt-default-mapper-rejected.f90 +71 -0
- offload/_root/data/findings/oop/cce-polymorphic-dispatch-device-link.f90 +100 -0
- offload/_root/data/findings/oop/cce-section-of-element-component-overlap.f90 +76 -0
- offload/_root/data/findings/oop/cce-select-type-guard-not-taken.f90 +91 -0
- offload/_root/data/findings/oop/cce-udr-derived-type-unsupported.f90 +69 -0
- offload/_root/data/findings/oop/cce21-element-component-map-lost.f90 +62 -0
- offload/_root/data/findings/oop/controls/alloccomp-comp-only.f90 +44 -0
- offload/_root/data/findings/oop/controls/alloccomp-whole-explicit-component.f90 +50 -0
- offload/_root/data/findings/oop/controls/alloccomp-whole.f90 +49 -0
- offload/_root/data/findings/oop/controls/elemsec-element.f90 +47 -0
- offload/_root/data/findings/oop/controls/final-local.f90 +64 -0
- offload/_root/data/findings/oop/controls/host-class-star-select-type.f90 +58 -0
- offload/_root/data/findings/oop/controls/host-firstprivate-defined-assignment.f90 +54 -0
- offload/_root/data/findings/oop/controls/host-lastprivate-defined-assignment.f90 +58 -0
- offload/_root/data/findings/oop/controls/host-private-finalization.f90 +51 -0
- offload/_root/data/findings/oop/controls/host-select-type.f90 +65 -0
- offload/_root/data/findings/oop/controls/parent-and-comp-component-only.f90 +45 -0
- offload/_root/data/findings/oop/controls/pdt-kind.f90 +46 -0
- offload/_root/data/findings/oop/controls/pdt-len-host.f90 +43 -0
- offload/_root/data/findings/oop/controls/pdt-len-unparameterized.f90 +46 -0
- offload/_root/data/findings/oop/controls/poly-dispatch-static.f90 +75 -0
- offload/_root/data/findings/oop/controls/section-alloc-whole-component.f90 +49 -0
- offload/_root/data/findings/oop/controls/section-element-whole-array.f90 +50 -0
- offload/_root/data/findings/oop/controls/section-element-whole-component.f90 +50 -0
- offload/_root/data/findings/oop/controls/section-fixed.f90 +43 -0
- offload/_root/data/findings/oop/controls/tbp-override.f90 +64 -0
- offload/_root/data/findings/oop/gcc-acc-parent-and-member-data-rejected.f90 +63 -0
- offload/_root/data/findings/oop/gcc-pdt-length-parameter-abort.f90 +68 -0
- offload/_root/data/findings/oop/gcc-polymorphic-dispatch-abort.f90 +97 -0
- offload/_root/data/findings/oop/gcc-vtab-not-marked-for-offload.f90 +94 -0
- offload/_root/data/findings/oop/nvhpc-copy-alloc-component-illegal-address.f90 +76 -0
- offload/_root/data/findings/oop/nvhpc-copy-pdt-length-parameter-illegal-address.f90 +69 -0
- offload/_root/data/findings/oop/nvhpc-named-mapper-rejected.f90 +65 -0
- offload/_root/data/findings/oop/nvhpc-polymorphic-dispatch-translate-failure.f90 +90 -0
- offload/_root/data/findings/oop/nvhpc-polymorphism-runtime-unsupported.f90 +94 -0
- offload/_root/data/findings/oop/nvhpc-type-bound-call-rejected.f90 +89 -0
- offload/_root/data/findings/oop/nvhpc-udr-derived-type-rejected.f90 +67 -0
- offload/_root/data/findings/reviews/afar-c-error-directive-in-target-link.json +217 -0
- offload/_root/data/findings/reviews/afar-c-lastprivate-distribute-parallel-for-small-type.json +113 -0
- offload/_root/data/findings/reviews/afar-c-teams-distribute-reduction-first-team.json +130 -0
- offload/_root/data/findings/reviews/afar-c-update-iterator-copy-mode.json +113 -0
- offload/_root/data/findings/reviews/afar-cce19-character-defaultmap.json +292 -0
- offload/_root/data/findings/reviews/afar-clang-requires-device-safesync-hang.json +191 -0
- offload/_root/data/findings/reviews/afar-flang-firstprivate-map-two-targets.json +130 -0
- offload/_root/data/findings/reviews/afar-flang-loop-bind-teams-reduction.json +126 -0
- offload/_root/data/findings/reviews/afar-flang-task-reduction-max.json +113 -0
- offload/_root/data/findings/reviews/afar-flang-thread-limit-target-parallel-do.json +113 -0
- offload/_root/data/findings/reviews/afar-loop-bind-thread-in-teams.json +191 -0
- offload/_root/data/findings/reviews/afar-nontemporal-assumed-shape-ice.json +113 -0
- offload/_root/data/findings/reviews/afar-udr-derived-type-link.json +113 -0
- offload/_root/data/findings/reviews/afar-xnack1-atomic-min-nested-parallel.json +113 -0
- offload/_root/data/findings/reviews/afar-xnack1-target-is-present.json +113 -0
- offload/_root/data/findings/reviews/apps--afar-cce-teams-private-array-nested-parallel-wrong.json +113 -0
- offload/_root/data/findings/reviews/apps--cce20-device-link-infer-address-spaces-crash.json +113 -0
- offload/_root/data/findings/reviews/apps--cce21-device-link-agpr-copy-mfma-assert.json +113 -0
- offload/_root/data/findings/reviews/apps--cce21-private-array-loaded-subscript-wrong.json +113 -0
- offload/_root/data/findings/reviews/apps--gcc-acc-c-tile-partial-tiles-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-c-ordered-doacross-link.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-c-reduction-task-link.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-absent-optional-target-crash.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-critical-target-parallel-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-dist-schedule-chunk.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-linear-parallel-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-named-critical-link.json +126 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-ordered-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-reduction-minus-rejected.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-sections-in-target-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--afar-flang-workdistribute-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--c-allocate-const-mem-firstprivate-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-acc-character-dummy-routine-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-acc-loop-seq-in-routine-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-allocators-stack-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-c-allocate-align-link.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-c-allocate-allocator-modifier-rejected.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-c-dist-schedule-chunk.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-c-f-pointer-device-link.json +130 -0
- offload/_root/data/findings/reviews/catalog--cce-c-long-double-ice.json +217 -0
- offload/_root/data/findings/reviews/catalog--cce-c-map-iterator-ice.json +217 -0
- offload/_root/data/findings/reviews/catalog--cce-c-recursive-function-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-c-sections-in-target-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-flang-allocate-in-target-crash.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-flang-lastprivate-parallel-in-seq-loop-wrong.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-flang-stop-in-target-crash.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-iterator-link.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-linear-lastprivate-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-reduction-inscan-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce-reduction-task-link.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce19-reduction-task-addrspacecast-ice.json +113 -0
- offload/_root/data/findings/reviews/catalog--cce20-c-defaultmap-private-storage-rejected.json +217 -0
- offload/_root/data/findings/reviews/catalog--cce20-map-self-rejected.json +204 -0
- offload/_root/data/findings/reviews/catalog--cce21-c-target-loop-ice.json +126 -0
- offload/_root/data/findings/reviews/catalog--defaultmap-present-private-array-abort.json +236 -0
- offload/_root/data/findings/reviews/catalog--nvhpc-acc-associate-illegal-address.json +113 -0
- offload/_root/data/findings/reviews/catalog--nvhpc-c-function-pointer-kernel-missing.json +268 -0
- offload/_root/data/findings/reviews/cce-acc-init-set-runtime-assert.json +113 -0
- offload/_root/data/findings/reviews/cce-acc-reduction-200-int8-scalars-wrong.json +113 -0
- offload/_root/data/findings/reviews/cce-acc-routine-bind-module-ice.json +113 -0
- offload/_root/data/findings/reviews/cce-c-dist-schedule-segv.json +113 -0
- offload/_root/data/findings/reviews/cce-c-map-delete-refcount.json +149 -0
- offload/_root/data/findings/reviews/cce-c-map-present-assert.json +126 -0
- offload/_root/data/findings/reviews/cce-c-openmp45-device-link.json +113 -0
- offload/_root/data/findings/reviews/cce-c-parallel-for-in-target.json +141 -0
- offload/_root/data/findings/reviews/cce-mapper-next-map-copy-back.json +208 -0
- offload/_root/data/findings/reviews/cce-uses-allocators-traits-omp50.json +191 -0
- offload/_root/data/findings/reviews/cce19-c-reduction-63-scalars-one-wrong.json +113 -0
- offload/_root/data/findings/reviews/cce19-target-parallel-guarded-loop.json +113 -0
- offload/_root/data/findings/reviews/cce19-target-parallel-single-ice.json +113 -0
- offload/_root/data/findings/reviews/cce21-alloc-2e32-sum-wrong.json +113 -0
- offload/_root/data/findings/reviews/cce21-defaultmap-aggregate-flag.json +210 -0
- offload/_root/data/findings/reviews/cce21-in-reduction-assumed-shape-write-lost.json +113 -0
- offload/_root/data/findings/reviews/cce21-in-reduction-taskwait-link.json +113 -0
- offload/_root/data/findings/reviews/clang-c-declare-target-to-omp52.json +113 -0
- offload/_root/data/findings/reviews/clang-c-linear-directive-name-hang.json +113 -0
- offload/_root/data/findings/reviews/clang-c-shared-declare-target-combined.json +132 -0
- offload/_root/data/findings/reviews/dataenv--cce-value-dummy-target-write-visible.json +113 -0
- offload/_root/data/findings/reviews/defaultmap-none-loop-variable.json +113 -0
- offload/_root/data/findings/reviews/fortran-schedule-static-in-target.json +113 -0
- offload/_root/data/findings/reviews/fresh--cce-common-block-name-in-map-rejected.json +113 -0
- offload/_root/data/findings/reviews/fresh--cce-list-directed-print-in-target-copy-crash.json +217 -0
- offload/_root/data/findings/reviews/fresh--cce19-acc-automatic-array-copyout-copy-crash.json +113 -0
- offload/_root/data/findings/reviews/fresh--cce21-combined-if-runtime-expr-loop-skipped.json +113 -0
- offload/_root/data/findings/reviews/fresh--nvhpc-acc-gang-worker-collapse-nested-vector-reduction-lost.json +113 -0
- offload/_root/data/findings/reviews/fresh--nvhpc-teams-loop-module-allocatable-assign-fort2-crash.json +113 -0
- offload/_root/data/findings/reviews/fuzz--1505-cce20.json +113 -0
- offload/_root/data/findings/reviews/fuzz--1540-afar.json +113 -0
- offload/_root/data/findings/reviews/fuzz--1978-cce19.json +130 -0
- offload/_root/data/findings/reviews/fuzz--2334-cce19.json +113 -0
- offload/_root/data/findings/reviews/fuzz--591-cce19.json +147 -0
- offload/_root/data/findings/reviews/fuzz--650-afar.json +113 -0
- offload/_root/data/findings/reviews/fuzz--916-afar.json +130 -0
- offload/_root/data/findings/reviews/fuzz--98-cce19.json +113 -0
- offload/_root/data/findings/reviews/fuzz--b1-121-afar.json +160 -0
- offload/_root/data/findings/reviews/fuzz--b2-209-cce19.json +141 -0
- offload/_root/data/findings/reviews/fuzz--b2-68-afar.json +113 -0
- offload/_root/data/findings/reviews/fuzz--b2-85-cce20.json +217 -0
- offload/_root/data/findings/reviews/fuzz--b3-188-cce19.json +113 -0
- offload/_root/data/findings/reviews/fuzz--b3-278-cce19.json +212 -0
- offload/_root/data/findings/reviews/fuzz--b3-54-afar.json +113 -0
- offload/_root/data/findings/reviews/fuzz--b3-61-cce20.json +191 -0
- offload/_root/data/findings/reviews/fuzz--b4-86-cce19.json +113 -0
- offload/_root/data/findings/reviews/fuzz--gcc-declare-reduction-module-not-found.json +113 -0
- offload/_root/data/findings/reviews/fuzz--gcc-target-simd-map-nontemporal-rejected.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-allocatable-component-implicit-map-illegal-address.json +141 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-assumed-length-character-dummy-map-ice.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-default-none-reduction-lastprivate-fort1-crash.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-defaultmap-firstprivate-lastprivate-ice.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-defaultmap-to-scalar-reduction-lost.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-depend-implicit-map-illegal-address.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-distribute-parallel-num-threads-writes-lost.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-end-distribute-simd-rejected.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-loop-character-achar-unsupported.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-map-always-after-map-to-not-copied-back.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-num-threads-reduction-identity-lost.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-target-parallel-firstprivate-translate-failure.json +191 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-target-parallel-single-hang.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-target-simd-collapse-translate-failure.json +113 -0
- offload/_root/data/findings/reviews/fuzz--nvhpc-target-simd-no-end-directive-rejected.json +113 -0
- offload/_root/data/findings/reviews/fuzz--par-s1-2082-gcc_g90.json +126 -0
- offload/_root/data/findings/reviews/fuzz--s1-2370-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-2592-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-3463-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-6760-cce20.json +130 -0
- offload/_root/data/findings/reviews/fuzz--s1-6888-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-7882-cce20.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-8634-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-91-cce21.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-9443-afar.json +113 -0
- offload/_root/data/findings/reviews/fuzz--s1-9914-cce19.json +141 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-bind-device-type-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-detach-delete-attach-underflow.json +314 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-gang-dim-collapse-force-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-init-set-shutdown-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-link-in-routine-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-acc-use-device-allocatable-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-c-motion-mapper-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-c-omp60-undocumented-rejected.json +217 -0
- offload/_root/data/findings/reviews/gcc--gcc-c-omp60-unimplemented-rejected.json +236 -0
- offload/_root/data/findings/reviews/gcc--gcc-c-target-in-task-mandatory-device-not-found.json +236 -0
- offload/_root/data/findings/reviews/gcc--gcc-c-uses-allocators-traits-unimplemented.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-declare-mapper-rejected.json +113 -0
- offload/_root/data/findings/reviews/gcc--gcc-defaultmap-to-pointer-copy-back.json +217 -0
- offload/_root/data/findings/reviews/gcc--gcc-loop-bind-default-none-rejected.json +113 -0
- offload/_root/data/findings/reviews/harvest--afar-flang-strided-target-update.json +141 -0
- offload/_root/data/findings/reviews/harvest--cce-acc-declare-create-module-allocatable-xnack1-fault.json +113 -0
- offload/_root/data/findings/reviews/harvest--cce-c-implicit-struct-map-partly-present.json +217 -0
- offload/_root/data/findings/reviews/harvest--cce-c-strided-target-update.json +141 -0
- offload/_root/data/findings/reviews/harvest--cce-ftn-target-parallel-thread-query-ice.json +130 -0
- offload/_root/data/findings/reviews/harvest--cce-named-constant-array-declare-target-routine-rejected.json +113 -0
- offload/_root/data/findings/reviews/harvest--cce-use-device-ptr-c-ptr-not-converted.json +113 -0
- offload/_root/data/findings/reviews/harvest--cce21-declare-target-link-module-variable-write-lost.json +113 -0
- offload/_root/data/findings/reviews/harvest--cce21-internal-procedure-calls-internal-in-target-fault.json +158 -0
- offload/_root/data/findings/reviews/harvest--gcc-acc-declare-create-allocatable-not-mapped.json +204 -0
- offload/_root/data/findings/reviews/harvest--gcc-c-same-item-two-maps-rejected.json +143 -0
- offload/_root/data/findings/reviews/harvest--gcc-c-strided-section-rejected.json +164 -0
- offload/_root/data/findings/reviews/harvest--gcc-c-target-data-struct-pointer-section-ice.json +113 -0
- offload/_root/data/findings/reviews/harvest--gcc-c-target-data-two-maps-ice.json +113 -0
- offload/_root/data/findings/reviews/harvest--gcc-teams-simd-matmul-allocatable-ice.json +113 -0
- offload/_root/data/findings/reviews/harvest--nvhpc-c-target-data-if-false-use-device-ptr-garbage.json +113 -0
- offload/_root/data/findings/reviews/harvest--nvhpc-named-constant-array-declare-target-routine-rejected.json +126 -0
- offload/_root/data/findings/reviews/harvest--nvhpc-use-device-ptr-c-ptr-not-found.json +113 -0
- offload/_root/data/findings/reviews/harvest--nvhpc2511-target-nowait-in-parallel-for-ice.json +130 -0
- offload/_root/data/findings/reviews/hecbench--gcc-c-float16-array-in-target-lto-ice.json +217 -0
- offload/_root/data/findings/reviews/hecbench--gcc-c-swar-popcount-assembler-error.json +126 -0
- offload/_root/data/findings/reviews/malloc--afar-device-malloc-in-kernel-corrupts-records.json +270 -0
- offload/_root/data/findings/reviews/multithread-allocatable-section-maps.json +191 -0
- offload/_root/data/findings/reviews/nested--afar-cce-c-call-result-member-in-target-rejected.json +113 -0
- offload/_root/data/findings/reviews/nested--afar-cce-c-update-struct-and-member-rejected.json +126 -0
- offload/_root/data/findings/reviews/nested--afar-flang-pointer-root-allocatable-component-enter-data-fault.json +191 -0
- offload/_root/data/findings/reviews/nested--cce-c-struct-and-nested-pointee-sections-ice.json +113 -0
- offload/_root/data/findings/reviews/nested--cce-fortran-nested-allocatable-component-copy-fault.json +214 -0
- offload/_root/data/findings/reviews/nested--cce-fortran-pointer-to-type-with-allocatable-scalar-component-typed-transfer.json +191 -0
- offload/_root/data/findings/reviews/nested--cce-fortran-update-to-pointer-root-allocatable-scalar-component-no-accelerator-object.json +297 -0
- offload/_root/data/findings/reviews/nested--gcc-acc-c-exit-data-of-a-pointer-array-element-target-hangs.json +204 -0
- offload/_root/data/findings/reviews/nested--gcc-acc-c-parent-and-shared-pointee-one-directive.json +130 -0
- offload/_root/data/findings/reviews/nested--gcc-acc-c-struct-and-member-array-one-directive.json +141 -0
- offload/_root/data/findings/reviews/nested--gcc-c-always-on-pointer-member-section-ice.json +113 -0
- offload/_root/data/findings/reviews/nested--gcc-c-declare-mapper-pointer-member-section-gpu-fault.json +113 -0
- offload/_root/data/findings/reviews/nested--gcc-c-from-struct-and-pointee-section-rejected.json +113 -0
- offload/_root/data/findings/reviews/nested--gcc-fortran-pointer-component-alloc-bounds-lost.json +217 -0
- offload/_root/data/findings/reviews/nested--gcc-fortran-root-and-element-pointer-components-ice.json +217 -0
- offload/_root/data/findings/reviews/nested--nvhpc-c-pointee-before-parent-in-one-map-list-copy-fault.json +204 -0
- offload/_root/data/findings/reviews/nested--nvhpc-c-update-from-structure-overwrites-attached-pointer-segv.json +191 -0
- offload/_root/data/findings/reviews/nvhpc-c-acc-atomic-update-sum-ice.json +277 -0
- offload/_root/data/findings/reviews/nvhpc-c-dist-schedule-chunk-compile-hang.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-c-map-present-ignored.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-c-ordered-in-target-nvcpfe-crash.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-c-parallel-for-firstprivate-in-target.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-defaultmap-firstprivate-explicit-map.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-defaultmap-from-allocatable-indexing.json +132 -0
- offload/_root/data/findings/reviews/nvhpc-depend-inoutset-ignored.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-dist-schedule-chunk-illegal-address.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-managed-acc-shutdown-host-access.json +113 -0
- offload/_root/data/findings/reviews/nvhpc-parallel-if-in-target-nvvm-ice.json +113 -0
- offload/_root/data/findings/reviews/oop--afar-final-dealloc-device-link.json +132 -0
- offload/_root/data/findings/reviews/oop--afar-pdt-length-parameter-not-implemented.json +113 -0
- offload/_root/data/findings/reviews/oop--cce-class-is-device-link.json +130 -0
- offload/_root/data/findings/reviews/oop--cce-copy-alloc-component-section-fault.json +217 -0
- offload/_root/data/findings/reviews/oop--cce-copy-parent-to-component-tofrom-lost.json +217 -0
- offload/_root/data/findings/reviews/oop--cce-copy-second-member-section-lost.json +113 -0
- offload/_root/data/findings/reviews/oop--cce-element-component-map-lost.json +113 -0
- offload/_root/data/findings/reviews/oop--cce-final-dealloc-device-abort.json +208 -0
- offload/_root/data/findings/reviews/oop--cce-pdt-default-mapper-rejected.json +191 -0
- offload/_root/data/findings/reviews/oop--cce-polymorphic-dispatch-device-link.json +247 -0
- offload/_root/data/findings/reviews/oop--cce-section-of-element-component-overlap.json +113 -0
- offload/_root/data/findings/reviews/oop--cce-select-type-guard-not-taken.json +191 -0
- offload/_root/data/findings/reviews/oop--cce-udr-derived-type-unsupported.json +132 -0
- offload/_root/data/findings/reviews/oop--gcc-acc-parent-and-member-data-rejected.json +141 -0
- offload/_root/data/findings/reviews/oop--gcc-pdt-length-parameter-abort.json +141 -0
- offload/_root/data/findings/reviews/oop--gcc-polymorphic-dispatch-abort.json +217 -0
- offload/_root/data/findings/reviews/oop--gcc-vtab-not-marked-for-offload.json +113 -0
- offload/_root/data/findings/reviews/oop--nvhpc-copy-alloc-component-illegal-address.json +113 -0
- offload/_root/data/findings/reviews/oop--nvhpc-copy-pdt-length-parameter-illegal-address.json +236 -0
- offload/_root/data/findings/reviews/oop--nvhpc-named-mapper-rejected.json +113 -0
- offload/_root/data/findings/reviews/oop--nvhpc-polymorphic-dispatch-translate-failure.json +223 -0
- offload/_root/data/findings/reviews/oop--nvhpc-polymorphism-runtime-unsupported.json +126 -0
- offload/_root/data/findings/reviews/oop--nvhpc-type-bound-call-rejected.json +113 -0
- offload/_root/data/findings/reviews/oop--nvhpc-udr-derived-type-rejected.json +113 -0
- offload/_root/data/findings/reviews/stress--afar-c-lastprivate-combined-target-not-mapped.json +113 -0
- offload/_root/data/findings/reviews/stress--afar-target-scalar-implicit-firstprivate.json +175 -0
- offload/_root/data/findings/reviews/stress--cce-acc-declare-create-scalar-serial-firstprivate.json +113 -0
- offload/_root/data/findings/reviews/stress--cce-c-distribute-lastprivate-lost.json +113 -0
- offload/_root/data/findings/reviews/stress--cce-c-flto-offload-dropped.json +204 -0
- offload/_root/data/findings/reviews/stress--cce-ftn-cif-record-split-abort.json +113 -0
- offload/_root/data/findings/reviews/stress--cce-lastprivate-num-threads-collapse-simd.json +113 -0
- offload/_root/data/findings/reviews/stress--cce-teams-reduction-many-teams-wrap.json +113 -0
- offload/_root/data/findings/reviews/stress--cce21-declare-target-scalar-map-write-lost.json +113 -0
- offload/_root/data/findings/reviews/stress--gcc-declare-target-allocatable-component-ice.json +191 -0
- offload/_root/data/findings/reviews/stress--nvhpc-acc-derived-type-component-not-copied.json +126 -0
- offload/_root/data/findings/reviews/stress--nvhpc-c-lastprivate-teams-distribute-parallel-for-lost.json +113 -0
- offload/_root/data/findings/reviews/stress--nvhpc-declare-target-scalar-write-lost.json +113 -0
- offload/_root/data/findings/reviews/stress--nvhpc-lastprivate-combined-target-not-mapped.json +113 -0
- offload/_root/data/findings/reviews/stress--nvhpc-target-scalar-implicit-firstprivate.json +130 -0
- offload/_root/data/findings/reviews/target-update-sections-in-parallel.json +113 -0
- offload/_root/data/findings/stress/afar-c-lastprivate-combined-target-not-mapped.c +72 -0
- offload/_root/data/findings/stress/afar-target-scalar-implicit-firstprivate.f90 +47 -0
- offload/_root/data/findings/stress/cce-acc-declare-create-scalar-serial-firstprivate.f90 +43 -0
- offload/_root/data/findings/stress/cce-c-distribute-lastprivate-lost.c +52 -0
- offload/_root/data/findings/stress/cce-c-flto-offload-dropped.c +73 -0
- offload/_root/data/findings/stress/cce-ftn-cif-record-split-abort.f90 +109 -0
- offload/_root/data/findings/stress/cce-lastprivate-num-threads-collapse-simd.f90 +66 -0
- offload/_root/data/findings/stress/cce-teams-reduction-many-teams-wrap.f90 +55 -0
- offload/_root/data/findings/stress/cce21-declare-target-scalar-map-write-lost.f90 +58 -0
- offload/_root/data/findings/stress/controls/gcc-declare-target-allocatable-component-control.f90 +29 -0
- offload/_root/data/findings/stress/gcc-declare-target-allocatable-component-ice.f90 +61 -0
- offload/_root/data/findings/stress/nvhpc-acc-derived-type-component-not-copied.f90 +33 -0
- offload/_root/data/findings/stress/nvhpc-c-lastprivate-teams-distribute-parallel-for-lost.c +62 -0
- offload/_root/data/findings/stress/nvhpc-declare-target-scalar-write-lost.f90 +43 -0
- offload/_root/data/findings/stress/nvhpc-lastprivate-combined-target-not-mapped.f90 +60 -0
- offload/_root/data/findings/stress/nvhpc-target-scalar-implicit-firstprivate.f90 +41 -0
- offload/_root/data/findings/target-update-sections-in-parallel.f90 +53 -0
- offload/_root/data/issues.json +1 -0
- offload/_root/data/search.json +1 -0
- offload/_root/data/vendor/checks/build.py +288 -0
- offload/_version.py +24 -0
- offload/canuse.py +88 -0
- offload/cli.py +52 -0
- offload/data.py +85 -0
- offload/engine/__init__.py +0 -0
- offload/engine/acc_c_gen.py +415 -0
- offload/engine/acc_gen.py +1104 -0
- offload/engine/acc_rules.py +656 -0
- offload/engine/apps.py +804 -0
- offload/engine/baseline.py +324 -0
- offload/engine/c_gen.py +883 -0
- offload/engine/c_program.py +913 -0
- offload/engine/c_rules.py +503 -0
- offload/engine/campaign.py +1180 -0
- offload/engine/campaigns/__init__.py +2 -0
- offload/engine/campaigns/hecbench.py +153 -0
- offload/engine/campaigns/nested.py +76 -0
- offload/engine/campaigns/oop.py +61 -0
- offload/engine/canary.py +275 -0
- offload/engine/catalog.py +860 -0
- offload/engine/citations.py +532 -0
- offload/engine/clang_oracle.py +208 -0
- offload/engine/combos.py +234 -0
- offload/engine/confirm/__init__.py +2 -0
- offload/engine/confirm/backlog.py +159 -0
- offload/engine/confirm/claims.py +423 -0
- offload/engine/confirm/collectors.py +665 -0
- offload/engine/confirm/decisions.py +202 -0
- offload/engine/confirm/draft.py +195 -0
- offload/engine/confirm/engine.py +157 -0
- offload/engine/confirm/execute.py +382 -0
- offload/engine/confirm/facts.py +467 -0
- offload/engine/confirm/findings.py +617 -0
- offload/engine/confirm/forms.py +145 -0
- offload/engine/confirm/ingest.py +372 -0
- offload/engine/confirm/jobs.py +215 -0
- offload/engine/confirm/legality.py +323 -0
- offload/engine/confirm/machines.py +254 -0
- offload/engine/confirm/minimize.py +268 -0
- offload/engine/confirm/model.py +249 -0
- offload/engine/confirm/ports.py +107 -0
- offload/engine/confirm/programs.py +222 -0
- offload/engine/confirm/registry.py +151 -0
- offload/engine/confirm/regress.py +278 -0
- offload/engine/confirm/rules.py +565 -0
- offload/engine/confirm/store.py +63 -0
- offload/engine/confirm/triage.py +838 -0
- offload/engine/confirm/validate.py +607 -0
- offload/engine/confirm/witness.py +355 -0
- offload/engine/corpus_check.py +388 -0
- offload/engine/coverage.py +318 -0
- offload/engine/dataenv_gen.py +1318 -0
- offload/engine/dataenv_rules.py +278 -0
- offload/engine/devtemps.py +146 -0
- offload/engine/expected.py +2559 -0
- offload/engine/f2c.py +1783 -0
- offload/engine/finding_claims.py +330 -0
- offload/engine/finding_header.py +229 -0
- offload/engine/finding_rows.py +382 -0
- offload/engine/flang_oracle.py +299 -0
- offload/engine/fsource.py +620 -0
- offload/engine/fuzz.py +2455 -0
- offload/engine/fuzz_base.py +2016 -0
- offload/engine/fuzz_campaign.py +592 -0
- offload/engine/fuzz_exec.py +798 -0
- offload/engine/fuzz_min.py +1049 -0
- offload/engine/fuzz_profile.py +340 -0
- offload/engine/fuzz_report.py +1270 -0
- offload/engine/fuzz_steer.py +181 -0
- offload/engine/gate.py +1013 -0
- offload/engine/gate_report.py +711 -0
- offload/engine/gate_run.py +118 -0
- offload/engine/gate_stored.py +466 -0
- offload/engine/gen.py +1114 -0
- offload/engine/gen_templates.py +2583 -0
- offload/engine/grammar.py +695 -0
- offload/engine/harness.py +1472 -0
- offload/engine/harvest/__init__.py +3 -0
- offload/engine/harvest/c_runtime.py +465 -0
- offload/engine/harvest/checks.py +534 -0
- offload/engine/harvest/convert.py +784 -0
- offload/engine/harvest/f_runtime.py +668 -0
- offload/engine/harvest/filters.py +338 -0
- offload/engine/harvest/history.py +122 -0
- offload/engine/harvest/inventory.py +399 -0
- offload/engine/harvest2/__init__.py +5 -0
- offload/engine/harvest2/aomp.py +119 -0
- offload/engine/harvest2/examples.py +116 -0
- offload/engine/harvest2/gomp.py +679 -0
- offload/engine/harvest2/hand.py +150 -0
- offload/engine/harvest2/split.py +78 -0
- offload/engine/harvest_known/__init__.py +2 -0
- offload/engine/harvest_known/apps.py +65 -0
- offload/engine/harvest_known/cases.py +128 -0
- offload/engine/harvest_known/centres.py +184 -0
- offload/engine/harvest_known/forum.py +180 -0
- offload/engine/harvest_known/relnotes.py +42 -0
- offload/engine/harvest_known/textscan.py +107 -0
- offload/engine/hdrwrap.py +42 -0
- offload/engine/hecbench.py +568 -0
- offload/engine/hecbench_report.py +265 -0
- offload/engine/hecbench_run.py +483 -0
- offload/engine/idioms.py +1427 -0
- offload/engine/kbody_cites.py +81 -0
- offload/engine/kbody_emit.py +949 -0
- offload/engine/kbody_gen.py +795 -0
- offload/engine/legality_review.py +236 -0
- offload/engine/localcfg.py +58 -0
- offload/engine/malloc_dd.py +267 -0
- offload/engine/mutate.py +1933 -0
- offload/engine/nested_cites.py +196 -0
- offload/engine/nested_emit.py +789 -0
- offload/engine/nested_gen.py +1721 -0
- offload/engine/offload_scope.py +197 -0
- offload/engine/ompvv.py +624 -0
- offload/engine/oop_gen.py +2249 -0
- offload/engine/prerun.py +1435 -0
- offload/engine/program_source.py +739 -0
- offload/engine/provenance.py +103 -0
- offload/engine/reduce.py +2098 -0
- offload/engine/report.py +3374 -0
- offload/engine/root.py +33 -0
- offload/engine/rules.py +4256 -0
- offload/engine/run_matrix.py +325 -0
- offload/engine/site/__init__.py +1 -0
- offload/engine/site/columns.py +53 -0
- offload/engine/site/data.py +648 -0
- offload/engine/site/header.py +228 -0
- offload/engine/site/inputs.py +115 -0
- offload/engine/site/matrix.py +434 -0
- offload/engine/site/scrub.py +294 -0
- offload/engine/skeleton.py +121 -0
- offload/engine/spec_text.py +242 -0
- offload/engine/stress.py +4122 -0
- offload/engine/stress_c.py +1000 -0
- offload/engine/stress_exec.py +805 -0
- offload/engine/stress_min.py +248 -0
- offload/engine/stress_report.py +552 -0
- offload/engine/textclean.py +97 -0
- offload/engine/toolchains.py +1070 -0
- offload/engine/transforms.py +511 -0
- offload/engine/usage.py +1252 -0
- offload/engine/widen.py +673 -0
- offload/engine/widen_progs.py +2396 -0
- offload/issues.py +146 -0
- offtarget-0.1.0.dist-info/METADATA +86 -0
- offtarget-0.1.0.dist-info/RECORD +886 -0
- offtarget-0.1.0.dist-info/WHEEL +4 -0
- offtarget-0.1.0.dist-info/entry_points.txt +2 -0
- offtarget-0.1.0.dist-info/licenses/LICENSE +21 -0
- 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")
|