25
25
#include < clang/Frontend/ChainedDiagnosticConsumer.h>
26
26
#include < clang/Frontend/CompilerInstance.h>
27
27
#include < clang/Frontend/FrontendActions.h>
28
+ #include < clang/Frontend/PrecompiledPreamble.h>
28
29
#include < clang/Frontend/TextDiagnosticBuffer.h>
29
30
#include < clang/Frontend/TextDiagnosticPrinter.h>
30
31
#include < clang/Frontend/Utils.h>
@@ -78,6 +79,12 @@ class SYCLToolchain {
78
79
}
79
80
}
80
81
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
+
81
88
// Similar to FrontendActionFactory, but we don't take ownership of
82
89
// `FrontendAction`, nor do we create copies of it as we only perform a single
83
90
// `ToolInvocation`.
@@ -140,9 +147,15 @@ class SYCLToolchain {
140
147
}
141
148
142
149
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
+ }
146
159
147
160
std::vector<std::string> CommandLine;
148
161
CommandLine.reserve (ASL.size () + 2 );
@@ -153,6 +166,79 @@ class SYCLToolchain {
153
166
return CommandLine;
154
167
}
155
168
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
+
156
242
public:
157
243
static SYCLToolchain &instance () {
158
244
static SYCLToolchain Instance;
@@ -162,7 +248,8 @@ class SYCLToolchain {
162
248
bool run (const InputArgList &UserArgList, BinaryFormat Format,
163
249
const char *SourceFilePath, FrontendAction &FEAction,
164
250
IntrusiveRefCntPtr<FileSystem> FSOverlay = nullptr ,
165
- DiagnosticConsumer *DiagConsumer = nullptr ) {
251
+ DiagnosticConsumer *DiagConsumer = nullptr ,
252
+ bool UseAutoPCH = false ) {
166
253
std::vector<std::string> CommandLine =
167
254
createCommandLine (UserArgList, Format, SourceFilePath);
168
255
@@ -175,9 +262,14 @@ class SYCLToolchain {
175
262
auto Files = llvm::makeIntrusiveRefCnt<clang::FileManager>(
176
263
clang::FileSystemOptions{" ." /* WorkingDir */ }, FS);
177
264
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
+
181
273
TI.setDiagnosticConsumer (DiagConsumer ? DiagConsumer : &IgnoreDiag);
182
274
183
275
return TI.run ();
@@ -217,6 +309,8 @@ class SYCLToolchain {
217
309
std::string ClangXXExe = (Prefix + " /bin/clang++" ).str();
218
310
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> ToolchainFS =
219
311
llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
312
+
313
+ PrecompiledPreambles Preambles;
220
314
};
221
315
222
316
class ClangDiagnosticWrapper {
@@ -348,9 +442,11 @@ Expected<ModuleUPtr> jit_compiler::compileDeviceCode(
348
442
DiagnosticOptions DiagOpts;
349
443
ClangDiagnosticWrapper Wrapper (BuildLog, &DiagOpts);
350
444
445
+ bool AutoPCH = UserArgList.hasArg (OPT_auto_pch);
446
+
351
447
if (SYCLToolchain::instance ().run (UserArgList, Format, SourceFile.Path , ELOA,
352
448
getInMemoryFS (SourceFile, IncludeFiles),
353
- Wrapper.consumer ())) {
449
+ Wrapper.consumer (), AutoPCH )) {
354
450
return ELOA.takeModule ();
355
451
} else {
356
452
return createStringError (BuildLog);
0 commit comments