2525#include < clang/Frontend/ChainedDiagnosticConsumer.h>
2626#include < clang/Frontend/CompilerInstance.h>
2727#include < clang/Frontend/FrontendActions.h>
28+ #include < clang/Frontend/PrecompiledPreamble.h>
2829#include < clang/Frontend/TextDiagnosticBuffer.h>
2930#include < clang/Frontend/TextDiagnosticPrinter.h>
3031#include < clang/Frontend/Utils.h>
@@ -78,6 +79,12 @@ class SYCLToolchain {
7879 }
7980 }
8081
82+ struct PrecompiledPreambles {
83+ using key = std::pair<std::string /* Opts*/ , std::string /* Preamble*/ >;
84+ std::mutex Mutex;
85+ std::map<key, std::shared_ptr<PrecompiledPreamble>> PreamblesMap;
86+ };
87+
8188 // Similar to FrontendActionFactory, but we don't take ownership of
8289 // `FrontendAction`, nor do we create copies of it as we only perform a single
8390 // `ToolInvocation`.
@@ -140,9 +147,15 @@ class SYCLToolchain {
140147 }
141148
142149 ArgStringList ASL;
143- for_each (DAL, [&DAL, &ASL](Arg *A) { A->render (DAL, ASL); });
144- for_each (UserArgList,
145- [&UserArgList, &ASL](Arg *A) { A->render (UserArgList, ASL); });
150+ for (Arg *A : DAL)
151+ A->render (DAL, ASL);
152+ for (Arg *A : UserArgList) {
153+ Option Group = A->getOption ().getGroup ();
154+ if (Group.isValid () && Group.getID () == OPT_sycl_rtc_only_Group)
155+ continue ;
156+
157+ A->render (UserArgList, ASL);
158+ }
146159
147160 std::vector<std::string> CommandLine;
148161 CommandLine.reserve (ASL.size () + 2 );
@@ -153,6 +166,79 @@ class SYCLToolchain {
153166 return CommandLine;
154167 }
155168
169+ class ActionWithPCHPreamble : public Action {
170+ std::string CmdLineOpts;
171+
172+ public:
173+ ActionWithPCHPreamble (FrontendAction &FEAction, std::string &&CmdLineOpts)
174+ : Action(FEAction), CmdLineOpts(std::move(CmdLineOpts)) {}
175+
176+ bool runInvocation (std::shared_ptr<CompilerInvocation> Invocation,
177+ FileManager *Files,
178+ std::shared_ptr<PCHContainerOperations> PCHContainerOps,
179+ DiagnosticConsumer *DiagConsumer) override {
180+ auto MainFilePath = Invocation->getFrontendOpts ().Inputs [0 ].getFile ();
181+ auto MainFileBuffer = Files->getBufferForFile (MainFilePath);
182+ assert (MainFileBuffer && " Can't get memory buffer for in-memory source?" );
183+
184+ PreambleBounds Bounds = ComputePreambleBounds (
185+ Invocation->getLangOpts (), **MainFileBuffer, 100 /* MaxLines */ );
186+
187+ PrecompiledPreambles::key key{
188+ std::move (CmdLineOpts),
189+ (*MainFileBuffer)->getBuffer ().substr (0 , Bounds.Size ).str ()};
190+
191+ std::shared_ptr<PrecompiledPreamble> Preamble;
192+ {
193+ PrecompiledPreambles &Preambles = SYCLToolchain::instance ().Preambles ;
194+ std::lock_guard<std::mutex> Lock{Preambles.Mutex };
195+ auto [It, Inserted] = Preambles.PreamblesMap .try_emplace (key);
196+
197+ if (Inserted) {
198+ PreambleCallbacks Callbacks;
199+ auto DiagIds = llvm::makeIntrusiveRefCnt<DiagnosticIDs>();
200+ auto DiagOpts = Invocation->getDiagnosticOpts ();
201+ auto Diags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(
202+ DiagIds, DiagOpts, DiagConsumer, false );
203+
204+ static std::string StoragePath =
205+ (SYCLToolchain::instance ().getPrefix () + " /preambles" ).str ();
206+ llvm::ErrorOr<PrecompiledPreamble> NewPreamble =
207+ PrecompiledPreamble::Build (
208+ *Invocation, MainFileBuffer->get (), Bounds, *Diags,
209+ Files->getVirtualFileSystemPtr (), PCHContainerOps,
210+ /* StorePreamblesInMemory*/ true , StoragePath, Callbacks,
211+ /* AllowASTWithErrors=*/ false );
212+
213+ if (!NewPreamble)
214+ return false ;
215+
216+ It->second = std::make_shared<PrecompiledPreamble>(
217+ std::move (NewPreamble.get ()));
218+ }
219+
220+ Preamble = It->second ;
221+ } // End lock
222+
223+ assert (Preamble);
224+ assert (Preamble->CanReuse (*Invocation, **MainFileBuffer, Bounds,
225+ Files->getVirtualFileSystem ()));
226+
227+ // FIXME: WHY release????
228+ auto Buf = llvm::MemoryBuffer::getMemBufferCopy (
229+ (*MainFileBuffer)->getBuffer (), MainFilePath)
230+ .release ();
231+
232+ auto VFS = Files->getVirtualFileSystemPtr ();
233+ Preamble->AddImplicitPreamble (*Invocation, VFS, Buf);
234+ auto NewFiles = makeIntrusiveRefCnt<FileManager>(
235+ Files->getFileSystemOpts (), std::move (VFS));
236+
237+ return Action::runInvocation (std::move (Invocation), NewFiles.get (),
238+ std::move (PCHContainerOps), DiagConsumer);
239+ }
240+ };
241+
156242public:
157243 static SYCLToolchain &instance () {
158244 static SYCLToolchain Instance;
@@ -162,7 +248,8 @@ class SYCLToolchain {
162248 bool run (const InputArgList &UserArgList, BinaryFormat Format,
163249 const char *SourceFilePath, FrontendAction &FEAction,
164250 IntrusiveRefCntPtr<FileSystem> FSOverlay = nullptr ,
165- DiagnosticConsumer *DiagConsumer = nullptr ) {
251+ DiagnosticConsumer *DiagConsumer = nullptr ,
252+ bool UseAutoPCH = false ) {
166253 std::vector<std::string> CommandLine =
167254 createCommandLine (UserArgList, Format, SourceFilePath);
168255
@@ -175,9 +262,14 @@ class SYCLToolchain {
175262 auto Files = llvm::makeIntrusiveRefCnt<clang::FileManager>(
176263 clang::FileSystemOptions{" ." /* WorkingDir */ }, FS);
177264
178- Action A{FEAction};
179- ToolInvocation TI{CommandLine, &A, Files.get (),
180- std::make_shared<PCHContainerOperations>()};
265+ Action Normal{FEAction};
266+ ActionWithPCHPreamble WithPreamble{FEAction,
267+ join (drop_end (CommandLine, 1 ), " " )};
268+ ToolInvocation TI{CommandLine,
269+ UseAutoPCH ? static_cast <Action *>(&WithPreamble)
270+ : &Normal,
271+ Files.get (), std::make_shared<PCHContainerOperations>()};
272+
181273 TI.setDiagnosticConsumer (DiagConsumer ? DiagConsumer : &IgnoreDiag);
182274
183275 return TI.run ();
@@ -217,6 +309,8 @@ class SYCLToolchain {
217309 std::string ClangXXExe = (Prefix + " /bin/clang++" ).str();
218310 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> ToolchainFS =
219311 llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
312+
313+ PrecompiledPreambles Preambles;
220314};
221315
222316class ClangDiagnosticWrapper {
@@ -348,9 +442,11 @@ Expected<ModuleUPtr> jit_compiler::compileDeviceCode(
348442 DiagnosticOptions DiagOpts;
349443 ClangDiagnosticWrapper Wrapper (BuildLog, &DiagOpts);
350444
445+ bool AutoPCH = UserArgList.hasArg (OPT_auto_pch);
446+
351447 if (SYCLToolchain::instance ().run (UserArgList, Format, SourceFile.Path , ELOA,
352448 getInMemoryFS (SourceFile, IncludeFiles),
353- Wrapper.consumer ())) {
449+ Wrapper.consumer (), AutoPCH )) {
354450 return ELOA.takeModule ();
355451 } else {
356452 return createStringError (BuildLog);
0 commit comments