Skip to content

Commit d3d96e2

Browse files
authored
[flang][OpenMP] Add -f[no]-openmp-simd (#150269)
Both clang and gfortran support the -fopenmp-simd flag, which enables OpenMP support only for simd constructs, while disabling the rest of OpenMP. Implement the appropriate parse tree rewriting to remove non-SIMD OpenMP constructs at the parsing stage. Add a new SimdOnly flang OpenMP IR pass which rewrites generated OpenMP FIR to handle untangling composite simd constructs, and clean up OpenMP operations leftover after the parse tree rewriting stage. With this approach, the two parts of the logic required to make the flag work can be self-contained within the parse tree rewriter and the MLIR pass, respectively. It does not need to be implemented within the core lowering logic itself. The flag is expected to have no effect if -fopenmp is passed explicitly, and is only expected to remove OpenMP constructs, not things like OpenMP library functions calls. This matches the behaviour of other compilers. --------- Signed-off-by: Kajetan Puchalski <[email protected]>
1 parent 9d1dd9a commit d3d96e2

File tree

19 files changed

+1280
-44
lines changed

19 files changed

+1280
-44
lines changed

clang/include/clang/Driver/Options.td

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3731,14 +3731,20 @@ def fopenmp_relocatable_target : Flag<["-"], "fopenmp-relocatable-target">,
37313731
def fnoopenmp_relocatable_target : Flag<["-"], "fnoopenmp-relocatable-target">,
37323732
Group<f_Group>, Flags<[NoArgumentUnused, HelpHidden]>,
37333733
Visibility<[ClangOption, CC1Option]>;
3734-
def fopenmp_simd : Flag<["-"], "fopenmp-simd">, Group<f_Group>,
3735-
Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>,
3736-
HelpText<"Emit OpenMP code only for SIMD-based constructs.">;
3734+
def fopenmp_simd : Flag<["-"], "fopenmp-simd">,
3735+
Group<f_Group>,
3736+
Flags<[NoArgumentUnused]>,
3737+
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
3738+
HelpText<"Emit OpenMP code only for SIMD-based constructs.">;
37373739
def fopenmp_enable_irbuilder : Flag<["-"], "fopenmp-enable-irbuilder">, Group<f_Group>,
37383740
Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>,
37393741
HelpText<"Use the experimental OpenMP-IR-Builder codegen path.">;
3740-
def fno_openmp_simd : Flag<["-"], "fno-openmp-simd">, Group<f_Group>,
3741-
Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option]>;
3742+
def fno_openmp_simd
3743+
: Flag<["-"], "fno-openmp-simd">,
3744+
Group<f_Group>,
3745+
Flags<[NoArgumentUnused]>,
3746+
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
3747+
HelpText<"Do not emit code for any OpenMP constructs.">;
37423748
def fopenmp_cuda_mode : Flag<["-"], "fopenmp-cuda-mode">, Group<f_Group>,
37433749
Flags<[NoArgumentUnused, HelpHidden]>, Visibility<[ClangOption, CC1Option]>;
37443750
def fno_openmp_cuda_mode : Flag<["-"], "fno-openmp-cuda-mode">, Group<f_Group>,

clang/lib/Driver/ToolChains/Flang.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
937937

938938
if (Args.hasArg(options::OPT_fopenmp_force_usm))
939939
CmdArgs.push_back("-fopenmp-force-usm");
940+
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
941+
options::OPT_fno_openmp_simd);
940942

941943
// FIXME: Clang supports a whole bunch more flags here.
942944
break;
@@ -952,6 +954,9 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
952954
<< A->getSpelling() << A->getValue();
953955
break;
954956
}
957+
} else {
958+
Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd,
959+
options::OPT_fno_openmp_simd);
955960
}
956961

957962
// Pass the path to compiler resource files.

flang/include/flang/Optimizer/OpenMP/Passes.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,9 @@ def GenericLoopConversionPass
112112
];
113113
}
114114

115+
def SimdOnlyPass : Pass<"omp-simd-only", "mlir::ModuleOp"> {
116+
let summary = "Filters out non-simd OpenMP constructs";
117+
let dependentDialects = ["mlir::omp::OpenMPDialect"];
118+
}
119+
115120
#endif //FORTRAN_OPTIMIZER_OPENMP_PASSES

