From c2f368916c71f2d7cc90e769a5d468b03c9a6c5f Mon Sep 17 00:00:00 2001 From: Steven Wu Date: Thu, 12 Sep 2024 17:02:25 -0700 Subject: [PATCH] [CAS] Add a mode to load PCMs built from CAS into regular compilation Usually, the PCMs and PCHs built from CAS are built to be used by other CAS enabled compilation tasks, thus it has additional steps to implicitly load dependencies from the CAS. Add a new option to allow a regular compilation instance to load the modules built from CAS by ignoring the CAS info inside the serialized AST. This allows tools like debugger to directly importing the PCMs without the need to access the CAS. In order to use this option, all dependencies modules need to be load explicitly. --- clang/include/clang/Driver/Options.td | 5 ++ .../include/clang/Frontend/CompilerInstance.h | 2 +- .../include/clang/Frontend/FrontendOptions.h | 3 + clang/lib/Frontend/CompilerInstance.cpp | 19 +++--- .../CAS/cas-module-file-use-without-cas.c | 63 +++++++++++++++++++ 5 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 clang/test/CAS/cas-module-file-use-without-cas.c diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c53523726345ee..a370078baf9c47 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8386,6 +8386,11 @@ def fcas_include_tree : Separate<["-"], "fcas-include-tree">, HelpText<"Configure the frontend to use a CAS include tree.">, MarshallingInfoString>; +defm module_load_ignore_cas : BoolFOption<"module-load-ignore-cas", + FrontendOpts<"ModuleLoadIgnoreCAS">, DefaultFalse, + PosFlag, + NegFlag>; + // FIXME: Add to driver under -fexperimental-cache=compile-job. defm cache_compile_job : BoolFOption<"cache-compile-job", FrontendOpts<"CacheCompileJob">, DefaultFalse, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 3ed6ca1a4d64b4..965f92b1e8f3c9 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -800,7 +800,7 @@ class CompilerInstance : public ModuleLoader { ArrayRef> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex, - cas::ObjectStore &CAS, cas::ActionCache &Cache, + cas::ObjectStore &CAS, cas::ActionCache &Cache, bool ignoreCAS, std::unique_ptr PCHBuffer = nullptr); /// Create a code completion consumer using the invocation; note that this diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index f51c2ebbcafdb3..4e0c4ce4b4b83d 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -552,6 +552,9 @@ class FrontendOptions { /// Use the provided CAS include tree. std::string CASIncludeTreeID; + /// If ignore all the CAS info from serialized AST like modules and PCHs. + bool ModuleLoadIgnoreCAS = false; + /// When the input is a module map, the original module map file from which /// that map was inferred, if any (for umbrella modules). std::string OriginalModuleMap; diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 153315977b893b..471c842523148b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -666,8 +666,9 @@ void CompilerInstance::createPCHExternalASTSource( getASTContext(), getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, DependencyCollectors, DeserializationListener, OwnDeserializationListener, Preamble, - getFrontendOpts().UseGlobalModuleIndex, - getOrCreateObjectStore(), getOrCreateActionCache(), std::move(PCHBuffer)); + getFrontendOpts().UseGlobalModuleIndex, getOrCreateObjectStore(), + getOrCreateActionCache(), getFrontendOpts().ModuleLoadIgnoreCAS, + std::move(PCHBuffer)); } IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( @@ -680,7 +681,7 @@ IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( ArrayRef> DependencyCollectors, void *DeserializationListener, bool OwnDeserializationListener, bool Preamble, bool UseGlobalModuleIndex, - cas::ObjectStore &CAS, cas::ActionCache &Cache, + cas::ObjectStore &CAS, cas::ActionCache &Cache, bool ignoreCAS, std::unique_ptr PCHBuffer) { HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); @@ -702,8 +703,9 @@ IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*Reader); - Reader->addListener(std::make_unique( - CAS, Cache, ModuleCache, PP.getDiagnostics())); + if (!ignoreCAS) + Reader->addListener(std::make_unique( + CAS, Cache, ModuleCache, PP.getDiagnostics())); auto Listener = std::make_unique(PP); auto &ListenerRef = *Listener; @@ -1897,9 +1899,10 @@ void CompilerInstance::createASTReader() { for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*TheASTReader); - TheASTReader->addListener(std::make_unique( - getOrCreateObjectStore(), getOrCreateActionCache(), getModuleCache(), - getDiagnostics())); + if (!FEOpts.ModuleLoadIgnoreCAS) + TheASTReader->addListener(std::make_unique( + getOrCreateObjectStore(), getOrCreateActionCache(), getModuleCache(), + getDiagnostics())); } bool CompilerInstance::loadModuleFile( diff --git a/clang/test/CAS/cas-module-file-use-without-cas.c b/clang/test/CAS/cas-module-file-use-without-cas.c new file mode 100644 index 00000000000000..303366a31755ca --- /dev/null +++ b/clang/test/CAS/cas-module-file-use-without-cas.c @@ -0,0 +1,63 @@ +// Tests for reusing a PCM output from CAS builds by a non-cas build. +// This is to simulate a configuration by debugger without CAS support. + +// REQUIRES: ondisk_cas + +// RUN: rm -rf %t %t.cas +// RUN: split-file %s %t + +// RUN: llvm-cas --cas %t.cas --ingest %t > %t/casid + +// == Build B + +// RUN: %clang_cc1 -triple x86_64-apple-macos11 \ +// RUN: -fmodules -fmodule-name=B -fno-implicit-modules \ +// RUN: -emit-module %t/module.modulemap -o %t/B.pcm \ +// RUN: -fcas-path %t.cas -fcas-fs @%t/casid \ +// RUN: -fcache-compile-job -Rcompile-job-cache &> %t/B.out.txt +// RUN: cat %t/B.out.txt | sed -E "s:^.*cache [a-z]+ for '([^']+)'.*$:\1:" > %t/B.key + +// == Build A, importing B + +// RUN: echo -n '-fmodule-file-cache-key %t/B.pcm ' > %t/B.import.rsp +// RUN: cat %t/B.key >> %t/B.import.rsp + +// RUN: %clang_cc1 -triple x86_64-apple-macos11 \ +// RUN: -fmodules -fmodule-name=A -fno-implicit-modules \ +// RUN: @%t/B.import.rsp -fmodule-file=%t/B.pcm \ +// RUN: -emit-module %t/module.modulemap -o %t/A.pcm \ +// RUN: -fcas-path %t.cas -fcas-fs @%t/casid \ +// RUN: -fcache-compile-job -Rcompile-job-cache &> %t/A.out.txt +// RUN: cat %t/A.out.txt | sed -E "s:^.*cache [a-z]+ for '([^']+)'.*$:\1:" > %t/A.key + +// == Build tu, importing A and B, without a CAS, this should fail. + +// RUN: not %clang_cc1 -triple x86_64-apple-macos11 \ +// RUN: -fmodules -fno-implicit-modules \ +// RUN: -fmodule-file=%t/A.pcm\ +// RUN: -fmodule-file=%t/B.pcm\ +// RUN: -fsyntax-only %t/tu.c + +// == Using option to ignore CAS info inside module + +// RUN: %clang_cc1 -triple x86_64-apple-macos11 \ +// RUN: -fmodules -fno-implicit-modules \ +// RUN: -fmodule-file=%t/A.pcm\ +// RUN: -fmodule-file=%t/B.pcm\ +// RUN: -fsyntax-only %t/tu.c -fmodule-load-ignore-cas + +//--- module.modulemap +module A { header "A.h" export * } +module B { header "B.h" } + +//--- A.h +#include "B.h" + +//--- B.h +void B(void); + +//--- tu.c +#include "A.h" +void tu(void) { + B(); +}