Skip to content

Commit d476f8a

Browse files
author
Artem Gindinson
committed
[SYCL][Driver] Improve the diagnostic for FPGA device link errors
FPGA compilations have a common use case of linking an object file against an arhive that contains a pre-compiled device image. If the archive was comprised without pulling in the object file in question, the presence of any device kernel in the object file would signal incomplete device code compilation/linkage. Within the SYCL flow, a check for this case is performed by the llvm-no-spir-kernel tool, so as to achieve a compile-time failure instead of an obscure runtime failure due to a missing kernel. This patch extends the Clang driver with the infrastructure to enhance error messages upon receiving specific error codes from external tools. The functionality is then used to enhance the diagnostic yielded by llvm-no-spir-kernel in the aforementioned case. Signed-off-by: Artem Gindinson <[email protected]>
1 parent 60def6d commit d476f8a

File tree

6 files changed

+77
-7
lines changed

6 files changed

+77
-7
lines changed

clang/include/clang/Driver/Job.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "clang/Basic/LLVM.h"
1313
#include "llvm/ADT/ArrayRef.h"
14+
#include "llvm/ADT/DenseMap.h"
1415
#include "llvm/ADT/Optional.h"
1516
#include "llvm/ADT/SmallVector.h"
1617
#include "llvm/ADT/StringRef.h"
@@ -39,6 +40,10 @@ struct CrashReportInfo {
3940
/// Command - An executable path/name and argument vector to
4041
/// execute.
4142
class Command {
43+
public:
44+
using ErrorCodeDiagMapTy = llvm::DenseMap<int, std::string>;
45+
46+
private:
4247
/// Source - The action which caused the creation of this job.
4348
const Action &Source;
4449

@@ -48,6 +53,10 @@ class Command {
4853
/// The executable to run.
4954
const char *Executable;
5055

56+
/// The container for custom driver-set diagnostic messages that are
57+
/// produced upon particular error codes returned by the command
58+
ErrorCodeDiagMapTy ErrorCodeDiagMap;
59+
5160
/// The list of program arguments (not including the implicit first
5261
/// argument, which will be the executable).
5362
llvm::opt::ArgStringList Arguments;
@@ -100,6 +109,15 @@ class Command {
100109
virtual int Execute(ArrayRef<Optional<StringRef>> Redirects,
101110
std::string *ErrMsg, bool *ExecutionFailed) const;
102111

112+
/// Store a custom driver diagnostic message upon a particular error code
113+
/// returned by the command
114+
void addDiagForErrorCode(int ErrorCode, StringRef CustomDiag);
115+
116+
/// Get the custom driver diagnostic message for a particular error code
117+
/// if such was stored. Returns an empty string if no diagnostic message
118+
/// was found for the given error code.
119+
StringRef getDiagForErrorCode(int ErrorCode) const;
120+
103121
/// getSource - Return the Action which caused the creation of this job.
104122
const Action &getSource() const { return Source; }
105123

clang/lib/Driver/Driver.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1686,7 +1686,7 @@ int Driver::ExecuteCompilation(
16861686
// diagnostics, so always print the diagnostic there.
16871687
const Tool &FailingTool = FailingCommand->getCreator();
16881688

1689-
if (!FailingCommand->getCreator().hasGoodDiagnostics() || CommandRes != 1) {
1689+
if (!FailingTool.hasGoodDiagnostics() || CommandRes != 1) {
16901690
// FIXME: See FIXME above regarding result code interpretation.
16911691
if (CommandRes < 0)
16921692
Diag(clang::diag::err_drv_command_signalled)
@@ -1695,6 +1695,10 @@ int Driver::ExecuteCompilation(
16951695
Diag(clang::diag::err_drv_command_failed)
16961696
<< FailingTool.getShortName() << CommandRes;
16971697
}
1698+
1699+
auto CustomDiag = FailingCommand->getDiagForErrorCode(CommandRes);
1700+
if (!CustomDiag.empty())
1701+
Diag(clang::diag::note_drv_command_failed_diag_msg) << CustomDiag;
16981702
}
16991703
return Res;
17001704
}

clang/lib/Driver/Job.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,17 @@ void Command::buildArgvForResponseFile(
173173
}
174174
}
175175

176+
void Command::addDiagForErrorCode(int ErrorCode, StringRef CustomDiag) {
177+
ErrorCodeDiagMap[ErrorCode] = CustomDiag.str();
178+
}
179+
180+
StringRef Command::getDiagForErrorCode(int ErrorCode) const {
181+
auto ErrorCodeDiagIt = ErrorCodeDiagMap.find(ErrorCode);
182+
if (ErrorCodeDiagIt != ErrorCodeDiagMap.end())
183+
return ErrorCodeDiagIt->second;
184+
return StringRef();
185+
}
186+
176187
/// Rewrite relative include-like flag paths to absolute ones.
177188
static void
178189
rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7431,18 +7431,29 @@ void SPIRCheck::ConstructJob(Compilation &C, const JobAction &JA,
74317431
// we need to exit. The expected output is the input as this is just an
74327432
// intermediate check with no functional change.
74337433
ArgStringList CheckArgs;
7434-
for (auto I : Inputs) {
7435-
CheckArgs.push_back(I.getFilename());
7436-
}
7434+
assert(Inputs.size() == 1 && "Unexpected number of inputs to the tool");
7435+
const InputInfo &InputFile = Inputs.front();
7436+
CheckArgs.push_back(InputFile.getFilename());
74377437

74387438
// Add output file, which is just a copy of the input to better fit in the
74397439
// toolchain flow.
74407440
CheckArgs.push_back("-o");
74417441
CheckArgs.push_back(Output.getFilename());
7442-
7443-
C.addCommand(std::make_unique<Command>(JA, *this,
7442+
auto Cmd = std::make_unique<Command>(
7443+
JA, *this,
74447444
TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())),
7445-
CheckArgs, None));
7445+
CheckArgs, None);
7446+
7447+
if (getToolChain().getTriple().getSubArch() ==
7448+
llvm::Triple::SPIRSubArch_fpga) {
7449+
const char *Msg = TCArgs.MakeArgString(
7450+
Twine("The FPGA image does not include all device kernels from ") +
7451+
Twine(InputFile.getBaseInput()) +
7452+
Twine(". Please re-generate the image"));
7453+
Cmd->addDiagForErrorCode(/*ErrorCode*/ 1, Msg);
7454+
}
7455+
7456+
C.addCommand(std::move(Cmd));
74467457
}
74477458

74487459
void SYCLPostLink::ConstructJob(Compilation &C, const JobAction &JA,

clang/lib/Driver/ToolChains/Clang.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ class LLVM_LIBRARY_VISIBILITY SYCLPostLink final : public Tool {
199199
: Tool("SYCL post link", "sycl-post-link", TC) {}
200200

201201
bool hasIntegratedCPP() const override { return false; }
202+
bool hasGoodDiagnostics() const override { return true; }
202203
void ConstructJob(Compilation &C, const JobAction &JA,
203204
const InputInfo &Output, const InputInfoList &Inputs,
204205
const llvm::opt::ArgList &TCArgs,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//==----- fpga_device_link_diag.cpp - SYCL FPGA linking diagnostic test ----==//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// REQUIRES: aoc, accelerator
10+
11+
// RUN: %clangxx -fsycl -fintelfpga %s -c -o test_obj.o
12+
// RUN: touch dummy.cpp
13+
// RUN: %clangxx -fsycl -fintelfpga dummy.cpp -c
14+
// RUN: %clangxx -fsycl -fintelfpga -fsycl-link=image dummy.o -o dummy_arch.a
15+
// RUN: not %clangxx -fsycl -fintelfpga test_obj.o dummy_arch.a 2>&1 | FileCheck %s --check-prefix=CHK-FPGA-LINK-DIAG
16+
// CHK-FPGA-LINK-DIAG: note: diagnostic msg: The FPGA image does not include all device kernels from test_obj.o. Please re-generate the image
17+
18+
template <typename name, typename Func>
19+
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
20+
kernelFunc();
21+
}
22+
23+
void foo() {
24+
kernel_single_task<class kernel>([]() {});
25+
}

0 commit comments

Comments
 (0)