flang/include/flang/Optimizer/Passes/Pipelines.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,16 @@ void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config);
119119
void createDefaultFIROptimizerPassPipeline(mlir::PassManager &pm,
120120
MLIRToLLVMPassPipelineConfig &pc);
121121

122+
/// Select which mode to enable OpenMP support in.
123+
enum class EnableOpenMP { None, Simd, Full };
124+
122125
/// Create a pass pipeline for lowering from HLFIR to FIR
123126
///
124127
/// \param pm - MLIR pass manager that will hold the pipeline definition
125128
/// \param optLevel - optimization level used for creating FIR optimization
126129
/// passes pipeline
127130
void createHLFIRToFIRPassPipeline(
128-
mlir::PassManager &pm, bool enableOpenMP,
131+
mlir::PassManager &pm, EnableOpenMP enableOpenMP,
129132
llvm::OptimizationLevel optLevel = defaultOptLevel);
130133

131134
struct OpenMPFIRPassPipelineOpts {

flang/include/flang/Semantics/openmp-directive-sets.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,22 @@ static const OmpDirectiveSet nestedWorkshareErrSet{
401401
Directive::OMPD_taskloop,
402402
} | workShareSet,
403403
};
404+
405+
//===----------------------------------------------------------------------===//
406+
// Misc directive sets
407+
//===----------------------------------------------------------------------===//
408+
409+
// Simple standalone directives than can be erased by -fopenmp-simd.
410+
static const OmpDirectiveSet simpleStandaloneNonSimdOnlySet{
411+
Directive::OMPD_taskyield,
412+
Directive::OMPD_barrier,
413+
Directive::OMPD_ordered,
414+
Directive::OMPD_target_enter_data,
415+
Directive::OMPD_target_exit_data,
416+
Directive::OMPD_target_update,
417+
Directive::OMPD_taskwait,
418+
};
419+
404420
} // namespace llvm::omp
405421

406422
#endif // FORTRAN_SEMANTICS_OPENMP_DIRECTIVE_SETS_H_

flang/include/flang/Support/LangOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ LANGOPT(OpenMPTeamSubscription, 1, 0)
5858
LANGOPT(OpenMPNoThreadState, 1, 0)
5959
/// Assume that no thread in a parallel region will encounter a parallel region
6060
LANGOPT(OpenMPNoNestedParallelism, 1, 0)
61+
/// Use SIMD only OpenMP support.
62+
LANGOPT(OpenMPSimd, 1, false)
6163

6264
LANGOPT(VScaleMin, 32, 0) ///< Minimum vscale range value
6365
LANGOPT(VScaleMax, 32, 0) ///< Maximum vscale range value

flang/include/flang/Tools/CrossToolHelpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
134134
///< functions.
135135
bool NSWOnLoopVarInc = true; ///< Add nsw flag to loop variable increments.
136136
bool EnableOpenMP = false; ///< Enable OpenMP lowering.
137+
bool EnableOpenMPSimd = false; ///< Enable OpenMP simd-only mode.
137138
std::string InstrumentFunctionEntry =
138139
""; ///< Name of the instrument-function that is called on each
139140
///< function-entry

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,8 +1162,15 @@ static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
11621162
clang::DiagnosticsEngine &diags) {
11631163
llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_fopenmp,
11641164
clang::driver::options::OPT_fno_openmp);
1165-
if (!arg || arg->getOption().matches(clang::driver::options::OPT_fno_openmp))
1166-
return true;
1165+
if (!arg ||
1166+
arg->getOption().matches(clang::driver::options::OPT_fno_openmp)) {
1167+
bool isSimdSpecified = args.hasFlag(
1168+
clang::driver::options::OPT_fopenmp_simd,
1169+
clang::driver::options::OPT_fno_openmp_simd, /*Default=*/false);
1170+
if (!isSimdSpecified)
1171+
return true;
1172+
res.getLangOpts().OpenMPSimd = 1;
1173+
}
11671174

