r238389 - [omp] Re-work Clang's handling of -fopenmp and undo r237769.

Chandler Carruth chandlerc at gmail.com
Wed May 27 18:52:39 PDT 2015


Author: chandlerc
Date: Wed May 27 20:52:38 2015
New Revision: 238389

URL: http://llvm.org/viewvc/llvm-project?rev=238389&view=rev
Log:
[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=<default>' 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.

Added:
    cfe/trunk/test/Driver/fopenmp.c
Modified:
    cfe/trunk/CMakeLists.txt
    cfe/trunk/include/clang/Config/config.h.cmake
    cfe/trunk/include/clang/Config/config.h.in
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/lib/Driver/Tools.cpp

Modified: cfe/trunk/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/CMakeLists.txt?rev=238389&r1=238388&r2=238389&view=diff
==============================================================================
--- cfe/trunk/CMakeLists.txt (original)
+++ cfe/trunk/CMakeLists.txt Wed May 27 20:52:38 2015
@@ -182,6 +182,9 @@ set(GCC_INSTALL_PREFIX "" CACHE PATH "Di
 set(DEFAULT_SYSROOT "" CACHE PATH
   "Default <path> to all compiler invocations for --sysroot=<path>." )
 
+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

Modified: cfe/trunk/include/clang/Config/config.h.cmake
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Config/config.h.cmake?rev=238389&r1=238388&r2=238389&view=diff
==============================================================================
--- cfe/trunk/include/clang/Config/config.h.cmake (original)
+++ cfe/trunk/include/clang/Config/config.h.cmake Wed May 27 20:52:38 2015
@@ -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}"
 

Modified: cfe/trunk/include/clang/Config/config.h.in
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Config/config.h.in?rev=238389&r1=238388&r2=238389&view=diff
==============================================================================
--- cfe/trunk/include/clang/Config/config.h.in (original)
+++ cfe/trunk/include/clang/Config/config.h.in Wed May 27 20:52:38 2015
@@ -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
 

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=238389&r1=238388&r2=238389&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Wed May 27 20:52:38 2015
@@ -876,6 +876,7 @@ def fno_objc_nonfragile_abi : Flag<["-"]
 def fobjc_sender_dependent_dispatch : Flag<["-"], "fobjc-sender-dependent-dispatch">, Group<f_Group>;
 def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
 def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
+def fno_openmp : Flag<["-"], "fno-openmp">, Group<f_Group>, Flags<[NoArgumentUnused]>;
 def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>;
 def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
 def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=238389&r1=238388&r2=238389&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Wed May 27 20:52:38 2015
@@ -2278,6 +2278,54 @@ static void addProfileRT(const ToolChain
   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<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 addSanitizerRuntime(const ToolChain &TC, const ArgList &Args,
                                 ArgStringList &CmdArgs, StringRef Sanitizer,
                                 bool IsShared) {
@@ -3804,10 +3852,23 @@ void Clang::ConstructJob(Compilation &C,
   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(Compilati
   Args.AddLastArg(CmdArgs, options::OPT_Mach);
 }
 
-enum LibOpenMP {
-  LibUnknown,
-  LibGOMP,
-  LibIOMP5
-};
-
-/// Map a -fopenmp=<blah> macro to the corresponding library.
-static LibOpenMP getOpenMPLibByName(StringRef Name) {
-  return llvm::StringSwitch<LibOpenMP>(Name).Case("libgomp", LibGOMP)
-                                            .Case("libiomp5", LibIOMP5)
-                                            .Default(LibUnknown);
-}
-
-/// Get the default -l<blah> 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(Compilat
 
   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(Compil
       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)

Added: cfe/trunk/test/Driver/fopenmp.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/fopenmp.c?rev=238389&view=auto
==============================================================================
--- cfe/trunk/test/Driver/fopenmp.c (added)
+++ cfe/trunk/test/Driver/fopenmp.c Wed May 27 20:52:38 2015
@@ -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"





More information about the cfe-commits mailing list