jansvoboda11 created this revision.
jansvoboda11 added reviewers: Bigcheese, dexonsmith.
Herald added a subscriber: dang.
jansvoboda11 requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

During a highly parallel build with `-fimplicit-modules`, multiple translation 
units may generate a PCM file for the same module at the same filesystem path 
in a short sequence.

When the first Clang instance tries to verify signature of the module on 
import, it discovers the new version of the PCM file (produced by latter Clang 
instance) that may have a different signature, leading to a mismatch and failed 
build.

To be able to debug such mismatch, it's invaluable to be able to compare the 
latter PCM (on disk) with the first one (overwritten).

This patch adds new -cc1 option `-fbackup-module` that tells Clang to store 
each PCM to the normal location **and** also to a path with an unique suffix 
(the PID of the Clang instance).

This is mostly additional change, but `PCHContainerGenerator` now doesn't 
unconditionally destroy the given `PCHBuffer` anymore and instead just 
decreases its reference count.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D101758

Files:
  clang/include/clang/Driver/Options.td
  clang/include/clang/Frontend/FrontendOptions.h
  clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/Serialization/PCHContainerOperations.cpp
  clang/test/Modules/backup-module.c
  clang/test/Modules/backup-module.h

Index: clang/test/Modules/backup-module.h
===================================================================
--- /dev/null
+++ clang/test/Modules/backup-module.h
@@ -0,0 +1 @@
+int function(void);
Index: clang/test/Modules/backup-module.c
===================================================================
--- /dev/null
+++ clang/test/Modules/backup-module.c
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t && mkdir %t
+// RUN: %clang_cc1 %S/backup-module.h -emit-pch -o %t/backup-module.pch
+// RUN: find %t -name 'backup-module.pch.*' | not grep backup-module
+//
+// RUN: %clang_cc1 %S/backup-module.h -emit-pch -o %t/backup-module.pch -fbackup-module
+// RUN: find %t -name 'backup-module.pch.*' | grep backup-module
+// RUN: find %t -name 'backup-module.pch.*' | xargs diff %t/backup-module.pch
+
+// The purpose of this test is to make sure that the module file backup has
+// the same contents as the original.
Index: clang/lib/Serialization/PCHContainerOperations.cpp
===================================================================
--- clang/lib/Serialization/PCHContainerOperations.cpp
+++ clang/lib/Serialization/PCHContainerOperations.cpp
@@ -37,14 +37,14 @@
   ~RawPCHContainerGenerator() override = default;
 
   void HandleTranslationUnit(ASTContext &Ctx) override {
+    // Decrease the reference count on function exit.
+    std::shared_ptr<PCHBuffer> Buffer = std::move(this->Buffer);
+
     if (Buffer->IsComplete) {
       // Make sure it hits disk now.
       *OS << Buffer->Data;
       OS->flush();
     }
-    // Free the space of the temporary buffer.
-    llvm::SmallVector<char, 0> Empty;
-    Buffer->Data = std::move(Empty);
   }
 };
 
Index: clang/lib/Frontend/FrontendActions.cpp
===================================================================
--- clang/lib/Frontend/FrontendActions.cpp
+++ clang/lib/Frontend/FrontendActions.cpp
@@ -9,8 +9,8 @@
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/Basic/FileManager.h"
-#include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/LangStandard.h"
+#include "clang/Basic/TargetInfo.h"
 #include "clang/Frontend/ASTConsumers.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
@@ -26,6 +26,7 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/Support/raw_ostream.h"
 #include <memory>
@@ -48,6 +49,26 @@
     CI.createSema(Action.getTranslationUnitKind(),
                   GetCodeCompletionConsumer(CI));
 }
+
+static void
+AddBackupPCHWriter(std::vector<std::unique_ptr<ASTConsumer>> &Consumers,
+                   CompilerInstance &CI, StringRef InFile,
+                   const std::string &OutFile,
+                   std::shared_ptr<PCHBuffer> &Buffer) {
+  std::string BackupOutFile =
+      OutFile + "." + std::to_string(llvm::sys::Process::getProcessId());
+
+  std::error_code EC;
+  auto OS = std::make_unique<llvm::raw_fd_ostream>(BackupOutFile, EC);
+  if (EC) {
+    CI.getDiagnostics().Report(diag::err_fe_error_opening)
+        << BackupOutFile << EC.message();
+    return;
+  }
+
+  Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
+      CI, std::string(InFile), BackupOutFile, std::move(OS), Buffer));
+}
 } // namespace
 
 //===----------------------------------------------------------------------===//
