[flang][OpenMP] Implement collapse for imperfectly nested loops (#202435)
Fixes #199092
Flang previously rejected intervening code between associated loops in a
collapsed nest (e.g. `collapse(2)` with statements between the outer and
inner DO). This patch removes that restriction and implements correct
lowering.
**Semantics:** accept intervening code retroactively for all versions,
except when perfect nesting is still required
OpenMP 5.0 introduced support for collapsing imperfectly nested loops
for worksharing-loop, simd, taskloop, and distribute constructs. OpenMP
5.1 later formalized this under the Canonical Loop Nest (CLN)
definition. This support is applied retroactively for all OpenMP
versions, since the semantics are safe to implement regardless of
version and for compatibility with other compilers.
The only case where perfect nesting is still enforced is when ordered
semantics require it:
- Pre-5.2: any ordered clause with an argument requires perfect nesting.
- 5.2+: perfect nesting is required only when the loop body contains
ordered directives with doacross (or the legacy depend(sink/source))
clauses.
A `DoacrossFinder` visitor is added to detect doacross directives in the
loop body while correctly not descending into nested OpenMP block/loop
constructs (which have their own binding context).
**Lowering**
Intervening statements are guarded by induction variable comparisons
within the flat `omp.loop_nest` body: "before" code executes when inner
induction variables equal their lower bounds; "after" code executes when
inner induction variables equal their last iteration values (`lb + ((ub
- lb) / step) * step)` for non-unit steps).
**Testing**
- Lowering lit test added
- Semantics tests: updated to remove expected errors for now-accepted
code; new tests added for coverage.
- llvm-test-suite update: (will add once opened)
Assisted by: Copilot