[llvm-branch-commits] [flang] [flang][OpenMP] Track reachable metadirective replacements (PR #219014)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Sep 18 23:19:46 PDT 2026
================
@@ -702,6 +745,170 @@ void OmpStructureChecker::CheckTraitSimd(
}
}
+void OmpStructureChecker::CollectMetadirectiveConstructSelectors(
+ const parser::ProgramUnit &programUnit) {
+ metadirectiveConstructSelectors_.clear();
+ MetadirectiveConstructSelectorCollector collector{
+ metadirectiveConstructSelectors_};
+ parser::Walk(programUnit, collector);
+}
+
+OmpStructureChecker::ConstructTraitSequence
+OmpStructureChecker::GetConstructTraitsForPath(
+ const EffectiveDirectivePath &path) const {
+ ConstructTraitSequence constructTraits;
+ for (auto directive{path.rbegin()}; directive != path.rend(); ++directive) {
+ // The construct trait set starts at the innermost target construct.
+ if (llvm::omp::allTargetSet.test(*directive)) {
+ constructTraits.clear();
+ }
+ for (llvm::omp::Directive leaf :
+ llvm::omp::getLeafConstructsOrSelf(*directive)) {
+ if (leaf == llvm::omp::Directive::OMPD_nothing ||
+ leaf == llvm::omp::Directive::OMPD_unknown) {
+ continue;
+ }
+ llvm::omp::VariantMatchInfo leafVMI;
+ AppendConstructTraitsForDirective(leaf, leafVMI);
+ if (leafVMI.ConstructTraits.empty()) {
+ // Source constructs without selector traits still occupy positions
+ // in the scoring context, including leaves of combined directives.
+ constructTraits.push_back(llvm::omp::TraitProperty::invalid);
----------------
MattPD wrote:
This code counts every leaf of every enclosing directive, while lowering's `collectEnclosingConstructTraits` derives positions from emitted-operation ancestry. The two disagree on three shapes. In each one, semantics skips a loop-nest check that the merge base and https://github.com/llvm/llvm-project/pull/224431 report. Lowering then selects the replacement and aborts with a "not yet implemented" error:
- `tile` and `unroll`: Semantics counts them. Lowering never sees them, because their operations have no region.
- `teams distribute parallel do`: Semantics puts `parallel` at source position 2. Lowering puts it at operation position 1.
- `assume`: Semantics counts it. Lowering emits nothing for it. OpenMP 5.2 section 8.3.3 classifies `assume` as informational, so lowering has the correct depth in this case.
You can reproduce the first case by saving the following to `tile.f90` and running `flang -fc1 -fopenmp -fopenmp-version=52 -emit-hlfir -o - tile.f90`:
```fortran
subroutine tile_gap(n, a)
integer :: n, a(n,n), i, j
!$omp tile sizes(2)
do i = 1, n
!$omp metadirective &
!$omp& when(implementation={vendor(score(3): llvm)}: simd collapse(2)) &
!$omp& when(device={arch(x86_64)}: nothing)
do j = 1, n
a(j,i) = j
end do
end do
end subroutine
```
At the merge base and on https://github.com/llvm/llvm-project/pull/224431 this reports "This construct requires a nest of depth 2". With this PR, semantics counts `tile`, scores `arch(x86_64)` 2^2 + 1 = 5 against 4, treats the SIMD replacement as unreachable, and omits the diagnostic. Lowering scores it 3 against 4, selects the SIMD replacement, and aborts with "not yet implemented: METADIRECTIVE variant with COLLAPSE or ORDERED requires a deeper perfectly-nested loop nest than is present". Removing the `tile` line restores the diagnostic, and `!$omp unroll partial(2)` behaves the same way.
The commit message states the invariant ("Reachability must use the same construct positions and depth as lowering"), but the tests do not compare the two phases. Could the two phases derive the position sequence from one shared source that skips informational leaves? Paired semantics and lowering tests would then cover three shapes: a construct selector under `teams distribute parallel do`, a metadirective inside `tile`, and a metadirective inside `assume`. The lowering-side causes are in https://github.com/llvm/llvm-project/pull/224431.
https://github.com/llvm/llvm-project/pull/219014
More information about the llvm-branch-commits
mailing list