Skip to content

Commit 6d1b5b6

Browse files
committed
[clang][Driver] Enable the SPIR-V backend for the new driver.
1 parent 4c947ec commit 6d1b5b6

File tree

3 files changed

+83
-17
lines changed

3 files changed

+83
-17
lines changed

clang/lib/Driver/Driver.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4981,15 +4981,24 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
49814981
// Compiling HIP in device-only non-RDC mode requires linking each action
49824982
// individually.
49834983
for (Action *&A : DeviceActions) {
4984-
// Special handling for the HIP SPIR-V toolchain because it doesn't use
4985-
// the SPIR-V backend yet doesn't report the output as an object.
49864984
bool IsAMDGCNSPIRV = A->getOffloadingToolChain() &&
49874985
A->getOffloadingToolChain()->getTriple().getOS() ==
49884986
llvm::Triple::OSType::AMDHSA &&
49894987
A->getOffloadingToolChain()->getTriple().isSPIRV();
4988+
bool UseSPIRVBackend = Args.hasFlag(options::OPT_use_spirv_backend,
4989+
options::OPT_no_use_spirv_backend,
4990+
/*Default=*/false);
4991+
4992+
// Special handling for the HIP SPIR-V toolchain in device-only.
4993+
// The translator path has a linking step, whereas the SPIR-V backend path
4994+
// does not to avoid any external dependency such as spirv-link. The
4995+
// linking step is skipped for the SPIR-V backend path.
4996+
bool IsAMDGCNSPIRVWithBackend = IsAMDGCNSPIRV && UseSPIRVBackend;
4997+
49904998
if ((A->getType() != types::TY_Object && !IsAMDGCNSPIRV &&
49914999
A->getType() != types::TY_LTO_BC) ||
4992-
HIPRelocatableObj || !HIPNoRDC || !offloadDeviceOnly())
5000+
HIPRelocatableObj || !HIPNoRDC || !offloadDeviceOnly() ||
5001+
(IsAMDGCNSPIRVWithBackend && offloadDeviceOnly()))
49935002
continue;
49945003
ActionList LinkerInput = {A};
49955004
A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image);
@@ -5228,9 +5237,20 @@ Action *Driver::ConstructPhaseAction(
52285237
OffloadingToolChain && OffloadingToolChain->getTriple().isSPIRV();
52295238
bool IsOffloadOpenMP = TargetDeviceOffloadKind == Action::OFK_OpenMP;
52305239

5240+
bool IsHIP = TargetDeviceOffloadKind == Action::OFK_HIP;
5241+
bool UseSPIRVBackend = Args.hasFlag(options::OPT_use_spirv_backend,
5242+
options::OPT_no_use_spirv_backend,
5243+
/*Default=*/false);
5244+
// If offloadDeviceOnly(), we call the SPIRV backend unless LLVM bitcode was
5245+
// requested explicitly or RDC is set. If !offloadDeviceOnly, we emit LLVM
5246+
// bitcode, and clang-linker-wrapper will compile it to SPIRV.
5247+
bool UseSPIRVBackendForHipDeviceOnlyNoRDC =
5248+
IsHIP && IsSPIRV && UseSPIRVBackend && offloadDeviceOnly() && !IsRDC;
5249+
52315250
bool IsLLVMBitcodeOutput =
52325251
IsEmitLLVM || IsOffloadSYCL ||
52335252
((IsOffloadAMDGPU || IsOffloadHIP) &&
5253+
!UseSPIRVBackendForHipDeviceOnlyNoRDC &&
52345254
((IsRDC || (IsNewOffloadDriver &&
52355255
(!offloadDeviceOnly() || (IsOffloadHIP && IsSPIRV)))) ||
52365256
IsOffloadOpenMP));
@@ -5247,6 +5267,22 @@ Action *Driver::ConstructPhaseAction(
52475267
: types::TY_LLVM_BC;
52485268
return C.MakeAction<BackendJobAction>(Input, Output);
52495269
}
5270+
5271+
// The SPIRV backend compilation path for HIP must avoid external
5272+
// dependencies. The default compilation path assembles and links its
5273+
// output, but the SPIRV assembler and linker are external tools. This code
5274+
// ensures the backend emits binary SPIRV directly to bypass those steps and
5275+
// avoid failures. Without -save-temps, the compiler may already skip
5276+
// assembling and linking. With -save-temps, these steps must be explicitly
5277+
// disabled, as done here. We also force skipping these steps regardless of
5278+
// -save-temps to avoid relying on optimizations (unless -S is set).
5279+
bool IsBinarySPIRVOutput =
5280+
UseSPIRVBackendForHipDeviceOnlyNoRDC && !Args.hasArg(options::OPT_S);
5281+
if (IsBinarySPIRVOutput) {
5282+
// The current HIP bundling expects the type to be types::TY_Image
5283+
return C.MakeAction<BackendJobAction>(Input, types::TY_Image);
5284+
}
5285+
52505286
return C.MakeAction<BackendJobAction>(Input, types::TY_PP_Asm);
52515287
}
52525288
case phases::Assemble:

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5057,6 +5057,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
50575057
Args.ClaimAllArgs(options::OPT_femit_dwarf_unwind_EQ);
50585058
}
50595059

