@@ -168,51 +168,6 @@ static std::string getDeviceLibraryFileName(StringRef BundleFileName,
168
168
return Result;
169
169
}
170
170
171
- // / @brief Checks if a code object \p CodeObjectInfo is compatible with a given
172
- // / target \p TargetInfo.
173
- // / @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
174
- bool isCodeObjectCompatible (const OffloadTargetInfo &CodeObjectInfo,
175
- const OffloadTargetInfo &TargetInfo) {
176
-
177
- // Compatible in case of exact match.
178
- if (CodeObjectInfo == TargetInfo) {
179
- DEBUG_WITH_TYPE (" CodeObjectCompatibility" ,
180
- dbgs () << " Compatible: Exact match: \t [CodeObject: "
181
- << CodeObjectInfo.str ()
182
- << " ]\t :\t [Target: " << TargetInfo.str () << " ]\n " );
183
- return true ;
184
- }
185
-
186
- // Incompatible if Kinds or Triples mismatch.
187
- if (!CodeObjectInfo.isOffloadKindCompatible (TargetInfo.OffloadKind ) ||
188
- !CodeObjectInfo.Triple .isCompatibleWith (TargetInfo.Triple )) {
189
- DEBUG_WITH_TYPE (
190
- " CodeObjectCompatibility" ,
191
- dbgs () << " Incompatible: Kind/Triple mismatch \t [CodeObject: "
192
- << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
193
- << " ]\n " );
194
- return false ;
195
- }
196
-
197
- // Incompatible if target IDs are incompatible.
198
- if (!clang::isCompatibleTargetID (CodeObjectInfo.TargetID ,
199
- TargetInfo.TargetID )) {
200
- DEBUG_WITH_TYPE (
201
- " CodeObjectCompatibility" ,
202
- dbgs () << " Incompatible: target IDs are incompatible \t [CodeObject: "
203
- << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
204
- << " ]\n " );
205
- return false ;
206
- }
207
-
208
- DEBUG_WITH_TYPE (
209
- " CodeObjectCompatibility" ,
210
- dbgs () << " Compatible: Code Objects are compatible \t [CodeObject: "
211
- << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
212
- << " ]\n " );
213
- return true ;
214
- }
215
-
216
171
namespace {
217
172
// / Generic file handler interface.
218
173
class FileHandler {
@@ -278,6 +233,20 @@ class FileHandler {
278
233
});
279
234
}
280
235
236
+ // / Get bundle IDs in \a Input in \a BundleIds.
237
+ virtual Error getBundleIDs (MemoryBuffer &Input,
238
+ std::set<StringRef> &BundleIds) {
239
+ if (Error Err = ReadHeader (Input))
240
+ return Err;
241
+ return forEachBundle (Input, [&](const BundleInfo &Info) -> Error {
242
+ BundleIds.insert (Info.BundleID );
243
+ Error Err = listBundleIDsCallback (Input, Info);
244
+ if (Err)
245
+ return Err;
246
+ return Error::success ();
247
+ });
248
+ }
249
+
281
250
// / For each bundle in \a Input, do \a Func.
282
251
Error forEachBundle (MemoryBuffer &Input,
283
252
std::function<Error(const BundleInfo &)> Func) {
@@ -1617,6 +1586,99 @@ Error OffloadBundler::ListBundleIDsInFile(
1617
1586
return FH->listBundleIDs (DecompressedInput);
1618
1587
}
1619
1588
1589
+ // / @brief Checks if a code object \p CodeObjectInfo is compatible with a given
1590
+ // / target \p TargetInfo.
1591
+ // / @link https://clang.llvm.org/docs/ClangOffloadBundler.html#bundle-entry-id
1592
+ bool isCodeObjectCompatible (const OffloadTargetInfo &CodeObjectInfo,
1593
+ const OffloadTargetInfo &TargetInfo) {
1594
+
1595
+ // Compatible in case of exact match.
1596
+ if (CodeObjectInfo == TargetInfo) {
1597
+ DEBUG_WITH_TYPE (" CodeObjectCompatibility" ,
1598
+ dbgs () << " Compatible: Exact match: \t [CodeObject: "
1599
+ << CodeObjectInfo.str ()
1600
+ << " ]\t :\t [Target: " << TargetInfo.str () << " ]\n " );
1601
+ return true ;
1602
+ }
1603
+
1604
+ // Incompatible if Kinds or Triples mismatch.
1605
+ if (!CodeObjectInfo.isOffloadKindCompatible (TargetInfo.OffloadKind ) ||
1606
+ !CodeObjectInfo.Triple .isCompatibleWith (TargetInfo.Triple )) {
1607
+ DEBUG_WITH_TYPE (
1608
+ " CodeObjectCompatibility" ,
1609
+ dbgs () << " Incompatible: Kind/Triple mismatch \t [CodeObject: "
1610
+ << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
1611
+ << " ]\n " );
1612
+ return false ;
1613
+ }
1614
+
1615
+ // Incompatible if Processors mismatch.
1616
+ llvm::StringMap<bool > CodeObjectFeatureMap, TargetFeatureMap;
1617
+ std::optional<StringRef> CodeObjectProc = clang::parseTargetID (
1618
+ CodeObjectInfo.Triple , CodeObjectInfo.TargetID , &CodeObjectFeatureMap);
1619
+ std::optional<StringRef> TargetProc = clang::parseTargetID (
1620
+ TargetInfo.Triple , TargetInfo.TargetID , &TargetFeatureMap);
1621
+
1622
+ // Both TargetProc and CodeObjectProc can't be empty here.
1623
+ if (!TargetProc || !CodeObjectProc ||
1624
+ CodeObjectProc.value () != TargetProc.value ()) {
1625
+ DEBUG_WITH_TYPE (" CodeObjectCompatibility" ,
1626
+ dbgs () << " Incompatible: Processor mismatch \t [CodeObject: "
1627
+ << CodeObjectInfo.str ()
1628
+ << " ]\t :\t [Target: " << TargetInfo.str () << " ]\n " );
1629
+ return false ;
1630
+ }
1631
+
1632
+ // Incompatible if CodeObject has more features than Target, irrespective of
1633
+ // type or sign of features.
1634
+ if (CodeObjectFeatureMap.getNumItems () > TargetFeatureMap.getNumItems ()) {
1635
+ DEBUG_WITH_TYPE (" CodeObjectCompatibility" ,
1636
+ dbgs () << " Incompatible: CodeObject has more features "
1637
+ " than target \t [CodeObject: "
1638
+ << CodeObjectInfo.str ()
1639
+ << " ]\t :\t [Target: " << TargetInfo.str () << " ]\n " );
1640
+ return false ;
1641
+ }
1642
+
1643
+ // Compatible if each target feature specified by target is compatible with
1644
+ // target feature of code object. The target feature is compatible if the
1645
+ // code object does not specify it (meaning Any), or if it specifies it
1646
+ // with the same value (meaning On or Off).
1647
+ for (const auto &CodeObjectFeature : CodeObjectFeatureMap) {
1648
+ auto TargetFeature = TargetFeatureMap.find (CodeObjectFeature.getKey ());
1649
+ if (TargetFeature == TargetFeatureMap.end ()) {
1650
+ DEBUG_WITH_TYPE (
1651
+ " CodeObjectCompatibility" ,
1652
+ dbgs ()
1653
+ << " Incompatible: Value of CodeObject's non-ANY feature is "
1654
+ " not matching with Target feature's ANY value \t [CodeObject: "
1655
+ << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
1656
+ << " ]\n " );
1657
+ return false ;
1658
+ } else if (TargetFeature->getValue () != CodeObjectFeature.getValue ()) {
1659
+ DEBUG_WITH_TYPE (
1660
+ " CodeObjectCompatibility" ,
1661
+ dbgs () << " Incompatible: Value of CodeObject's non-ANY feature is "
1662
+ " not matching with Target feature's non-ANY value "
1663
+ " \t [CodeObject: "
1664
+ << CodeObjectInfo.str ()
1665
+ << " ]\t :\t [Target: " << TargetInfo.str () << " ]\n " );
1666
+ return false ;
1667
+ }
1668
+ }
1669
+
1670
+ // CodeObject is compatible if all features of Target are:
1671
+ // - either, present in the Code Object's features map with the same sign,
1672
+ // - or, the feature is missing from CodeObjects's features map i.e. it is
1673
+ // set to ANY
1674
+ DEBUG_WITH_TYPE (
1675
+ " CodeObjectCompatibility" ,
1676
+ dbgs () << " Compatible: Target IDs are compatible \t [CodeObject: "
1677
+ << CodeObjectInfo.str () << " ]\t :\t [Target: " << TargetInfo.str ()
1678
+ << " ]\n " );
1679
+ return true ;
1680
+ }
1681
+
1620
1682
// / Bundle the files. Return true if an error was found.
1621
1683
1622
1684
Error OffloadBundler::BundleFiles () {
@@ -1920,13 +1982,81 @@ getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
1920
1982
return !CompatibleTargets.empty ();
1921
1983
}
1922
1984
1985
+ // Check that each code object file in the input archive conforms to following
1986
+ // rule: for a specific processor, a feature either shows up in all target IDs,
1987
+ // or does not show up in any target IDs. Otherwise the target ID combination is
1988
+ // invalid.
1989
+ static Error
1990
+ CheckHeterogeneousArchive (StringRef ArchiveName,
1991
+ const OffloadBundlerConfig &BundlerConfig) {
1992
+ std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1993
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1994
+ MemoryBuffer::getFileOrSTDIN (ArchiveName, true , false );
1995
+ if (std::error_code EC = BufOrErr.getError ())
1996
+ return createFileError (ArchiveName, EC);
1997
+
1998
+ ArchiveBuffers.push_back (std::move (*BufOrErr));
1999
+ Expected<std::unique_ptr<llvm::object::Archive>> LibOrErr =
2000
+ Archive::create (ArchiveBuffers.back ()->getMemBufferRef ());
2001
+ if (!LibOrErr)
2002
+ return LibOrErr.takeError ();
2003
+
2004
+ auto Archive = std::move (*LibOrErr);
2005
+
2006
+ Error ArchiveErr = Error::success ();
2007
+ auto ChildEnd = Archive->child_end ();
2008
+
2009
+ // / Iterate over all bundled code object files in the input archive.
2010
+ for (auto ArchiveIter = Archive->child_begin (ArchiveErr);
2011
+ ArchiveIter != ChildEnd; ++ArchiveIter) {
2012
+ if (ArchiveErr)
2013
+ return ArchiveErr;
2014
+ auto ArchiveChildNameOrErr = (*ArchiveIter).getName ();
2015
+ if (!ArchiveChildNameOrErr)
2016
+ return ArchiveChildNameOrErr.takeError ();
2017
+
2018
+ auto CodeObjectBufferRefOrErr = (*ArchiveIter).getMemoryBufferRef ();
2019
+ if (!CodeObjectBufferRefOrErr)
2020
+ return CodeObjectBufferRefOrErr.takeError ();
2021
+
2022
+ auto CodeObjectBuffer =
2023
+ MemoryBuffer::getMemBuffer (*CodeObjectBufferRefOrErr, false );
2024
+
2025
+ Expected<std::unique_ptr<FileHandler>> FileHandlerOrErr =
2026
+ CreateFileHandler (*CodeObjectBuffer, BundlerConfig);
2027
+ if (!FileHandlerOrErr)
2028
+ return FileHandlerOrErr.takeError ();
2029
+
2030
+ std::unique_ptr<FileHandler> &FileHandler = *FileHandlerOrErr;
2031
+ assert (FileHandler);
2032
+
2033
+ std::set<StringRef> BundleIds;
2034
+ auto CodeObjectFileError =
2035
+ FileHandler->getBundleIDs (*CodeObjectBuffer, BundleIds);
2036
+ if (CodeObjectFileError)
2037
+ return CodeObjectFileError;
2038
+
2039
+ auto &&ConflictingArchs = clang::getConflictTargetIDCombination (BundleIds);
2040
+ if (ConflictingArchs) {
2041
+ std::string ErrMsg =
2042
+ Twine (" conflicting TargetIDs [" + ConflictingArchs.value ().first +
2043
+ " , " + ConflictingArchs.value ().second + " ] found in " +
2044
+ ArchiveChildNameOrErr.get () + " of " + ArchiveName)
2045
+ .str ();
2046
+ return createStringError (inconvertibleErrorCode (), ErrMsg);
2047
+ }
2048
+ }
2049
+
2050
+ return ArchiveErr;
2051
+ }
2052
+
1923
2053
// / UnbundleArchive takes an archive file (".a") as input containing bundled
1924
2054
// / code object files, and a list of offload targets (not host), and extracts
1925
2055
// / the code objects into a new archive file for each offload target. Each
1926
2056
// / resulting archive file contains all code object files corresponding to that
1927
2057
// / particular offload target. The created archive file does not
1928
2058
// / contain an index of the symbols and code object files are named as
1929
- // / <<Parent Bundle Name>-<CodeObject's GPUArch >>, with ':' replaced with '_'.
2059
+ // / <<Parent Bundle Name>-<CodeObject's TargetID >>, with ':' replaced with '_'.
1930
2060
Error OffloadBundler::UnbundleArchive () {
1931
2061
std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
1932
2062
@@ -1945,6 +2075,16 @@ Error OffloadBundler::UnbundleArchive() {
1945
2075
1946
2076
StringRef IFName = BundlerConfig.InputFileNames .front ();
1947
2077
2078
+ if (BundlerConfig.CheckInputArchive ) {
2079
+ // For a specific processor, a feature either shows up in all target IDs, or
2080
+ // does not show up in any target IDs. Otherwise the target ID combination
2081
+ // is invalid.
2082
+ auto ArchiveError = CheckHeterogeneousArchive (IFName, BundlerConfig);
2083
+ if (ArchiveError) {
2084
+ return ArchiveError;
2085
+ }
2086
+ }
2087
+
1948
2088
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
1949
2089
MemoryBuffer::getFileOrSTDIN (IFName, true , false );
1950
2090
if (std::error_code EC = BufOrErr.getError ())
0 commit comments