Skip to content

[Driver][FPGA][SYCL] Add specific timing diagnostic for FPGA AOT #3965

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions clang/include/clang/Driver/Job.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ struct ResponseFileSupport {
class Command {
public:
using ErrorCodeDiagMapTy = llvm::DenseMap<int, std::string>;
using ErrorCodeExitMapTy = llvm::DenseMap<int, bool>;

private:
/// Source - The action which caused the creation of this job.
Expand All @@ -132,6 +133,11 @@ class Command {
/// "invalid input" error can be ruled out
ErrorCodeDiagMapTy ErrorCodeDiagMap;

/// Similar to the container for the diagnostic messages, this container
/// is used to signify if the toolchain should error and exit right away
/// or if we should continue compilation.
ErrorCodeExitMapTy ErrorCodeExitMap;

/// The list of program arguments (not including the implicit first
/// argument, which will be the executable).
llvm::opt::ArgStringList Arguments;
Expand Down Expand Up @@ -198,11 +204,19 @@ class Command {
/// returned by the command
void addDiagForErrorCode(int ErrorCode, StringRef CustomDiag);

/// Store if the compilation should exit upon a particular error code
/// returned by the command
void addExitForErrorCode(int ErrorCode, bool Exit);

/// Get the custom driver diagnostic message for a particular error code
/// if such was stored. Returns an empty string if no diagnostic message
/// was found for the given error code.
StringRef getDiagForErrorCode(int ErrorCode) const;

/// Will the tool exit when a particular error code is encountered. Returns
/// true if not set (always exit)
bool getWillExitForErrorCode(int ErrorCode) const;

/// getSource - Return the Action which caused the creation of this job.
const Action &getSource() const { return Source; }

Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Driver/Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ static bool ActionFailed(const Action *A,
if (FailingCommands.empty())
return false;

for (const auto &CI : FailingCommands)
if (!CI.second->getWillExitForErrorCode(CI.first))
return false;

// CUDA/HIP/SYCL can have the same input source code compiled multiple times
// so do not compile again if there are already failures. It is OK to abort
// the CUDA pipeline on errors.
Expand Down Expand Up @@ -285,7 +289,9 @@ void Compilation::ExecuteJobs(const JobList &Jobs,
if (int Res = ExecuteCommand(Job, FailingCommand)) {
FailingCommands.push_back(std::make_pair(Res, FailingCommand));
// Bail as soon as one command fails in cl driver mode.
if (TheDriver.IsCLMode())
// Do not bail when the tool is setup to allow for continuation upon
// failure.
if (TheDriver.IsCLMode() && FailingCommand->getWillExitForErrorCode(Res))
return;
}
}
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Driver/Job.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,24 @@ void Command::addDiagForErrorCode(int ErrorCode, StringRef CustomDiag) {
ErrorCodeDiagMap[ErrorCode] = CustomDiag.str();
}

void Command::addExitForErrorCode(int ErrorCode, bool Exit) {
ErrorCodeExitMap[ErrorCode] = Exit;
}

StringRef Command::getDiagForErrorCode(int ErrorCode) const {
auto ErrorCodeDiagIt = ErrorCodeDiagMap.find(ErrorCode);
if (ErrorCodeDiagIt != ErrorCodeDiagMap.end())
return ErrorCodeDiagIt->second;
return StringRef();
}

bool Command::getWillExitForErrorCode(int ErrorCode) const {
auto ErrorCodeExitIt = ErrorCodeExitMap.find(ErrorCode);
if (ErrorCodeExitIt != ErrorCodeExitMap.end())
return ErrorCodeExitIt->second;
return true;
}

/// Rewrite relative include-like flag paths to absolute ones.
static void
rewriteIncludes(const llvm::ArrayRef<const char *> &Args, size_t Idx,
Expand Down
22 changes: 20 additions & 2 deletions clang/lib/Driver/ToolChains/SYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ const char *SYCL::Linker::constructLLVMSpirvCommand(
return OutputFileName;
}

static void addFPGATimingDiagnostic(std::unique_ptr<Command> &Cmd,
Compilation &C) {
const char *Msg = C.getArgs().MakeArgString(
"The FPGA image generated during this compile contains timing violations "
"and may produce functional errors if used. Refer to the Intel oneAPI "
"DPC++ FPGA Optimization Guide section on Timing Failures for more "
"information.");
Cmd->addDiagForErrorCode(/*ErrorCode*/ 42, Msg);
Cmd->addExitForErrorCode(/*ErrorCode*/ 42, false);
}

void SYCL::constructLLVMForeachCommand(Compilation &C, const JobAction &JA,
std::unique_ptr<Command> InputCommand,
const InputInfoList &InputFiles,
Expand Down Expand Up @@ -119,8 +130,14 @@ void SYCL::constructLLVMForeachCommand(Compilation &C, const JobAction &JA,
SmallString<128> ForeachPath(C.getDriver().Dir);
llvm::sys::path::append(ForeachPath, "llvm-foreach");
const char *Foreach = C.getArgs().MakeArgString(ForeachPath);
C.addCommand(std::make_unique<Command>(JA, *T, ResponseFileSupport::None(),
Foreach, ForeachArgs, None));

auto Cmd = std::make_unique<Command>(JA, *T, ResponseFileSupport::None(),
Foreach, ForeachArgs, None);
// FIXME: Add the FPGA specific timing diagnostic to the foreach call.
// The foreach call obscures the return codes from the tool it is calling
// to the compiler itself.
addFPGATimingDiagnostic(Cmd, C);
C.addCommand(std::move(Cmd));
}

// The list should match pre-built SYCL device library files located in
Expand Down Expand Up @@ -525,6 +542,7 @@ void SYCL::fpga::BackendCompiler::ConstructJob(
const char *Exec = C.getArgs().MakeArgString(ExecPath);
auto Cmd = std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Exec, CmdArgs, None);
addFPGATimingDiagnostic(Cmd, C);
if (!ForeachInputs.empty())
constructLLVMForeachCommand(C, JA, std::move(Cmd), ForeachInputs, Output,
this, ReportOptArg, ForeachExt);
Expand Down
22 changes: 22 additions & 0 deletions clang/test/Driver/Inputs/SYCL/aoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh
## Simple aoc replacement script that returns '42' that is used to test
## special return code processing for FPGA AOT.

while [[ $# -gt 0 ]] ; do
opt="$1"
case $opt in
-o)
shift
OUTFILE=$1
;;
*)
shift
;;
esac
done

if [ "$OUTFILE" != "" ] ; then
echo "dummy file contents" > $OUTFILE
fi

exit 42
15 changes: 15 additions & 0 deletions clang/test/Driver/sycl-intelfpga-return-check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// REQUIRES: system-linux

/// Tests behavior with aoc -fintelpga.
/// Uses a dummy aoc which returns '42' to make sure we properly emit a
/// diagnostic and also do not stop compilation
// RUN: env PATH=%S/Inputs/SYCL:$PATH \
// RUN: not %clangxx -fsycl -fintelfpga -Xshardware %s -v 2>&1 \
// RUN: | FileCheck %s -check-prefix ERROR_OUTPUT
// ERROR_OUTPUT: ld{{.*}} -o a.out
// ERROR_OUTPUT: The FPGA image generated during this compile contains timing violations

int main()
{
return 0;
}
23 changes: 23 additions & 0 deletions llvm/test/tools/llvm-foreach/retain-return-val.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// REQUIRES: system-linux
// Test that the return value from the called tool is retained.
// Runs a script within a script so we can retain the return code without
// the testing infrastructure getting in the way.

// RUN: echo 'Content of first file' > %t1.tgt
// RUN: echo 'Content of second file' > %t2.tgt
// RUN: echo "%t1.tgt" > %t.list
// RUN: echo "%t2.tgt" >> %t.list

// RUN: echo "#!/bin/sh" > %t.sh
// RUN: echo "cat \$1" >> %t.sh
// RUN: echo "exit 21" >> %t.sh
// RUN: chmod 777 %t.sh
// RUN: echo "#!/bin/sh" > %t2.sh
// RUN: echo "llvm-foreach --in-replace=\"{}\" --in-file-list=%t.list -- %t.sh \"{}\" > %t.res" >> %t2.sh
// RUN: echo "echo \$? >> %t.res" >> %t2.sh
// RUN: chmod 777 %t2.sh
// RUN: %t2.sh
// RUN: FileCheck < %t.res %s
// CHECK: Content of first file
// CHECK: Content of second file
// CHECK: 21
9 changes: 6 additions & 3 deletions llvm/tools/llvm-foreach/llvm-foreach.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ int main(int argc, char **argv) {
if (!OutputFileList.empty())
error(EC, "error opening the file '" + OutputFileList + "'");

int Res = 0;
std::string ResOutArg;
std::string IncOutArg;
std::vector<std::string> ResInArgs(InReplaceArgs.size());
Expand Down Expand Up @@ -225,13 +226,15 @@ int main(int argc, char **argv) {
int Result =
sys::ExecuteAndWait(Prog, Args, /*Env=*/None, /*Redirects=*/None,
/*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
if (Result != 0)
error(ErrMsg);
if (Result != 0) {
errs() << "llvm-foreach: " << ErrMsg << '\n';
Res = Result;
}
}

if (!OutputFileList.empty()) {
OS.close();
}

return 0;
return Res;
}