Skip to content

Commit 3b96b65

Browse files
lamb-jronlieb
authored andcommitted
[clang-offload-bundler] Add support for -check-input-archive (llvm#73709)
In this patch, we add support for checking a heterogeneous archive. We also significantly improve the clang-offload-bundler documentation. Change-Id: I332f5810bfc90b1f702d05295767789c33e4e22b
1 parent 1acc4c0 commit 3b96b65

File tree

3 files changed

+115
-157
lines changed

3 files changed

+115
-157
lines changed

clang/docs/ClangOffloadBundler.rst

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,10 @@ Compatibility Rules for Bundle Entry ID
295295
A code object, specified using its Bundle Entry ID, can be loaded and
296296
executed on a target processor, if:
297297

298-
* Their offload kind are the same.
299-
* Their target triple are compatible.
300-
* Their Target ID are compatible as defined in :ref:`compatibility-target-id`.
301-
298+
* Their offload kinds are the same.
299+
* Their target triples are compatible.
300+
* Their Target IDs are compatible as defined in :ref:`compatibility-target-id`.
301+
302302
.. _clang-target-id:
303303

304304
Target ID
@@ -410,10 +410,18 @@ collection of device binaries for a specific target.
410410
where, Fi-Tj-DeviceBinary.X represents device binary of i-th bundled device
411411
binary file for target Tj.
412412

413-
clang-offload-bundler extracts compatible device binaries for a given target
413+
The clang-offload-bundler extracts compatible device binaries for a given target
414414
from the bundled device binaries in a heterogeneous device archive and creates
415415
a target-specific device archive without bundling.
416416

417+
The clang-offload-bundler determines whether a device binary is compatible
418+
with a target by comparing bundle IDs. Two bundle IDs are considered
419+
compatible if:
420+
421+
* Their offload kinds are the same
422+
* Their target triples are the same
423+
* Their Target IDs are the same
424+
417425
Creating a Heterogeneous Device Archive
418426
---------------------------------------
419427

@@ -428,7 +436,7 @@ Creating a Heterogeneous Device Archive
428436
-Xopenmp-target=nvptx64-nvidia-cuda -march=sm_70 \
429437
-Xopenmp-target=nvptx64-nvidia-cuda -march=sm_80 \
430438
-c func_1.c -o func_1.o
431-
439+
432440
clang -O2 -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa,amdgcn-amd-amdhsa,
433441
nvptx64-nvidia-cuda, nvptx64-nvidia-cuda \
434442
-Xopenmp-target=amdgcn-amd-amdhsa -march=gfx906:sramecc-:xnack+ \
@@ -491,18 +499,12 @@ Additional Options while Archive Unbundling
491499
Check if input heterogeneous device archive follows rules for composition
492500
as defined in :ref:`code-object-composition` before creating device-specific
493501
archive(s).
494-
clang-offload-bundler determines whether a device binary is compatible with a
495-
target by comparing bundle ID's. Two bundle ID's are considered compatible if:
496502

497503
**-debug-only=CodeObjectCompatibility**
498504
Verbose printing of matched/unmatched comparisons between bundle entry id of
499505
a device binary from HDA and bundle entry ID of a given target processor
500506
(see :ref:`compatibility-bundle-entry-id`).
501507

502-
* Their offload kind are the same
503-
* Their target triple are the same
504-
* Their GPUArch are the same
505-
506508
Compression and Decompression
507509
=============================
508510

clang/lib/Driver/OffloadBundler.cpp

Lines changed: 96 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -164,51 +164,6 @@ static std::string getDeviceLibraryFileName(StringRef BundleFileName,
164164
return Result;
165165
}
166166

167-
/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
168-
/// target \p TargetInfo.
169-
/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
170-
bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
171-
const OffloadTargetInfo &TargetInfo) {
172-
173-
// Compatible in case of exact match.
174-
if (CodeObjectInfo == TargetInfo) {
175-
DEBUG_WITH_TYPE("CodeObjectCompatibility",
176-
dbgs() << "Compatible: Exact match: \t[CodeObject: "
177-
<< CodeObjectInfo.str()
178-
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
179-
return true;
180-
}
181-
182-
// Incompatible if Kinds or Triples mismatch.
183-
if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
184-
!CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
185-
DEBUG_WITH_TYPE(
186-
"CodeObjectCompatibility",
187-
dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
188-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
189-
<< "]\n");
190-
return false;
191-
}
192-
193-
// Incompatible if target IDs are incompatible.
194-
if (!clang::isCompatibleTargetID(CodeObjectInfo.TargetID,
195-
TargetInfo.TargetID)) {
196-
DEBUG_WITH_TYPE(
197-
"CodeObjectCompatibility",
198-
dbgs() << "Incompatible: target IDs are incompatible \t[CodeObject: "
199-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
200-
<< "]\n");
201-
return false;
202-
}
203-
204-
DEBUG_WITH_TYPE(
205-
"CodeObjectCompatibility",
206-
dbgs() << "Compatible: Code Objects are compatible \t[CodeObject: "
207-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
208-
<< "]\n");
209-
return true;
210-
}
211-
212167
namespace {
213168
/// Generic file handler interface.
214169
class FileHandler {
@@ -1130,6 +1085,99 @@ Error OffloadBundler::ListBundleIDsInFile(
11301085
return FH->listBundleIDs(DecompressedInput);
11311086
}
11321087

1088+
/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
1089+
/// target \p TargetInfo.
1090+
/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
1091+
bool isCodeObjectCompatible(const OffloadTargetInfo &CodeObjectInfo,
1092+
const OffloadTargetInfo &TargetInfo) {
1093+
1094+
// Compatible in case of exact match.
1095+
if (CodeObjectInfo == TargetInfo) {
1096+
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1097+
dbgs() << "Compatible: Exact match: \t[CodeObject: "
1098+
<< CodeObjectInfo.str()
1099+
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1100+
return true;
1101+
}
1102+
1103+
// Incompatible if Kinds or Triples mismatch.
1104+
if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
1105+
!CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
1106+
DEBUG_WITH_TYPE(
1107+
"CodeObjectCompatibility",
1108+
dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1109+
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1110+
<< "]\n");
1111+
return false;
1112+
}
1113+
1114+
// Incompatible if Processors mismatch.
1115+
llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1116+
std::optional<StringRef> CodeObjectProc = clang::parseTargetID(
1117+
CodeObjectInfo.Triple, CodeObjectInfo.TargetID, &CodeObjectFeatureMap);
1118+
std::optional<StringRef> TargetProc = clang::parseTargetID(
1119+
TargetInfo.Triple, TargetInfo.TargetID, &TargetFeatureMap);
1120+
1121+
// Both TargetProc and CodeObjectProc can't be empty here.
1122+
if (!TargetProc || !CodeObjectProc ||
1123+
CodeObjectProc.value() != TargetProc.value()) {
1124+
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1125+
dbgs() << "Incompatible: Processor mismatch \t[CodeObject: "
1126+
<< CodeObjectInfo.str()
1127+
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1128+
return false;
1129+
}
1130+
1131+
// Incompatible if CodeObject has more features than Target, irrespective of
1132+
// type or sign of features.
1133+
if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1134+
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1135+
dbgs() << "Incompatible: CodeObject has more features "
1136+
"than target \t[CodeObject: "
1137+
<< CodeObjectInfo.str()
1138+
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1139+
return false;
1140+
}
1141+
1142+
// Compatible if each target feature specified by target is compatible with
1143+
// target feature of code object. The target feature is compatible if the
1144+
// code object does not specify it (meaning Any), or if it specifies it
1145+
// with the same value (meaning On or Off).
1146+
for (const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1147+
auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1148+
if (TargetFeature == TargetFeatureMap.end()) {
1149+
DEBUG_WITH_TYPE(
1150+
"CodeObjectCompatibility",
1151+
dbgs()
1152+
<< "Incompatible: Value of CodeObject's non-ANY feature is "
1153+
"not matching with Target feature's ANY value \t[CodeObject: "
1154+
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1155+
<< "]\n");
1156+
return false;
1157+
} else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1158+
DEBUG_WITH_TYPE(
1159+
"CodeObjectCompatibility",
1160+
dbgs() << "Incompatible: Value of CodeObject's non-ANY feature is "
1161+
"not matching with Target feature's non-ANY value "
1162+
"\t[CodeObject: "
1163+
<< CodeObjectInfo.str()
1164+
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1165+
return false;
1166+
}
1167+
}
1168+
1169+
// CodeObject is compatible if all features of Target are:
1170+
// - either, present in the Code Object's features map with the same sign,
1171+
// - or, the feature is missing from CodeObjects's features map i.e. it is
1172+
// set to ANY
1173+
DEBUG_WITH_TYPE(
1174+
"CodeObjectCompatibility",
1175+
dbgs() << "Compatible: Target IDs are compatible \t[CodeObject: "
1176+
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1177+
<< "]\n");
1178+
return true;
1179+
}
1180+
11331181
/// Bundle the files. Return true if an error was found.
11341182
Error OffloadBundler::BundleFiles() {
11351183
std::error_code EC;
@@ -1348,99 +1396,6 @@ static Archive::Kind getDefaultArchiveKindForHost() {
13481396
: Archive::K_GNU;
13491397
}
13501398

1351-
/// @brief Checks if a code object \p CodeObjectInfo is compatible with a given
1352-
/// target \p TargetInfo.
1353-
/// @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
1354-
bool isCodeObjectCompatible(OffloadTargetInfo &CodeObjectInfo,
1355-
OffloadTargetInfo &TargetInfo) {
1356-
1357-
// Compatible in case of exact match.
1358-
if (CodeObjectInfo == TargetInfo) {
1359-
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1360-
dbgs() << "Compatible: Exact match: \t[CodeObject: "
1361-
<< CodeObjectInfo.str()
1362-
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1363-
return true;
1364-
}
1365-
1366-
// Incompatible if Kinds or Triples mismatch.
1367-
if (!CodeObjectInfo.isOffloadKindCompatible(TargetInfo.OffloadKind) ||
1368-
!CodeObjectInfo.Triple.isCompatibleWith(TargetInfo.Triple)) {
1369-
DEBUG_WITH_TYPE(
1370-
"CodeObjectCompatibility",
1371-
dbgs() << "Incompatible: Kind/Triple mismatch \t[CodeObject: "
1372-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1373-
<< "]\n");
1374-
return false;
1375-
}
1376-
1377-
// Incompatible if Processors mismatch.
1378-
llvm::StringMap<bool> CodeObjectFeatureMap, TargetFeatureMap;
1379-
std::optional<StringRef> CodeObjectProc = clang::parseTargetID(
1380-
CodeObjectInfo.Triple, CodeObjectInfo.TargetID, &CodeObjectFeatureMap);
1381-
std::optional<StringRef> TargetProc = clang::parseTargetID(
1382-
TargetInfo.Triple, TargetInfo.TargetID, &TargetFeatureMap);
1383-
1384-
// Both TargetProc and CodeObjectProc can't be empty here.
1385-
if (!TargetProc || !CodeObjectProc ||
1386-
CodeObjectProc.value() != TargetProc.value()) {
1387-
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1388-
dbgs() << "Incompatible: Processor mismatch \t[CodeObject: "
1389-
<< CodeObjectInfo.str()
1390-
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1391-
return false;
1392-
}
1393-
1394-
// Incompatible if CodeObject has more features than Target, irrespective of
1395-
// type or sign of features.
1396-
if (CodeObjectFeatureMap.getNumItems() > TargetFeatureMap.getNumItems()) {
1397-
DEBUG_WITH_TYPE("CodeObjectCompatibility",
1398-
dbgs() << "Incompatible: CodeObject has more features "
1399-
"than target \t[CodeObject: "
1400-
<< CodeObjectInfo.str()
1401-
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1402-
return false;
1403-
}
1404-
1405-
// Compatible if each target feature specified by target is compatible with
1406-
// target feature of code object. The target feature is compatible if the
1407-
// code object does not specify it (meaning Any), or if it specifies it
1408-
// with the same value (meaning On or Off).
1409-
for (const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1410-
auto TargetFeature = TargetFeatureMap.find(CodeObjectFeature.getKey());
1411-
if (TargetFeature == TargetFeatureMap.end()) {
1412-
DEBUG_WITH_TYPE(
1413-
"CodeObjectCompatibility",
1414-
dbgs()
1415-
<< "Incompatible: Value of CodeObject's non-ANY feature is "
1416-
"not matching with Target feature's ANY value \t[CodeObject: "
1417-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1418-
<< "]\n");
1419-
return false;
1420-
} else if (TargetFeature->getValue() != CodeObjectFeature.getValue()) {
1421-
DEBUG_WITH_TYPE(
1422-
"CodeObjectCompatibility",
1423-
dbgs() << "Incompatible: Value of CodeObject's non-ANY feature is "
1424-
"not matching with Target feature's non-ANY value "
1425-
"\t[CodeObject: "
1426-
<< CodeObjectInfo.str()
1427-
<< "]\t:\t[Target: " << TargetInfo.str() << "]\n");
1428-
return false;
1429-
}
1430-
}
1431-
1432-
// CodeObject is compatible if all features of Target are:
1433-
// - either, present in the Code Object's features map with the same sign,
1434-
// - or, the feature is missing from CodeObjects's features map i.e. it is
1435-
// set to ANY
1436-
DEBUG_WITH_TYPE(
1437-
"CodeObjectCompatibility",
1438-
dbgs() << "Compatible: Target IDs are compatible \t[CodeObject: "
1439-
<< CodeObjectInfo.str() << "]\t:\t[Target: " << TargetInfo.str()
1440-
<< "]\n");
1441-
return true;
1442-
}
1443-
14441399
/// @brief Computes a list of targets among all given targets which are
14451400
/// compatible with this code object
14461401
/// @param [in] CodeObjectInfo Code Object
@@ -1468,8 +1423,9 @@ getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
14681423
// rule: for a specific processor, a feature either shows up in all target IDs,
14691424
// or does not show up in any target IDs. Otherwise the target ID combination is
14701425
// invalid.
1471-
static Error CheckHeterogeneousArchive(StringRef ArchiveName,
1472-
const OffloadBundlerConfig &BundlerConfig) {
1426+
static Error
1427+
CheckHeterogeneousArchive(StringRef ArchiveName,
1428+
const OffloadBundlerConfig &BundlerConfig) {
14731429
std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
14741430
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
14751431
MemoryBuffer::getFileOrSTDIN(ArchiveName, true, false);

clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,11 @@ int main(int argc, const char **argv) {
130130
BundleAlignment("bundle-align",
131131
cl::desc("Alignment of bundle for binary files"),
132132
cl::init(1), cl::cat(ClangOffloadBundlerCategory));
133-
cl::opt<bool>
134-
CheckInputArchive("check-input-archive",
135-
cl::desc("Check if input heterogeneous archive is "
136-
"valid in terms of TargetID rules.\n"),
137-
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
133+
cl::opt<bool> CheckInputArchive(
134+
"check-input-archive",
135+
cl::desc("Check if input heterogeneous archive is "
136+
"valid in terms of TargetID rules.\n"),
137+
cl::init(false), cl::cat(ClangOffloadBundlerCategory));
138138
cl::opt<bool> HipOpenmpCompatible(
139139
"hip-openmp-compatible",
140140
cl::desc("Treat hip and hipv4 offload kinds as "

0 commit comments

Comments
 (0)