@@ -168,51 +168,6 @@ static std::string getDeviceLibraryFileName(StringRef BundleFileName,
168168 return Result;
169169}
170170
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-
216171namespace {
217172// / Generic file handler interface.
218173class FileHandler {
@@ -278,6 +233,20 @@ class FileHandler {
278233 });
279234 }
280235
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+
281250 // / For each bundle in \a Input, do \a Func.
282251 Error forEachBundle (MemoryBuffer &Input,
283252 std::function<Error(const BundleInfo &)> Func) {
@@ -1617,6 +1586,99 @@ Error OffloadBundler::ListBundleIDsInFile(
16171586 return FH->listBundleIDs (DecompressedInput);
16181587}
16191588
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+
16201682// / Bundle the files. Return true if an error was found.
16211683
16221684Error OffloadBundler::BundleFiles () {
@@ -1920,13 +1982,81 @@ getCompatibleOffloadTargets(OffloadTargetInfo &CodeObjectInfo,
19201982 return !CompatibleTargets.empty ();
19211983}
19221984
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+
19232053// / UnbundleArchive takes an archive file (".a") as input containing bundled
19242054// / code object files, and a list of offload targets (not host), and extracts
19252055// / the code objects into a new archive file for each offload target. Each
19262056// / resulting archive file contains all code object files corresponding to that
19272057// / particular offload target. The created archive file does not
19282058// / 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 '_'.
19302060Error OffloadBundler::UnbundleArchive () {
19312061 std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
19322062
@@ -1945,6 +2075,16 @@ Error OffloadBundler::UnbundleArchive() {
19452075
19462076 StringRef IFName = BundlerConfig.InputFileNames .front ();
19472077
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+
19482088 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
19492089 MemoryBuffer::getFileOrSTDIN (IFName, true , false );
19502090 if (std::error_code EC = BufOrErr.getError ())
0 commit comments