r342305 - [modules] Driver support for precompiling a collection of files as a single

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 14 18:21:17 PDT 2018


Author: rsmith
Date: Fri Sep 14 18:21:16 2018
New Revision: 342305

URL: http://llvm.org/viewvc/llvm-project?rev=342305&view=rev
Log:
[modules] Driver support for precompiling a collection of files as a single
action.

Added:
    cfe/trunk/test/Driver/header-module.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
    cfe/trunk/include/clang/Driver/Action.h
    cfe/trunk/lib/Driver/Action.cpp
    cfe/trunk/lib/Driver/Driver.cpp
    cfe/trunk/lib/Driver/ToolChain.cpp
    cfe/trunk/lib/Driver/ToolChains/Clang.cpp
    cfe/trunk/lib/Driver/Types.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Fri Sep 14 18:21:16 2018
@@ -296,6 +296,9 @@ def warn_drv_vectorize_needs_hvx : Warni
   "auto-vectorization requires HVX, use -mhvx to enable it">,
   InGroup<OptionIgnored>;
 
+def err_drv_module_header_wrong_kind : Error<
+  "header file '%0' input type '%1' does not match type of prior input "
+  "in module compilation; use '-x %2' to override">;
 def err_drv_modules_validate_once_requires_timestamp : Error<
   "option '-fmodules-validate-once-per-build-session' requires "
   "'-fbuild-session-timestamp=<seconds since Epoch>' or '-fbuild-session-file=<file>'">;

Modified: cfe/trunk/include/clang/Driver/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Action.h?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Action.h (original)
+++ cfe/trunk/include/clang/Driver/Action.h Fri Sep 14 18:21:16 2018
@@ -59,6 +59,7 @@ public:
     OffloadClass,
     PreprocessJobClass,
     PrecompileJobClass,
+    HeaderModulePrecompileJobClass,
     AnalyzeJobClass,
     MigrateJobClass,
     CompileJobClass,
