Skip to content

Commit 6ea38f0

Browse files
authored
[Driver][SYCL][FPGA] Allow for multiple AOCX device binaries for FPGA (#2909)
Initial implementation only allowed for a single AOCR/AOCX binary to be used in a single FPGA compilation. This restriction is being lifted and we are allowing multiple FPGA device images to be added to the final executable. Allow for list file creation for aocx/aocr files with update extensions when unbundling the archives. To handle this, we are also enabling the rename functionality for file-table-tform Improve 'aoc' check in FPGA test for systems that have aoc installed remove fpga_device_link_diag.cpp test, as we no longer do the spir check Add TODO for improvement of output type and naming for aocx/aocr unbundles
1 parent 5c3e538 commit 6ea38f0

File tree

8 files changed

+193
-205
lines changed

8 files changed

+193
-205
lines changed

clang/include/clang/Driver/Action.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ class SPIRVTranslatorJobAction : public JobAction {
717717
// Provides a check of the given input file for the existence of SPIR kernel
718718
// code. This is currently only used for FPGA specific tool chains and can
719719
// be expanded to perform other SPIR checks if needed.
720+
// TODO: No longer being used for FPGA (or elsewhere), cleanup needed.
720721
class SPIRCheckJobAction : public JobAction {
721722
void anchor() override;
722723

@@ -779,7 +780,7 @@ class FileTableTformJobAction : public JobAction {
779780

780781
public:
781782
struct Tform {
782-
enum Kind { EXTRACT, EXTRACT_DROP_TITLE, REPLACE };
783+
enum Kind { EXTRACT, EXTRACT_DROP_TITLE, REPLACE, RENAME };
783784

784785
Tform() = default;
785786
Tform(Kind K, std::initializer_list<StringRef> Args) : TheKind(K) {
@@ -801,6 +802,10 @@ class FileTableTformJobAction : public JobAction {
801802
// <To> from another file table passed as input to this action.
802803
void addReplaceColumnTform(StringRef From, StringRef To);
803804

805+
// Renames a column with title <From> in this table with a column with title
806+
// <To> passed as input to this action.
807+
void addRenameColumnTform(StringRef From, StringRef To);
808+
804809
static bool classof(const Action *A) {
805810
return A->getKind() == FileTableTformJobClass;
806811
}

clang/lib/Driver/Action.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,11 @@ void FileTableTformJobAction::addReplaceColumnTform(StringRef From,
515515
Tforms.emplace_back(Tform(Tform::REPLACE, {From, To}));
516516
}
517517

518+
void FileTableTformJobAction::addRenameColumnTform(StringRef From,
519+
StringRef To) {
520+
Tforms.emplace_back(Tform(Tform::RENAME, {From, To}));
521+
}
522+
518523
void StaticLibJobAction::anchor() {}
519524

520525
StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type)

clang/lib/Driver/Driver.cpp

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,10 +3682,6 @@ class OffloadingActionBuilder final {
36823682
/// construction. Does not track AOT binary inputs triples.
36833683
SmallVector<llvm::Triple, 4> SYCLTripleList;
36843684

3685-
/// Running count of FPGA device binaries.
3686-
unsigned FPGAxCount = 0;
3687-
unsigned FPGArCount = 0;
3688-
36893685
/// Type of output file for FPGA device compilation.
36903686
types::ID FPGAOutType = types::TY_FPGA_AOCX;
36913687

@@ -3916,20 +3912,6 @@ class OffloadingActionBuilder final {
39163912
.isWindowsMSVCEnvironment()))
39173913
FPGAObjectInputs.push_back(IA);
39183914
}
3919-
// When creating FPGA device fat objects, all host objects are
3920-
// partially linked. Gather that list here.
3921-
if (IA->getType() == types::TY_Object ||
3922-
IA->getType() == types::TY_FPGA_AOCX ||
3923-
IA->getType() == types::TY_FPGA_AOCR) {
3924-
// Keep track of the number of FPGA devices encountered
3925-
// Only one of these is allowed at a single time.
3926-
if (IA->getType() == types::TY_FPGA_AOCX)
3927-
FPGAxCount++;
3928-
if (IA->getType() == types::TY_FPGA_AOCR)
3929-
FPGArCount++;
3930-
if ((FPGAxCount && FPGArCount) || FPGAxCount > 1 || FPGArCount > 1)
3931-
C.getDriver().Diag(clang::diag::err_drv_bad_fpga_device_count);
3932-
}
39333915
}
39343916
for (unsigned I = 0; I < ToolChains.size(); ++I) {
39353917
SYCLDeviceActions.push_back(UA);
@@ -4089,59 +4071,6 @@ class OffloadingActionBuilder final {
40894071
// Current list is empty, nothing to process.
40904072
continue;
40914073

4092-
// Perform a check for device kernels. This is done for FPGA when an
4093-
// aocx or aocr based file is found.
4094-
if (FPGAxCount || FPGArCount) {
4095-
ActionList DeviceObjects;
4096-
for (const auto &I : LI) {
4097-
if (I->getType() == types::TY_Object) {
4098-
// Perform a check for SPIR kernel.
4099-
auto *DeviceCheckAction =
4100-
C.MakeAction<SPIRCheckJobAction>(I, types::TY_Object);
4101-
DeviceObjects.push_back(DeviceCheckAction);
4102-
continue;
4103-
}
4104-
// We want to move the AOCX/AOCR binary to the front of the objects
4105-
// allowing it to be picked up instead of the other device objects
4106-
// at runtime.
4107-
// TODO: In the presense of existing FPGA Device binaries (AOCX)
4108-
// we do not need to perform/add the SPIR-V generated device
4109-
// binaries from sources or objects.
4110-
if (types::isFPGA(I->getType())) {
4111-
// Do not perform a device link and only pass the aocr
4112-
// file to the offline compilation before wrapping. Just
4113-
// wrap an aocx file.
4114-
Action *DeviceWrappingAction;
4115-
if (I->getType() == types::TY_FPGA_AOCR) {
4116-
auto *DeviceBECompileAction =
4117-
C.MakeAction<BackendCompileJobAction>(I, FPGAOutType);
4118-
DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
4119-
DeviceBECompileAction, types::TY_Object);
4120-
} else
4121-
DeviceWrappingAction =
4122-
C.MakeAction<OffloadWrapperJobAction>(I, types::TY_Object);
4123-
DA.add(*DeviceWrappingAction, **TC, /*BoundArch=*/nullptr,
4124-
Action::OFK_SYCL);
4125-
continue;
4126-
}
4127-
DeviceObjects.push_back(I);
4128-
}
4129-
if (!DeviceObjects.empty()) {
4130-
// When aocx or aocr is found, there is an expectation that none of
4131-
// the other objects processed have any kernel. So, there
4132-
// is no need in device code split and backend compile here. Just
4133-
// link and wrap the device binary.
4134-
auto *DeviceLinkAction =
4135-
C.MakeAction<LinkJobAction>(DeviceObjects, types::TY_LLVM_BC);
4136-
auto *SPIRVTranslateAction = C.MakeAction<SPIRVTranslatorJobAction>(
4137-
DeviceLinkAction, types::TY_SPIRV);
4138-
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
4139-
SPIRVTranslateAction, types::TY_Object);
4140-
DA.add(*DeviceWrappingAction, **TC, /*BoundArch=*/nullptr,
4141-
Action::OFK_SYCL);
4142-
}
4143-
continue;
4144-
}
41454074
ActionList DeviceLibObjects;
41464075
ActionList LinkObjects;
41474076
auto TT = SYCLTripleList[I];
@@ -4153,9 +4082,33 @@ class OffloadingActionBuilder final {
41534082
// FPGA aoco does not go through the link, everything else does.
41544083
if (Input->getType() == types::TY_FPGA_AOCO)
41554084
DeviceLibObjects.push_back(Input);
4156-
else
4085+
// FPGA aocr/aocx does not go through the link and is passed
4086+
// directly to the backend compilation step (aocr) or wrapper (aocx)
4087+
else if (types::isFPGA(Input->getType())) {
4088+
Action *FPGAAOTAction;
4089+
constexpr char COL_CODE[] = "Code";
4090+
constexpr char COL_ZERO[] = "0";
4091+
if (Input->getType() == types::TY_FPGA_AOCR)
4092+
// Generate AOCX/AOCR
4093+
FPGAAOTAction =
4094+
C.MakeAction<BackendCompileJobAction>(Input, FPGAOutType);
4095+
else if (Input->getType() == types::TY_FPGA_AOCX)
4096+
FPGAAOTAction = Input;
4097+
else
4098+
llvm_unreachable("Unexpected FPGA input type.");
4099+
auto *RenameAction = C.MakeAction<FileTableTformJobAction>(
4100+
FPGAAOTAction, types::TY_Tempfilelist);
4101+
RenameAction->addRenameColumnTform(COL_ZERO, COL_CODE);
4102+
auto *DeviceWrappingAction = C.MakeAction<OffloadWrapperJobAction>(
4103+
RenameAction, types::TY_Object);
4104+
DA.add(*DeviceWrappingAction, **TC, /*BoundArch=*/nullptr,
4105+
Action::OFK_SYCL);
4106+
} else
41574107
LinkObjects.push_back(Input);
41584108
}
4109+
if (LinkObjects.empty())
4110+
continue;
4111+
41594112
// The linkage actions subgraph leading to the offload wrapper.
41604113
// [cond] Means incoming/outgoing dependence is created only when cond
41614114
// is true. A function of:
@@ -5145,9 +5098,10 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args,
51455098
// archive unbundling for Windows.
51465099
if (!isStaticArchiveFile(LA))
51475100
continue;
5148-
// FPGA AOCX files are archives, but we do not want to unbundle them here
5149-
// as they have already been unbundled and processed for linking.
5150-
if (hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCX))
5101+
// FPGA AOCX/AOCR files are archives, but we do not want to unbundle them
5102+
// here as they have already been unbundled and processed for linking.
5103+
if (hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCX) ||
5104+
hasFPGABinary(C, LA.str(), types::TY_FPGA_AOCR))
51515105
continue;
51525106
// For offload-static-libs we add an unbundling action for each static
51535107
// archive which produces list files with extracted objects. Device lists
@@ -6151,6 +6105,9 @@ InputInfo Driver::BuildJobsForActionNoCache(
61516105
TI = types::TY_TempAOCOfilelist;
61526106
Ext = "txt";
61536107
}
6108+
if (JA->getType() == types::TY_FPGA_AOCR)
6109+
// AOCR files are always unbundled into a list file.
6110+
TI = types::TY_Tempfilelist;
61546111
} else if (EffectiveTriple.getSubArch() !=
61556112
llvm::Triple::SPIRSubArch_fpga) {
61566113
if (UI.DependentOffloadKind == Action::OFK_SYCL) {

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7672,10 +7672,15 @@ void OffloadBundler::ConstructJobMultipleOutputs(
76727672
bool IsFPGADepLibUnbundle = JA.getType() == types::TY_FPGA_Dependencies_List;
76737673

76747674
if (InputType == types::TY_FPGA_AOCX || InputType == types::TY_FPGA_AOCR) {
7675-
// Override type with archive object
7675+
// Override type with AOCX/AOCR which will unbundle to a list containing
7676+
// binaries with the appropriate file extension (.aocx/.aocr).
7677+
// TODO - representation of the output file from the unbundle for these
7678+
// types (aocx/aocr) are always list files. We should represent this
7679+
// better in the output extension and type for improved understanding
7680+
// of file contents and debuggability.
76767681
if (getToolChain().getTriple().getSubArch() ==
76777682
llvm::Triple::SPIRSubArch_fpga)
7678-
TypeArg = "ao";
7683+
TypeArg = InputType == types::TY_FPGA_AOCX ? "aocx" : "aocr";
76797684
else
76807685
TypeArg = "aoo";
76817686
}
@@ -7884,7 +7889,8 @@ void OffloadWrapper::ConstructJob(Compilation &C, const JobAction &JA,
78847889
const InputInfo &I = Inputs[0];
78857890
assert(I.isFilename() && "Invalid input.");
78867891

7887-
if (I.getType() == types::TY_Tempfiletable)
7892+
if (I.getType() == types::TY_Tempfiletable ||
7893+
I.getType() == types::TY_Tempfilelist)
78887894
// wrapper actual input files are passed via the batch job file table:
78897895
WrapperArgs.push_back(C.getArgs().MakeArgString("-batch"));
78907896
WrapperArgs.push_back(C.getArgs().MakeArgString(I.getFilename()));
@@ -8302,6 +8308,15 @@ void FileTableTform::ConstructJob(Compilation &C, const JobAction &JA,
83028308
addArgs(CmdArgs, TCArgs, {Arg});
83038309
break;
83048310
}
8311+
case FileTableTformJobAction::Tform::RENAME: {
8312+
assert(Tf.TheArgs.size() == 2 && "from/to names expected");
8313+
SmallString<128> Arg("-rename=");
8314+
Arg += Tf.TheArgs[0];
8315+
Arg += ",";
8316+
Arg += Tf.TheArgs[1];
8317+
addArgs(CmdArgs, TCArgs, {Arg});
8318+
break;
8319+
}
83058320
default:
83068321
llvm_unreachable("unknown file table transformation kind");
83078322
}

clang/lib/Driver/Types.cpp

Lines changed: 61 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -254,65 +254,67 @@ bool types::isSrcFile(ID Id) {
254254

255255
types::ID types::lookupTypeForExtension(llvm::StringRef Ext) {
256256
return llvm::StringSwitch<types::ID>(Ext)
257-
.Case("c", TY_C)
258-
.Case("C", TY_CXX)
259-
.Case("F", TY_Fortran)
260-
.Case("f", TY_PP_Fortran)
261-
.Case("h", TY_CHeader)
262-
.Case("H", TY_CXXHeader)
263-
.Case("i", TY_PP_C)
264-
.Case("m", TY_ObjC)
265-
.Case("M", TY_ObjCXX)
266-
.Case("o", TY_Object)
267-
.Case("S", TY_Asm)
268-
.Case("s", TY_PP_Asm)
269-
.Case("bc", TY_LLVM_BC)
270-
.Case("cc", TY_CXX)
271-
.Case("CC", TY_CXX)
272-
.Case("cl", TY_CL)
273-
.Case("cp", TY_CXX)
274-
.Case("cu", TY_CUDA)
275-
.Case("hh", TY_CXXHeader)
276-
.Case("ii", TY_PP_CXX)
277-
.Case("ll", TY_LLVM_IR)
278-
.Case("mi", TY_PP_ObjC)
279-
.Case("mm", TY_ObjCXX)
280-
.Case("rs", TY_RenderScript)
281-
.Case("adb", TY_Ada)
282-
.Case("ads", TY_Ada)
283-
.Case("asm", TY_PP_Asm)
284-
.Case("ast", TY_AST)
285-
.Case("ccm", TY_CXXModule)
286-
.Case("cpp", TY_CXX)
287-
.Case("CPP", TY_CXX)
288-
.Case("c++", TY_CXX)
289-
.Case("C++", TY_CXX)
290-
.Case("cui", TY_PP_CUDA)
291-
.Case("cxx", TY_CXX)
292-
.Case("CXX", TY_CXX)
293-
.Case("F90", TY_Fortran)
294-
.Case("f90", TY_PP_Fortran)
295-
.Case("F95", TY_Fortran)
296-
.Case("f95", TY_PP_Fortran)
297-
.Case("for", TY_PP_Fortran)
298-
.Case("FOR", TY_PP_Fortran)
299-
.Case("fpp", TY_Fortran)
300-
.Case("FPP", TY_Fortran)
301-
.Case("gch", TY_PCH)
302-
.Case("hip", TY_HIP)
303-
.Case("hpp", TY_CXXHeader)
304-
.Case("hxx", TY_CXXHeader)
305-
.Case("iim", TY_PP_CXXModule)
306-
.Case("lib", TY_Object)
307-
.Case("mii", TY_PP_ObjCXX)
308-
.Case("obj", TY_Object)
309-
.Case("ifs", TY_IFS)
310-
.Case("pch", TY_PCH)
311-
.Case("pcm", TY_ModuleFile)
312-
.Case("c++m", TY_CXXModule)
313-
.Case("cppm", TY_CXXModule)
314-
.Case("cxxm", TY_CXXModule)
315-
.Default(TY_INVALID);
257+
.Case("c", TY_C)
258+
.Case("C", TY_CXX)
259+
.Case("F", TY_Fortran)
260+
.Case("f", TY_PP_Fortran)
261+
.Case("h", TY_CHeader)
262+
.Case("H", TY_CXXHeader)
263+
.Case("i", TY_PP_C)
264+
.Case("m", TY_ObjC)
265+
.Case("M", TY_ObjCXX)
266+
.Case("o", TY_Object)
267+
.Case("S", TY_Asm)
268+
.Case("s", TY_PP_Asm)
269+
.Case("bc", TY_LLVM_BC)
270+
.Case("cc", TY_CXX)
271+
.Case("CC", TY_CXX)
272+
.Case("cl", TY_CL)
273+
.Case("cp", TY_CXX)
274+
.Case("cu", TY_CUDA)
275+
.Case("hh", TY_CXXHeader)
276+
.Case("ii", TY_PP_CXX)
277+
.Case("ll", TY_LLVM_IR)
278+
.Case("mi", TY_PP_ObjC)
279+
.Case("mm", TY_ObjCXX)
280+
.Case("rs", TY_RenderScript)
281+
.Case("adb", TY_Ada)
282+
.Case("ads", TY_Ada)
283+
.Case("asm", TY_PP_Asm)
284+
.Case("ast", TY_AST)
285+
.Case("ccm", TY_CXXModule)
286+
.Case("cpp", TY_CXX)
287+
.Case("CPP", TY_CXX)
288+
.Case("c++", TY_CXX)
289+
.Case("C++", TY_CXX)
290+
.Case("cui", TY_PP_CUDA)
291+
.Case("cxx", TY_CXX)
292+
.Case("CXX", TY_CXX)
293+
.Case("F90", TY_Fortran)
294+
.Case("f90", TY_PP_Fortran)
295+
.Case("F95", TY_Fortran)
296+
.Case("f95", TY_PP_Fortran)
297+
.Case("for", TY_PP_Fortran)
298+
.Case("FOR", TY_PP_Fortran)
299+
.Case("fpp", TY_Fortran)
300+
.Case("FPP", TY_Fortran)
301+
.Case("gch", TY_PCH)
302+
.Case("hip", TY_HIP)
303+
.Case("hpp", TY_CXXHeader)
304+
.Case("hxx", TY_CXXHeader)
305+
.Case("iim", TY_PP_CXXModule)
306+
.Case("lib", TY_Object)
307+
.Case("mii", TY_PP_ObjCXX)
308+
.Case("obj", TY_Object)
309+
.Case("ifs", TY_IFS)
310+
.Case("pch", TY_PCH)
311+
.Case("pcm", TY_ModuleFile)
312+
.Case("c++m", TY_CXXModule)
313+
.Case("cppm", TY_CXXModule)
314+
.Case("cxxm", TY_CXXModule)
315+
.Case("aocr", TY_FPGA_AOCR)
316+
.Case("aocx", TY_FPGA_AOCX)
317+
.Default(TY_INVALID);
316318
}
317319

318320
types::ID types::lookupTypeForTypeSpecifier(const char *Name) {

0 commit comments

Comments
 (0)