Skip to content

Commit 9dadb1f

Browse files
authored
[Flang][OpenMP] Add frontend support for -fopenmp-targets (#100155)
This patch adds support for the `-fopenmp-targets` option to the `bbc` and `flang -fc1` tools. It adds an `OMPTargetTriples` property to the `LangOptions` structure, which is filled with the triples represented by the compiler option. This is used to initialize the `omp.target_triples` module attribute for later use by lowering stages.
1 parent 6d2bbba commit 9dadb1f

File tree

5 files changed

+165
-84
lines changed

5 files changed

+165
-84
lines changed

flang/include/flang/Frontend/LangOptions.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
#define FORTRAN_FRONTEND_LANGOPTIONS_H
1717

1818
#include <string>
19+
#include <vector>
20+
21+
#include "llvm/TargetParser/Triple.h"
1922

2023
namespace Fortran::frontend {
2124

@@ -58,6 +61,9 @@ class LangOptions : public LangOptionsBase {
5861
/// host code generation.
5962
std::string OMPHostIRFile;
6063

64+
/// List of triples passed in using -fopenmp-targets.
65+
std::vector<llvm::Triple> OMPTargetTriples;
66+
6167
LangOptions();
6268
};
6369

flang/include/flang/Tools/CrossToolHelpers.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,19 @@ struct OffloadModuleOpts {
131131
bool OpenMPThreadSubscription, bool OpenMPNoThreadState,
132132
bool OpenMPNoNestedParallelism, bool OpenMPIsTargetDevice,
133133
bool OpenMPIsGPU, bool OpenMPForceUSM, uint32_t OpenMPVersion,
134-
std::string OMPHostIRFile = {}, bool NoGPULib = false)
134+
std::string OMPHostIRFile = {},
135+
const std::vector<llvm::Triple> &OMPTargetTriples = {},
136+
bool NoGPULib = false)
135137
: OpenMPTargetDebug(OpenMPTargetDebug),
136138
OpenMPTeamSubscription(OpenMPTeamSubscription),
137139
OpenMPThreadSubscription(OpenMPThreadSubscription),
138140
OpenMPNoThreadState(OpenMPNoThreadState),
139141
OpenMPNoNestedParallelism(OpenMPNoNestedParallelism),
140142
OpenMPIsTargetDevice(OpenMPIsTargetDevice), OpenMPIsGPU(OpenMPIsGPU),
141143
OpenMPForceUSM(OpenMPForceUSM), OpenMPVersion(OpenMPVersion),
142-
OMPHostIRFile(OMPHostIRFile), NoGPULib(NoGPULib) {}
144+
OMPHostIRFile(OMPHostIRFile),
145+
OMPTargetTriples(OMPTargetTriples.begin(), OMPTargetTriples.end()),
146+
NoGPULib(NoGPULib) {}
143147

144148
OffloadModuleOpts(Fortran::frontend::LangOptions &Opts)
145149
: OpenMPTargetDebug(Opts.OpenMPTargetDebug),
@@ -150,7 +154,7 @@ struct OffloadModuleOpts {
150154
OpenMPIsTargetDevice(Opts.OpenMPIsTargetDevice),
151155
OpenMPIsGPU(Opts.OpenMPIsGPU), OpenMPForceUSM(Opts.OpenMPForceUSM),
152156
OpenMPVersion(Opts.OpenMPVersion), OMPHostIRFile(Opts.OMPHostIRFile),
153-
NoGPULib(Opts.NoGPULib) {}
157+
OMPTargetTriples(Opts.OMPTargetTriples), NoGPULib(Opts.NoGPULib) {}
154158

155159
uint32_t OpenMPTargetDebug = 0;
156160
bool OpenMPTeamSubscription = false;
@@ -162,6 +166,7 @@ struct OffloadModuleOpts {
162166
bool OpenMPForceUSM = false;
163167
uint32_t OpenMPVersion = 11;
164168
std::string OMPHostIRFile = {};
169+
std::vector<llvm::Triple> OMPTargetTriples = {};
165170
bool NoGPULib = false;
166171
};
167172

@@ -185,6 +190,9 @@ struct OffloadModuleOpts {
185190
if (!Opts.OMPHostIRFile.empty())
186191
offloadMod.setHostIRFilePath(Opts.OMPHostIRFile);
187192
}
193+
auto strTriples = llvm::to_vector(llvm::map_range(Opts.OMPTargetTriples,
194+
[](llvm::Triple triple) { return triple.normalize(); }));
195+
offloadMod.setTargetTriples(strTriples);
188196
}
189197
}
190198

flang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 126 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -929,90 +929,11 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
929929
Fortran::common::LanguageFeature::CUDA);
930930
}
931931

