"The provided host compiler IR file '%0' is required to generate code for OpenMP target regions but cannot be found.">;
def err_drv_omp_host_target_not_supported : Error<
"The target '%0' is not a supported OpenMP host target.">;
+def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
+ "The option -fopenmp-targets must be used in conjunction with a -fopenmp option compatible with offloading, please use -fopenmp=libomp or -fopenmp=libiomp5.">;
+def warn_drv_omp_offload_target_duplicate : Warning<
+ "The OpenMP offloading target '%0' is similar to target '%1' already specified - will be ignored.">,
+ InGroup<OpenMPTarget>;
def err_drv_bitcode_unsupported_on_toolchain : Error<
"-fembed-bitcode is not supported on versions of iOS prior to 6.0">;
OFK_Host = 0x01,
// The device offloading tool chains - one bit for each programming model.
OFK_Cuda = 0x02,
+ OFK_OpenMP = 0x04,
};
static const char *getClassName(ActionClass AC);
LTOKind LTOMode;
public:
+ enum OpenMPRuntimeKind {
+ /// An unknown OpenMP runtime. We can't generate effective OpenMP code
+ /// without knowing what runtime to target.
+ OMPRT_Unknown,
+
+ /// The LLVM OpenMP runtime. When completed and integrated, this will become
+ /// the default for Clang.
+ OMPRT_OMP,
+
+ /// The GNU OpenMP runtime. Clang doesn't support generating OpenMP code for
+ /// this runtime but can swallow the pragmas, and find and link against the
+ /// runtime library itself.
+ OMPRT_GOMP,
+
+ /// The legacy name for the LLVM OpenMP runtime from when it was the Intel
+ /// OpenMP runtime. We support this mode for users with existing
+ /// dependencies on this runtime library name.
+ OMPRT_IOMP5
+ };
+
// Diag - Forwarding function for diagnostics.
DiagnosticBuilder Diag(unsigned DiagID) const {
return Diags.Report(DiagID);
bool embedBitcodeEnabled() const { return BitcodeEmbed == EmbedBitcode; }
bool embedBitcodeMarkerOnly() const { return BitcodeEmbed == EmbedMarker; }
+ /// Compute the desired OpenMP runtime from the flags provided.
+ OpenMPRuntimeKind getOpenMPRuntime(const llvm::opt::ArgList &Args) const;
+
/// @}
/// @name Primary Functionality
/// @{
break;
case OFK_Cuda:
return "device-cuda";
+ case OFK_OpenMP:
+ return "device-openmp";
// TODO: Add other programming models here.
}
std::string Res("host");
if (ActiveOffloadKindMask & OFK_Cuda)
Res += "-cuda";
+ if (ActiveOffloadKindMask & OFK_OpenMP)
+ Res += "-openmp";
// TODO: Add other programming models here.
}
}
+/// Compute the desired OpenMP runtime from the flags provided.
+Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
+ StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME);
+
+ const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);
+ if (A)
+ RuntimeName = A->getValue();
+
+ auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName)
+ .Case("libomp", OMPRT_OMP)
+ .Case("libgomp", OMPRT_GOMP)
+ .Case("libiomp5", OMPRT_IOMP5)
+ .Default(OMPRT_Unknown);
+
+ if (RT == OMPRT_Unknown) {
+ if (A)
+ Diag(diag::err_drv_unsupported_option_argument)
+ << A->getOption().getName() << A->getValue();
+ else
+ // FIXME: We could use a nicer diagnostic here.
+ Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
+ }
+
+ return RT;
+}
+
void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
InputList &Inputs) {
C.addOffloadDeviceToolChain(&TC, Action::OFK_Cuda);
}
+ //
+ // OpenMP
+ //
+ // We need to generate an OpenMP toolchain if the user specified targets with
+ // the -fopenmp-targets option.
+ if (Arg *OpenMPTargets =
+ C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) {
+ if (OpenMPTargets->getNumValues()) {
+ // We expect that -fopenmp-targets is always used in conjunction with the
+ // option -fopenmp specifying a valid runtime with offloading support,
+ // i.e. libomp or libiomp.
+ bool HasValidOpenMPRuntime = C.getInputArgs().hasFlag(
+ options::OPT_fopenmp, options::OPT_fopenmp_EQ,
+ options::OPT_fno_openmp, false);
+ if (HasValidOpenMPRuntime) {
+ OpenMPRuntimeKind OpenMPKind = getOpenMPRuntime(C.getInputArgs());
+ HasValidOpenMPRuntime =
+ OpenMPKind == OMPRT_OMP || OpenMPKind == OMPRT_IOMP5;
+ }
+
+ if (HasValidOpenMPRuntime) {
+ llvm::StringMap<const char *> FoundNormalizedTriples;
+ for (const char *Val : OpenMPTargets->getValues()) {
+ llvm::Triple TT(Val);
+ std::string NormalizedName = TT.normalize();
+
+ // Make sure we don't have a duplicate triple.
+ auto Duplicate = FoundNormalizedTriples.find(NormalizedName);
+ if (Duplicate != FoundNormalizedTriples.end()) {
+ Diag(clang::diag::warn_drv_omp_offload_target_duplicate)
+ << Val << Duplicate->second;
+ continue;
+ }
+
+ // Store the current triple so that we can check for duplicates in the
+ // following iterations.
+ FoundNormalizedTriples[NormalizedName] = Val;
+
+ // If the specified target is invalid, emit a diagnostic.
+ if (TT.getArch() == llvm::Triple::UnknownArch)
+ Diag(clang::diag::err_drv_invalid_omp_target) << Val;
+ else {
+ const ToolChain &TC = getToolChain(C.getInputArgs(), TT);
+ C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP);
+ }
+ }
+ } else
+ Diag(clang::diag::err_drv_expecting_fopenmp_with_fopenmp_targets);
+ } else
+ Diag(clang::diag::warn_drv_empty_joined_argument)
+ << OpenMPTargets->getAsString(C.getInputArgs());
+ }
+
//
// TODO: Add support for other offloading programming models here.
//
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
}
-namespace {
-enum OpenMPRuntimeKind {
- /// An unknown OpenMP runtime. We can't generate effective OpenMP code
- /// without knowing what runtime to target.
- OMPRT_Unknown,
-
- /// The LLVM OpenMP runtime. When completed and integrated, this will become
- /// the default for Clang.
- OMPRT_OMP,
-
- /// The GNU OpenMP runtime. Clang doesn't support generating OpenMP code for
- /// this runtime but can swallow the pragmas, and find and link against the
- /// runtime library itself.
- OMPRT_GOMP,
-
- /// The legacy name for the LLVM OpenMP runtime from when it was the Intel
- /// OpenMP runtime. We support this mode for users with existing dependencies
- /// on this runtime library name.
- OMPRT_IOMP5
-};
-}
-
-/// Compute the desired OpenMP runtime from the flag provided.
-static OpenMPRuntimeKind getOpenMPRuntime(const ToolChain &TC,
- const ArgList &Args) {
- StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME);
-
- const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);
- if (A)
- RuntimeName = A->getValue();
-
- auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName)
- .Case("libomp", OMPRT_OMP)
- .Case("libgomp", OMPRT_GOMP)
- .Case("libiomp5", OMPRT_IOMP5)
- .Default(OMPRT_Unknown);
-
- if (RT == OMPRT_Unknown) {
- if (A)
- TC.getDriver().Diag(diag::err_drv_unsupported_option_argument)
- << A->getOption().getName() << A->getValue();
- else
- // FIXME: We could use a nicer diagnostic here.
- TC.getDriver().Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
- }
-
- return RT;
-}
-
static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
const ArgList &Args) {
if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false))
return;
- switch (getOpenMPRuntime(TC, Args)) {
- case OMPRT_OMP:
+ switch (TC.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
CmdArgs.push_back("-lomp");
break;
- case OMPRT_GOMP:
+ case Driver::OMPRT_GOMP:
CmdArgs.push_back("-lgomp");
break;
- case OMPRT_IOMP5:
+ case Driver::OMPRT_IOMP5:
CmdArgs.push_back("-liomp5");
break;
- case OMPRT_Unknown:
+ case Driver::OMPRT_Unknown:
// Already diagnosed.
break;
}
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
options::OPT_fno_openmp, false) &&
JA.isDeviceOffloading(Action::OFK_None)) {
- switch (getOpenMPRuntime(getToolChain(), Args)) {
- case OMPRT_OMP:
- case OMPRT_IOMP5:
+ switch (getToolChain().getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
+ case Driver::OMPRT_IOMP5:
// Clang can generate useful OpenMP code for these two runtime libraries.
CmdArgs.push_back("-fopenmp");
WantPthread = true;
// Also link the particular OpenMP runtimes.
- switch (getOpenMPRuntime(ToolChain, Args)) {
- case OMPRT_OMP:
+ switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
CmdArgs.push_back("-lomp");
break;
- case OMPRT_GOMP:
+ case Driver::OMPRT_GOMP:
CmdArgs.push_back("-lgomp");
// FIXME: Exclude this for platforms with libgomp that don't require
// librt. Most modern Linux platforms require it, but some may not.
CmdArgs.push_back("-lrt");
break;
- case OMPRT_IOMP5:
+ case Driver::OMPRT_IOMP5:
CmdArgs.push_back("-liomp5");
break;
- case OMPRT_Unknown:
+ case Driver::OMPRT_Unknown:
// Already diagnosed.
break;
}
CmdArgs.push_back("-nodefaultlib:vcompd.lib");
CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
TC.getDriver().Dir + "/../lib"));
- switch (getOpenMPRuntime(getToolChain(), Args)) {
- case OMPRT_OMP:
+ switch (TC.getDriver().getOpenMPRuntime(Args)) {
+ case Driver::OMPRT_OMP:
CmdArgs.push_back("-defaultlib:libomp.lib");
break;
- case OMPRT_IOMP5:
+ case Driver::OMPRT_IOMP5:
CmdArgs.push_back("-defaultlib:libiomp5md.lib");
break;
- case OMPRT_GOMP:
+ case Driver::OMPRT_GOMP:
break;
- case OMPRT_Unknown:
+ case Driver::OMPRT_Unknown:
// Already diagnosed.
break;
}
--- /dev/null
+///
+/// Perform several driver tests for OpenMP offloading
+///
+
+/// ###########################################################################
+
+/// Check whether an invalid OpenMP target is specified:
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets=aaa-bbb-ccc-ddd %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-INVALID-TARGET %s
+// RUN: %clang -### -fopenmp -fopenmp-targets=aaa-bbb-ccc-ddd %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-INVALID-TARGET %s
+// CHK-INVALID-TARGET: error: OpenMP target is invalid: 'aaa-bbb-ccc-ddd'
+
+/// ###########################################################################
+
+/// Check warning for empty -fopenmp-targets
+// RUN: %clang -### -fopenmp=libomp -fopenmp-targets= %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-EMPTY-OMPTARGETS %s
+// RUN: %clang -### -fopenmp -fopenmp-targets= %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-EMPTY-OMPTARGETS %s
+// CHK-EMPTY-OMPTARGETS: warning: joined argument expects additional value: '-fopenmp-targets='
+
+/// ###########################################################################
+
+/// Check error for no -fopenmp option
+// RUN: %clang -### -fopenmp-targets=powerpc64le-ibm-linux-gnu %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-NO-FOPENMP %s
+// RUN: %clang -### -fopenmp=libgomp -fopenmp-targets=powerpc64le-ibm-linux-gnu %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-NO-FOPENMP %s
+// CHK-NO-FOPENMP: error: The option -fopenmp-targets must be used in conjunction with a -fopenmp option compatible with offloading, please use -fopenmp=libomp or -fopenmp=libiomp5.
+
+/// ###########################################################################
+
+/// Check warning for duplicate offloading targets.
+// RUN: %clang -### -ccc-print-phases -fopenmp -fopenmp-targets=powerpc64le-ibm-linux-gnu,powerpc64le-ibm-linux-gnu %s 2>&1 \
+// RUN: | FileCheck -check-prefix=CHK-DUPLICATES %s
+// CHK-DUPLICATES: warning: The OpenMP offloading target 'powerpc64le-ibm-linux-gnu' is similar to target 'powerpc64le-ibm-linux-gnu' already specified - will be ignored.