diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index e7ba2b26a4b67678bfe839cf1e161c19d45a1773..09e216082630c4a77aaad4e61d4fcfc4f798a111 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1200,7 +1200,15 @@ enum CXTranslationUnit_Flags { * included into the set of code completions returned from this translation * unit. */ - CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80 + CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80, + + /** + * \brief Used to indicate that the precompiled preamble should be created on + * the first parse. Otherwise it will be created on the first reparse. This + * trades runtime on the first parse (serializing the preamble takes time) for + * reduced runtime on the second parse (can now reuse the preamble). + */ + CXTranslationUnit_CreatePreambleOnFirstParse = 0x100 }; /** diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index d326a53dc2a5b43684d3fb7e8f9468dda3f8eefb..a5f7af5714395916b0c91c212f7f17cbeb5ba5b8 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -737,14 +737,15 @@ private: /// \brief Helper function for \c LoadFromCompilerInvocation() and /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. /// - /// \param PrecompilePreamble Whether to precompile the preamble of this - /// translation unit, to improve the performance of reparsing. + /// \param PrecompilePreambleAfterNParses After how many parses the preamble + /// of this translation unit should be precompiled, to improve the performance + /// of reparsing. Set to zero to disable preambles. /// /// \returns \c true if a catastrophic failure occurred (which means that the /// \c ASTUnit itself is invalid), or \c false otherwise. bool LoadFromCompilerInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - bool PrecompilePreamble); + unsigned PrecompilePreambleAfterNParses); public: @@ -783,7 +784,8 @@ public: ASTFrontendAction *Action = nullptr, ASTUnit *Unit = nullptr, bool Persistent = true, StringRef ResourceFilesPath = StringRef(), bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, - bool PrecompilePreamble = false, bool CacheCodeCompletionResults = false, + unsigned PrecompilePreambleAfterNParses = 0, + bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false, std::unique_ptr<ASTUnit> *ErrAST = nullptr); @@ -807,7 +809,8 @@ public: std::shared_ptr<PCHContainerOperations> PCHContainerOps, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr, bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, - bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); @@ -842,7 +845,8 @@ public: bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, ArrayRef<RemappedFile> RemappedFiles = None, bool RemappedFilesKeepOriginalName = true, - bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 0d5dd536589fe83bf550309df55e542a8ce33884..e6ba29201f857696ac38b39201d103781b150d59 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1725,9 +1725,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( std::shared_ptr<PCHContainerOperations> PCHContainerOps, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTFrontendAction *Action, ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath, - bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool UserFilesAreVolatile, std::unique_ptr<ASTUnit> *ErrAST) { + bool OnlyLocalDecls, bool CaptureDiagnostics, + unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile, + std::unique_ptr<ASTUnit> *ErrAST) { assert(CI && "A CompilerInvocation is required"); std::unique_ptr<ASTUnit> OwnAST; @@ -1746,8 +1747,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( } AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - if (PrecompilePreamble) - AST->PreambleRebuildCounter = 2; + if (PrecompilePreambleAfterNParses > 0) + AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses; AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion @@ -1864,7 +1865,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr<PCHContainerOperations> PCHContainerOps, - bool PrecompilePreamble) { + unsigned PrecompilePreambleAfterNParses) { if (!Invocation) return true; @@ -1874,8 +1875,8 @@ bool ASTUnit::LoadFromCompilerInvocation( ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer; - if (PrecompilePreamble) { - PreambleRebuildCounter = 2; + if (PrecompilePreambleAfterNParses > 0) { + PreambleRebuildCounter = PrecompilePreambleAfterNParses; OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); } @@ -1894,9 +1895,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( CompilerInvocation *CI, std::shared_ptr<PCHContainerOperations> PCHContainerOps, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, FileManager *FileMgr, - bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) { + bool OnlyLocalDecls, bool CaptureDiagnostics, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, + bool UserFilesAreVolatile) { // Create the AST unit. std::unique_ptr<ASTUnit> AST(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); @@ -1919,7 +1921,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation( llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> > DiagCleanup(Diags.get()); - if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble)) + if (AST->LoadFromCompilerInvocation(PCHContainerOps, + PrecompilePreambleAfterNParses)) return nullptr; return AST; } @@ -1930,12 +1933,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine( IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, ArrayRef<RemappedFile> RemappedFiles, bool RemappedFilesKeepOriginalName, - bool PrecompilePreamble, TranslationUnitKind TUKind, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, bool ForSerialization, - llvm::Optional<StringRef> ModuleFormat, - std::unique_ptr<ASTUnit> *ErrAST) { + llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector<StoredDiagnostic, 4> StoredDiagnostics; @@ -2002,7 +2004,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble)) { + if (AST->LoadFromCompilerInvocation(PCHContainerOps, + PrecompilePreambleAfterNParses)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. if (ErrAST) { diff --git a/test/Index/complete-preamble.cpp b/test/Index/complete-preamble.cpp index c57c88ab330aa3b7594275dc075ea950dd04cb59..15720f9a297f89a6b5277dfee7db148f90a7f93b 100644 --- a/test/Index/complete-preamble.cpp +++ b/test/Index/complete-preamble.cpp @@ -3,6 +3,15 @@ void f() { std:: } -// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50) +// RUN: env CINDEXTEST_EDITING=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=SECOND %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=FIRST %s + +// FIRST: Precompiling preamble +// FIRST: Parsing +// FIRST: Reparsing +// SECOND: Parsing +// SECOND: Precompiling preamble +// SECOND: Reparsing + +// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50) diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 948195debaefcb9bd20a4a72a2f38649d9101135..48f22eb4bbf656fa62c244c1a5f1a8bc921c8def 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -76,7 +76,9 @@ static unsigned getDefaultParsingOptions() { options |= CXTranslationUnit_SkipFunctionBodies; if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS")) options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - + if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE")) + options |= CXTranslationUnit_CreatePreambleOnFirstParse; + return options; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 768cd6a5b2398cb3b3910ae74f70685d4784edbd..5022417d9af244a8edba5f73186e4472e4055b01 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3083,6 +3083,8 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, setThreadBackgroundPriority(); bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CreatePreambleOnFirstParse = + options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. TranslationUnitKind TUKind = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete; @@ -3157,13 +3159,18 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, unsigned NumErrors = Diags->getClient()->getNumErrors(); std::unique_ptr<ASTUnit> ErrUnit; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), /*CaptureDiagnostics=*/true, *RemappedFiles.get(), - /*RemappedFilesKeepOriginalName=*/true, PrecompilePreamble, TUKind, - CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, + /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, + TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, /*UserFilesAreVolatile=*/true, ForSerialization, CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(), diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index d198f404a08fc6db6c1cebb4a28ff3baaf40e525..5bfc4245eac1b0a55a373ba3d15054041cbdd430 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -601,6 +601,7 @@ static CXErrorCode clang_indexSourceFile_Impl( bool Persistent = requestedToGetTU; bool OnlyLocalDecls = false; bool PrecompilePreamble = false; + bool CreatePreambleOnFirstParse = false; bool CacheCodeCompletionResults = false; PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); PPOpts.AllowPCHWithCompilerErrors = true; @@ -608,6 +609,8 @@ static CXErrorCode clang_indexSourceFile_Impl( if (requestedToGetTU) { OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; + CreatePreambleOnFirstParse = + TU_options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. CacheCodeCompletionResults = TU_options & CXTranslationUnit_CacheCompletionResults; @@ -620,11 +623,16 @@ static CXErrorCode clang_indexSourceFile_Impl( if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) PPOpts.DetailedRecord = false; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; DiagnosticErrorTrap DiagTrap(*Diags); bool Success = ASTUnit::LoadFromCompilerInvocationAction( CInvok.get(), CXXIdx->getPCHContainerOperations(), Diags, IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(), - OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, + OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses, CacheCodeCompletionResults, /*IncludeBriefCommentsInCodeCompletion=*/false, /*UserFilesAreVolatile=*/true);