]> granicus.if.org Git - clang/commitdiff
Prototype of modules codegen
authorDavid Blaikie <dblaikie@gmail.com>
Mon, 30 Jan 2017 05:00:26 +0000 (05:00 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Mon, 30 Jan 2017 05:00:26 +0000 (05:00 +0000)
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

25 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/ExternalASTSource.h
include/clang/Basic/LangOptions.def
include/clang/Basic/Module.h
include/clang/Driver/CC1Options.td
include/clang/Sema/MultiplexExternalSemaSource.h
include/clang/Serialization/ASTBitCodes.h
include/clang/Serialization/ASTReader.h
include/clang/Serialization/ASTWriter.h
lib/AST/ASTContext.cpp
lib/AST/ExternalASTSource.cpp
lib/Basic/Module.cpp
lib/CodeGen/CodeGenModule.cpp
lib/Frontend/CompilerInvocation.cpp
lib/Lex/ModuleMap.cpp
lib/Sema/MultiplexExternalSemaSource.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/Inputs/codegen/bar.h [new file with mode: 0644]
test/Modules/Inputs/codegen/bar.modulemap [new file with mode: 0644]
test/Modules/Inputs/codegen/foo.h [new file with mode: 0644]
test/Modules/Inputs/codegen/foo.modulemap [new file with mode: 0644]
test/Modules/Inputs/codegen/use.cpp [new file with mode: 0644]
test/Modules/codegen.test [new file with mode: 0644]

index 95429bf8cee48e212b490b800d8e8cc181779d54..e6287dc0659c31ed1fc6c48cd14a85140293ae2c 100644 (file)
@@ -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);
index 2e99f395f495578881092ffef2ddf89af2d94a77..9e48a6a2f31d4f0850c04e885574ee0f2743b163 100644 (file)
@@ -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.
   ///
index d944a9d78ab9bc43efa09c4f141b4c13805c6d22..d02909eb07ecc33b8d8be7cea24e77a918100b04 100644 (file)
@@ -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")
index 31c5c7ec9ca885f13530d39b335ca43ba258f35c..da74d0be86e47a7504680b517dc07c4fd4ecd8f4 100644 (file)
@@ -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 {
index 11ab274bff09a4ac5d5f2fa77688525d0c7c64a2..35475b4f1eb52878a96305cfba107b13c81cc3c3 100644 (file)
@@ -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'.">;
index 37157204ea10744e087c07f27a5a244fc358e591..93e83dc026d96c17c3b5c67ff4cdf46b9369af51 100644 (file)
@@ -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,
index 3a4adc0c0b820ee8833ab3b1f62d678526c61fd6..32322b59baf88c243e583989fffc08b50ef3ceb0 100644 (file)
@@ -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.
index aacabb16ca939aac2801e73be2625c67cf6e0555..5a57911c1b23f77d1b6e25c35a3f7e9fc1d30ac7 100644 (file)
@@ -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);
index 0d6b0268109dc9444794240a1f343f1b77305017..23afa639ded60cd14e60138cb025cfde5d97bf83 100644 (file)
@@ -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.
index 07721b2ba7cbc4c73328c26436f295f6219f3168..1539a52e7fdd81855f05afd2bdb310c06219106e 100644 (file)
@@ -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);
index e3de8c5fefa2b5e8885cf6e10c2b7f802f3c8716..26b1aef0a8fdf6e76b174c6cede10c9e0fe1d0f8 100644 (file)
@@ -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)
index 80bbc24f3db3256aa677c4763d64582dc0eb176e..719ff6709ff348502895135ba1c8f8548c3f8772 100644 (file)
@@ -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;
index f9866957a14a4784114033f5e59b5e5ad587ced6..d8e1d58115097d01cb8aab646b9671bc89f779b1 100644 (file)
@@ -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.
index ee46f921ccbd020e5cbbcf108c98f6a6cbfedb1d..a8c1e6165774a0601379586fa68701535e46ae03 100644 (file)
@@ -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);
index 1488f624da64fcc04169767ec5c409f0e447c2e2..1db5becac4b32c9cfe32d20a8d6da131693bb4a0 100644 (file)
@@ -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());
index 077a56ff8e7ff84869c617940dd91aa96445b350..c97e4dfdd6d3aca936aa19d7fd106d4d37bcfc49 100644 (file)
@@ -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;
index 44cef7de312b9a9614078168f47ec23a42cd9378..e3122039c7d81c8133fb68db9a2774b0c61dc365 100644 (file)
@@ -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));
 }
index a0caca9b26c993890d598561e242d88cdb8b70f4..cfd4c38888d5a01d10379a314aaf9755b0a38f8a 100644 (file)
@@ -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);
index 292861755bace8a945ea3647aa9818464ede6658..6629036809f6cc7dd41816fb61d6194a6f6485d0 100644 (file)
@@ -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 (file)
index 0000000..a00e8f7
--- /dev/null
@@ -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 (file)
index 0000000..f1dc625
--- /dev/null
@@ -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 (file)
index 0000000..b3a7af7
--- /dev/null
@@ -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 (file)
index 0000000..2e095d2
--- /dev/null
@@ -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 (file)
index 0000000..b55a31f
--- /dev/null
@@ -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 (file)
index 0000000..538dfd8
--- /dev/null
@@ -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}}