Skip to content

Commit 219d4ef

Browse files
mdtoguchiLu, John
andauthored
[Driver][SYCL][FPGA] Improve AOCX archive behaviors with -fsycl-link=image (#11592)
Use of -fsycl-link=image allows for FPGA users to create a full device binary and store it in an archive to be used later. This archive can then be picked up and linked in. The information stored in the archive was not sufficient, causing the device binary to not be 'visible' when linked in. Improve the situation here by saving all of the information provided by the wrapping step (including symbols) in the archive, but also be sure that this entire final binary is saved as it would be if we were performing a full E2E compilation. To accomodate the ability to pass around the needed symbols and properties that are used when wrapping the final binaries for any AOCR or AOCX type archives, update the way this information is passed around. Multiple binaries are added to the archive, including the full wrapped .bc file that is gathered and passed along to any subsequent wrapping sequence that occurs. --------- Signed-off-by: Lu, John <[email protected]> Co-authored-by: Lu, John <[email protected]>
1 parent 6083ddd commit 219d4ef

File tree

15 files changed

+817
-151
lines changed

15 files changed

+817
-151
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,9 @@ class OffloadUnbundlingJobAction final : public JobAction {
641641
/// action.
642642
SmallVector<DependentActionInfo, 6> DependentActionInfoArray;
643643

644+
/// Provides a specific type to be used that overrides the input type.
645+
types::ID DependentType = types::TY_Nothing;
646+
644647
std::string TargetString;
645648

646649
public:
@@ -663,6 +666,12 @@ class OffloadUnbundlingJobAction final : public JobAction {
663666
static bool classof(const Action *A) {
664667
return A->getKind() == OffloadUnbundlingJobClass;
665668
}
669+
670+
/// Set the dependent type.
671+
void setDependentType(types::ID Type) { DependentType = Type; }
672+
673+
/// Get the dependent type.
674+
types::ID getDependentType() const { return DependentType; }
666675
};
667676

668677
class OffloadWrapperJobAction : public JobAction {
@@ -680,6 +689,17 @@ class OffloadWrapperJobAction : public JobAction {
680689
static bool classof(const Action *A) {
681690
return A->getKind() == OffloadWrapperJobClass;
682691
}
692+
693+
// Set the compilation step setting. This is used to tell the wrapper job
694+
// action that the compilation step to create the object should be performed
695+
// after the wrapping step is complete.
696+
void setCompileStep(bool SetValue) { CompileStep = SetValue; }
697+
698+
// Get the compilation step setting.
699+
bool getCompileStep() const { return CompileStep; }
700+
701+
private:
702+
bool CompileStep = true;
683703
};
684704

685705
class OffloadPackagerJobAction : public JobAction {
@@ -809,6 +829,7 @@ class FileTableTformJobAction : public JobAction {
809829
public:
810830
static constexpr const char *COL_CODE = "Code";
811831
static constexpr const char *COL_ZERO = "0";
832+
static constexpr const char *COL_SYM_AND_PROPS = "SymAndProps";
812833

813834
struct Tform {
814835
enum Kind {

clang/lib/Driver/Driver.cpp

Lines changed: 132 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3451,24 +3451,8 @@ static bool hasSYCLDefaultSection(Compilation &C, const StringRef &File) {
34513451

34523452
static bool hasOffloadSections(Compilation &C, const StringRef &File,
34533453
DerivedArgList &Args) {
3454-
// Do not do the check if the file doesn't exist
3455-
if (!llvm::sys::fs::exists(File))
3456-
return false;
3457-
3458-
bool IsArchive = isStaticArchiveFile(File);
3459-
if (!(IsArchive || isObjectFile(File.str())))
3460-
return false;
3461-
3462-
llvm::Triple TT(C.getDefaultToolChain().getTriple());
3463-
// Checking uses -check-section option with the input file, no output
3464-
// file and the target triple being looked for.
3465-
// TODO - Improve checking to check for explicit offload target instead
3466-
// of the generic host availability.
3467-
const char *Targets = Args.MakeArgString(Twine("-targets=host-") + TT.str());
3468-
const char *Inputs = Args.MakeArgString(Twine("-input=") + File.str());
3469-
SmallVector<StringRef, 6> BundlerArgs = {IsArchive ? "-type=ao" : "-type=o",
3470-
Targets, Inputs, "-check-section"};
3471-
return runBundler(BundlerArgs, C);
3454+
SmallVector<std::string, 4> Sections(getOffloadSections(C, File));
3455+
return !Sections.empty();
34723456
}
34733457

34743458
// Simple helper function for Linker options, where the option is valid if
@@ -4836,6 +4820,10 @@ class OffloadingActionBuilder final {
48364820
/// List of static archives to extract FPGA dependency info from
48374821
ActionList FPGAArchiveInputs;
48384822

4823+
/// List of AOCR based archives that contain BC members to use for
4824+
/// providing symbols and properties.
4825+
ActionList FPGAAOCArchives;
4826+
48394827
// SYCLInstallation is needed in order to link SYCLDeviceLibs
48404828
SYCLInstallationDetector SYCLInstallation;
48414829

@@ -5281,6 +5269,9 @@ class OffloadingActionBuilder final {
52815269

52825270
// List of device objects that go through the device link step.
52835271
ActionList LinkObjects;
5272+
5273+
// List of FPGA AOC specific device objects/archives.
5274+
ActionList FPGAAOCDevices;
52845275
auto TargetTriple = TC->getTriple();
52855276
auto IsNVPTX = TargetTriple.isNVPTX();
52865277
auto IsAMDGCN = TargetTriple.isAMDGCN();
@@ -5301,27 +5292,16 @@ class OffloadingActionBuilder final {
53015292
}
53025293
// FPGA aocr/aocx does not go through the link and is passed
53035294
// directly to the backend compilation step (aocr) or wrapper (aocx)
5304-
Action *FPGAAOTAction;
5305-
if (Input->getType() == types::TY_FPGA_AOCR ||
5306-
Input->getType() == types::TY_FPGA_AOCR_EMU)
5307-
// Generate AOCX/AOCR
5308-
FPGAAOTAction =
5309-
C.MakeAction<BackendCompileJobAction>(Input, FPGAOutType);
5310-
else if (Input->getType() == types::TY_FPGA_AOCX)
5311-
FPGAAOTAction = Input;
5312-
else
5313-
llvm_unreachable("Unexpected FPGA input type.");
5314-
// Rename the column within the table. The list of files that is
5315-
// produced from the AOT offline complation step is just a list of
5316-
// files. Rename with the [Code] designator to be processed by
5317-
// the offload-wrapper in -batch mode.
5318-
auto *RenameAction = C.MakeAction<FileTableTformJobAction>(
5319-
FPGAAOTAction, types::TY_Tempfilelist, types::TY_Tempfilelist);
5320-
RenameAction->addRenameColumnTform(FileTableTformJobAction::COL_ZERO,
5321-
FileTableTformJobAction::COL_CODE);
5322-
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
5323-
RenameAction, types::TY_Object);
5324-
addDeps(DeviceWrappingAction, TC, BoundArch);
5295+
if (Args.hasArg(options::OPT_fintelfpga)) {
5296+
if (Input->getType() == types::TY_FPGA_AOCR ||
5297+
Input->getType() == types::TY_FPGA_AOCR_EMU ||
5298+
Input->getType() == types::TY_FPGA_AOCX)
5299+
// Save the AOCR device items. These will be processed along
5300+
// with the FPGAAOCArchives.
5301+
FPGAAOCDevices.push_back(Input);
5302+
else
5303+
llvm_unreachable("Unexpected FPGA input type.");
5304+
}
53255305
continue;
53265306
} else if (!types::isFPGA(Input->getType())) {
53275307
// No need for any conversion if we are coming in from the
@@ -5342,6 +5322,73 @@ class OffloadingActionBuilder final {
53425322
LinkObjects.push_back(ConvertSPIRVAction);
53435323
}
53445324
}
5325+
// Process AOCR/AOCR_EMU
5326+
if (FPGAAOCDevices.size()) {
5327+
assert(FPGAAOCDevices.size() == FPGAAOCArchives.size() &&
5328+
"Unexpected number of AOC binaries");
5329+
// Generate AOCX/AOCR
5330+
// Input is the unbundled device binary. Perform an additional
5331+
// unbundle against the input file associated to grab the wrapped
5332+
// device binary.
5333+
for (auto AOCRItem : llvm::zip(FPGAAOCArchives, FPGAAOCDevices)) {
5334+
Action *Archive = std::get<0>(AOCRItem);
5335+
Action *Device = std::get<1>(AOCRItem);
5336+
5337+
auto *UnbundleAction = C.MakeAction<OffloadUnbundlingJobAction>(
5338+
Archive, types::TY_Tempfilelist);
5339+
UnbundleAction->registerDependentActionInfo(TC, /*BoundArch=*/"",
5340+
Action::OFK_SYCL);
5341+
auto *RenameUnbundle = C.MakeAction<FileTableTformJobAction>(
5342+
UnbundleAction, types::TY_Tempfilelist, types::TY_Tempfilelist);
5343+
RenameUnbundle->addRenameColumnTform(
5344+
FileTableTformJobAction::COL_ZERO,
5345+
FileTableTformJobAction::COL_SYM_AND_PROPS);
5346+
5347+
// Wrap the unbundled device binary along with the additional
5348+
// .bc file that contains the Symbols and Properties
5349+
if (Device->getType() == types::TY_FPGA_AOCX) {
5350+
auto *RenameAction = C.MakeAction<FileTableTformJobAction>(
5351+
Device, types::TY_Tempfilelist, types::TY_Tempfilelist);
5352+
RenameAction->addRenameColumnTform(
5353+
FileTableTformJobAction::COL_ZERO,
5354+
FileTableTformJobAction::COL_CODE);
5355+
ActionList WrapperItems({RenameAction, RenameUnbundle});
5356+
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
5357+
WrapperItems, types::TY_Object);
5358+
addDeps(DeviceWrappingAction, TC, BoundArch);
5359+
} else {
5360+
auto *FPGAAOTAction =
5361+
C.MakeAction<BackendCompileJobAction>(Device, FPGAOutType);
5362+
auto *RenameAction = C.MakeAction<FileTableTformJobAction>(
5363+
FPGAAOTAction, types::TY_Tempfilelist, types::TY_Tempfilelist);
5364+
RenameAction->addRenameColumnTform(
5365+
FileTableTformJobAction::COL_ZERO,
5366+
FileTableTformJobAction::COL_CODE);
5367+
ActionList WrapperItems({RenameAction, RenameUnbundle});
5368+
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
5369+
WrapperItems, types::TY_Object);
5370+
5371+
Action *DeviceAction = DeviceWrappingAction;
5372+
if (Args.hasArg(options::OPT_fsycl_link_EQ)) {
5373+
if (auto *OWA = dyn_cast<OffloadWrapperJobAction>(DeviceAction))
5374+
OWA->setCompileStep(false);
5375+
ActionList BundlingActions;
5376+
BundlingActions.push_back(DeviceWrappingAction);
5377+
DeviceAction =
5378+
C.MakeAction<OffloadBundlingJobAction>(BundlingActions);
5379+
// We created a bundled section for the wrapped images that
5380+
// are not compiled. Create another image set that are
5381+
// compiled. This set would be extracted for feeding into
5382+
// the offline compilation step when consumed.
5383+
Action *CompiledDeviceAction =
5384+
C.MakeAction<OffloadWrapperJobAction>(WrapperItems,
5385+
types::TY_Object);
5386+
addDeps(CompiledDeviceAction, TC, nullptr);
5387+
}
5388+
addDeps(DeviceAction, TC, nullptr);
5389+
}
5390+
}
5391+
}
53455392
for (const auto &A : SYCLFinalDeviceList) {
53465393
// Given the list of archives that have final device binaries, take
53475394
// those archives and unbundle all of the devices seen. These will
@@ -5689,14 +5736,39 @@ class OffloadingActionBuilder final {
56895736
}
56905737

56915738
// After the Link, wrap the files before the final host link
5739+
// Add the unbundled wrapped AOC device binary to the wrapper
5740+
// call.
56925741
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
56935742
WrapperInputs, types::TY_Object);
56945743

56955744
if (IsSpirvAOT) {
5696-
bool AddBA =
5697-
(TargetTriple.getSubArch() == llvm::Triple::SPIRSubArch_gen &&
5698-
BoundArch != nullptr);
5699-
addDeps(DeviceWrappingAction, TC, AddBA ? BoundArch : nullptr);
5745+
// For FPGA with -fsycl-link, we need to bundle the output.
5746+
if (TargetTriple.getSubArch() == llvm::Triple::SPIRSubArch_fpga) {
5747+
Action *DeviceAction = DeviceWrappingAction;
5748+
if (Args.hasArg(options::OPT_fsycl_link_EQ)) {
5749+
// We do not want to compile the wrapped binary before the link.
5750+
if (auto *OWA = dyn_cast<OffloadWrapperJobAction>(DeviceAction))
5751+
OWA->setCompileStep(false);
5752+
ActionList BundlingActions;
5753+
BundlingActions.push_back(DeviceWrappingAction);
5754+
DeviceAction =
5755+
C.MakeAction<OffloadBundlingJobAction>(BundlingActions);
5756+
// We created a bundled section for the wrapped images that
5757+
// are not compiled. Create another image set that are
5758+
// compiled. This set would be extracted for feeding into
5759+
// the offline compilation step when consumed.
5760+
Action *CompiledDeviceAction =
5761+
C.MakeAction<OffloadWrapperJobAction>(WrapperInputs,
5762+
types::TY_Object);
5763+
addDeps(CompiledDeviceAction, TC, nullptr);
5764+
}
5765+
addDeps(DeviceAction, TC, nullptr);
5766+
} else {
5767+
bool AddBA =
5768+
(TargetTriple.getSubArch() == llvm::Triple::SPIRSubArch_gen &&
5769+
BoundArch != nullptr);
5770+
addDeps(DeviceWrappingAction, TC, AddBA ? BoundArch : nullptr);
5771+
}
57005772
} else {
57015773
withBoundArchForToolChain(TC, [&](const char *BoundArch) {
57025774
addDeps(DeviceWrappingAction, TC, BoundArch);
@@ -6346,13 +6418,22 @@ class OffloadingActionBuilder final {
63466418
Action *Current = C.MakeAction<InputAction>(*InputArg, Type);
63476419
return Current;
63486420
};
6349-
// Populate FPGA static archives that could contain dep files to be
6350-
// incorporated into the aoc compilation
6421+
// Populate FPGA archives that could contain dep files to be
6422+
// incorporated into the aoc compilation. Consider AOCR type archives
6423+
// as well for tracking symbols and properties information.
63516424
if (SYCLfpgaTriple && Args.hasArg(options::OPT_fintelfpga)) {
63526425
SmallVector<const char *, 16> LinkArgs(getLinkerArgs(C, Args));
63536426
for (StringRef LA : LinkArgs) {
6354-
if (isStaticArchiveFile(LA) && hasOffloadSections(C, LA, Args))
6427+
if (isStaticArchiveFile(LA) && hasOffloadSections(C, LA, Args)) {
63556428
FPGAArchiveInputs.push_back(makeInputAction(LA, types::TY_Archive));
6429+
for (types::ID Type : {types::TY_FPGA_AOCR, types::TY_FPGA_AOCR_EMU,
6430+
types::TY_FPGA_AOCX}) {
6431+
if (hasFPGABinary(C, LA.str(), Type)) {
6432+
FPGAAOCArchives.push_back(makeInputAction(LA, Type));
6433+
break;
6434+
}
6435+
}
6436+
}
63566437
}
63576438
}
63586439
// Discover any objects and archives that contain final device binaries.
@@ -6604,7 +6685,6 @@ class OffloadingActionBuilder final {
66046685
// An FPGA AOCX input does not have a host dependence to the unbundler
66056686
if (HostAction->getType() == types::TY_FPGA_AOCX)
66066687
return false;
6607-
66086688
recordHostAction(HostAction, InputArg);
66096689

66106690
// If we are supporting bundling/unbundling and the current action is an
@@ -8862,9 +8942,13 @@ InputInfoList Driver::BuildJobsForActionNoCache(
88628942
Ext = "txt";
88638943
}
88648944
if (JA->getType() == types::TY_FPGA_AOCR ||
8865-
JA->getType() == types::TY_FPGA_AOCR_EMU)
8945+
JA->getType() == types::TY_FPGA_AOCX ||
8946+
JA->getType() == types::TY_FPGA_AOCR_EMU) {
8947+
if (IsFPGAObjLink)
8948+
continue;
88668949
// AOCR files are always unbundled into a list file.
88678950
TI = types::TY_Tempfilelist;
8951+
}
88688952
} else {
88698953
if (UI.DependentOffloadKind == Action::OFK_SYCL)
88708954
// Do not add the current info for device with FPGA device. The

0 commit comments

Comments
 (0)