[flang][OpenMP] Tolerate compiler directives in loop constructs (#169346)

PR168884 flagged compiler directives (!dir$ ...) inside OpenMP loop
constructs as errors. This caused some customer applications to fail to
compile (issue 169229).

Downgrade the error to a warning, and gracefully ignore compiler
directives when lowering loop constructs to MLIR.

Fixes https://github.com/llvm/llvm-project/issues/169229
This commit is contained in:
Krzysztof Parzyszek 2025-11-24 16:48:27 -06:00 committed by GitHub
parent 4e7ce57e0e
commit 9cff3f51d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 15 deletions

View File

@ -796,6 +796,28 @@ static void processTileSizesFromOpenMPConstruct(
}
}
static pft::Evaluation *getNestedDoConstruct(pft::Evaluation &eval) {
for (pft::Evaluation &nested : eval.getNestedEvaluations()) {
// In an OpenMPConstruct there can be compiler directives:
// 1 <<OpenMPConstruct>>
// 2 CompilerDirective: !unroll
// <<DoConstruct>> -> 8
if (nested.getIf<parser::CompilerDirective>())
continue;
// Within a DoConstruct, there can be compiler directives, plus
// there is a DoStmt before the body:
// <<DoConstruct>> -> 8
// 3 NonLabelDoStmt -> 7: do i = 1, n
// <<DoConstruct>> -> 7
if (nested.getIf<parser::NonLabelDoStmt>())
continue;
assert(nested.getIf<parser::DoConstruct>() &&
"Unexpected construct in the nested evaluations");
return &nested;
}
llvm_unreachable("Expected do loop to be in the nested evaluations");
}
/// Populates the sizes vector with values if the given OpenMPConstruct
/// contains a loop construct with an inner tiling construct.
void collectTileSizesFromOpenMPConstruct(
@ -818,7 +840,7 @@ int64_t collectLoopRelatedInfo(
int64_t numCollapse = 1;
// Collect the loops to collapse.
lower::pft::Evaluation *doConstructEval = &eval.getFirstNestedEvaluation();
lower::pft::Evaluation *doConstructEval = getNestedDoConstruct(eval);
if (doConstructEval->getIf<parser::DoConstruct>()->IsDoConcurrent()) {
TODO(currentLocation, "Do Concurrent in Worksharing loop construct");
}
@ -844,7 +866,7 @@ void collectLoopRelatedInfo(
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
// Collect the loops to collapse.
lower::pft::Evaluation *doConstructEval = &eval.getFirstNestedEvaluation();
lower::pft::Evaluation *doConstructEval = getNestedDoConstruct(eval);
if (doConstructEval->getIf<parser::DoConstruct>()->IsDoConcurrent()) {
TODO(currentLocation, "Do Concurrent in Worksharing loop construct");
}
@ -885,9 +907,8 @@ void collectLoopRelatedInfo(
iv.push_back(bounds->name.thing.symbol);
loopVarTypeSize = std::max(loopVarTypeSize,
bounds->name.thing.symbol->GetUltimate().size());
collapseValue--;
doConstructEval =
&*std::next(doConstructEval->getNestedEvaluations().begin());
if (--collapseValue)
doConstructEval = getNestedDoConstruct(*doConstructEval);
} while (collapseValue > 0);
convertLoopBounds(converter, currentLocation, result, loopVarTypeSize);

View File

@ -267,7 +267,7 @@ void OmpStructureChecker::CheckNestedBlock(const parser::OpenMPLoopConstruct &x,
for (auto &stmt : body) {
if (auto *dir{parser::Unwrap<parser::CompilerDirective>(stmt)}) {
context_.Say(dir->source,
"Compiler directives are not allowed inside OpenMP loop constructs"_err_en_US);
"Compiler directives are not allowed inside OpenMP loop constructs"_warn_en_US);
} else if (parser::Unwrap<parser::DoConstruct>(stmt)) {
++nestedCount;
} else if (auto *omp{parser::Unwrap<parser::OpenMPLoopConstruct>(stmt)}) {

View File

@ -2419,13 +2419,6 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
}
}
CheckAssocLoopLevel(level, GetAssociatedClause());
} else {
unsigned version{context_.langOptions().OpenMPVersion};
context_.Say(GetContext().directiveSource,
"A DO loop must follow the %s directive"_err_en_US,
parser::ToUpperCaseLetters(
llvm::omp::getOpenMPDirectiveName(GetContext().directive, version)
.str()));
}
}
}

View File

@ -0,0 +1,21 @@
!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
! Check that this compiles successfully, but not rely on any specific output.
!CHECK: omp.parallel
program omp_cdir_crash
implicit none
integer, parameter :: n = 10
real :: a(n)
integer :: i
!$omp parallel do
!dir$ unroll
do i = 1, n
a(i) = real(i)
end do
!$omp end parallel do
print *, 'a(1)=', a(1), ' a(n)=', a(n)
end program omp_cdir_crash

View File

@ -33,10 +33,9 @@
END DO outer
! Accept directives between parallel do and actual loop.
!ERROR: A DO loop must follow the PARALLEL DO directive
!$OMP PARALLEL DO
!WARNING: Unrecognized compiler directive was ignored [-Wignored-directive]
!ERROR: Compiler directives are not allowed inside OpenMP loop constructs
!WARNING: Compiler directives are not allowed inside OpenMP loop constructs
!DIR$ VECTOR ALIGNED
DO 20 i=1,N
a = a + 0.5