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