Skip to content

Commit 92d3176

Browse files
[DRAFT][SYCL RTC] Implement --auto-pch support
1 parent 45af04d commit 92d3176

File tree

8 files changed

+276
-17
lines changed

8 files changed

+276
-17
lines changed

clang/include/clang/Driver/Options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ enum ClangVisibility {
4141
FlangOption = (1 << 4),
4242
FC1Option = (1 << 5),
4343
DXCOption = (1 << 6),
44+
SYCLRTCOnlyOption = (1 << 7),
4445
};
4546

4647
enum ID {

clang/include/clang/Driver/Options.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ def FC1Option : OptionVisibility;
107107
// are made available when the driver is running in DXC compatibility mode.
108108
def DXCOption : OptionVisibility;
109109

110+
def SYCLRTCOnlyOption : OptionVisibility;
111+
110112
/////////
111113
// Docs
112114

@@ -195,6 +197,11 @@ def sycl_Group : OptionGroup<"<SYCL group>">, Group<f_Group>,
195197
DocName<"SYCL options">,
196198
Visibility<[ClangOption, CLOption]>;
197199

200+
def sycl_rtc_only_Group : OptionGroup<"<SYCL RTC only group">,
201+
Group<f_Group>,
202+
DocName<"SYCL RTC specific options">,
203+
Visibility<[SYCLRTCOnlyOption]>;
204+
198205
def cuda_Group : OptionGroup<"<CUDA group>">, Group<f_Group>,
199206
DocName<"CUDA options">,
200207
Visibility<[ClangOption, CLOption]>;
@@ -7460,6 +7467,13 @@ def fsyclbin : Flag<["-"], "fsyclbin">, Alias<fsyclbin_EQ>,
74607467
AliasArgs<["executable"]>;
74617468
} // let Group = sycl_Group
74627469

7470+
let Visibility = [SYCLRTCOnlyOption] in {
7471+
let Group = sycl_rtc_only_Group in {
7472+
def auto_pch : Flag<["--"], "auto-pch">,
7473+
HelpText<"Enable Auto-PCH for SYCL RTC Compilation">;
7474+
} // let Group = sycl_rtc_only_Group
7475+
} // let Visibility = [SYCLRTCOnlyOption]
7476+
74637477
// FIXME: -fsycl-explicit-simd is deprecated. remove it when support is dropped.
74647478
def : Flag<["-"], "fsycl-explicit-simd">, Flags<[Deprecated]>,
74657479
Group<clang_ignored_legacy_options_Group>,

clang/include/clang/Frontend/PrecompiledPreamble.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ class PrecompiledPreamble {
8787
DiagnosticsEngine &Diagnostics,
8888
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
8989
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
90-
bool StoreInMemory, StringRef StoragePath,
91-
PreambleCallbacks &Callbacks);
90+
bool StoreInMemory, StringRef StoragePath, PreambleCallbacks &Callbacks,
91+
bool AllowASTWithErrors = true);
9292

9393
PrecompiledPreamble(PrecompiledPreamble &&);
9494
PrecompiledPreamble &operator=(PrecompiledPreamble &&);

clang/lib/Frontend/PrecompiledPreamble.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,10 @@ class TempPCHFile {
249249
class PrecompilePreambleAction : public ASTFrontendAction {
250250
public:
251251
PrecompilePreambleAction(std::shared_ptr<PCHBuffer> Buffer, bool WritePCHFile,
252-
PreambleCallbacks &Callbacks)
252+
PreambleCallbacks &Callbacks,
253+
bool AllowASTWithErrors = true)
253254
: Buffer(std::move(Buffer)), WritePCHFile(WritePCHFile),
254-
Callbacks(Callbacks) {}
255+
Callbacks(Callbacks), AllowASTWithErrors(AllowASTWithErrors) {}
255256

256257
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
257258
StringRef InFile) override;
@@ -287,16 +288,18 @@ class PrecompilePreambleAction : public ASTFrontendAction {
287288
bool WritePCHFile; // otherwise the PCH is written into the PCHBuffer only.
288289
std::unique_ptr<llvm::raw_pwrite_stream> FileOS; // null if in-memory
289290
PreambleCallbacks &Callbacks;
291+
bool AllowASTWithErrors;
290292
};
291293

292294
class PrecompilePreambleConsumer : public PCHGenerator {
293295
public:
294296
PrecompilePreambleConsumer(PrecompilePreambleAction &Action, Preprocessor &PP,
295297
ModuleCache &ModCache, StringRef isysroot,
296-
std::shared_ptr<PCHBuffer> Buffer)
298+
std::shared_ptr<PCHBuffer> Buffer,
299+
bool AllowASTWithErrors = true)
297300
: PCHGenerator(PP, ModCache, "", isysroot, std::move(Buffer),
298301
ArrayRef<std::shared_ptr<ModuleFileExtension>>(),
299-
/*AllowASTWithErrors=*/true),
302+
AllowASTWithErrors),
300303
Action(Action) {}
301304

302305
bool HandleTopLevelDecl(DeclGroupRef DG) override {
@@ -337,7 +340,8 @@ PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI,
337340
Sysroot.clear();
338341

339342
return std::make_unique<PrecompilePreambleConsumer>(
340-
*this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, Buffer);
343+
*this, CI.getPreprocessor(), CI.getModuleCache(), Sysroot, Buffer,
344+
AllowASTWithErrors);
341345
}
342346

