From: Chandler Carruth Date: Thu, 28 May 2015 01:52:38 +0000 (+0000) Subject: [omp] Re-work Clang's handling of -fopenmp and undo r237769. X-Git-Tag: llvmorg-3.7.0-rc1~3642 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9c6b4f8528a1b9933f8c5c6f7de1c963e022a305;p=platform%2Fupstream%2Fllvm.git [omp] Re-work Clang's handling of -fopenmp and undo r237769. This isn't an actual revert of r237769, it just restores the behavior of the Clang driver prior to it while completely re-implementing how that behavior works. This also re-does the work of making the default OpenMP runtime selectable at CMake (or configure) time to work in the way all of our other such hooks do (config.h, configure and cmake hooks, etc.). I've re-implemented how we manage the '-fopenmp' flagset in an important way. Now, the "default" hook just makes '-fopenmp' equivalent to '-fopenmp=' rather than a separate special beast. Also, there is an '-fno-openmp' flag which does the obvious thing. Also, the code is shared between all the places to select a known OpenMP runtime and act on it. Finally, and most significantly, I've taught the driver to inspect the selected runtime when choosing whether to propagate the '-fopenmp' flag to the frontend in the CC1 commandline. Without this, it isn't possible to use Clang with libgomp, even if you were happy with the serial, boring way in which it worked previously (ignoring all #pragmas but linking in the library to satisfy direct calls into the runtime). While I'm here, I've gone ahead and sketched out a path for the future name of LLVM's OpenMP runtime (libomp) and the legacy support for its current name (libiomp5) in what seems a more reasonable way. To re-enable LLVM's OpenMP runtime (which I think should wait until the normal getting started instructions are a reasonable way for falks to check out, build, and install Clang with the runtime) all that needs to change is the default string in the CMakeLists.txt and configure.ac file. No code changes necessary. I also added a test for the driver's behavior around OpenMP since it was *completely missing* previously. Makes it unsurprising that we got it wrong. llvm-svn: 238389 --- diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 4a8d333..628428a 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -182,6 +182,9 @@ set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." ) set(DEFAULT_SYSROOT "" CACHE PATH "Default to all compiler invocations for --sysroot=." ) +set(CLANG_DEFAULT_OPENMP_RUNTIME "libgomp" CACHE STRING + "Default OpenMP runtime used by -fopenmp.") + set(CLANG_VENDOR "" CACHE STRING "Vendor-specific text for showing with version information.") @@ -441,11 +444,6 @@ if(CLANG_ENABLE_STATIC_ANALYZER) add_definitions(-DCLANG_ENABLE_STATIC_ANALYZER) endif() -set(OPENMP_DEFAULT_LIB "" CACHE STRING "OpenMP library used by default for -fopenmp.") -if(OPENMP_DEFAULT_LIB) - add_definitions(-DOPENMP_DEFAULT_LIB=${OPENMP_DEFAULT_LIB}) -endif() - # Clang version information set(CLANG_EXECUTABLE_VERSION "${CLANG_VERSION_MAJOR}.${CLANG_VERSION_MINOR}" CACHE STRING diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake index 5d89b1a..78a5086 100644 --- a/clang/include/clang/Config/config.h.cmake +++ b/clang/include/clang/Config/config.h.cmake @@ -8,6 +8,9 @@ /* Bug report URL. */ #define BUG_REPORT_URL "${BUG_REPORT_URL}" +/* Default OpenMP runtime used by -fopenmp. */ +#define CLANG_DEFAULT_OPENMP_RUNTIME "${CLANG_DEFAULT_OPENMP_RUNTIME}" + /* Multilib suffix for libdir. */ #define CLANG_LIBDIR_SUFFIX "${CLANG_LIBDIR_SUFFIX}" diff --git a/clang/include/clang/Config/config.h.in b/clang/include/clang/Config/config.h.in index dba05db..4395e73 100644 --- a/clang/include/clang/Config/config.h.in +++ b/clang/include/clang/Config/config.h.in @@ -8,6 +8,9 @@ /* Bug report URL. */ #undef BUG_REPORT_URL +/* Default OpenMP runtime used by -fopenmp. */ +#undef CLANG_DEFAULT_OPENMP_RUNTIME + /* Multilib suffix for libdir. */ #undef CLANG_LIBDIR_SUFFIX diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index dec917b..7e39a9a 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -876,6 +876,7 @@ def fno_objc_nonfragile_abi : Flag<["-"], "fno-objc-nonfragile-abi">, Group, Group; def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group; def fopenmp : Flag<["-"], "fopenmp">, Group, Flags<[CC1Option, NoArgumentUnused]>; +def fno_openmp : Flag<["-"], "fno-openmp">, Group, Flags<[NoArgumentUnused]>; def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group; def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group; def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index 527038f..893f204 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -2278,6 +2278,54 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "profile"))); } +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 runtim 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(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 addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs, StringRef Sanitizer, bool IsShared) { @@ -3804,10 +3852,23 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); // Forward flags for OpenMP - if (Args.hasArg(options::OPT_fopenmp_EQ) || - Args.hasArg(options::OPT_fopenmp)) { - CmdArgs.push_back("-fopenmp"); - } + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) + switch (getOpenMPRuntime(getToolChain(), Args)) { + case OMPRT_OMP: + case OMPRT_IOMP5: + // Clang can generate useful OpenMP code for these two runtime libraries. + CmdArgs.push_back("-fopenmp"); + break; + default: + // By default, if Clang doesn't know how to generate useful OpenMP code + // for a specific runtime library, we just don't pass the '-fopenmp' flag + // down to the actual compilation. + // FIXME: It would be better to have a mode which *only* omits IR + // generation based on the OpenMP support so that we get consistent + // semantic analysis, etc. + break; + } const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); Sanitize.addArgs(Args, CmdArgs); @@ -6238,33 +6299,6 @@ void darwin::Link::AddLinkArgs(Compilation &C, Args.AddLastArg(CmdArgs, options::OPT_Mach); } -enum LibOpenMP { - LibUnknown, - LibGOMP, - LibIOMP5 -}; - -/// Map a -fopenmp= macro to the corresponding library. -static LibOpenMP getOpenMPLibByName(StringRef Name) { - return llvm::StringSwitch(Name).Case("libgomp", LibGOMP) - .Case("libiomp5", LibIOMP5) - .Default(LibUnknown); -} - -/// Get the default -l flag to use for -fopenmp, if no library is -/// specified. This can be overridden at configure time. -static const char *getDefaultOpenMPLibFlag() { -#ifndef OPENMP_DEFAULT_LIB -#define OPENMP_DEFAULT_LIB iomp5 -#endif - -#define STR2(lib) #lib -#define STR(lib) STR2(lib) - return "-l" STR(OPENMP_DEFAULT_LIB); -#undef STR -#undef STR2 -} - void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -6322,21 +6356,22 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) { - switch (getOpenMPLibByName(A->getValue())) { - case LibGOMP: + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + switch (getOpenMPRuntime(getToolChain(), Args)) { + case OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case OMPRT_GOMP: CmdArgs.push_back("-lgomp"); break; - case LibIOMP5: + case OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; - case LibUnknown: - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(); + case OMPRT_Unknown: + // Already diagnosed. break; } - } else if (Args.hasArg(options::OPT_fopenmp)) { - CmdArgs.push_back(getDefaultOpenMPLibFlag()); } AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); @@ -8043,30 +8078,36 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (NeedsSanitizerDeps) linkSanitizerRuntimeDeps(ToolChain, CmdArgs); - bool WantPthread = true; - if (const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ)) { - switch (getOpenMPLibByName(A->getValue())) { - case LibGOMP: + bool WantPthread = Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads); + + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + // OpenMP runtimes implies pthreads when using the GNU toolchain. + // FIXME: Does this really make sense for all GNU toolchains? + WantPthread = true; + + // Also link the particular OpenMP runtimes. + switch (getOpenMPRuntime(ToolChain, Args)) { + case OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case 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 LibIOMP5: + case OMPRT_IOMP5: CmdArgs.push_back("-liomp5"); break; - case LibUnknown: - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << A->getValue(); + case OMPRT_Unknown: + // Already diagnosed. break; } - } else if (Args.hasArg(options::OPT_fopenmp)) { - CmdArgs.push_back(getDefaultOpenMPLibFlag()); - } else { - WantPthread = Args.hasArg(options::OPT_pthread) || - Args.hasArg(options::OPT_pthreads); } + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); if (WantPthread && !isAndroid) diff --git a/clang/test/Driver/fopenmp.c b/clang/test/Driver/fopenmp.c new file mode 100644 index 0000000..c7eec5f --- /dev/null +++ b/clang/test/Driver/fopenmp.c @@ -0,0 +1,24 @@ +// RUN: %clang -target x86_64-linux-gnu -fopenmp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-NO-OPENMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 -c %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CC1-OPENMP +// +// CHECK-CC1-OPENMP: "-cc1" +// CHECK-CC1-OPENMP: "-fopenmp" +// +// CHECK-CC1-NO-OPENMP: "-cc1" +// CHECK-CC1-NO-OPENMP-NOT: "-fopenmp" +// +// RUN: %clang -target x86_64-linux-gnu -fopenmp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-OMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libgomp %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-GOMP +// RUN: %clang -target x86_64-linux-gnu -fopenmp=libiomp5 %s -o %t -### 2>&1 | FileCheck %s --check-prefix=CHECK-LD-IOMP5 +// +// CHECK-LD-OMP: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-OMP: "-lomp" +// +// CHECK-LD-GOMP: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-GOMP: "-lgomp" +// +// CHECK-LD-IOMP5: "{{.*}}ld{{(.exe)?}}" +// CHECK-LD-IOMP5: "-liomp5"