Skip to content

Commit c878063

Browse files
authored
[Driver][SYCL] Enable ability to consume fat objects containing SPIR-V (#5251)
* [Driver][SYCL] Enable ability to consume fat objects containing SPIR-V When a user creates objects/archives based off of -fsycl-device-obj=spirv we want to be able to consume these objects seamlessly. After any objects are unbundled, we will pass these through spirv-to-ir-wrapper to potentially convert them to LLVM-IR before performing the device link. Toolchain flow will resemble: fat object | unbundle | +-------+------+ | | spirv-to-ir | | | llvm-link | | | wrap | | | +-------+------+ | link * [NFC] update to use new tool name * clang format * Update comment and adjust wrapper call from review feedback * Adjust tests to check for llvm-foreach call with spirv-to-ir-wrapper * fix comment newline
1 parent 7ae7ca8 commit c878063

20 files changed

+313
-157
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class Action {
8282
BackendCompileJobClass,
8383
FileTableTformJobClass,
8484
AppendFooterJobClass,
85+
SpirvToIrWrapperJobClass,
8586
StaticLibJobClass,
8687

8788
JobClassFirst = PreprocessJobClass,
@@ -858,6 +859,17 @@ class AppendFooterJobAction : public JobAction {
858859
}
859860
};
860861

862+
class SpirvToIrWrapperJobAction : public JobAction {
863+
void anchor() override;
864+
865+
public:
866+
SpirvToIrWrapperJobAction(Action *Input, types::ID Type);
867+
868+
static bool classof(const Action *A) {
869+
return A->getKind() == SpirvToIrWrapperJobClass;
870+
}
871+
};
872+
861873
class StaticLibJobAction : public JobAction {
862874
void anchor() override;
863875

clang/include/clang/Driver/ToolChain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ class ToolChain {
158158
mutable std::unique_ptr<Tool> BackendCompiler;
159159
mutable std::unique_ptr<Tool> AppendFooter;
160160
mutable std::unique_ptr<Tool> FileTableTform;
161+
mutable std::unique_ptr<Tool> SpirvToIrWrapper;
161162

162163
Tool *getClang() const;
163164
Tool *getFlang() const;
@@ -175,6 +176,7 @@ class ToolChain {
175176
Tool *getBackendCompiler() const;
176177
Tool *getAppendFooter() const;
177178
Tool *getTableTform() const;
179+
Tool *getSpirvToIrWrapper() const;
178180

179181
mutable bool SanitizerArgsChecked = false;
180182
mutable std::unique_ptr<XRayArgs> XRayArguments;

clang/lib/Driver/Action.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ const char *Action::getClassName(ActionClass AC) {
6161
return "static-lib-linker";
6262
case ForEachWrappingClass:
6363
return "foreach";
64+
case SpirvToIrWrapperJobClass:
65+
return "spirv-to-ir-wrapper";
6466
}
6567

6668
llvm_unreachable("invalid class");
@@ -544,6 +546,12 @@ void StaticLibJobAction::anchor() {}
544546
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)
545547
: JobAction(StaticLibJobClass, Inputs, Type) {}
546548

549+
void SpirvToIrWrapperJobAction::anchor() {}
550+
551+
SpirvToIrWrapperJobAction::SpirvToIrWrapperJobAction(Action *Input,
552+
types::ID Type)
553+
: JobAction(SpirvToIrWrapperJobClass, Input, Type) {}
554+
547555
ForEachWrappingAction::ForEachWrappingAction(JobAction *TFormInput,
548556
JobAction *Job)
549557
: Action(ForEachWrappingClass, {TFormInput, Job}, Job->getType()) {}

clang/lib/Driver/Driver.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3089,6 +3089,14 @@ bool Driver::checkForOffloadStaticLib(Compilation &C,
30893089
return false;
30903090
}
30913091

3092+
/// Check whether the given input tree contains any clang-offload-dependency
3093+
/// actions.
3094+
static bool ContainsOffloadDepsAction(const Action *A) {
3095+
if (isa<OffloadDepsJobAction>(A))
3096+
return true;
3097+
return llvm::any_of(A->inputs(), ContainsOffloadDepsAction);
3098+
}
3099+
30923100
namespace {
30933101
/// Provides a convenient interface for different programming models to generate
30943102
/// the required device actions.
@@ -4614,7 +4622,19 @@ class OffloadingActionBuilder final {
46144622
DA.add(*DeviceWrappingAction, *TC, BoundArch, Action::OFK_SYCL);
46154623
continue;
46164624
} else if (!types::isFPGA(Input->getType())) {
4617-
LinkObjects.push_back(Input);
4625+
// No need for any conversion if we are coming in from the
4626+
// clang-offload-deps or regular compilation path.
4627+
if (isNVPTX || isAMDGCN || ContainsOffloadDepsAction(Input) ||
4628+
ContainsCompileOrAssembleAction(Input)) {
4629+
LinkObjects.push_back(Input);
4630+
continue;
4631+
}
4632+
Action *ConvertSPIRVAction =
4633+
C.MakeAction<SpirvToIrWrapperJobAction>(
4634+
Input, Input->getType() == types::TY_Archive
4635+
? types::TY_Tempfilelist
4636+
: types::TY_LLVM_BC);
4637+
LinkObjects.push_back(ConvertSPIRVAction);
46184638
}
46194639
}
46204640
if (LinkObjects.empty())

clang/lib/Driver/ToolChain.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@ Tool *ToolChain::getTableTform() const {
371371
return FileTableTform.get();
372372
}
373373

374+
Tool *ToolChain::getSpirvToIrWrapper() const {
375+
if (!SpirvToIrWrapper)
376+
SpirvToIrWrapper.reset(new tools::SpirvToIrWrapper(*this));
377+
return SpirvToIrWrapper.get();
378+
}
379+
374380
Tool *ToolChain::getTool(Action::ActionClass AC) const {
375381
switch (AC) {
376382
case Action::AssembleJobClass:
@@ -431,6 +437,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const {
431437

432438
case Action::FileTableTformJobClass:
433439
return getTableTform();
440+
441+
case Action::SpirvToIrWrapperJobClass:
442+
return getSpirvToIrWrapper();
434443
}
435444

436445
llvm_unreachable("Invalid tool kind.");

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8590,6 +8590,9 @@ void OffloadBundler::ConstructJobMultipleOutputs(
85908590
if (IsFPGADepUnbundle)
85918591
TypeArg = "o";
85928592

8593+
if (InputType == types::TY_Archive && getToolChain().getTriple().isSPIR())
8594+
TypeArg = "aoo";
8595+
85938596
// Get the type.
85948597
CmdArgs.push_back(TCArgs.MakeArgString(Twine("-type=") + TypeArg));
85958598

@@ -9393,3 +9396,38 @@ void AppendFooter::ConstructJob(Compilation &C, const JobAction &JA,
93939396
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
93949397
CmdArgs, None));
93959398
}
9399+
9400+
void SpirvToIrWrapper::ConstructJob(Compilation &C, const JobAction &JA,
9401+
const InputInfo &Output,
9402+
const InputInfoList &Inputs,
9403+
const llvm::opt::ArgList &TCArgs,
9404+
const char *LinkingOutput) const {
9405+
InputInfoList ForeachInputs;
9406+
ArgStringList CmdArgs;
9407+
9408+
assert(Inputs.size() == 1 &&
9409+
"Only one input expected to spirv-to-ir-wrapper");
9410+
9411+
// Input File
9412+
for (const auto &I : Inputs) {
9413+
if (I.getType() == types::TY_Archive)
9414+
ForeachInputs.push_back(I);
9415+
addArgs(CmdArgs, TCArgs, {I.getFilename()});
9416+
}
9417+
9418+
// Output File
9419+
addArgs(CmdArgs, TCArgs, {"-o", Output.getFilename()});
9420+
9421+
auto Cmd = std::make_unique<Command>(
9422+
JA, *this, ResponseFileSupport::None(),
9423+
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
9424+
CmdArgs, None);
9425+
if (!ForeachInputs.empty()) {
9426+
StringRef ParallelJobs =
9427+
TCArgs.getLastArgValue(options::OPT_fsycl_max_parallel_jobs_EQ);
9428+
tools::SYCL::constructLLVMForeachCommand(
9429+
C, JA, std::move(Cmd), ForeachInputs, Output, this, "",
9430+
types::getTypeTempSuffix(types::TY_Tempfilelist), ParallelJobs);
9431+
} else
9432+
C.addCommand(std::move(Cmd));
9433+
}

clang/lib/Driver/ToolChains/Clang.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,21 @@ class LLVM_LIBRARY_VISIBILITY AppendFooter final : public Tool {
266266
const char *LinkingOutput) const override;
267267
};
268268

269+
/// SPIR-V to LLVM-IR wrapper tool
270+
class LLVM_LIBRARY_VISIBILITY SpirvToIrWrapper final : public Tool {
271+
public:
272+
SpirvToIrWrapper(const ToolChain &TC)
273+
: Tool("Convert SPIR-V to LLVM-IR if needed", "spirv-to-ir-wrapper", TC) {
274+
}
275+
276+
bool hasIntegratedCPP() const override { return false; }
277+
bool hasGoodDiagnostics() const override { return true; }
278+
void ConstructJob(Compilation &C, const JobAction &JA,
279+
const InputInfo &Output, const InputInfoList &Inputs,
280+
const llvm::opt::ArgList &TCArgs,
281+
const char *LinkingOutput) const override;
282+
};
283+
269284
} // end namespace tools
270285

271286
} // end namespace driver

clang/lib/Driver/ToolChains/SYCL.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
186186
const ArgList &Args, StringRef SubArchName, StringRef OutputFilePrefix,
187187
const InputInfoList &InputFiles) const {
188188
// Split inputs into libraries which have 'archive' type and other inputs
189-
// which can be either objects or list files. Objects/list files are linked
190-
// together in a usual way, but the libraries need to be linked differently.
189+
// which can be either objects or list files. Object files are linked together
190+
// in a usual way, but the libraries/list files need to be linked differently.
191191
// We need to fetch only required symbols from the libraries. With the current
192192
// llvm-link command line interface that can be achieved with two step
193193
// linking: at the first step we will link objects into an intermediate
@@ -236,7 +236,7 @@ const char *SYCL::Linker::constructLLVMLinkCommand(
236236
if (II.getType() == types::TY_Tempfilelist) {
237237
// Pass the unbundled list with '@' to be processed.
238238
std::string FileName(II.getFilename());
239-
Objs.push_back(C.getArgs().MakeArgString("@" + FileName));
239+
Libs.push_back(C.getArgs().MakeArgString("@" + FileName));
240240
} else if (II.getType() == types::TY_Archive && !LinkSYCLDeviceLibs) {
241241
Libs.push_back(II.getFilename());
242242
} else

clang/test/Driver/sycl-device-lib.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,5 @@
139139
// RUN: touch libsycl-crt.o
140140
// RUN: %clangxx -fsycl libsycl-crt.o --sysroot=%S/Inputs/SYCL -### 2>&1 \
141141
// RUN: | FileCheck %s -check-prefix=SYCL_LLVM_LINK_USER_ONLY_NEEDED
142-
// SYCL_LLVM_LINK_USER_ONLY_NEEDED: llvm-link{{.*}} "{{.*}}.o" "-o" "{{.*}}.bc" "--suppress-warnings"
142+
// SYCL_LLVM_LINK_USER_ONLY_NEEDED: llvm-link{{.*}} "{{.*}}.bc" "-o" "{{.*}}.bc" "--suppress-warnings"
143143
// SYCL_LLVM_LINK_USER_ONLY_NEEDED: llvm-link{{.*}} "-only-needed" "{{.*}}" "-o" "{{.*}}.bc" "--suppress-warnings"

clang/test/Driver/sycl-intelfpga-aoco.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,24 +83,26 @@
8383
// CHK-FPGA-AOCO-PHASES-EMU: 13: clang-offload-deps, {12}, ir, (host-sycl)
8484
// CHK-FPGA-AOCO-PHASES-EMU: 14: input, "[[INPUTA]]", archive
8585
// CHK-FPGA-AOCO-PHASES-EMU: 15: clang-offload-unbundler, {14}, archive
86-
// CHK-FPGA-AOCO-PHASES-EMU: 16: linker, {6, 13, 15}, ir, (device-sycl)
87-
// CHK-FPGA-AOCO-PHASES-EMU: 17: sycl-post-link, {16}, tempfiletable, (device-sycl)
88-
// CHK-FPGA-AOCO-PHASES-EMU: 18: file-table-tform, {17}, tempfilelist, (device-sycl)
89-
// CHK-FPGA-AOCO-PHASES-EMU: 19: llvm-spirv, {18}, tempfilelist, (device-sycl)
90-
// CHK-FPGA-AOCO-PHASES-EMU: 20: input, "[[INPUTA]]", archive
91-
// CHK-FPGA-AOCO-PHASES-EMU: 21: clang-offload-unbundler, {20}, fpga_dep_list
92-
// CHK-FPGA-AOCO-PHASES-EMU: 22: backend-compiler, {19, 21}, fpga_aocx, (device-sycl)
93-
// CHK-FPGA-AOCO-PHASES-EMU: 23: file-table-tform, {17, 22}, tempfiletable, (device-sycl)
94-
// CHK-FPGA-AOCO-PHASES-EMU: 24: clang-offload-wrapper, {23}, object, (device-sycl)
95-
// CHK-FPGA-AOCO-PHASES-EMU: 25: offload, "host-sycl (x86_64-unknown-linux-gnu)" {11}, "device-sycl (spir64_fpga-unknown-unknown)" {24}, image
86+
// CHK-FPGA-AOCO-PHASES-EMU: 16: spirv-to-ir-wrapper, {15}, tempfilelist, (device-sycl)
87+
// CHK-FPGA-AOCO-PHASES-EMU: 17: linker, {6, 13, 16}, ir, (device-sycl)
88+
// CHK-FPGA-AOCO-PHASES-EMU: 18: sycl-post-link, {17}, tempfiletable, (device-sycl)
89+
// CHK-FPGA-AOCO-PHASES-EMU: 19: file-table-tform, {18}, tempfilelist, (device-sycl)
90+
// CHK-FPGA-AOCO-PHASES-EMU: 20: llvm-spirv, {19}, tempfilelist, (device-sycl)
91+
// CHK-FPGA-AOCO-PHASES-EMU: 21: input, "[[INPUTA]]", archive
92+
// CHK-FPGA-AOCO-PHASES-EMU: 22: clang-offload-unbundler, {21}, fpga_dep_list
93+
// CHK-FPGA-AOCO-PHASES-EMU: 23: backend-compiler, {20, 22}, fpga_aocx, (device-sycl)
94+
// CHK-FPGA-AOCO-PHASES-EMU: 24: file-table-tform, {18, 23}, tempfiletable, (device-sycl)
95+
// CHK-FPGA-AOCO-PHASES-EMU: 25: clang-offload-wrapper, {24}, object, (device-sycl)
96+
// CHK-FPGA-AOCO-PHASES-EMU: 26: offload, "host-sycl (x86_64-unknown-linux-gnu)" {11}, "device-sycl (spir64_fpga-unknown-unknown)" {25}, image
9697

9798
/// aoco emulation test, checking tools
9899
// RUN: %clangxx -target x86_64-unknown-linux-gnu -fsycl -fno-sycl-device-lib=all -fintelfpga %t_aoco.a -### %s 2>&1 \
99100
// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO-EMU,CHK-FPGA-AOCO-EMU-LIN %s
100101
// RUN: %clang_cl -fsycl -fno-sycl-device-lib=all -fintelfpga %t_aoco_cl.a -### %s 2>&1 \
101102
// RUN: | FileCheck -check-prefixes=CHK-FPGA-AOCO-EMU,CHK-FPGA-AOCO-EMU-WIN %s
102-
// CHK-FPGA-AOCO-EMU: clang-offload-bundler{{.*}} "-type=a" "-targets=sycl-spir64_fpga-unknown-unknown" "-inputs=[[INPUTLIB:.+\.a]]" "-outputs=[[OUTLIB:.+\.a]]" "-unbundle"
103-
// CHK-FPGA-AOCO-EMU: llvm-link{{.*}} "[[OUTLIB]]" "-o" "[[LINKEDBC:.+\.bc]]"
103+
// CHK-FPGA-AOCO-EMU: clang-offload-bundler{{.*}} "-type=aoo" "-targets=sycl-spir64_fpga-unknown-unknown" "-inputs=[[INPUTLIB:.+\.a]]" "-outputs=[[OUTLIB:.+\.a]]" "-unbundle"
104+
// CHK-FPGA-AOCO-EMU: llvm-foreach{{.*}} "--out-ext=txt" "--in-file-list=[[OUTLIB]]" "--in-replace=[[OUTLIB]]" "--out-file-list=[[DEVICELIST:.+\.txt]]" "--out-replace=[[DEVICELIST]]" "--" {{.*}}spirv-to-ir-wrapper{{.*}} "[[OUTLIB]]" "-o" "[[DEVICELIST]]"
105+
// CHK-FPGA-AOCO-EMU: llvm-link{{.*}} "@[[DEVICELIST]]" "-o" "[[LINKEDBC:.+\.bc]]"
104106
// CHK-FPGA-AOCO-EMU: sycl-post-link{{.*}} "-split-esimd"{{.*}} "-O2" "-spec-const=default" "-o" "[[SPLTABLE:.+\.table]]" "[[LINKEDBC]]"
105107
// CHK-FPGA-AOCO-EMU: file-table-tform{{.*}} "-o" "[[TABLEOUT:.+\.txt]]" "[[SPLTABLE]]"
106108
// CHK-FPGA-AOCO-EMU: llvm-spirv{{.*}} "-o" "[[TARGSPV:.+\.txt]]" {{.*}} "[[TABLEOUT]]"

0 commit comments

Comments
 (0)