5060+
bool IsAMDSPIRVForHIPDevice =
5061+
IsHIPDevice && getToolChain().getTriple().isSPIRV() &&
5062+
getToolChain().getTriple().getVendor() == llvm::Triple::AMD;
5063+
50605064
if (isa<AnalyzeJobAction>(JA)) {
50615065
assert(JA.getType() == types::TY_Plist && "Invalid output type.");
50625066
CmdArgs.push_back("-analyze");
@@ -5154,6 +5158,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
51545158
rewriteKind = RK_Fragile;
51555159
} else if (JA.getType() == types::TY_CIR) {
51565160
CmdArgs.push_back("-emit-cir");
5161+
} else if (JA.getType() == types::TY_Image && IsAMDSPIRVForHIPDevice) {
5162+
CmdArgs.push_back("-emit-obj");
51575163
} else {
51585164
assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!");
51595165
}
@@ -9084,7 +9090,9 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
90849090
OPT_fno_lto,
90859091
OPT_flto,
90869092
OPT_flto_partitions_EQ,
9087-
OPT_flto_EQ};
9093+
OPT_flto_EQ,
9094+
OPT_use_spirv_backend};
9095+
90889096
const llvm::DenseSet<unsigned> LinkerOptions{OPT_mllvm, OPT_Zlinker_input};
90899097
auto ShouldForwardForToolChain = [&](Arg *A, const ToolChain &TC) {
90909098
// Don't forward -mllvm to toolchains that don't support LLVM.

clang/lib/Driver/ToolChains/HIPAMD.cpp

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,9 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA,
159159

160160
// For SPIR-V the inputs for the job are device AMDGCN SPIR-V flavoured bitcode
161161
// and the output is either a compiled SPIR-V binary or bitcode (-emit-llvm). It
162-
// calls llvm-link and then the llvm-spirv translator. Once the SPIR-V BE will
163-
// be promoted from experimental, we will switch to using that. TODO: consider
164-
// if we want to run any targeted optimisations over IR here, over generic
165-
// SPIR-V.
162+
// calls llvm-link and then the llvm-spirv translator or the SPIR-V BE.
163+
// TODO: consider if we want to run any targeted optimisations over IR here,
164+
// over generic SPIR-V.
166165
void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
167166
Compilation &C, const JobAction &JA, const InputInfoList &Inputs,
168167
const InputInfo &Output, const llvm::opt::ArgList &Args) const {
@@ -173,17 +172,40 @@ void AMDGCN::Linker::constructLinkAndEmitSpirvCommand(
173172
const char *LinkedBCFilePath = HIP::getTempFile(C, LinkedBCFilePrefix, "bc");
174173
InputInfo LinkedBCFile(&JA, LinkedBCFilePath, Output.getBaseInput());
175174

175+
bool UseSPIRVBackend =
176+
Args.hasFlag(options::OPT_use_spirv_backend,
177+
options::OPT_no_use_spirv_backend, /*Default=*/false);
178+
176179
constructLlvmLinkCommand(C, JA, Inputs, LinkedBCFile, Args);
177180

178-
// Emit SPIR-V binary.
179-
llvm::opt::ArgStringList TrArgs{
180-
"--spirv-max-version=1.6",
181-
"--spirv-ext=+all",
182-
"--spirv-allow-unknown-intrinsics",
183-
"--spirv-lower-const-expr",
184-
"--spirv-preserve-auxdata",
185-
"--spirv-debug-info-version=nonsemantic-shader-200"};
186-
SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile, TrArgs);
181+
if (UseSPIRVBackend) {
182+
// This code handles the case in the new driver when --offload-device-only
183+
// is unset and clang-linker-wrapper forwards the bitcode that must be
184+
// compiled to SPIR-V.
185+
186+
llvm::opt::ArgStringList CmdArgs;
187+
const char *Triple =
188+
C.getArgs().MakeArgString("-triple=spirv64-amd-amdhsa");
189+
190+
CmdArgs.append({"-cc1", Triple, "-emit-obj", "-disable-llvm-optzns",
191+
LinkedBCFile.getFilename(), "-o", Output.getFilename()});
192+
193+
const char *Exec = getToolChain().getDriver().getClangProgramPath();
194+
C.addCommand(std::make_unique<Command>(JA, *this,
195+
ResponseFileSupport::None(), Exec,
196+
CmdArgs, LinkedBCFile, Output));
197+
} else {
198+
// Emit SPIR-V binary using the translator
199+
llvm::opt::ArgStringList TrArgs{
200+
"--spirv-max-version=1.6",
201+
"--spirv-ext=+all",
202+
"--spirv-allow-unknown-intrinsics",
203+
"--spirv-lower-const-expr",
204+
"--spirv-preserve-auxdata",
205+
"--spirv-debug-info-version=nonsemantic-shader-200"};
206+
SPIRV::constructTranslateCommand(C, *this, JA, Output, LinkedBCFile,
207+
TrArgs);
208+
}
187209
}
188210

189211
// For amdgcn the inputs of the linker job are device bitcode and output is

0 commit comments

Comments
 (0)