Skip to content

Commit 6431be6

Browse files
author
Artem Gindinson
authored
[SYCL][Driver] Improve the diagnostic for FPGA device link errors (#1077)
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. Document the error-code handling infrastructure specifics Signed-off-by: Artem Gindinson <[email protected]>
1 parent a84a576 commit 6431be6

File tree

6 files changed

+85
-7
lines changed

6 files changed

+85
-7
lines changed

clang/include/clang/Driver/Job.h

Lines changed: 26 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,18 @@ 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+
/// In order to add such a diagnostic for an external tool, consider the
59+
/// following criteria:
60+
/// 1) Does the command's executable return different codes upon different
61+
/// types of errors?
62+
/// 2) If the executable provides a single error code for various error types,
63+
/// is only a certain type of failure expected to occur within the driver
64+
/// flow? E.g. the driver guarantees a valid input to the tool, so any
65+
/// "invalid input" error can be ruled out
66+
ErrorCodeDiagMapTy ErrorCodeDiagMap;
67+
5168
/// The list of program arguments (not including the implicit first
5269
/// argument, which will be the executable).
5370
llvm::opt::ArgStringList Arguments;
@@ -100,6 +117,15 @@ class Command {
100117
virtual int Execute(ArrayRef<Optional<StringRef>> Redirects,
101118
std::string *ErrMsg, bool *ExecutionFailed) const;
102119

120+
/// Store a custom driver diagnostic message upon a particular error code
121+
/// returned by the command
122+
void addDiagForErrorCode(int ErrorCode, StringRef CustomDiag);
123+
124+
/// Get the custom driver diagnostic message for a particular error code
125+
/// if such was stored. Returns an empty string if no diagnostic message
126+
/// was found for the given error code.
127+
StringRef getDiagForErrorCode(int ErrorCode) const;
128+
103129
/// getSource - Return the Action which caused the creation of this job.
104130
const Action &getSource() const { return Source; }
105131

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)