11681175
unsigned numErrorsBefore = diags.getNumErrors();
11691176
llvm::Triple t(res.getTargetOpts().triple);

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ bool CodeGenAction::beginSourceFileAction() {
298298
bool isOpenMPEnabled =
299299
ci.getInvocation().getFrontendOpts().features.IsEnabled(
300300
Fortran::common::LanguageFeature::OpenMP);
301+
bool isOpenMPSimd = ci.getInvocation().getLangOpts().OpenMPSimd;
301302

302303
fir::OpenMPFIRPassPipelineOpts opts;
303304

@@ -329,12 +330,13 @@ bool CodeGenAction::beginSourceFileAction() {
329330
if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
330331
mlirModule->getOperation()))
331332
opts.isTargetDevice = offloadMod.getIsTargetDevice();
333+
}
332334

333-
// WARNING: This pipeline must be run immediately after the lowering to
334-
// ensure that the FIR is correct with respect to OpenMP operations/
335-
// attributes.
335+
// WARNING: This pipeline must be run immediately after the lowering to
336+
// ensure that the FIR is correct with respect to OpenMP operations/
337+
// attributes.
338+
if (isOpenMPEnabled || isOpenMPSimd)
336339
fir::createOpenMPFIRPassPipeline(pm, opts);
337-
}
338340

339341
pm.enableVerifier(/*verifyPasses=*/true);
340342
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
@@ -617,12 +619,14 @@ void CodeGenAction::lowerHLFIRToFIR() {
617619
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
618620
pm.enableVerifier(/*verifyPasses=*/true);
619621

622+
fir::EnableOpenMP enableOpenMP = fir::EnableOpenMP::None;
623+
if (ci.getInvocation().getFrontendOpts().features.IsEnabled(
624+
Fortran::common::LanguageFeature::OpenMP))
625+
enableOpenMP = fir::EnableOpenMP::Full;
626+
if (ci.getInvocation().getLangOpts().OpenMPSimd)
627+
enableOpenMP = fir::EnableOpenMP::Simd;
620628
// Create the pass pipeline
621-
fir::createHLFIRToFIRPassPipeline(
622-
pm,
623-
ci.getInvocation().getFrontendOpts().features.IsEnabled(
624-
Fortran::common::LanguageFeature::OpenMP),
625-
level);
629+
fir::createHLFIRToFIRPassPipeline(pm, enableOpenMP, level);
626630
(void)mlir::applyPassManagerCLOptions(pm);
627631

628632
mlir::TimingScope timingScopeMLIRPasses = timingScopeRoot.nest(
@@ -748,6 +752,9 @@ void CodeGenAction::generateLLVMIR() {
748752
Fortran::common::LanguageFeature::OpenMP))
749753
config.EnableOpenMP = true;
750754

755+
if (ci.getInvocation().getLangOpts().OpenMPSimd)
756+
config.EnableOpenMPSimd = true;
757+
751758
if (ci.getInvocation().getLoweringOpts().getIntegerWrapAround())
752759
config.NSWOnLoopVarInc = false;
753760

flang/lib/Lower/OpenMP/ClauseProcessor.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,15 @@ void ClauseProcessor::processTODO(mlir::Location currentLocation,
208208
if (!x)
209209
return;
210210
unsigned version = semaCtx.langOptions().OpenMPVersion;
211-
TODO(currentLocation,
212-
"Unhandled clause " + llvm::omp::getOpenMPClauseName(id).upper() +
213-
" in " +
214-
llvm::omp::getOpenMPDirectiveName(directive, version).upper() +
215-
" construct");
211+
bool isSimdDirective = llvm::omp::getOpenMPDirectiveName(directive, version)
212+
.upper()
213+
.find("SIMD") != llvm::StringRef::npos;
214+
if (!semaCtx.langOptions().OpenMPSimd || isSimdDirective)
215+
TODO(currentLocation,
216+
"Unhandled clause " + llvm::omp::getOpenMPClauseName(id).upper() +
217+
" in " +
218+
llvm::omp::getOpenMPDirectiveName(directive, version).upper() +
219+
" construct");
216220
};
217221

218222
for (ClauseIterator it = clauses.begin(); it != clauses.end(); ++it)

0 commit comments

Comments
 (0)