Skip to content

Commit 3a99558

Browse files
authored
[Driver][SYCL][FPGA] Use opencl-aot for AOT when doing FPGA emulation (#3440)
When performing AOT compilation for FPGA, we call 'aoc' to perform the offline compilation. Update this behavior to use opencl-aot when we know we are performing emulation instead of running on hardware. When creating FPGA AOCX/AOCR archives when performing emulation, create archives which contain .spv items as opposed to using the regular aocx and aocr binaries. The expected input type for AOCX/AOCR were considered for hardware usage with FPGA. In this part, we allow for the differentiation of the type of archive created, whether it be emulation or hardware. Depending on how these archives are created, we make sure we take the proper flow to process the contents. Also perform some cleanup in the needed triple arch representation for fpga, where we didn't need to define all of the different types we were wrapping for FPGA specific binaries.
1 parent ef4e6dd commit 3a99558

20 files changed

+498
-148
lines changed

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ def err_drv_invalid_Xsycl_frontend_with_args : Error<
134134
"invalid -Xsycl-target-frontend argument: '%0', options requiring arguments are unsupported">;
135135
def err_drv_bad_fpga_device_count : Error<
136136
"More than one FPGA specific device binary found in input objects">;
137+
def warn_drv_mismatch_fpga_archive : Warning<
138+
"FPGA archive '%0' does not contain matching emulation/hardware expectancy">,
139+
InGroup<SyclFPGAMismatch>;
137140
def err_drv_unsupported_opt_dpcpp : Error<"option '%0' unsupported with DPC++">;
138141
def err_drv_argument_only_allowed_with : Error<
139142
"invalid argument '%0' only allowed with '%1'">;

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1182,6 +1182,7 @@ def Sycl2017Compat : DiagGroup<"sycl-2017-compat">;
11821182
def Sycl2020Compat : DiagGroup<"sycl-2020-compat">;
11831183
def SyclStrict : DiagGroup<"sycl-strict", [ Sycl2017Compat, Sycl2020Compat]>;
11841184
def SyclTarget : DiagGroup<"sycl-target">;
1185+
def SyclFPGAMismatch : DiagGroup<"sycl-fpga-mismatch">;
11851186

11861187
// Backend warnings.
11871188
def BackendInlineAsm : DiagGroup<"inline-asm">;

clang/include/clang/Driver/Driver.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,13 @@ class Driver {
641641

642642
void setOffloadStaticLibSeen() { OffloadStaticLibSeen = true; }
643643

644+
/// FPGA Emulation Mode. By default, this is true due to the fact that
645+
/// an external option setting is required to target hardware.
646+
bool FPGAEmulationMode = true;
647+
void setFPGAEmulationMode(bool IsEmulation) {
648+
FPGAEmulationMode = IsEmulation;
649+
}
650+
644651
/// Returns true if an offload static library is found.
645652
bool checkForOffloadStaticLib(Compilation &C,
646653
llvm::opt::DerivedArgList &Args) const;
@@ -690,6 +697,10 @@ class Driver {
690697
return FPGATempDepFiles[FileName];
691698
}
692699

700+
/// isFPGAEmulationMode - Compilation mode is determined to be used for
701+
/// FPGA Emulation. This is only used for SYCL offloading to FPGA device.
702+
bool isFPGAEmulationMode() const { return FPGAEmulationMode; };
703+
693704
/// addIntegrationFiles - Add the integration files that will be populated
694705
/// by the device compilation and used by the host compile.
695706
void addIntegrationFiles(StringRef IntHeaderName, StringRef FileName) const {

clang/include/clang/Driver/Types.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,10 @@ TYPE("tempAOCOfilelist", TempAOCOfilelist, INVALID, "txt", phases
108108
TYPE("archive", Archive, INVALID, "a", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
109109
TYPE("wholearchive", WholeArchive, INVALID, "a", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
110110
TYPE("fpga_aocx", FPGA_AOCX, INVALID, "aocx", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
111+
TYPE("fpga_aocx_emu", FPGA_AOCX_EMU, INVALID, "aocx", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
111112
TYPE("fpga_aocr", FPGA_AOCR, INVALID, "aocr", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
113+
TYPE("fpga_aocr_emu", FPGA_AOCR_EMU, INVALID, "aocr", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
112114
TYPE("fpga_aoco", FPGA_AOCO, INVALID, "aoco", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
113-
TYPE("fpga_dependencies", FPGA_Dependencies, INVALID, "d", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
114-
TYPE("fpga_dependencies_list", FPGA_Dependencies_List, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
115+
TYPE("fpga_dep", FPGA_Dependencies, INVALID, "d", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
116+
TYPE("fpga_dep_list", FPGA_Dependencies_List, INVALID, "txt", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
115117
TYPE("none", Nothing, INVALID, nullptr, phases::Compile, phases::Backend, phases::Assemble, phases::Link)

clang/lib/Driver/Driver.cpp

Lines changed: 86 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,22 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
13771377
// Populate the tool chains for the offloading devices, if any.
13781378
CreateOffloadingDeviceToolChains(*C, Inputs);
13791379

1380+
// Determine FPGA emulation status.
1381+
if (C->hasOffloadToolChain<Action::OFK_SYCL>()) {
1382+
auto SYCLTCRange = C->getOffloadToolChains<Action::OFK_SYCL>();
1383+
ArgStringList TargetArgs;
1384+
const ToolChain *TC = SYCLTCRange.first->second;
1385+
const toolchains::SYCLToolChain *SYCLTC =
1386+
static_cast<const toolchains::SYCLToolChain *>(TC);
1387+
SYCLTC->TranslateBackendTargetArgs(*TranslatedArgs, TargetArgs);
1388+
for (StringRef ArgString : TargetArgs) {
1389+
if (ArgString.equals("-hardware") || ArgString.equals("-simulation")) {
1390+
setFPGAEmulationMode(false);
1391+
break;
1392+
}
1393+
}
1394+
}
1395+
13801396
// Construct the list of abstract actions to perform for this compilation. On
13811397
// MachO targets this uses the driver-driver and universal actions.
13821398
if (TC.getTriple().isOSBinFormatMachO())
@@ -4210,11 +4226,13 @@ class OffloadingActionBuilder final {
42104226
Action *FPGAAOTAction;
42114227
constexpr char COL_CODE[] = "Code";
42124228
constexpr char COL_ZERO[] = "0";
4213-
if (Input->getType() == types::TY_FPGA_AOCR)
4229+
if (Input->getType() == types::TY_FPGA_AOCR ||
4230+
Input->getType() == types::TY_FPGA_AOCR_EMU)
42144231
// Generate AOCX/AOCR
42154232
FPGAAOTAction =
42164233
C.MakeAction<BackendCompileJobAction>(Input, FPGAOutType);
4217-
else if (Input->getType() == types::TY_FPGA_AOCX)
4234+
else if (Input->getType() == types::TY_FPGA_AOCX ||
4235+
Input->getType() == types::TY_FPGA_AOCX_EMU)
42184236
FPGAAOTAction = Input;
42194237
else
42204238
llvm_unreachable("Unexpected FPGA input type.");
@@ -4563,9 +4581,15 @@ class OffloadingActionBuilder final {
45634581
(SYCLLinkTargets || (WrapDeviceOnlyBinary && !SYCLfpgaTriple));
45644582

45654583
// Set the FPGA output type based on command line (-fsycl-link).
4566-
if (auto * A = C.getInputArgs().getLastArg(options::OPT_fsycl_link_EQ))
4584+
if (auto *A = C.getInputArgs().getLastArg(options::OPT_fsycl_link_EQ)) {
45674585
FPGAOutType = (A->getValue() == StringRef("early"))
4568-
? types::TY_FPGA_AOCR : types::TY_FPGA_AOCX;
4586+
? types::TY_FPGA_AOCR
4587+
: types::TY_FPGA_AOCX;
4588+
if (C.getDriver().isFPGAEmulationMode())
4589+
FPGAOutType = (A->getValue() == StringRef("early"))
4590+
? types::TY_FPGA_AOCR_EMU
4591+
: types::TY_FPGA_AOCX_EMU;
4592+
}
45694593

45704594
// Populate FPGA static archives that could contain dep files to be
45714595
// incorporated into the aoc compilation
@@ -4709,6 +4733,46 @@ class OffloadingActionBuilder final {
47094733
return C.MakeAction<OffloadAction>(HDep, DDeps);
47104734
}
47114735

4736+
// Update Input action to reflect FPGA device archive specifics based
4737+
// on archive contents.
4738+
bool updateInputForFPGA(Action *&A, const Arg *InputArg,
4739+
DerivedArgList &Args) {
4740+
std::string InputName = InputArg->getAsString(Args);
4741+
const Driver &D = C.getDriver();
4742+
bool IsFPGAEmulation = D.isFPGAEmulationMode();
4743+
// Only check for FPGA device information when using fpga SubArch.
4744+
if (A->getType() == types::TY_Object && isObjectFile(InputName))
4745+
return true;
4746+
4747+
auto ArchiveTypeMismatch = [&D, &InputName](bool EmitDiag) {
4748+
if (EmitDiag)
4749+
D.Diag(clang::diag::warn_drv_mismatch_fpga_archive) << InputName;
4750+
};
4751+
// Type FPGA aoco is a special case for static archives
4752+
if (A->getType() == types::TY_FPGA_AOCO) {
4753+
if (!hasFPGABinary(C, InputName, types::TY_FPGA_AOCO))
4754+
return false;
4755+
A = C.MakeAction<InputAction>(*InputArg, types::TY_FPGA_AOCO);
4756+
return true;
4757+
}
4758+
4759+
SmallVector<std::pair<types::ID, bool>, 4> FPGAAOCTypes = {
4760+
{types::TY_FPGA_AOCX, false},
4761+
{types::TY_FPGA_AOCR, false},
4762+
{types::TY_FPGA_AOCX_EMU, true},
4763+
{types::TY_FPGA_AOCR_EMU, true}};
4764+
for (const auto &ArchiveType : FPGAAOCTypes) {
4765+
bool BinaryFound = hasFPGABinary(C, InputName, ArchiveType.first);
4766+
if (BinaryFound && ArchiveType.second == IsFPGAEmulation) {
4767+
// Binary matches check and emulation type, we keep this one.
4768+
A = C.MakeAction<InputAction>(*InputArg, ArchiveType.first);
4769+
return true;
4770+
}
4771+
ArchiveTypeMismatch(BinaryFound && ArchiveType.second != IsFPGAEmulation);
4772+
}
4773+
return true;
4774+
}
4775+
47124776
/// Generate an action that adds a host dependence to a device action. The
47134777
/// results will be kept in this action builder. Return true if an error was
47144778
/// found.
@@ -4719,7 +4783,8 @@ class OffloadingActionBuilder final {
47194783
return true;
47204784

47214785
// An FPGA AOCX input does not have a host dependence to the unbundler
4722-
if (HostAction->getType() == types::TY_FPGA_AOCX)
4786+
if (HostAction->getType() == types::TY_FPGA_AOCX ||
4787+
HostAction->getType() == types::TY_FPGA_AOCX_EMU)
47234788
return false;
47244789

47254790
// If we are supporting bundling/unbundling and the current action is an
@@ -4734,7 +4799,6 @@ class OffloadingActionBuilder final {
47344799
!InputArg->getOption().hasFlag(options::LinkerInput) &&
47354800
(!types::isSrcFile(HostAction->getType()) ||
47364801
HostAction->getType() == types::TY_PP_HIP)) {
4737-
std::string InputName = InputArg->getAsString(Args);
47384802
ActionList HostActionList;
47394803
Action *A(HostAction);
47404804
// Only check for FPGA device information when using fpga SubArch.
@@ -4743,22 +4807,13 @@ class OffloadingActionBuilder final {
47434807
HasFPGATarget |= TI->second->getTriple().getSubArch() ==
47444808
llvm::Triple::SPIRSubArch_fpga;
47454809
bool isArchive = !(HostAction->getType() == types::TY_Object &&
4746-
isObjectFile(InputName));
4810+
isObjectFile(InputArg->getAsString(Args)));
47474811
if (!HasFPGATarget && isArchive &&
47484812
HostAction->getType() == types::TY_FPGA_AOCO)
47494813
// Archive with Non-FPGA target with AOCO type should not be unbundled.
47504814
return false;
4751-
if (HasFPGATarget && isArchive) {
4752-
// Type FPGA aoco is a special case for -foffload-static-lib.
4753-
if (HostAction->getType() == types::TY_FPGA_AOCO) {
4754-
if (!hasFPGABinary(C, InputName, types::TY_FPGA_AOCO))
4755-
return false;
4756-
A = C.MakeAction<InputAction>(*InputArg, types::TY_FPGA_AOCO);
4757-
} else if (hasFPGABinary(C, InputName, types::TY_FPGA_AOCX))
4758-
A = C.MakeAction<InputAction>(*InputArg, types::TY_FPGA_AOCX);
4759-
else if (hasFPGABinary(C, InputName, types::TY_FPGA_AOCR))
4760-
A = C.MakeAction<InputAction>(*InputArg, types::TY_FPGA_AOCR);
4761-
}
4815+
if (HasFPGATarget && !updateInputForFPGA(A, InputArg, Args))
4816+
return false;
47624817
auto UnbundlingHostAction = C.MakeAction<OffloadUnbundlingJobAction>(A);
47634818
UnbundlingHostAction->registerDependentActionInfo(
47644819
C.getSingleOffloadToolChain<Action::OFK_Host>(),
@@ -4795,7 +4850,8 @@ class OffloadingActionBuilder final {
47954850
if ((OffloadKind == Action::OFK_None && CanUseBundler) ||
47964851
(HasFPGATarget && ((Args.hasArg(options::OPT_fsycl_link_EQ) &&
47974852
HostAction->getType() == types::TY_Object) ||
4798-
HostAction->getType() == types::TY_FPGA_AOCX)))
4853+
HostAction->getType() == types::TY_FPGA_AOCX ||
4854+
HostAction->getType() == types::TY_FPGA_AOCX_EMU)))
47994855
if (auto *UA = dyn_cast<OffloadUnbundlingJobAction>(HostAction))
48004856
HostAction = UA->getInputs().back();
48014857

@@ -5245,8 +5301,13 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
52455301
continue;
52465302
// FPGA AOCX/AOCR files are archives, but we do not want to unbundle them
52475303
// here as they have already been unbundled and processed for linking.
5304+
// TODO: The multiple binary checks for FPGA types getting a little out
5305+
// of hand. Improve this by doing a single scan of the args and holding
5306+
// that in a data structure for reference.
52485307
if (hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCX) ||
5249-
hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCR))
5308+
hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCR) ||
5309+
hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCX_EMU) ||
5310+
hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCR_EMU))
52505311
continue;
52515312
// For offload-static-libs we add an unbundling action for each static
52525313
// archive which produces list files with extracted objects. Device lists
@@ -5279,7 +5340,9 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
52795340
};
52805341
if (auto *IA = dyn_cast<InputAction>(LI)) {
52815342
if (IA->getType() == types::TY_FPGA_AOCR ||
5282-
IA->getType() == types::TY_FPGA_AOCX) {
5343+
IA->getType() == types::TY_FPGA_AOCX ||
5344+
IA->getType() == types::TY_FPGA_AOCR_EMU ||
5345+
IA->getType() == types::TY_FPGA_AOCX_EMU) {
52835346
// Add to unbundler.
52845347
UnbundlerInput = LI;
52855348
} else {
@@ -6249,7 +6312,8 @@ InputInfo Driver::BuildJobsForActionNoCache(
62496312
TI = types::TY_TempAOCOfilelist;
62506313
Ext = "txt";
62516314
}
6252-
if (JA->getType() == types::TY_FPGA_AOCR)
6315+
if (JA->getType() == types::TY_FPGA_AOCR ||
6316+
JA->getType() == types::TY_FPGA_AOCR_EMU)
62536317
// AOCR files are always unbundled into a list file.
62546318
TI = types::TY_Tempfilelist;
62556319
} else if (EffectiveTriple.getSubArch() !=

clang/lib/Driver/ToolChain.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
#include "InputInfo.h"
1111
#include "ToolChains/Arch/ARM.h"
1212
#include "ToolChains/Clang.h"
13-
#include "ToolChains/InterfaceStubs.h"
1413
#include "ToolChains/Flang.h"
14+
#include "ToolChains/InterfaceStubs.h"
1515
#include "clang/Basic/ObjCRuntime.h"
1616
#include "clang/Basic/Sanitizers.h"
1717
#include "clang/Config/config.h"
@@ -33,6 +33,7 @@
3333
#include "llvm/Option/ArgList.h"
3434
#include "llvm/Option/OptTable.h"
3535
#include "llvm/Option/Option.h"
36+
#include "llvm/Support/CommandLine.h"
3637
#include "llvm/Support/ErrorHandling.h"
3738
#include "llvm/Support/FileSystem.h"
3839
#include "llvm/Support/Path.h"

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7774,7 +7774,7 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
77747774
Triples += ',';
77757775
Triples += Action::GetOffloadKindName(Action::OFK_SYCL);
77767776
Triples += '-';
7777-
Triples += llvm::Triple::getArchTypeName(llvm::Triple::fpga_dep);
7777+
Triples += types::getTypeName(types::TY_FPGA_Dependencies);
77787778
}
77797779
CmdArgs.push_back(TCArgs.MakeArgString(Triples));
77807780

@@ -7841,17 +7841,21 @@ void OffloadBundler::ConstructJobMultipleOutputs(
78417841
bool IsFPGADepUnbundle = JA.getType() == types::TY_FPGA_Dependencies;
78427842
bool IsFPGADepLibUnbundle = JA.getType() == types::TY_FPGA_Dependencies_List;
78437843

7844-
if (InputType == types::TY_FPGA_AOCX || InputType == types::TY_FPGA_AOCR) {
7844+
if (InputType == types::TY_FPGA_AOCX || InputType == types::TY_FPGA_AOCR ||
7845+
InputType == types::TY_FPGA_AOCX_EMU ||
7846+
InputType == types::TY_FPGA_AOCR_EMU) {
78457847
// Override type with AOCX/AOCR which will unbundle to a list containing
78467848
// binaries with the appropriate file extension (.aocx/.aocr).
78477849
// TODO - representation of the output file from the unbundle for these
78487850
// types (aocx/aocr) are always list files. We should represent this
78497851
// better in the output extension and type for improved understanding
78507852
// of file contents and debuggability.
78517853
if (getToolChain().getTriple().getSubArch() ==
7852-
llvm::Triple::SPIRSubArch_fpga)
7853-
TypeArg = InputType == types::TY_FPGA_AOCX ? "aocx" : "aocr";
7854-
else
7854+
llvm::Triple::SPIRSubArch_fpga) {
7855+
bool isAOCX = InputType == types::TY_FPGA_AOCX ||
7856+
InputType == types::TY_FPGA_AOCX_EMU;
7857+
TypeArg = isAOCX ? "aocx" : "aocr";
7858+
} else
78557859
TypeArg = "aoo";
78567860
}
78577861
if (InputType == types::TY_FPGA_AOCO || IsFPGADepLibUnbundle)
@@ -7919,7 +7923,7 @@ void OffloadBundler::ConstructJobMultipleOutputs(
79197923
// file as it does not match the type being bundled.
79207924
Triples += Action::GetOffloadKindName(Action::OFK_SYCL);
79217925
Triples += '-';
7922-
Triples += llvm::Triple::getArchTypeName(llvm::Triple::fpga_dep);
7926+
Triples += types::getTypeName(types::TY_FPGA_Dependencies);
79237927
}
79247928
CmdArgs.push_back(TCArgs.MakeArgString(Triples));
79257929

@@ -7993,9 +7997,12 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
79937997
// to the target triple setting.
79947998
if (TT.getSubArch() == llvm::Triple::SPIRSubArch_fpga &&
79957999
TCArgs.hasArg(options::OPT_fsycl_link_EQ)) {
8000+
SmallString<16> FPGAArch("fpga_");
79968001
auto *A = C.getInputArgs().getLastArg(options::OPT_fsycl_link_EQ);
7997-
TT.setArchName((A->getValue() == StringRef("early")) ? "fpga_aocr"
7998-
: "fpga_aocx");
8002+
FPGAArch += A->getValue() == StringRef("early") ? "aocr" : "aocx";
8003+
if (C.getDriver().isFPGAEmulationMode())
8004+
FPGAArch += "_emu";
8005+
TT.setArchName(FPGAArch);
79998006
TT.setVendorName("intel");
80008007
TT.setEnvironment(llvm::Triple::SYCLDevice);
80018008
TargetTripleOpt = TT.str();
@@ -8032,6 +8039,7 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
80328039
if (TC.getTriple().getSubArch() == llvm::Triple::NoSubArch) {
80338040
// Only store compile/link opts in the image descriptor for the SPIR-V
80348041
// target; AOT compilation has already been performed otherwise.
8042+
TC.AddImpliedTargetArgs(TT, TCArgs, BuildArgs);
80358043
TC.TranslateBackendTargetArgs(TCArgs, BuildArgs);
80368044
createArgString("-compile-opts=");
80378045
BuildArgs.clear();

0 commit comments

Comments
 (0)