@@ -118,6 +139,8 @@
       FrontendOpts.IncludeTimestamps, +CI.getLangOpts().CacheGeneratedPCH));
   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
+  if (CI.getInvocation().getFrontendOpts().BackupGeneratedModuleFile)
+    AddBackupPCHWriter(Consumers, CI, InFile, OutputFile, Buffer);
 
   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
 }
@@ -181,6 +204,8 @@
       +CI.getFrontendOpts().BuildingImplicitModule));
   Consumers.push_back(CI.getPCHContainerWriter().CreatePCHContainerGenerator(
       CI, std::string(InFile), OutputFile, std::move(OS), Buffer));
+  if (CI.getInvocation().getFrontendOpts().BackupGeneratedModuleFile)
+    AddBackupPCHWriter(Consumers, CI, InFile, OutputFile, Buffer);
   return std::make_unique<MultiplexConsumer>(std::move(Consumers));
 }
 
Index: clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
===================================================================
--- clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
@@ -240,6 +240,8 @@
     std::unique_ptr<llvm::LLVMContext> VMContext = std::move(this->VMContext);
     std::unique_ptr<llvm::Module> M = std::move(this->M);
     std::unique_ptr<CodeGen::CodeGenModule> Builder = std::move(this->Builder);
+    // Decrease the reference count on function exit.
+    std::shared_ptr<PCHBuffer> Buffer = std::move(this->Buffer);
 
     if (Diags.hasErrorOccurred())
       return;
@@ -306,10 +308,6 @@
                              LangOpts,
                              Ctx.getTargetInfo().getDataLayoutString(), M.get(),
                              BackendAction::Backend_EmitObj, std::move(OS));
-
-    // Free the memory for the temporary buffer.
-    llvm::SmallVector<char, 0> Empty;
-    SerializedAST = std::move(Empty);
   }
 };
 
Index: clang/include/clang/Frontend/FrontendOptions.h
===================================================================
--- clang/include/clang/Frontend/FrontendOptions.h
+++ clang/include/clang/Frontend/FrontendOptions.h
@@ -274,6 +274,9 @@
   /// Whether we can generate the global module index if needed.
   unsigned GenerateGlobalModuleIndex : 1;
 
+  /// Whether we are backing up the generated module file to an unique location.
+  unsigned BackupGeneratedModuleFile : 1;
+
   /// Whether we include declaration dumps in AST dumps.
   unsigned ASTDumpDecls : 1;
 
@@ -459,11 +462,11 @@
         FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false),
         FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false),
         SkipFunctionBodies(false), UseGlobalModuleIndex(true),
-        GenerateGlobalModuleIndex(true), ASTDumpDecls(false),
-        ASTDumpLookups(false), BuildingImplicitModule(false),
-        ModulesEmbedAllFiles(false), IncludeTimestamps(true),
-        UseTemporary(true), AllowPCMWithCompilerErrors(false),
-        TimeTraceGranularity(500) {}
+        GenerateGlobalModuleIndex(true), BackupGeneratedModuleFile(false),
+        ASTDumpDecls(false), ASTDumpLookups(false),
+        BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
+        IncludeTimestamps(true), UseTemporary(true),
+        AllowPCMWithCompilerErrors(false), TimeTraceGranularity(500) {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
   /// extension. For example, "c" would return Language::C.
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2068,6 +2068,10 @@
 def fsystem_module : Flag<["-"], "fsystem-module">, Flags<[CC1Option]>,
   HelpText<"Build this module as a system module. Only used with -emit-module">,
   MarshallingInfoFlag<FrontendOpts<"IsSystemModule">>;
+def fbackup_module : Flag<["-"], "fbackup-module">,
+  Group<f_Group>, Flags<[CC1Option, NoDriverOption]>,
+  HelpText<"Backup the generated pre-compiled module/header to an unique location.">,
+  MarshallingInfoFlag<FrontendOpts<"BackupGeneratedModuleFile">>;
 def fmodule_map_file : Joined<["-"], "fmodule-map-file=">,
   Group<f_Group>, Flags<[NoXarchOption,CC1Option]>, MetaVarName<"<file>">,
   HelpText<"Load this module map file">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D101758: [... Jan Svoboda via Phabricator via cfe-commits

Reply via email to