932-
// -fopenmp and -fopenacc
932+
// -fopenacc
933933
if (args.hasArg(clang::driver::options::OPT_fopenacc)) {
934934
res.getFrontendOpts().features.Enable(
935935
Fortran::common::LanguageFeature::OpenACC);
936936
}
937-
if (args.hasArg(clang::driver::options::OPT_fopenmp)) {
938-
// By default OpenMP is set to 1.1 version
939-
res.getLangOpts().OpenMPVersion = 11;
940-
res.getFrontendOpts().features.Enable(
941-
Fortran::common::LanguageFeature::OpenMP);
942-
if (int Version = getLastArgIntValue(
943-
args, clang::driver::options::OPT_fopenmp_version_EQ,
944-
res.getLangOpts().OpenMPVersion, diags)) {
945-
res.getLangOpts().OpenMPVersion = Version;
946-
}
947-
if (args.hasArg(clang::driver::options::OPT_fopenmp_force_usm)) {
948-
res.getLangOpts().OpenMPForceUSM = 1;
949-
}
950-
if (args.hasArg(clang::driver::options::OPT_fopenmp_is_target_device)) {
951-
res.getLangOpts().OpenMPIsTargetDevice = 1;
952-
953-
// Get OpenMP host file path if any and report if a non existent file is
954-
// found
955-
if (auto *arg = args.getLastArg(
956-
clang::driver::options::OPT_fopenmp_host_ir_file_path)) {
957-
res.getLangOpts().OMPHostIRFile = arg->getValue();
958-
if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile))
959-
diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found)
960-
<< res.getLangOpts().OMPHostIRFile;
961-
}
962-
963-
if (args.hasFlag(
964-
clang::driver::options::OPT_fopenmp_assume_teams_oversubscription,
965-
clang::driver::options::
966-
OPT_fno_openmp_assume_teams_oversubscription,
967-
/*Default=*/false))
968-
res.getLangOpts().OpenMPTeamSubscription = true;
969-
970-
if (args.hasArg(
971-
clang::driver::options::OPT_fopenmp_assume_no_thread_state))
972-
res.getLangOpts().OpenMPNoThreadState = 1;
973-
974-
if (args.hasArg(
975-
clang::driver::options::OPT_fopenmp_assume_no_nested_parallelism))
976-
res.getLangOpts().OpenMPNoNestedParallelism = 1;
977-
978-
if (args.hasFlag(clang::driver::options::
979-
OPT_fopenmp_assume_threads_oversubscription,
980-
clang::driver::options::
981-
OPT_fno_openmp_assume_threads_oversubscription,
982-
/*Default=*/false))
983-
res.getLangOpts().OpenMPThreadSubscription = true;
984-
985-
if ((args.hasArg(clang::driver::options::OPT_fopenmp_target_debug) ||
986-
args.hasArg(clang::driver::options::OPT_fopenmp_target_debug_EQ))) {
987-
res.getLangOpts().OpenMPTargetDebug = getLastArgIntValue(
988-
args, clang::driver::options::OPT_fopenmp_target_debug_EQ,
989-
res.getLangOpts().OpenMPTargetDebug, diags);
990-
991-
if (!res.getLangOpts().OpenMPTargetDebug &&
992-
args.hasArg(clang::driver::options::OPT_fopenmp_target_debug))
993-
res.getLangOpts().OpenMPTargetDebug = 1;
994-
}
995-
if (args.hasArg(clang::driver::options::OPT_nogpulib))
996-
res.getLangOpts().NoGPULib = 1;
997-
}
998-
999-
switch (llvm::Triple(res.getTargetOpts().triple).getArch()) {
1000-
case llvm::Triple::nvptx:
1001-
case llvm::Triple::nvptx64:
1002-
case llvm::Triple::amdgcn:
1003-
if (!res.getLangOpts().OpenMPIsTargetDevice) {
1004-
const unsigned diagID = diags.getCustomDiagID(
1005-
clang::DiagnosticsEngine::Error,
1006-
"OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
1007-
diags.Report(diagID);
1008-
}
1009-
res.getLangOpts().OpenMPIsGPU = 1;
1010-
break;
1011-
default:
1012-
res.getLangOpts().OpenMPIsGPU = 0;
1013-
break;
1014-
}
1015-
}
1016937

1017938
// -pedantic
1018939
if (args.hasArg(clang::driver::options::OPT_pedantic)) {
@@ -1042,6 +963,130 @@ static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
1042963
return diags.getNumErrors() == numErrorsBefore;
1043964
}
1044965

