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