Skip to content

Commit 52d12b5

Browse files
committed
[SYCL] Add option to sycl-post-link to embed module properties/symbols as metadata
Signed-off-by: Sarnie, Nick <[email protected]>
1 parent 57b8401 commit 52d12b5

File tree

4 files changed

+122
-24
lines changed

4 files changed

+122
-24
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10717,6 +10717,10 @@ getTripleBasedSYCLPostLinkOpts(const ToolChain &TC, const JobAction &JA,
1071710717
(IsAOT || NewOffloadDriver))
1071810718
addArgs(PostLinkArgs, TCArgs,
1071910719
{"-generate-device-image-default-spec-consts"});
10720+
bool IsUsingLTO = TC.getDriver().isUsingLTO(/*IsDeviceOffloadAction=*/true);
10721+
auto LTOMode = TC.getDriver().getLTOMode(/*IsDeviceOffloadAction=*/true);
10722+
if (IsUsingLTO && LTOMode == LTOK_Thin)
10723+
addArgs(PostLinkArgs, TCArgs, {"-embed-aux-info-as-metadata"});
1072010724
}
1072110725

1072210726
// sycl-post-link tool normally outputs a file table (see the tool sources for

clang/test/Driver/sycl-lto.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
// Verify there's no error and we see the expected cc1 flags with the new offload driver.
88
// RUN: %clangxx -fsycl --offload-new-driver -foffload-lto=thin %s -### 2>&1 | FileCheck -check-prefix=CHECK_SUPPORTED %s
99
// CHECK_SUPPORTED: clang{{.*}} "-cc1" "-triple" "spir64-unknown-unknown" {{.*}} "-flto=thin" "-flto-unit"
10+
// CHECK_SUPPORTED: sycl-post-link{{.*}} -embed-aux-info-as-metadata
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; This test verifies the -embed-aux-info-as-metadata option.
2+
; In particular, we should see the properties and symbols file are not added to the output table
3+
; and are instead embedded in the module as metadata.
4+
;
5+
; RUN: sycl-post-link -split=source -embed-aux-info-as-metadata -symbols -S < %s -o %t.table
6+
; RUN: FileCheck %s -input-file=%t.table -check-prefix=CHECK-TABLE
7+
; RUN: FileCheck %s -input-file=%t_0.ll -check-prefix=CHECK-BAR
8+
; RUN: FileCheck %s -input-file=%t_1.ll -check-prefix=CHECK-FOO
9+
10+
; CHECK-TABLE: [Code]
11+
; CHECK-TABLE: {{.*}}_0.ll
12+
; CHECK-TABLE: {{.*}}_1.ll
13+
14+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
15+
target triple = "spir64-unknown-unknown"
16+
17+
; CHECK-FOO: define dso_local spir_func noundef void @foo
18+
define dso_local spir_func noundef void @foo(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 {
19+
entry:
20+
ret void
21+
}
22+
23+
define dso_local spir_func noundef void @bar(i32 noundef %a, i32 noundef %b) #1 {
24+
entry:
25+
ret void
26+
}
27+
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "sycl-module-id"="test.cpp" "sycl-grf-size"="128" }
28+
attributes #1 = { convergent mustprogress noinline norecurse nounwind "sycl-module-id"="test.cpp" "sycl-grf-size"="256" }
29+
; CHECK-FOO: !sycl_properties = !{![[#FOO_PROP:]]}
30+
; CHECK-FOO: !sycl_symbol_table = !{![[#FOO_SYM:]]}
31+
; CHECK-FOO: ![[#FOO_PROP]] = !{!"[SYCL/devicelib req mask]\0ADeviceLibReqMask=1|0\0A[SYCL/device requirements]\0Aaspects=2|AAAAAAAAAAA\0A[SYCL/misc properties]\0Asycl-grf-size=1|128\0A"}
32+
; CHECK-FOO: ![[#FOO_SYM]] = !{!"foo\0A"}
33+
34+
; CHECK-BAR: !sycl_properties = !{![[#BAR_PROP:]]}
35+
; CHECK-BAR: !sycl_symbol_table = !{![[#BAR_SYM:]]}
36+
; CHECK-BAR: ![[#BAR_PROP]] = !{!"[SYCL/devicelib req mask]\0ADeviceLibReqMask=1|0\0A[SYCL/device requirements]\0Aaspects=2|AAAAAAAAAAA\0A[SYCL/misc properties]\0Asycl-grf-size=1|256\0A"}
37+
; CHECK-BAR: ![[#BAR_SYM]] = !{!"bar\0A"}

llvm/tools/sycl-post-link/sycl-post-link.cpp

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
using namespace llvm;
7676

7777
using string_vector = std::vector<std::string>;
78+
using PropSetRegTy = llvm::util::PropertySetRegistry;
7879

7980
namespace {
8081

@@ -251,6 +252,11 @@ cl::opt<bool> GenerateDeviceImageWithDefaultSpecConsts{
251252
"replaced with default values from specialization id(s)."),
252253
cl::cat(PostLinkCat)};
253254

255+
cl::opt<bool> EmbedAuxillaryInfoAsMetadata{
256+
"embed-aux-info-as-metadata",
257+
cl::desc("Embed the module properties and symbols as metadata"),
258+
cl::cat(PostLinkCat)};
259+
254260
struct GlobalBinImageProps {
255261
bool EmitKernelParamInfo;
256262
bool EmitProgramMetadata;
@@ -393,10 +399,31 @@ std::string makeResultFileName(Twine Ext, int I, StringRef Suffix) {
393399
.str();
394400
}
395401

396-
void saveModuleIR(Module &M, StringRef OutFilename) {
402+
// Add the module properties and symbol table as metadata. This is used when we
403+
// compile with thinLTO, as sycl-post-link is run early.
404+
void addAuxInfoAsMetadata(Module &M, const PropSetRegTy &PropSet,
405+
const std::string &SymT) {
406+
auto AddMD = [&M](StringRef MDName, const std::string &MDVal) {
407+
auto NamedMD = M.getOrInsertNamedMetadata(MDName);
408+
auto MDStr = MDString::get(M.getContext(), MDVal);
409+
SmallVector<Metadata *, 2> MD{MDStr};
410+
auto MDOp = MDNode::get(M.getContext(), MD);
411+
NamedMD->addOperand(MDOp);
412+
};
413+
std::string Buf;
414+
raw_string_ostream OStr(Buf);
415+
PropSet.write(OStr);
416+
AddMD("sycl_properties", Buf);
417+
AddMD("sycl_symbol_table", SymT);
418+
}
419+
420+
void saveModuleIR(Module &M, StringRef OutFilename, const PropSetRegTy &PropSet,
421+
const std::string &SymT) {
397422
std::error_code EC;
398423
raw_fd_ostream Out{OutFilename, EC, sys::fs::OF_None};
399424
checkError(EC, "error opening the file '" + OutFilename + "'");
425+
if (EmbedAuxillaryInfoAsMetadata)
426+
addAuxInfoAsMetadata(M, PropSet, SymT);
400427

401428
ModulePassManager MPM;
402429
ModuleAnalysisManager MAM;
@@ -409,11 +436,12 @@ void saveModuleIR(Module &M, StringRef OutFilename) {
409436
MPM.run(M, MAM);
410437
}
411438

412-
std::string saveModuleIR(Module &M, int I, StringRef Suff) {
439+
std::string saveModuleIR(Module &M, int I, StringRef Suff,
440+
const PropSetRegTy &PropSet, const std::string &SymT) {
413441
DUMP_ENTRY_POINTS(M, EmitOnlyKernelsAsEntryPoints, "saving IR");
414442
StringRef FileExt = (OutputAssembly) ? ".ll" : ".bc";
415443
std::string OutFilename = makeResultFileName(FileExt, I, Suff);
416-
saveModuleIR(M, OutFilename);
444+
saveModuleIR(M, OutFilename, PropSet, SymT);
417445
return OutFilename;
418446
}
419447

@@ -436,10 +464,8 @@ bool isImportedFunction(const Function &F) {
436464
return ReturnValue;
437465
}
438466

439-
std::string saveModuleProperties(module_split::ModuleDesc &MD,
440-
const GlobalBinImageProps &GlobProps, int I,
441-
StringRef Suff) {
442-
using PropSetRegTy = llvm::util::PropertySetRegistry;
467+
PropSetRegTy getModuleProperties(module_split::ModuleDesc &MD,
468+
const GlobalBinImageProps &GlobProps) {
443469
PropSetRegTy PropSet;
444470
Module &M = MD.getModule();
445471
{
@@ -646,6 +672,14 @@ std::string saveModuleProperties(module_split::ModuleDesc &MD,
646672
PropSet.add(PropSetRegTy::SYCL_MISC_PROP, "specConstsReplacedWithDefault",
647673
1);
648674

675+
return PropSet;
676+
}
677+
678+
std::string saveModuleProperties(module_split::ModuleDesc &MD,
679+
const GlobalBinImageProps &GlobProps,
680+
const PropSetRegTy &PropSet, int I,
681+
StringRef Suff) {
682+
649683
std::error_code EC;
650684
std::string SCFile = makeResultFileName(".prop", I, Suff);
651685
raw_fd_ostream SCOut(SCFile, EC);
@@ -655,9 +689,7 @@ std::string saveModuleProperties(module_split::ModuleDesc &MD,
655689
return SCFile;
656690
}
657691

658-
// Saves specified collection of symbols to a file.
659-
std::string saveModuleSymbolTable(const module_split::EntryPointSet &Es, int I,
660-
StringRef Suffix) {
692+
std::string getModuleSymbolTable(const module_split::EntryPointSet &Es) {
661693
#ifndef NDEBUG
662694
if (DebugPostLink > 0) {
663695
llvm::errs() << "ENTRY POINTS saving Sym table {\n";
@@ -673,6 +705,12 @@ std::string saveModuleSymbolTable(const module_split::EntryPointSet &Es, int I,
673705
for (const auto *F : Es) {
674706
SymT = (Twine(SymT) + Twine(F->getName()) + Twine("\n")).str();
675707
}
708+
return SymT;
709+
}
710+
711+
// Saves specified collection of symbols to a file.
712+
std::string saveModuleSymbolTable(const std::string &SymT, int I,
713+
StringRef Suffix) {
676714
// Save to file.
677715
std::string OutFileName = makeResultFileName(".sym", I, Suffix);
678716
writeToFile(OutFileName, SymT);
@@ -757,22 +795,28 @@ IrPropSymFilenameTriple saveModule(module_split::ModuleDesc &MD, int I,
757795
StringRef IRFilename = "") {
758796
IrPropSymFilenameTriple Res;
759797
StringRef Suffix = getModuleSuffix(MD);
760-
798+
GlobalBinImageProps Props = {EmitKernelParamInfo, EmitProgramMetadata,
799+
EmitExportedSymbols, EmitImportedSymbols,
800+
DeviceGlobals};
801+
PropSetRegTy PropSet = getModuleProperties(MD, Props);
802+
std::string SymT = getModuleSymbolTable(MD.entries());
761803
if (!IRFilename.empty()) {
762804
// don't save IR, just record the filename
763805
Res.Ir = IRFilename.str();
764806
} else {
765807
MD.cleanup();
766-
Res.Ir = saveModuleIR(MD.getModule(), I, Suffix);
808+
Res.Ir = saveModuleIR(MD.getModule(), I, Suffix, PropSet, SymT);
767809
}
768-
GlobalBinImageProps Props = {EmitKernelParamInfo, EmitProgramMetadata,
769-
EmitExportedSymbols, EmitImportedSymbols,
770-
DeviceGlobals};
771-
Res.Prop = saveModuleProperties(MD, Props, I, Suffix);
772-
773-
if (DoSymGen) {
810+
// We don't need a seperate file with properties if we saved it as
811+
// metadata inside the module itself.
812+
if (!EmbedAuxillaryInfoAsMetadata)
813+
Res.Prop = saveModuleProperties(MD, Props, PropSet, I, Suffix);
814+
815+
// Only save the symbol table to a seperate module if it
816+
// was requested and was not placed inside the module itself.
817+
if (DoSymGen && !EmbedAuxillaryInfoAsMetadata) {
774818
// save the names of the entry points - the symbol table
775-
Res.Sym = saveModuleSymbolTable(MD.entries(), I, Suffix);
819+
Res.Sym = saveModuleSymbolTable(SymT, I, Suffix);
776820
}
777821
return Res;
778822
}
@@ -1071,10 +1115,12 @@ std::vector<std::unique_ptr<util::SimpleTable>>
10711115
processInputModule(std::unique_ptr<Module> M) {
10721116
// Construct the resulting table which will accumulate all the outputs.
10731117
SmallVector<StringRef, MAX_COLUMNS_IN_FILE_TABLE> ColumnTitles{
1074-
StringRef(COL_CODE), StringRef(COL_PROPS)};
1075-
1076-
if (DoSymGen) {
1077-
ColumnTitles.push_back(COL_SYM);
1118+
StringRef(COL_CODE)};
1119+
if (!EmbedAuxillaryInfoAsMetadata) {
1120+
ColumnTitles.push_back(COL_PROPS);
1121+
if (DoSymGen) {
1122+
ColumnTitles.push_back(COL_SYM);
1123+
}
10781124
}
10791125
Expected<std::unique_ptr<util::SimpleTable>> TableE =
10801126
util::SimpleTable::create(ColumnTitles);
@@ -1185,7 +1231,13 @@ processInputModule(std::unique_ptr<Module> M) {
11851231
"' can't be used");
11861232
}
11871233
MMs.front().cleanup();
1188-
saveModuleIR(MMs.front().getModule(), OutputFiles[0].Filename);
1234+
const auto &ModuleProps = getModuleProperties(
1235+
MMs.front(),
1236+
{EmitKernelParamInfo, EmitProgramMetadata, EmitExportedSymbols,
1237+
EmitImportedSymbols, DeviceGlobals});
1238+
std::string SymT = getModuleSymbolTable(MMs.front().entries());
1239+
saveModuleIR(MMs.front().getModule(), OutputFiles[0].Filename,
1240+
ModuleProps, SymT);
11891241
return Tables;
11901242
}
11911243
// Empty IR file name directs saveModule to generate one and save IR to
@@ -1338,6 +1390,10 @@ int main(int argc, char **argv) {
13381390
return 1;
13391391
}
13401392

1393+
if (!DoSymGen && EmbedAuxillaryInfoAsMetadata)
1394+
errs() << "error: -" << EmbedAuxillaryInfoAsMetadata.ArgStr
1395+
<< " can't be used without -" << DoSymGen.ArgStr << "\n";
1396+
13411397
SMDiagnostic Err;
13421398
std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
13431399
// It is OK to use raw pointer here as we control that it does not outlive M

0 commit comments

Comments
 (0)