@@ -398,12 +399,36 @@ public:
 class PrecompileJobAction : public JobAction {
   void anchor() override;
 
+protected:
+  PrecompileJobAction(ActionClass Kind, Action *Input, types::ID OutputType);
+
 public:
   PrecompileJobAction(Action *Input, types::ID OutputType);
 
   static bool classof(const Action *A) {
-    return A->getKind() == PrecompileJobClass;
+    return A->getKind() == PrecompileJobClass ||
+           A->getKind() == HeaderModulePrecompileJobClass;
+  }
+};
+
+class HeaderModulePrecompileJobAction : public PrecompileJobAction {
+  void anchor() override;
+
+  const char *ModuleName;
+
+public:
+  HeaderModulePrecompileJobAction(Action *Input, types::ID OutputType,
+                                  const char *ModuleName);
+
+  static bool classof(const Action *A) {
+    return A->getKind() == HeaderModulePrecompileJobClass;
   }
+
+  void addModuleHeaderInput(Action *Input) {
+    getInputs().push_back(Input);
+  }
+
+  const char *getModuleName() const { return ModuleName; }
 };
 
 class AnalyzeJobAction : public JobAction {

Modified: cfe/trunk/lib/Driver/Action.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Action.cpp?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Action.cpp (original)
+++ cfe/trunk/lib/Driver/Action.cpp Fri Sep 14 18:21:16 2018
@@ -26,6 +26,7 @@ const char *Action::getClassName(ActionC
     return "offload";
   case PreprocessJobClass: return "preprocessor";
   case PrecompileJobClass: return "precompiler";
+  case HeaderModulePrecompileJobClass: return "header-module-precompiler";
   case AnalyzeJobClass: return "analyzer";
   case MigrateJobClass: return "migrator";
   case CompileJobClass: return "compiler";
@@ -319,6 +320,19 @@ void PrecompileJobAction::anchor() {}
 PrecompileJobAction::PrecompileJobAction(Action *Input, types::ID OutputType)
     : JobAction(PrecompileJobClass, Input, OutputType) {}
 
+PrecompileJobAction::PrecompileJobAction(ActionClass Kind, Action *Input,
+                                         types::ID OutputType)
+    : JobAction(Kind, Input, OutputType) {
+  assert(isa<PrecompileJobAction>((Action*)this) && "invalid action kind");
+}
+
+void HeaderModulePrecompileJobAction::anchor() {}
+
+HeaderModulePrecompileJobAction::HeaderModulePrecompileJobAction(
+    Action *Input, types::ID OutputType, const char *ModuleName)
+    : PrecompileJobAction(HeaderModulePrecompileJobClass, Input, OutputType),
+      ModuleName(ModuleName) {}
+
 void AnalyzeJobAction::anchor() {}
 
 AnalyzeJobAction::AnalyzeJobAction(Action *Input, types::ID OutputType)

Modified: cfe/trunk/lib/Driver/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Driver.cpp (original)
+++ cfe/trunk/lib/Driver/Driver.cpp Fri Sep 14 18:21:16 2018
@@ -3010,6 +3010,7 @@ void Driver::BuildActions(Compilation &C
   OffloadingActionBuilder OffloadBuilder(C, Args, Inputs);
 
   // Construct the actions to perform.
+  HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr;
   ActionList LinkerInputs;
 
   llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PL;
@@ -3106,13 +3107,29 @@ void Driver::BuildActions(Compilation &C
         break;
       }
 
+      // Each precompiled header file after a module file action is a module
+      // header of that same module file, rather than being compiled to a
+      // separate PCH.
+      if (Phase == phases::Precompile && HeaderModuleAction &&
+          getPrecompiledType(InputType) == types::TY_PCH) {
+        HeaderModuleAction->addModuleHeaderInput(Current);
+        Current = nullptr;
+        break;
+      }
+
+      // FIXME: Should we include any prior module file outputs as inputs of
+      // later actions in the same command line?
+
       // Otherwise construct the appropriate action.
-      auto *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current);
+      Action *NewCurrent = ConstructPhaseAction(C, Args, Phase, Current);
 
       // We didn't create a new action, so we will just move to the next phase.
       if (NewCurrent == Current)
         continue;
 
+      if (auto *HMA = dyn_cast<HeaderModulePrecompileJobAction>(NewCurrent))
+        HeaderModuleAction = HMA;
+
       Current = NewCurrent;
 
       // Use the current host action in any of the offloading actions, if
@@ -3192,10 +3209,25 @@ Action *Driver::ConstructPhaseAction(
     types::ID OutputTy = getPrecompiledType(Input->getType());
     assert(OutputTy != types::TY_INVALID &&
            "Cannot precompile this input type!");
+
+    // If we're given a module name, precompile header file inputs as a
+    // module, not as a precompiled header.
+    const char *ModName = nullptr;
+    if (OutputTy == types::TY_PCH) {
+      if (Arg *A = Args.getLastArg(options::OPT_fmodule_name_EQ))
+        ModName = A->getValue();
+      if (ModName)
+        OutputTy = types::TY_ModuleFile;
+    }
+
     if (Args.hasArg(options::OPT_fsyntax_only)) {
       // Syntax checks should not emit a PCH file
       OutputTy = types::TY_Nothing;
     }
+
+    if (ModName)
+      return C.MakeAction<HeaderModulePrecompileJobAction>(Input, OutputTy,
+                                                           ModName);
     return C.MakeAction<PrecompileJobAction>(Input, OutputTy);
   }
   case phases::Compile: {
@@ -3448,7 +3480,7 @@ class ToolSelector final {
   ///  - Backend + Compile.
   const Tool *
   combineAssembleBackendCompile(ArrayRef<JobActionInfo> ActionInfo,
-                                const ActionList *&Inputs,
+                                ActionList &Inputs,
                                 ActionList &CollapsedOffloadAction) {
     if (ActionInfo.size() < 3 || !canCollapseAssembleAction())
       return nullptr;
@@ -3474,13 +3506,13 @@ class ToolSelector final {
     if (!T->hasIntegratedAssembler())
       return nullptr;
 
-    Inputs = &CJ->getInputs();
+    Inputs = CJ->getInputs();
     AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo,
                                  /*NumElements=*/3);
     return T;
   }
   const Tool *combineAssembleBackend(ArrayRef<JobActionInfo> ActionInfo,
-                                     const ActionList *&Inputs,
+                                     ActionList &Inputs,
                                      ActionList &CollapsedOffloadAction) {
     if (ActionInfo.size() < 2 || !canCollapseAssembleAction())
       return nullptr;
@@ -3507,13 +3539,13 @@ class ToolSelector final {
     if (!T->hasIntegratedAssembler())
       return nullptr;
 
-    Inputs = &BJ->getInputs();
+    Inputs = BJ->getInputs();
     AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo,
                                  /*NumElements=*/2);
     return T;
   }
   const Tool *combineBackendCompile(ArrayRef<JobActionInfo> ActionInfo,
-                                    const ActionList *&Inputs,
+                                    ActionList &Inputs,
                                     ActionList &CollapsedOffloadAction) {
     if (ActionInfo.size() < 2)
       return nullptr;
@@ -3545,7 +3577,7 @@ class ToolSelector final {
     if (T->canEmitIR() && ((SaveTemps && !InputIsBitcode) || EmbedBitcode))
       return nullptr;
 
-    Inputs = &CJ->getInputs();
+    Inputs = CJ->getInputs();
     AppendCollapsedOffloadAction(CollapsedOffloadAction, ActionInfo,
                                  /*NumElements=*/2);
     return T;
@@ -3555,22 +3587,28 @@ class ToolSelector final {
   /// preprocessor action, and the current input is indeed a preprocessor
   /// action. If combining results in the collapse of offloading actions, those
   /// are appended to \a CollapsedOffloadAction.
-  void combineWithPreprocessor(const Tool *T, const ActionList *&Inputs,
+  void combineWithPreprocessor(const Tool *T, ActionList &Inputs,
                                ActionList &CollapsedOffloadAction) {
     if (!T || !canCollapsePreprocessorAction() || !T->hasIntegratedCPP())
       return;
 
     // Attempt to get a preprocessor action dependence.
     ActionList PreprocessJobOffloadActions;
-    auto *PJ = getPrevDependentAction(*Inputs, PreprocessJobOffloadActions);
-    if (!PJ || !isa<PreprocessJobAction>(PJ))
-      return;
+    ActionList NewInputs;
+    for (Action *A : Inputs) {
+      auto *PJ = getPrevDependentAction({A}, PreprocessJobOffloadActions);
+      if (!PJ || !isa<PreprocessJobAction>(PJ)) {
+        NewInputs.push_back(A);
+        continue;
+      }
 
-    // This is legal to combine. Append any offload action we found and set the
-    // current inputs to preprocessor inputs.
-    CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(),
-                                  PreprocessJobOffloadActions.end());
-    Inputs = &PJ->getInputs();
+      // This is legal to combine. Append any offload action we found and add the
+      // current input to preprocessor inputs.
+      CollapsedOffloadAction.append(PreprocessJobOffloadActions.begin(),
+                                    PreprocessJobOffloadActions.end());
+      NewInputs.append(PJ->input_begin(), PJ->input_end());
+    }
+    Inputs = NewInputs;
   }
 
 public:
@@ -3588,7 +3626,7 @@ public:
   /// connected to collapsed actions are updated accordingly. The latter enables
   /// the caller of the selector to process them afterwards instead of just
   /// dropping them. If no suitable tool is found, null will be returned.
-  const Tool *getTool(const ActionList *&Inputs,
+  const Tool *getTool(ActionList &Inputs,
                       ActionList &CollapsedOffloadAction) {
     //
     // Get the largest chain of actions that we could combine.
@@ -3624,7 +3662,7 @@ public:
     if (!T)
       T = combineBackendCompile(ActionChain, Inputs, CollapsedOffloadAction);
     if (!T) {
-      Inputs = &BaseAction->getInputs();
+      Inputs = BaseAction->getInputs();
       T = TC.SelectTool(*BaseAction);
     }
 
@@ -3769,7 +3807,7 @@ InputInfo Driver::BuildJobsForActionNoCa
   }
 
 
-  const ActionList *Inputs = &A->getInputs();
+  ActionList Inputs = A->getInputs();
 
   const JobAction *JA = cast<JobAction>(A);
   ActionList CollapsedOffloadActions;
@@ -3795,7 +3833,7 @@ InputInfo Driver::BuildJobsForActionNoCa
 
   // Only use pipes when there is exactly one input.
   InputInfoList InputInfos;
-  for (const Action *Input : *Inputs) {
+  for (const Action *Input : Inputs) {
     // Treat dsymutil and verify sub-jobs as being at the top-level too, they
     // shouldn't get temporary output names.
     // FIXME: Clean this up.
@@ -3814,6 +3852,10 @@ InputInfo Driver::BuildJobsForActionNoCa
   if (JA->getType() == types::TY_dSYM)
     BaseInput = InputInfos[0].getFilename();
 
+  // ... and in header module compilations, which use the module name.
+  if (auto *ModuleJA = dyn_cast<HeaderModulePrecompileJobAction>(JA))
+    BaseInput = ModuleJA->getModuleName();
+
   // Append outputs of offload device jobs to the input list
   if (!OffloadDependencesInputInfo.empty())
     InputInfos.append(OffloadDependencesInputInfo.begin(),

Modified: cfe/trunk/lib/Driver/ToolChain.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChain.cpp?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChain.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChain.cpp Fri Sep 14 18:21:16 2018
@@ -302,6 +302,7 @@ Tool *ToolChain::getTool(Action::ActionC
 
   case Action::CompileJobClass:
   case Action::PrecompileJobClass:
+  case Action::HeaderModulePrecompileJobClass:
   case Action::PreprocessJobClass:
   case Action::AnalyzeJobClass:
   case Action::MigrateJobClass:

Modified: cfe/trunk/lib/Driver/ToolChains/Clang.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/Clang.cpp?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains/Clang.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains/Clang.cpp Fri Sep 14 18:21:16 2018
@@ -3144,17 +3144,54 @@ void Clang::ConstructJob(Compilation &C,
 
   // Check number of inputs for sanity. We need at least one input.
   assert(Inputs.size() >= 1 && "Must have at least one input.");
-  const InputInfo &Input = Inputs[0];
   // CUDA/HIP compilation may have multiple inputs (source file + results of
   // device-side compilations). OpenMP device jobs also take the host IR as a
-  // second input. All other jobs are expected to have exactly one
-  // input.
+  // second input. Module precompilation accepts a list of header files to
+  // include as part of the module. All other jobs are expected to have exactly
+  // one input.
   bool IsCuda = JA.isOffloading(Action::OFK_Cuda);
   bool IsHIP = JA.isOffloading(Action::OFK_HIP);
   bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP);
-  assert((IsCuda || IsHIP || (IsOpenMPDevice && Inputs.size() == 2) ||
-          Inputs.size() == 1) &&
-         "Unable to handle multiple inputs.");
+  bool IsModulePrecompile =
+      isa<PrecompileJobAction>(JA) && JA.getType() == types::TY_ModuleFile;
+  bool IsHeaderModulePrecompile = isa<HeaderModulePrecompileJobAction>(JA);
+
+  // A header module compilation doesn't have a main input file, so invent a
+  // fake one as a placeholder.
+  // FIXME: Pick the language based on the header file language.
+  const char *ModuleName = [&]{
+    auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
+    return ModuleNameArg ? ModuleNameArg->getValue() : "";
+  }();
+  InputInfo HeaderModuleInput(types::TY_CXXModule, ModuleName, ModuleName);
+
+  const InputInfo &Input =
+      IsHeaderModulePrecompile ? HeaderModuleInput : Inputs[0];
+
+  InputInfoList ModuleHeaderInputs;
+  const InputInfo *CudaDeviceInput = nullptr;
+  const InputInfo *OpenMPDeviceInput = nullptr;
+  for (const InputInfo &I : Inputs) {
+    if (&I == &Input) {
+      // This is the primary input.
+    } else if (IsModulePrecompile &&
+               types::getPrecompiledType(I.getType()) == types::TY_PCH) {
+      types::ID Expected =
+          types::lookupHeaderTypeForSourceType(Inputs[0].getType());
+      if (I.getType() != Expected) {
+        D.Diag(diag::err_drv_module_header_wrong_kind)
+            << I.getFilename() << types::getTypeName(I.getType())
+            << types::getTypeName(Expected);
+      }
+      ModuleHeaderInputs.push_back(I);
+    } else if ((IsCuda || IsHIP) && !CudaDeviceInput) {
+      CudaDeviceInput = &I;
+    } else if (IsOpenMPDevice && !OpenMPDeviceInput) {
+      OpenMPDeviceInput = &I;
+    } else {
+      llvm_unreachable("unexpectedly given multiple inputs");
+    }
+  }
 
   const llvm::Triple *AuxTriple =
       IsCuda ? getToolChain().getAuxTriple() : nullptr;
@@ -3267,7 +3304,9 @@ void Clang::ConstructJob(Compilation &C,
     if (JA.getType() == types::TY_Nothing)
       CmdArgs.push_back("-fsyntax-only");
     else if (JA.getType() == types::TY_ModuleFile)
-      CmdArgs.push_back("-emit-module-interface");
+      CmdArgs.push_back(IsHeaderModulePrecompile
+                            ? "-emit-header-module"
+                            : "-emit-module-interface");
     else if (UsePCH)
       CmdArgs.push_back("-emit-pch");
     else
@@ -4729,10 +4768,18 @@ void Clang::ConstructJob(Compilation &C,
 
   addDashXForInput(Args, Input, CmdArgs);
 
-  if (Input.isFilename())
-    CmdArgs.push_back(Input.getFilename());
-  else
-    Input.getInputArg().renderAsInput(Args, CmdArgs);
+  ArrayRef<InputInfo> FrontendInputs = Input;
+  if (IsHeaderModulePrecompile)
+    FrontendInputs = ModuleHeaderInputs;
+  else if (Input.isNothing())
+    FrontendInputs = {};
+
+  for (const InputInfo &Input : FrontendInputs) {
+    if (Input.isFilename())
+      CmdArgs.push_back(Input.getFilename());
+    else
+      Input.getInputArg().renderAsInput(Args, CmdArgs);
+  }
 
   Args.AddAllArgs(CmdArgs, options::OPT_undef);
 
@@ -4765,10 +4812,9 @@ void Clang::ConstructJob(Compilation &C,
   if (IsCuda) {
     // Host-side cuda compilation receives all device-side outputs in a single
     // fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
-    if (Inputs.size() > 1) {
-      assert(Inputs.size() == 2 && "More than one GPU binary!");
+    if (CudaDeviceInput) {
       CmdArgs.push_back("-fcuda-include-gpubinary");
-      CmdArgs.push_back(Inputs[1].getFilename());
+      CmdArgs.push_back(CudaDeviceInput->getFilename());
     }
 
     if (Args.hasFlag(options::OPT_fcuda_rdc, options::OPT_fno_cuda_rdc, false))
@@ -4785,9 +4831,9 @@ void Clang::ConstructJob(Compilation &C,
   // only the relevant declarations are emitted.
   if (IsOpenMPDevice) {
     CmdArgs.push_back("-fopenmp-is-device");
-    if (Inputs.size() == 2) {
+    if (OpenMPDeviceInput) {
       CmdArgs.push_back("-fopenmp-host-ir-file-path");
-      CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename()));
+      CmdArgs.push_back(Args.MakeArgString(OpenMPDeviceInput->getFilename()));
     }
   }
 

Modified: cfe/trunk/lib/Driver/Types.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Types.cpp?rev=342305&r1=342304&r2=342305&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Types.cpp (original)
+++ cfe/trunk/lib/Driver/Types.cpp Fri Sep 14 18:21:16 2018
@@ -312,9 +312,11 @@ ID types::lookupHeaderTypeForSourceType(
   default:
     return Id;
 
+  // FIXME: Handle preprocessed input types.
   case types::TY_C:
     return types::TY_CHeader;
   case types::TY_CXX:
+  case types::TY_CXXModule:
     return types::TY_CXXHeader;
   case types::TY_ObjC:
     return types::TY_ObjCHeader;

Added: cfe/trunk/test/Driver/header-module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/header-module.cpp?rev=342305&view=auto
==============================================================================
--- cfe/trunk/test/Driver/header-module.cpp (added)
+++ cfe/trunk/test/Driver/header-module.cpp Fri Sep 14 18:21:16 2018
@@ -0,0 +1,13 @@
+// Check compiling a header module to a .pcm file.
+//
+// RUN: %clang -fmodules-ts -fmodule-name=foobar -x c++-header --precompile %S/Inputs/header1.h %S/Inputs/header2.h %S/Inputs/header3.h -o %t.pcm -v 2>&1 | FileCheck %s --check-prefix=CHECK-PRECOMPILE
+//
+// CHECK-PRECOMPILE: -cc1 {{.*}} -emit-header-module
+// CHECK-PRECOMPILE-SAME: -fmodules-ts
+// CHECK-PRECOMPILE-SAME: -fno-implicit-modules
+// CHECK-PRECOMPILE-SAME: -fmodule-name=foobar
+// CHECK-PRECOMPILE-SAME: -o {{.*}}.pcm
+// CHECK-PRECOMPILE-SAME: -x c++
+// CHECK-PRECOMPILE-SAME: header1.h
+// CHECK-PRECOMPILE-SAME: header2.h
+// CHECK-PRECOMPILE-SAME: header3.h




More information about the cfe-commits mailing list