summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2017-01-30 05:00:26 +0000
committerDavid Blaikie <dblaikie@gmail.com>2017-01-30 05:00:26 +0000
commit91a91ae6153e47b0fd2297ca0a6b5da71309cc82 (patch)
treef85d508bad5545016f7a7dc26a00be0177d22bc6
parenta20c033fff75dd646149ff39536609b795eab81f (diff)
Prototype of modules codegen
First pass at generating weak definitions of inline functions from module files (& skipping (-O0) or emitting available_externally (optimizations) definitions where those modules are used). External functions defined in modules are emitted into the modular object file as well (this may turn an existing ODR violation (if that module were imported into multiple translations) into valid/linkable code). Internal symbols (static functions, for example) are not correctly supported yet. The symbol will be produced, internal, in the modular object - unreferenceable from the users. Reviewers: rsmith Differential Revision: https://reviews.llvm.org/D28845 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@293456 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h2
-rw-r--r--include/clang/AST/ExternalASTSource.h5
-rw-r--r--include/clang/Basic/LangOptions.def1
-rw-r--r--include/clang/Basic/Module.h2
-rw-r--r--include/clang/Driver/CC1Options.td4
-rw-r--r--include/clang/Sema/MultiplexExternalSemaSource.h2
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--include/clang/Serialization/ASTReader.h4
-rw-r--r--include/clang/Serialization/ASTWriter.h1
-rw-r--r--lib/AST/ASTContext.cpp25
-rw-r--r--lib/AST/ExternalASTSource.cpp5
-rw-r--r--lib/Basic/Module.cpp2
-rw-r--r--lib/CodeGen/CodeGenModule.cpp2
-rw-r--r--lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--lib/Lex/ModuleMap.cpp13
-rw-r--r--lib/Sema/MultiplexExternalSemaSource.cpp9
-rw-r--r--lib/Serialization/ASTReader.cpp30
-rw-r--r--lib/Serialization/ASTWriter.cpp22
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp9
-rw-r--r--test/Modules/Inputs/codegen/bar.h2
-rw-r--r--test/Modules/Inputs/codegen/bar.modulemap1
-rw-r--r--test/Modules/Inputs/codegen/foo.h10
-rw-r--r--test/Modules/Inputs/codegen/foo.modulemap1
-rw-r--r--test/Modules/Inputs/codegen/use.cpp2
-rw-r--r--test/Modules/codegen.test64
25 files changed, 199 insertions, 22 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 95429bf8ce..e6287dc065 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -2494,7 +2494,7 @@ public:
///
/// \returns true if the function/var must be CodeGen'ed/deserialized even if
/// it is not used.
- bool DeclMustBeEmitted(const Decl *D);
+ bool DeclMustBeEmitted(const Decl *D, bool ForModularCodegen = false);
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD);
diff --git a/include/clang/AST/ExternalASTSource.h b/include/clang/AST/ExternalASTSource.h
index 2e99f395f4..9e48a6a2f3 100644
--- a/include/clang/AST/ExternalASTSource.h
+++ b/include/clang/AST/ExternalASTSource.h
@@ -16,6 +16,7 @@
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclBase.h"
+#include "clang/Basic/Module.h"
#include "llvm/ADT/DenseMap.h"
namespace clang {
@@ -169,6 +170,10 @@ public:
/// Return a descriptor for the corresponding module, if one exists.
virtual llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID);
+ enum ExtKind { EK_Always, EK_Never, EK_ReplyHazy };
+
+ virtual ExtKind hasExternalDefinitions(unsigned ID);
+
/// \brief Finds all declarations lexically contained within the given
/// DeclContext, after applying an optional filter predicate.
///
diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index d944a9d78a..d02909eb07 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -201,6 +201,7 @@ LANGOPT(SizedDeallocation , 1, 0, "sized deallocation")
LANGOPT(AlignedAllocation , 1, 0, "aligned allocation")
LANGOPT(NewAlignOverride , 32, 0, "maximum alignment guaranteed by '::operator new(size_t)'")
LANGOPT(ConceptsTS , 1, 0, "enable C++ Extensions for Concepts")
+BENIGN_LANGOPT(ModularCodegen , 1, 0, "Modular codegen")
BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision")
BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records")
BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form")
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 31c5c7ec9c..da74d0be86 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -205,6 +205,8 @@ public:
/// and headers from used modules.
unsigned NoUndeclaredIncludes : 1;
+ unsigned WithCodegen : 1;
+
/// \brief Describes the visibility of the various names within a
/// particular module.
enum NameVisibilityKind {
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 11ab274bff..35475b4f1e 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -432,6 +432,10 @@ def fmodules_local_submodule_visibility :
Flag<["-"], "fmodules-local-submodule-visibility">,
HelpText<"Enforce name visibility rules across submodules of the same "
"top-level module.">;
+def fmodule_codegen :
+ Flag<["-"], "fmodules-codegen">,
+ HelpText<"Generate code for uses of this module that assumes an explicit "
+ "object file will be built for the module">;
def fmodule_format_EQ : Joined<["-"], "fmodule-format=">,
HelpText<"Select the container format for clang modules and PCH. "
"Supported options are 'raw' and 'obj'.">;
diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h
index 37157204ea..93e83dc026 100644
--- a/include/clang/Sema/MultiplexExternalSemaSource.h
+++ b/include/clang/Sema/MultiplexExternalSemaSource.h
@@ -90,6 +90,8 @@ public:
/// initializers themselves.
CXXCtorInitializer **GetExternalCXXCtorInitializers(uint64_t Offset) override;
+ ExtKind hasExternalDefinitions(unsigned ID) override;
+
/// \brief Find all declarations with the given name in the
/// given context.
bool FindExternalVisibleDeclsByName(const DeclContext *DC,
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 3a4adc0c0b..32322b59ba 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -591,6 +591,8 @@ namespace clang {
/// \brief Record code for declarations associated with OpenCL extensions.
OPENCL_EXTENSION_DECLS = 59,
+
+ MODULAR_CODEGEN_DECLS = 60,
};
/// \brief Record types used within a source manager block.
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index aacabb16ca..5a57911c1b 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -715,6 +715,8 @@ private:
/// the consumer eagerly.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
+
/// \brief The IDs of all tentative definitions stored in the chain.
///
/// Sema keeps track of all tentative definitions in a TU because it has to
@@ -1968,6 +1970,8 @@ public:
/// \brief Return a descriptor for the corresponding module.
llvm::Optional<ASTSourceDescriptor> getSourceDescriptor(unsigned ID) override;
+ ExtKind hasExternalDefinitions(unsigned ID) override;
+
/// \brief Retrieve a selector from the given module with its local ID
/// number.
Selector getLocalSelector(ModuleFile &M, unsigned LocalID);
diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h
index 0d6b026810..23afa639de 100644
--- a/include/clang/Serialization/ASTWriter.h
+++ b/include/clang/Serialization/ASTWriter.h
@@ -365,6 +365,7 @@ private:
/// IDs, since they will be written out to an EAGERLY_DESERIALIZED_DECLS
/// record.
SmallVector<uint64_t, 16> EagerlyDeserializedDecls;
+ SmallVector<uint64_t, 16> ModularCodegenDecls;
/// \brief DeclContexts that have received extensions since their serialized
/// form.
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 07721b2ba7..1539a52e7f 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -8882,8 +8882,22 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
- return adjustGVALinkageForAttributes(
+ auto L = adjustGVALinkageForAttributes(
*this, basicGVALinkageForFunction(*this, FD), FD);
+ auto EK = ExternalASTSource::EK_ReplyHazy;
+ if (auto *Ext = getExternalSource())
+ EK = Ext->hasExternalDefinitions(FD->getOwningModuleID());
+ switch (EK) {
+ case ExternalASTSource::EK_Never:
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ break;
+ case ExternalASTSource::EK_Always:
+ return GVA_AvailableExternally;
+ case ExternalASTSource::EK_ReplyHazy:
+ break;
+ }
+ return L;
}
static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
@@ -8968,7 +8982,7 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
*this, basicGVALinkageForVariable(*this, VD), VD);
}
-bool ASTContext::DeclMustBeEmitted(const Decl *D) {
+bool ASTContext::DeclMustBeEmitted(const Decl *D, bool ForModularCodegen) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
@@ -9032,10 +9046,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
}
}
+ GVALinkage Linkage = GetGVALinkageForFunction(FD);
+
+ if (Linkage == GVA_DiscardableODR && ForModularCodegen)
+ return true;
+
// static, static inline, always_inline, and extern inline functions can
// always be deferred. Normal inline functions can be deferred in C99/C++.
// Implicit template instantiations can also be deferred in C++.
- return !isDiscardableGVALinkage(GetGVALinkageForFunction(FD));
+ return !isDiscardableGVALinkage(Linkage);
}
const VarDecl *VD = cast<VarDecl>(D);
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index e3de8c5fef..26b1aef0a8 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -28,6 +28,11 @@ ExternalASTSource::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind
+ExternalASTSource::hasExternalDefinitions(unsigned ID) {
+ return EK_ReplyHazy;
+}
+
ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M)
: Signature(M.Signature), ClangModule(&M) {
if (M.Directory)
diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp
index 80bbc24f3d..719ff6709f 100644
--- a/lib/Basic/Module.cpp
+++ b/lib/Basic/Module.cpp
@@ -33,7 +33,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
IsExplicit(IsExplicit), IsSystem(false), IsExternC(false),
IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false),
InferExportWildcard(false), ConfigMacrosExhaustive(false),
- NoUndeclaredIncludes(false), NameVisibility(Hidden) {
+ NoUndeclaredIncludes(false), WithCodegen(false), NameVisibility(Hidden) {
if (Parent) {
if (!Parent->isAvailable())
IsAvailable = false;
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f9866957a1..d8e1d58115 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -2796,7 +2796,7 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator(
// We are guaranteed to have a strong definition somewhere else,
// so we can use available_externally linkage.
if (Linkage == GVA_AvailableExternally)
- return llvm::Function::AvailableExternallyLinkage;
+ return llvm::GlobalValue::AvailableExternallyLinkage;
// Note that Apple's kernel linker doesn't support symbol
// coalescing, so we need to avoid linkonce and weak linkages there.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index ee46f921cc..a8c1e61657 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1955,6 +1955,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
Args.hasArg(OPT_fmodules_decluse) || Opts.ModulesStrictDeclUse;
Opts.ModulesLocalVisibility =
Args.hasArg(OPT_fmodules_local_submodule_visibility) || Opts.ModulesTS;
+ Opts.ModularCodegen = Args.hasArg(OPT_fmodule_codegen);
Opts.ModulesSearchAll = Opts.Modules &&
!Args.hasArg(OPT_fno_modules_search_all) &&
Args.hasArg(OPT_fmodules_search_all);
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index 1488f624da..1db5becac4 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -91,6 +91,7 @@ ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticsEngine &Diags,
HeaderInfo(HeaderInfo), BuiltinIncludeDir(nullptr),
SourceModule(nullptr), NumCreatedModules(0) {
MMapLangOpts.LineComment = true;
+ MMapLangOpts.ModularCodegen = LangOpts.ModularCodegen;
}
ModuleMap::~ModuleMap() {
@@ -554,16 +555,17 @@ Module *ModuleMap::lookupModuleQualified(StringRef Name, Module *Context) const{
return Context->findSubmodule(Name);
}
-std::pair<Module *, bool>
-ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
- bool IsExplicit) {
+std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
+ Module *Parent,
+ bool IsFramework,
+ bool IsExplicit) {
// Try to find an existing module with this name.
if (Module *Sub = lookupModuleQualified(Name, Parent))
return std::make_pair(Sub, false);
// Create a new module with this name.
- Module *Result = new Module(Name, SourceLocation(), Parent,
- IsFramework, IsExplicit, NumCreatedModules++);
+ Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
+ IsExplicit, NumCreatedModules++);
if (!Parent) {
if (LangOpts.CurrentModule == Name)
SourceModule = Result;
@@ -1499,6 +1501,7 @@ void ModuleMapParser::parseModuleDecl() {
(!ActiveModule->Parent && ModuleName == "Darwin"))
ActiveModule->NoUndeclaredIncludes = true;
ActiveModule->Directory = Directory;
+ ActiveModule->WithCodegen = L.getLangOpts().ModularCodegen;
if (!ActiveModule->Parent) {
StringRef MapFileName(ModuleMapFile->getName());
diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp
index 077a56ff8e..c97e4dfdd6 100644
--- a/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -94,6 +94,15 @@ MultiplexExternalSemaSource::GetExternalCXXCtorInitializers(uint64_t Offset) {
return nullptr;
}
+ExternalASTSource::ExtKind
+MultiplexExternalSemaSource::hasExternalDefinitions(unsigned int ID) {
+ for (const auto &S : Sources)
+ if (auto EK = S->hasExternalDefinitions(ID))
+ if (EK != EK_ReplyHazy)
+ return EK;
+ return EK_ReplyHazy;
+}
+
bool MultiplexExternalSemaSource::
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) {
bool AnyDeclsFound = false;
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 44cef7de31..e3122039c7 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2607,7 +2607,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
break;
case SUBMODULE_BLOCK_ID:
- if (ASTReadResult Result = ReadSubmoduleBlock(F, ClientLoadCapabilities))
+ if (ASTReadResult Result =
+ ReadSubmoduleBlock(F, ClientLoadCapabilities))
return Result;
break;
@@ -2772,6 +2773,14 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
break;
+ case MODULAR_CODEGEN_DECLS:
+ // FIXME: Skip reading this record if our ASTConsumer doesn't care about
+ // them (ie: if we're not codegenerating this module).
+ if (F.Kind == MK_MainFile)
+ for (unsigned I = 0, N = Record.size(); I != N; ++I)
+ EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
+ break;
+
case SPECIAL_TYPES:
if (SpecialTypes.empty()) {
for (unsigned I = 0, N = Record.size(); I != N; ++I)
@@ -4628,6 +4637,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
bool InferExplicitSubmodules = Record[Idx++];
bool InferExportWildcard = Record[Idx++];
bool ConfigMacrosExhaustive = Record[Idx++];
+ bool WithCodegen = Record[Idx++];
Module *ParentModule = nullptr;
if (Parent)
@@ -4635,8 +4645,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
// Retrieve this (sub)module from the module map, creating it if
// necessary.
- CurrentModule = ModMap.findOrCreateModule(Name, ParentModule, IsFramework,
- IsExplicit).first;
+ CurrentModule =
+ ModMap.findOrCreateModule(Name, ParentModule, IsFramework, IsExplicit)
+ .first;
// FIXME: set the definition loc for CurrentModule, or call
// ModMap.setInferredModuleAllowedBy()
@@ -4672,6 +4683,7 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
CurrentModule->InferExplicitSubmodules = InferExplicitSubmodules;
CurrentModule->InferExportWildcard = InferExportWildcard;
CurrentModule->ConfigMacrosExhaustive = ConfigMacrosExhaustive;
+ CurrentModule->WithCodegen = WithCodegen;
if (DeserializationListener)
DeserializationListener->ModuleRead(GlobalID, CurrentModule);
@@ -7895,6 +7907,18 @@ ASTReader::getSourceDescriptor(unsigned ID) {
return None;
}
+ExternalASTSource::ExtKind ASTReader::hasExternalDefinitions(unsigned ID) {
+ const Module *M = getSubmodule(ID);
+ if (!M || !M->WithCodegen)
+ return EK_ReplyHazy;
+
+ ModuleFile *MF = ModuleMgr.lookup(M->getASTFile());
+ assert(MF); // ?
+ if (MF->Kind == ModuleKind::MK_MainFile)
+ return EK_Never;
+ return EK_Always;
+}
+
Selector ASTReader::getLocalSelector(ModuleFile &M, unsigned LocalID) {
return DecodeSelector(getGlobalSelectorID(M, LocalID));
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index a0caca9b26..cfd4c38888 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -1044,6 +1044,7 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(IDENTIFIER_OFFSET);
RECORD(IDENTIFIER_TABLE);
RECORD(EAGERLY_DESERIALIZED_DECLS);
+ RECORD(MODULAR_CODEGEN_DECLS);
RECORD(SPECIAL_TYPES);
RECORD(STATISTICS);
RECORD(TENTATIVE_DEFINITIONS);
@@ -2589,6 +2590,7 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExplicit...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InferExportWild...
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ConfigMacrosExh...
+ Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // WithCodegen
Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
unsigned DefinitionAbbrev = Stream.EmitAbbrev(std::move(Abbrev));
@@ -2677,11 +2679,18 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) {
// Emit the definition of the block.
{
- RecordData::value_type Record[] = {
- SUBMODULE_DEFINITION, ID, ParentID, Mod->IsFramework, Mod->IsExplicit,
- Mod->IsSystem, Mod->IsExternC, Mod->InferSubmodules,
- Mod->InferExplicitSubmodules, Mod->InferExportWildcard,
- Mod->ConfigMacrosExhaustive};
+ RecordData::value_type Record[] = {SUBMODULE_DEFINITION,
+ ID,
+ ParentID,
+ Mod->IsFramework,
+ Mod->IsExplicit,
+ Mod->IsSystem,
+ Mod->IsExternC,
+ Mod->InferSubmodules,
+ Mod->InferExplicitSubmodules,
+ Mod->InferExportWildcard,
+ Mod->ConfigMacrosExhaustive,
+ Mod->WithCodegen};
Stream.EmitRecordWithBlob(DefinitionAbbrev, Record, Mod->Name);
}
@@ -4694,6 +4703,9 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
if (!EagerlyDeserializedDecls.empty())
Stream.EmitRecord(EAGERLY_DESERIALIZED_DECLS, EagerlyDeserializedDecls);
+ if (Context.getLangOpts().ModularCodegen)
+ Stream.EmitRecord(MODULAR_CODEGEN_DECLS, ModularCodegenDecls);
+
// Write the record containing tentative definitions.
if (!TentativeDefinitions.empty())
Stream.EmitRecord(TENTATIVE_DEFINITIONS, TentativeDefinitions);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 292861755b..6629036809 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -2153,7 +2153,7 @@ void ASTWriter::WriteDeclAbbrevs() {
/// relatively painless since they would presumably only do it for top-level
/// decls.
static bool isRequiredDecl(const Decl *D, ASTContext &Context,
- bool WritingModule) {
+ bool WritingModule, bool ModularCode) {
// An ObjCMethodDecl is never considered as "required" because its
// implementation container always is.
@@ -2169,7 +2169,7 @@ static bool isRequiredDecl(const Decl *D, ASTContext &Context,
return false;
}
- return Context.DeclMustBeEmitted(D);
+ return Context.DeclMustBeEmitted(D, ModularCode);
}
void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
@@ -2213,8 +2213,11 @@ void ASTWriter::WriteDecl(ASTContext &Context, Decl *D) {
// Note declarations that should be deserialized eagerly so that we can add
// them to a record in the AST file later.
- if (isRequiredDecl(D, Context, WritingModule))
+ if (isRequiredDecl(D, Context, WritingModule, false))
EagerlyDeserializedDecls.push_back(ID);
+ else if (Context.getLangOpts().ModularCodegen && WritingModule &&
+ isRequiredDecl(D, Context, true, true))
+ ModularCodegenDecls.push_back(ID);
}
void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) {
diff --git a/test/Modules/Inputs/codegen/bar.h b/test/Modules/Inputs/codegen/bar.h
new file mode 100644
index 0000000000..a00e8f70e0
--- /dev/null
+++ b/test/Modules/Inputs/codegen/bar.h
@@ -0,0 +1,2 @@
+#include "foo.h"
+inline void bar() { foo(); }
diff --git a/test/Modules/Inputs/codegen/bar.modulemap b/test/Modules/Inputs/codegen/bar.modulemap
new file mode 100644
index 0000000000..f1dc625857
--- /dev/null
+++ b/test/Modules/Inputs/codegen/bar.modulemap
@@ -0,0 +1 @@
+module bar { header "bar.h" }
diff --git a/test/Modules/Inputs/codegen/foo.h b/test/Modules/Inputs/codegen/foo.h
new file mode 100644
index 0000000000..b3a7af7c9d
--- /dev/null
+++ b/test/Modules/Inputs/codegen/foo.h
@@ -0,0 +1,10 @@
+void f1(int &);
+static void f2() {}
+inline void foo() {
+ static int i;
+ f1(i);
+ f2();
+}
+inline void foo2() {
+}
+void foo_ext() {}
diff --git a/test/Modules/Inputs/codegen/foo.modulemap b/test/Modules/Inputs/codegen/foo.modulemap
new file mode 100644
index 0000000000..2e095d2794
--- /dev/null
+++ b/test/Modules/Inputs/codegen/foo.modulemap
@@ -0,0 +1 @@
+module foo { header "foo.h" }
diff --git a/test/Modules/Inputs/codegen/use.cpp b/test/Modules/Inputs/codegen/use.cpp
new file mode 100644
index 0000000000..b55a31fe15
--- /dev/null
+++ b/test/Modules/Inputs/codegen/use.cpp
@@ -0,0 +1,2 @@
+#include "bar.h"
+int main() { bar(); }
diff --git a/test/Modules/codegen.test b/test/Modules/codegen.test
new file mode 100644
index 0000000000..538dfd87ae
--- /dev/null
+++ b/test/Modules/codegen.test
@@ -0,0 +1,64 @@
+RUN: rm -rf %t
+
+RUN: %clang_cc1 -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=foo %S/Inputs/codegen/foo.modulemap -o %t/foo.pcm
+RUN: %clang_cc1 -fmodules-codegen -x c++ -fmodules -emit-module -fmodule-name=bar %S/Inputs/codegen/bar.modulemap -o %t/bar.pcm -fmodule-file=%t/foo.pcm
+
+RUN: %clang_cc1 -emit-llvm %t/foo.pcm -o - | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -emit-llvm %t/bar.pcm -o - -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR %s
+RUN: %clang_cc1 -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen/use.cpp -emit-llvm -o - | FileCheck --check-prefix=USE-CMN --check-prefix=USE %s
+
+RUN: %clang_cc1 -O2 -disable-llvm-passes -emit-llvm %t/foo.pcm -o - | FileCheck --check-prefix=FOO %s
+RUN: %clang_cc1 -O2 -disable-llvm-passes -emit-llvm %t/bar.pcm -o - -fmodule-file=%t/foo.pcm | FileCheck --check-prefix=BAR-CMN --check-prefix=BAR-OPT %s
+RUN: %clang_cc1 -O2 -disable-llvm-passes -fmodules -fmodule-file=%t/foo.pcm -fmodule-file=%t/bar.pcm %S/Inputs/codegen/use.cpp -emit-llvm -o - | FileCheck --check-prefix=USE-CMN --check-prefix=USE-OPT %s
+
+FOO-NOT: comdat
+FOO: $_Z3foov = comdat any
+FOO: $_Z4foo2v = comdat any
+FOO: $_ZZ3foovE1i = comdat any
+FOO: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+FOO-NOT: {{comdat|define|declare}}
+FOO: define void @_Z7foo_extv()
+FOO-NOT: {{define|declare}}
+FOO: define weak_odr void @_Z3foov() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+FOO: declare void @_Z2f1Ri(i32*
+FOO-NOT: {{define|declare}}
+
+FIXME: this internal function should be weak_odr, comdat, and with a new mangling
+FOO: define internal void @_ZL2f2v() #{{[0-9]+}}
+FOO-NOT: {{define|declare}}
+
+FOO: define weak_odr void @_Z4foo2v() #{{[0-9]+}} comdat
+FOO-NOT: {{define|declare}}
+
+
+BAR-CMN-NOT: comdat
+BAR-CMN: $_Z3barv = comdat any
+BAR-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+BAR-CMN-NOT: {{comdat|define|declare}}
+BAR-CMN: define weak_odr void @_Z3barv() #{{[0-9]+}} comdat
+BAR-CMN-NOT: {{define|declare}}
+BAR: declare void @_Z3foov()
+Include all the available_externally definitions required for bar (foo -> f2)
+BAR-OPT: define available_externally void @_Z3foov()
+BAR-CMN-NOT: {{define|declare}}
+BAR-OPT: declare void @_Z2f1Ri(i32*
+BAR-OPT-NOT: {{define|declare}}
+BAR-OPT: define available_externally void @_ZL2f2v()
+BAR-OPT-NOT: {{define|declare}}
+
+
+USE-OPT: @_ZZ3foovE1i = linkonce_odr global i32 0, comdat
+USE-CMN-NOT: {{comdat|define|declare}}
+USE-CMN: define i32 @main()
+USE-CMN-NOT: {{define|declare}}
+USE: declare void @_Z3barv()
+Include all the available_externally definitions required for main (bar -> foo -> f2)
+USE-OPT: define available_externally void @_Z3barv()
+USE-CMN-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_Z3foov()
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: declare void @_Z2f1Ri(i32*
+USE-OPT-NOT: {{define|declare}}
+USE-OPT: define available_externally void @_ZL2f2v()
+USE-OPT-NOT: {{define|declare}}