343347
template <class T> bool moveOnNoError(llvm::ErrorOr<T> Val, T &Output) {
@@ -415,7 +419,8 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
415419
DiagnosticsEngine &Diagnostics,
416420
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
417421
std::shared_ptr<PCHContainerOperations> PCHContainerOps, bool StoreInMemory,
418-
StringRef StoragePath, PreambleCallbacks &Callbacks) {
422+
StringRef StoragePath, PreambleCallbacks &Callbacks,
423+
bool AllowASTWithErrors) {
419424
assert(VFS && "VFS is null");
420425

421426
auto PreambleInvocation = std::make_shared<CompilerInvocation>(Invocation);
@@ -511,7 +516,7 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build(
511516
auto Act = std::make_unique<PrecompilePreambleAction>(
512517
std::move(Buffer),
513518
/*WritePCHFile=*/Storage->getKind() == PCHStorage::Kind::TempFile,
514-
Callbacks);
519+
Callbacks, AllowASTWithErrors);
515520
if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0]))
516521
return BuildPreambleError::BeginSourceFileFailed;
517522

clang/test/Driver/sycl-unsupported.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,15 @@
6464
// UNSUPPORTED_OPT-NOT: clang{{.*}} "-fsycl-is-device"{{.*}} "[[OPT_CC1]]{{.*}}"
6565
// UNSUPPORTED_OPT: clang{{.*}} "-fsycl-is-host"{{.*}} "[[OPT_CC1]]{{.*}}"
6666

67+
// "--auto-pch" should only be enabled for SYCL RTC compilations, regular driver
68+
// shouldn't know about it:
69+
//
70+
// RUN: not %clangxx -### %s --auto-pch 2>&1 | FileCheck %s --check-prefix AUTO_PCH
71+
// RUN: not %clangxx -fsycl-device-only -### %s --auto-pch 2>&1 | FileCheck %s --check-prefix AUTO_PCH
72+
// RUN: not %clangxx -fsycl -### %s --auto-pch 2>&1 | FileCheck %s --check-prefix AUTO_PCH
73+
//
74+
// AUTO_PCH: error: unknown argument: '--auto-pch'
75+
6776
// FPGA support has been removed, usage of any FPGA specific options and any
6877
// options that have FPGA specific arguments should emit a specific error
6978
// diagnostic.

sycl-jit/jit-compiler/lib/rtc/DeviceCompilation.cpp

Lines changed: 104 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
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+
156242
public:
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

222316
class 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);

sycl/doc/extensions/experimental/sycl_ext_oneapi_kernel_compiler.asciidoc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,58 @@ build_options{{
11271127
Relax the requirement that parameter types for free-function kernels must be
11281128
forward-declarable.
11291129

1130+
===== `--auto-pch`
1131+
1132+
Enable auto-detection of the preamble and use it as a pre-compiled header to
1133+
speed up subsequent compilations of TUs matching the preamble/compilation
1134+
options. Example of the code that can benefit from this:
1135+
1136+
[source,c++]
1137+
----
1138+
#include <sycl/ext/oneapi/free_function_queries.hpp>
1139+
#include <sycl/ext/oneapi/kernel_properties/properties.hpp>
1140+
1141+
// Auto-detected preamble ends before next line:
1142+
namespace syclext = sycl::ext::oneapi;
1143+
namespace syclexp = sycl::ext::oneapi::experimental;
1144+
1145+
extern "C"
1146+
SYCL_EXT_ONEAPI_FUNCTION_PROPERTY((syclexp::nd_range_kernel<1>))
1147+
void iota(float start, float *ptr) {
1148+
size_t id = syclext::this_work_item::get_nd_item<1>().get_global_linear_id();
1149+
ptr[id] = start + static_cast<float>(id);
1150+
}
1151+
----
1152+
1153+
Limitations:
1154+
1155+
* Preamble detection is done at the Lexer level and can't handle code like
1156+
1157+
[source,c++]
1158+
----
1159+
#if 1
1160+
#include <sycl/sycl.hpp>
1161+
#else
1162+
// Auto-detected preamble ends in the middle of `#else` and would fail to compile.
1163+
void foo() {}
1164+
#endif
1165+
----
1166+
1167+
* Any changes in either preamble or compilation options (including
1168+
`-DSOMETHING`!) result in a creation of a new pre-compiled header/preamble.
1169+
1170+
* No support (including not reporting any errors) for `+__DATE__+`/`+__TIME__+`
1171+
macros inside auto-detected preamble (transitively in regards to the
1172+
includes).
1173+
1174+
* Files used inside preamble must not change between different compilations (at
1175+
least for the same auto-detected preamble).
1176+
1177+
* Auto-generated pre-compiled headers/preambles are stored in memory only. That means:
1178+
- No persistency between invocations
1179+
- Currently there is no eviction mechanism, so application is expected to use
1180+
the option only when number of preambles is limited.
1181+
11301182
=== Known issues and limitations when the language is `sycl`
11311183

11321184
==== Changing the compiler action or output

0 commit comments

Comments
 (0)