966+
/// Parses all OpenMP related arguments if the -fopenmp option is present,
967+
/// populating the \c res object accordingly. Returns false if new errors are
968+
/// generated.
969+
static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args,
970+
clang::DiagnosticsEngine &diags) {
971+
if (!args.hasArg(clang::driver::options::OPT_fopenmp))
972+
return true;
973+
974+
unsigned numErrorsBefore = diags.getNumErrors();
975+
llvm::Triple t(res.getTargetOpts().triple);
976+
977+
// By default OpenMP is set to 1.1 version
978+
res.getLangOpts().OpenMPVersion = 11;
979+
res.getFrontendOpts().features.Enable(
980+
Fortran::common::LanguageFeature::OpenMP);
981+
if (int Version = getLastArgIntValue(
982+
args, clang::driver::options::OPT_fopenmp_version_EQ,
983+
res.getLangOpts().OpenMPVersion, diags)) {
984+
res.getLangOpts().OpenMPVersion = Version;
985+
}
986+
if (args.hasArg(clang::driver::options::OPT_fopenmp_force_usm)) {
987+
res.getLangOpts().OpenMPForceUSM = 1;
988+
}
989+
if (args.hasArg(clang::driver::options::OPT_fopenmp_is_target_device)) {
990+
res.getLangOpts().OpenMPIsTargetDevice = 1;
991+
992+
// Get OpenMP host file path if any and report if a non existent file is
993+
// found
994+
if (auto *arg = args.getLastArg(
995+
clang::driver::options::OPT_fopenmp_host_ir_file_path)) {
996+
res.getLangOpts().OMPHostIRFile = arg->getValue();
997+
if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile))
998+
diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found)
999+
<< res.getLangOpts().OMPHostIRFile;
1000+
}
1001+
1002+
if (args.hasFlag(
1003+
clang::driver::options::OPT_fopenmp_assume_teams_oversubscription,
1004+
clang::driver::options::
1005+
OPT_fno_openmp_assume_teams_oversubscription,
1006+
/*Default=*/false))
1007+
res.getLangOpts().OpenMPTeamSubscription = true;
1008+
1009+
if (args.hasArg(clang::driver::options::OPT_fopenmp_assume_no_thread_state))
1010+
res.getLangOpts().OpenMPNoThreadState = 1;
1011+
1012+
if (args.hasArg(
1013+
clang::driver::options::OPT_fopenmp_assume_no_nested_parallelism))
1014+
res.getLangOpts().OpenMPNoNestedParallelism = 1;
1015+
1016+
if (args.hasFlag(
1017+
clang::driver::options::OPT_fopenmp_assume_threads_oversubscription,
1018+
clang::driver::options::
1019+
OPT_fno_openmp_assume_threads_oversubscription,
1020+
/*Default=*/false))
1021+
res.getLangOpts().OpenMPThreadSubscription = true;
1022+
1023+
if ((args.hasArg(clang::driver::options::OPT_fopenmp_target_debug) ||
1024+
args.hasArg(clang::driver::options::OPT_fopenmp_target_debug_EQ))) {
1025+
res.getLangOpts().OpenMPTargetDebug = getLastArgIntValue(
1026+
args, clang::driver::options::OPT_fopenmp_target_debug_EQ,
1027+
res.getLangOpts().OpenMPTargetDebug, diags);
1028+
1029+
if (!res.getLangOpts().OpenMPTargetDebug &&
1030+
args.hasArg(clang::driver::options::OPT_fopenmp_target_debug))
1031+
res.getLangOpts().OpenMPTargetDebug = 1;
1032+
}
1033+
if (args.hasArg(clang::driver::options::OPT_nogpulib))
1034+
res.getLangOpts().NoGPULib = 1;
1035+
}
1036+
1037+
switch (llvm::Triple(res.getTargetOpts().triple).getArch()) {
1038+
case llvm::Triple::nvptx:
1039+
case llvm::Triple::nvptx64:
1040+
case llvm::Triple::amdgcn:
1041+
if (!res.getLangOpts().OpenMPIsTargetDevice) {
1042+
const unsigned diagID = diags.getCustomDiagID(
1043+
clang::DiagnosticsEngine::Error,
1044+
"OpenMP AMDGPU/NVPTX is only prepared to deal with device code.");
1045+
diags.Report(diagID);
1046+
}
1047+
res.getLangOpts().OpenMPIsGPU = 1;
1048+
break;
1049+
default:
1050+
res.getLangOpts().OpenMPIsGPU = 0;
1051+
break;
1052+
}
1053+
1054+
// Get the OpenMP target triples if any.
1055+
if (auto *arg =
1056+
args.getLastArg(clang::driver::options::OPT_fopenmp_targets_EQ)) {
1057+
enum ArchPtrSize { Arch16Bit, Arch32Bit, Arch64Bit };
1058+
auto getArchPtrSize = [](const llvm::Triple &triple) {
1059+
if (triple.isArch16Bit())
1060+
return Arch16Bit;
1061+
if (triple.isArch32Bit())
1062+
return Arch32Bit;
1063+
assert(triple.isArch64Bit() && "Expected 64-bit architecture");
1064+
return Arch64Bit;
1065+
};
1066+
1067+
for (unsigned i = 0; i < arg->getNumValues(); ++i) {
1068+
llvm::Triple tt(arg->getValue(i));
1069+
1070+
if (tt.getArch() == llvm::Triple::UnknownArch ||
1071+
!(tt.getArch() == llvm::Triple::aarch64 || tt.isPPC() ||
1072+
tt.getArch() == llvm::Triple::systemz ||
1073+
tt.getArch() == llvm::Triple::nvptx ||
1074+
tt.getArch() == llvm::Triple::nvptx64 ||
1075+
tt.getArch() == llvm::Triple::amdgcn ||
1076+
tt.getArch() == llvm::Triple::x86 ||
1077+
tt.getArch() == llvm::Triple::x86_64))
1078+
diags.Report(clang::diag::err_drv_invalid_omp_target)
1079+
<< arg->getValue(i);
1080+
else if (getArchPtrSize(t) != getArchPtrSize(tt))
1081+
diags.Report(clang::diag::err_drv_incompatible_omp_arch)
1082+
<< arg->getValue(i) << t.str();
1083+
else
1084+
res.getLangOpts().OMPTargetTriples.push_back(tt);
1085+
}
1086+
}
1087+
return diags.getNumErrors() == numErrorsBefore;
1088+
}
1089+
10451090
/// Parses all floating point related arguments and populates the
10461091
/// CompilerInvocation accordingly.
10471092
/// Returns false if new errors are generated.
@@ -1277,6 +1322,7 @@ bool CompilerInvocation::createFromArgs(
12771322
success &= parseVectorLibArg(invoc.getCodeGenOpts(), args, diags);
12781323
success &= parseSemaArgs(invoc, args, diags);
12791324
success &= parseDialectArgs(invoc, args, diags);
1325+
success &= parseOpenMPArgs(invoc, args, diags);
12801326
success &= parseDiagArgs(invoc, args, diags);
12811327

12821328
// Collect LLVM (-mllvm) and MLIR (-mmlir) options.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda %s -o - | FileCheck %s
2+
! RUN: bbc -emit-hlfir -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa,nvptx64-nvidia-cuda %s -o - | FileCheck %s
3+
4+
! This test checks the addition of the omp.target_triples attribute when the
5+
! -fopenmp-targets option is set
6+
7+
!CHECK: module attributes {
8+
!CHECK-SAME: omp.target_triples = ["amdgcn-amd-amdhsa", "nvptx64-nvidia-cuda"]
9+
program targets
10+
end program targets

flang/tools/bbc/bbc.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ static llvm::cl::opt<bool> enableOpenMPForceUSM(
149149
llvm::cl::desc("force openmp unified shared memory mode"),
150150
llvm::cl::init(false));
151151

152+
static llvm::cl::list<std::string> targetTriplesOpenMP(
153+
"fopenmp-targets",
154+
llvm::cl::desc("comma-separated list of OpenMP offloading triples"),
155+
llvm::cl::CommaSeparated);
156+
152157
// A simplified subset of the OpenMP RTL Flags from Flang, only the primary
153158
// positive options are available, no negative options e.g. fopen_assume* vs
154159
// fno_open_assume*
@@ -380,11 +385,17 @@ static llvm::LogicalResult convertFortranSourceToMLIR(
380385
"-fopenmp-is-target-device is also set";
381386
return mlir::failure();
382387
}
388+
// Construct offloading target triples vector.
389+
std::vector<llvm::Triple> targetTriples;
390+
targetTriples.reserve(targetTriplesOpenMP.size());
391+
for (llvm::StringRef s : targetTriplesOpenMP)
392+
targetTriples.emplace_back(s);
393+
383394
auto offloadModuleOpts = OffloadModuleOpts(
384395
setOpenMPTargetDebug, setOpenMPTeamSubscription,
385396
setOpenMPThreadSubscription, setOpenMPNoThreadState,
386397
setOpenMPNoNestedParallelism, enableOpenMPDevice, enableOpenMPGPU,
387-
enableOpenMPForceUSM, setOpenMPVersion, "", setNoGPULib);
398+
enableOpenMPForceUSM, setOpenMPVersion, "", targetTriples, setNoGPULib);
388399
setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts);
389400
setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);
390401
}

0 commit comments

Comments
 (0)