|
18 | 18 | #include "llvm/ADT/ArrayRef.h" |
19 | 19 | #include "llvm/ADT/DenseMap.h" |
20 | 20 | #include "llvm/ADT/STLExtras.h" |
| 21 | +#include "llvm/ADT/SetVector.h" |
21 | 22 | #include "llvm/ADT/SmallString.h" |
22 | 23 | #include "llvm/ADT/SmallVector.h" |
23 | 24 | #include "llvm/ADT/StringExtras.h" |
24 | 25 | #include "llvm/ADT/StringMap.h" |
25 | 26 | #include "llvm/ADT/StringRef.h" |
| 27 | +#include "llvm/ADT/StringSet.h" |
26 | 28 | #include "llvm/ADT/iterator_range.h" |
27 | 29 | #include "llvm/IR/ConstantRange.h" |
28 | 30 | #include "llvm/IR/GlobalValue.h" |
@@ -1317,72 +1319,75 @@ struct TypeIdSummary { |
1317 | 1319 | std::map<uint64_t, WholeProgramDevirtResolution> WPDRes; |
1318 | 1320 | }; |
1319 | 1321 |
|
| 1322 | +/// Encapsulate the names of CFI target functions. It interfaces with ThinLTO to |
| 1323 | +/// determine efficiently which of the names need to be exported for a |
| 1324 | +/// particular module. |
1320 | 1325 | class CfiFunctionIndex { |
1321 | | - DenseMap<GlobalValue::GUID, std::set<std::string, std::less<>>> Index; |
1322 | | - using IndexIterator = |
1323 | | - DenseMap<GlobalValue::GUID, |
1324 | | - std::set<std::string, std::less<>>>::const_iterator; |
1325 | | - using NestedIterator = std::set<std::string, std::less<>>::const_iterator; |
| 1326 | + // `Names` is the authoritative source of data. `ThinLTOToNamesIndex` is there |
| 1327 | + // just to efficiently retrieve which names in this index need exporting for |
| 1328 | + // a particular module index. We cannot guarantee the ThinLTO GUIDs are |
| 1329 | + // collision - free, so we associate a collection to a guid. Functions with |
| 1330 | + // the same name may have different GUIDs, too. So we index a list of names |
| 1331 | + // with the same GUID under that GUID key. We don't need the reverse because |
| 1332 | + // the queries from ThinLTO use GUIDs as key. |
| 1333 | + // Note that StringSet rehashing doesn't move keys, so we can safely store the |
| 1334 | + // StringRef value inserted in `Names` in ThinLTOToNamesIndex, and avoid |
| 1335 | + // copies. |
| 1336 | + // Design note: we could do away with Names and use ThinLTOToNamesIndex as |
| 1337 | + // index and data source, but opted against, for a small heap penalty, to |
| 1338 | + // avoid confusion wrt the role GUIDs play in this case: they are an artifact |
| 1339 | + // of the need to interface with ThinLTO, not otherwise necessary to CFI. |
| 1340 | + StringSet<> Names; |
| 1341 | + |
| 1342 | + using InternalIndexGroup = SetVector<StringRef>; |
| 1343 | + DenseMap<GlobalValue::GUID, InternalIndexGroup> ThinLTOToNamesIndex; |
| 1344 | + |
| 1345 | + using NestedIterator = InternalIndexGroup::const_iterator; |
1326 | 1346 |
|
1327 | 1347 | public: |
1328 | | - // Iterates keys of the DenseMap. |
1329 | | - class GUIDIterator : public iterator_adaptor_base<GUIDIterator, IndexIterator, |
1330 | | - std::forward_iterator_tag, |
1331 | | - GlobalValue::GUID> { |
1332 | | - using base = GUIDIterator::iterator_adaptor_base; |
1333 | | - |
1334 | | - public: |
1335 | | - GUIDIterator() = default; |
1336 | | - explicit GUIDIterator(IndexIterator I) : base(I) {} |
1337 | | - |
1338 | | - GlobalValue::GUID operator*() const { return this->wrapped()->first; } |
1339 | | - }; |
1340 | | - |
1341 | 1348 | CfiFunctionIndex() = default; |
1342 | | - template <typename It> CfiFunctionIndex(It B, It E) { |
1343 | | - for (; B != E; ++B) |
1344 | | - emplace(*B); |
1345 | | - } |
1346 | 1349 |
|
1347 | | - std::vector<StringRef> symbols() const { |
1348 | | - std::vector<StringRef> Symbols; |
1349 | | - for (auto &[GUID, Syms] : Index) { |
1350 | | - (void)GUID; |
1351 | | - llvm::append_range(Symbols, Syms); |
1352 | | - } |
| 1350 | + /// API used for serialization, e.g. YAML. |
| 1351 | + std::vector<std::pair<StringRef, GlobalValue::GUID>> |
| 1352 | + getSortedSymbols() const { |
| 1353 | + std::vector<std::pair<StringRef, GlobalValue::GUID>> Symbols; |
| 1354 | + for (auto &[GUID, Names] : ThinLTOToNamesIndex) |
| 1355 | + for (auto Name : Names) |
| 1356 | + Symbols.emplace_back(Name, GUID); |
| 1357 | + llvm::sort(Symbols, std::less<>()); |
1353 | 1358 | return Symbols; |
1354 | 1359 | } |
1355 | 1360 |
|
1356 | | - GUIDIterator guid_begin() const { return GUIDIterator(Index.begin()); } |
1357 | | - GUIDIterator guid_end() const { return GUIDIterator(Index.end()); } |
1358 | | - iterator_range<GUIDIterator> guids() const { |
1359 | | - return make_range(guid_begin(), guid_end()); |
| 1361 | + /// get the set of GUIDs that should also be exported because they are the |
| 1362 | + /// GUIDs of the cfi functions encapsulated here. |
| 1363 | + auto getExportedThinLTOGUIDs() const { |
| 1364 | + return map_range(ThinLTOToNamesIndex, [](auto I) { return I.first; }); |
1360 | 1365 | } |
1361 | 1366 |
|
1362 | | - iterator_range<NestedIterator> forGuid(GlobalValue::GUID GUID) const { |
1363 | | - auto I = Index.find(GUID); |
1364 | | - if (I == Index.end()) |
| 1367 | + /// get the name(s) associated with a given ThinLTO GUID. This enables |
| 1368 | + /// efficient identification of the subset of names that should be included in |
| 1369 | + /// a module summary. |
| 1370 | + auto getMatchingNamesForThinLTOGUID(GlobalValue::GUID GUID) const { |
| 1371 | + auto I = ThinLTOToNamesIndex.find(GUID); |
| 1372 | + if (I == ThinLTOToNamesIndex.end()) |
1365 | 1373 | return make_range(NestedIterator{}, NestedIterator{}); |
1366 | 1374 | return make_range(I->second.begin(), I->second.end()); |
1367 | 1375 | } |
1368 | 1376 |
|
1369 | | - template <typename... Args> void emplace(Args &&...A) { |
1370 | | - StringRef S(std::forward<Args>(A)...); |
1371 | | - GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage( |
1372 | | - GlobalValue::dropLLVMManglingEscape(S)); |
1373 | | - Index[GUID].emplace(S); |
| 1377 | + /// Add the function name and the GUID that ThinLTO uses for it. |
| 1378 | + void addSymbolWithThinLTOGUID(StringRef Name, GlobalValue::GUID GUID) { |
| 1379 | + auto [Iter, _] = Names.insert(Name); |
| 1380 | + ThinLTOToNamesIndex[GUID].insert(Iter->first()); |
1374 | 1381 | } |
1375 | 1382 |
|
1376 | | - size_t count(StringRef S) const { |
1377 | | - GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage( |
1378 | | - GlobalValue::dropLLVMManglingEscape(S)); |
1379 | | - auto I = Index.find(GUID); |
1380 | | - if (I == Index.end()) |
1381 | | - return 0; |
1382 | | - return I->second.count(S); |
| 1383 | + bool contains(StringRef Name) const { |
| 1384 | + return Names.find(Name) != Names.end(); |
1383 | 1385 | } |
1384 | 1386 |
|
1385 | | - bool empty() const { return Index.empty(); } |
| 1387 | + bool empty() const { |
| 1388 | + assert(Names.empty() == ThinLTOToNamesIndex.empty()); |
| 1389 | + return Names.empty(); |
| 1390 | + } |
1386 | 1391 | }; |
1387 | 1392 |
|
1388 | 1393 | /// 160 bits SHA1 |
@@ -1566,7 +1571,7 @@ class ModuleSummaryIndex { |
1566 | 1571 | // in the way some record are interpreted, like flags for instance. |
1567 | 1572 | // Note that incrementing this may require changes in both BitcodeReader.cpp |
1568 | 1573 | // and BitcodeWriter.cpp. |
1569 | | - static constexpr uint64_t BitcodeSummaryVersion = 13; |
| 1574 | + static constexpr uint64_t BitcodeSummaryVersion = 14; |
1570 | 1575 |
|
1571 | 1576 | // Regular LTO module name for ASM writer |
1572 | 1577 | static constexpr const char *getRegularLTOModuleName() { |
|
0 commit comments