Skip to content

Commit 6f7db23

Browse files
committed
decouple cfi from thinlto
1 parent b29bf9f commit 6f7db23

32 files changed

Lines changed: 429 additions & 164 deletions

llvm/include/llvm/IR/AutoUpgrade.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ namespace llvm {
6363
/// module is modified.
6464
LLVM_ABI bool UpgradeModuleFlags(Module &M);
6565

66+
/// Upgrade the cfi.functions metadata node by calculating and inserting
67+
/// the GUID for each function entry if it's missing.
68+
LLVM_ABI bool UpgradeCFIFunctionsMetadata(Module &M);
69+
6670
/// Convert legacy nvvm.annotations metadata to appropriate function
6771
/// attributes.
6872
LLVM_ABI void UpgradeNVVMAnnotations(Module &M);

llvm/include/llvm/IR/ModuleSummaryIndex.h

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
#include "llvm/ADT/ArrayRef.h"
1919
#include "llvm/ADT/DenseMap.h"
2020
#include "llvm/ADT/STLExtras.h"
21+
#include "llvm/ADT/SetVector.h"
2122
#include "llvm/ADT/SmallString.h"
2223
#include "llvm/ADT/SmallVector.h"
2324
#include "llvm/ADT/StringExtras.h"
2425
#include "llvm/ADT/StringMap.h"
2526
#include "llvm/ADT/StringRef.h"
27+
#include "llvm/ADT/StringSet.h"
2628
#include "llvm/ADT/iterator_range.h"
2729
#include "llvm/IR/ConstantRange.h"
2830
#include "llvm/IR/GlobalValue.h"
@@ -1317,72 +1319,75 @@ struct TypeIdSummary {
13171319
std::map<uint64_t, WholeProgramDevirtResolution> WPDRes;
13181320
};
13191321

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.
13201325
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;
13261346

13271347
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-
13411348
CfiFunctionIndex() = default;
1342-
template <typename It> CfiFunctionIndex(It B, It E) {
1343-
for (; B != E; ++B)
1344-
emplace(*B);
1345-
}
13461349

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<>());
13531358
return Symbols;
13541359
}
13551360

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; });
13601365
}
13611366

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())
13651373
return make_range(NestedIterator{}, NestedIterator{});
13661374
return make_range(I->second.begin(), I->second.end());
13671375
}
13681376

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());
13741381
}
13751382

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();
13831385
}
13841386

1385-
bool empty() const { return Index.empty(); }
1387+
bool empty() const {
1388+
assert(Names.empty() == ThinLTOToNamesIndex.empty());
1389+
return Names.empty();
1390+
}
13861391
};
13871392

13881393
/// 160 bits SHA1
@@ -1566,7 +1571,7 @@ class ModuleSummaryIndex {
15661571
// in the way some record are interpreted, like flags for instance.
15671572
// Note that incrementing this may require changes in both BitcodeReader.cpp
15681573
// and BitcodeWriter.cpp.
1569-
static constexpr uint64_t BitcodeSummaryVersion = 13;
1574+
static constexpr uint64_t BitcodeSummaryVersion = 14;
15701575

15711576
// Regular LTO module name for ASM writer
15721577
static constexpr const char *getRegularLTOModuleName() {

llvm/include/llvm/IR/ModuleSummaryIndexYAML.h

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,24 @@ template <> struct CustomMappingTraits<TypeIdSummaryMapTy> {
327327
}
328328
};
329329

330+
template <> struct MappingTraits<std::pair<StringRef, GlobalValue::GUID>> {
331+
static void mapping(IO &io,
332+
std::pair<StringRef, GlobalValue::GUID> &NameAndGUID) {
333+
io.mapRequired("Name", NameAndGUID.first);
334+
io.mapRequired("GUID", NameAndGUID.second);
335+
}
336+
};
337+
338+
using StringAndGUID = std::pair<llvm::StringRef, llvm::GlobalValue::GUID>;
339+
340+
} // namespace yaml
341+
} // namespace llvm
342+
343+
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringAndGUID)
344+
345+
namespace llvm {
346+
namespace yaml {
347+
330348
template <> struct MappingTraits<ModuleSummaryIndex> {
331349
static void mapping(IO &io, ModuleSummaryIndex& index) {
332350
io.mapOptional("GlobalValueMap", index.GlobalValueMap);
@@ -352,25 +370,25 @@ template <> struct MappingTraits<ModuleSummaryIndex> {
352370
index.WithGlobalValueDeadStripping);
353371

354372
if (io.outputting()) {
355-
auto CfiFunctionDefs = index.CfiFunctionDefs.symbols();
356-
llvm::sort(CfiFunctionDefs);
373+
auto CfiFunctionDefs = index.CfiFunctionDefs.getSortedSymbols();
357374
io.mapOptional("CfiFunctionDefs", CfiFunctionDefs);
358-
auto CfiFunctionDecls(index.CfiFunctionDecls.symbols());
359-
llvm::sort(CfiFunctionDecls);
375+
auto CfiFunctionDecls(index.CfiFunctionDecls.getSortedSymbols());
360376
io.mapOptional("CfiFunctionDecls", CfiFunctionDecls);
361377
} else {
362-
std::vector<std::string> CfiFunctionDefs;
378+
std::vector<std::pair<StringRef, GlobalValue::GUID>> CfiFunctionDefs;
363379
io.mapOptional("CfiFunctionDefs", CfiFunctionDefs);
364-
index.CfiFunctionDefs = {CfiFunctionDefs.begin(), CfiFunctionDefs.end()};
365-
std::vector<std::string> CfiFunctionDecls;
380+
for (auto &[S, G] : CfiFunctionDefs)
381+
index.CfiFunctionDefs.addSymbolWithThinLTOGUID(S, G);
382+
std::vector<std::pair<StringRef, GlobalValue::GUID>> CfiFunctionDecls;
366383
io.mapOptional("CfiFunctionDecls", CfiFunctionDecls);
367-
index.CfiFunctionDecls = {CfiFunctionDecls.begin(),
368-
CfiFunctionDecls.end()};
384+
for (auto &[S, G] : CfiFunctionDecls)
385+
index.CfiFunctionDecls.addSymbolWithThinLTOGUID(S, G);
386+
;
369387
}
370388
}
371389
};
372390

373-
} // End yaml namespace
374-
} // End llvm namespace
391+
} // namespace yaml
392+
} // namespace llvm
375393

376394
#endif

llvm/lib/AsmParser/LLParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ bool LLParser::validateEndOfModule(bool UpgradeDebugInfo) {
476476
llvm::UpgradeDebugInfo(*M);
477477

478478
UpgradeModuleFlags(*M);
479+
UpgradeCFIFunctionsMetadata(*M);
479480
UpgradeNVVMAnnotations(*M);
480481
UpgradeSectionAttributes(*M);
481482
copyModuleAttrToFunctions(*M);

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3979,6 +3979,8 @@ Error BitcodeReader::materializeMetadata() {
39793979
}
39803980
}
39813981

3982+
UpgradeCFIFunctionsMetadata(*TheModule);
3983+
39823984
DeferredMetadataInfo.clear();
39833985
return Error::success();
39843986
}
@@ -8146,17 +8148,43 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
81468148

81478149
case bitc::FS_CFI_FUNCTION_DEFS: {
81488150
auto &CfiFunctionDefs = TheIndex.cfiFunctionDefs();
8149-
for (unsigned I = 0; I != Record.size(); I += 2)
8150-
CfiFunctionDefs.emplace(Strtab.data() + Record[I],
8151-
static_cast<size_t>(Record[I + 1]));
8151+
if (Version < 14) {
8152+
for (unsigned I = 0; I != Record.size(); I += 2) {
8153+
StringRef Name(Strtab.data() + Record[I],
8154+
static_cast<size_t>(Record[I + 1]));
8155+
GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage(
8156+
GlobalValue::dropLLVMManglingEscape(Name));
8157+
CfiFunctionDefs.addSymbolWithThinLTOGUID(Name, GUID);
8158+
}
8159+
} else {
8160+
for (unsigned I = 0; I != Record.size(); I += 3) {
8161+
GlobalValue::GUID ThinLTOGUID = Record[I];
8162+
StringRef Name(Strtab.data() + Record[I + 1],
8163+
static_cast<size_t>(Record[I + 2]));
8164+
CfiFunctionDefs.addSymbolWithThinLTOGUID(Name, ThinLTOGUID);
8165+
}
8166+
}
81528167
break;
81538168
}
81548169

81558170
case bitc::FS_CFI_FUNCTION_DECLS: {
81568171
auto &CfiFunctionDecls = TheIndex.cfiFunctionDecls();
8157-
for (unsigned I = 0; I != Record.size(); I += 2)
8158-
CfiFunctionDecls.emplace(Strtab.data() + Record[I],
8159-
static_cast<size_t>(Record[I + 1]));
8172+
if (Version < 14) {
8173+
for (unsigned I = 0; I != Record.size(); I += 2) {
8174+
StringRef Name(Strtab.data() + Record[I],
8175+
static_cast<size_t>(Record[I + 1]));
8176+
GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage(
8177+
GlobalValue::dropLLVMManglingEscape(Name));
8178+
CfiFunctionDecls.addSymbolWithThinLTOGUID(Name, GUID);
8179+
}
8180+
} else {
8181+
for (unsigned I = 0; I != Record.size(); I += 3) {
8182+
GlobalValue::GUID ThinLTOGUID = Record[I];
8183+
StringRef Name(Strtab.data() + Record[I + 1],
8184+
static_cast<size_t>(Record[I + 2]));
8185+
CfiFunctionDecls.addSymbolWithThinLTOGUID(Name, ThinLTOGUID);
8186+
}
8187+
}
81608188
break;
81618189
}
81628190

llvm/lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,21 +5316,30 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
53165316
getReferencedTypeIds(FS, ReferencedTypeIds);
53175317
}
53185318

5319-
SmallVector<StringRef, 4> Functions;
5319+
struct CfiFunctionRecord {
5320+
GlobalValue::GUID GUID = 0;
5321+
StringRef Name;
5322+
bool operator<(const CfiFunctionRecord &RHS) const {
5323+
return Name < RHS.Name;
5324+
}
5325+
};
5326+
SmallVector<CfiFunctionRecord, 4> Functions;
53205327
auto EmitCfiFunctions = [&](const CfiFunctionIndex &CfiIndex,
53215328
bitc::GlobalValueSummarySymtabCodes Code) {
53225329
if (CfiIndex.empty())
53235330
return;
53245331
for (GlobalValue::GUID GUID : DefOrUseGUIDs) {
5325-
auto Defs = CfiIndex.forGuid(GUID);
5326-
llvm::append_range(Functions, Defs);
5332+
auto Names = CfiIndex.getMatchingNamesForThinLTOGUID(GUID);
5333+
for (StringRef Name : Names)
5334+
Functions.push_back({GUID, Name});
53275335
}
53285336
if (Functions.empty())
53295337
return;
53305338
llvm::sort(Functions);
5331-
for (const auto &S : Functions) {
5332-
NameVals.push_back(StrtabBuilder.add(S));
5333-
NameVals.push_back(S.size());
5339+
for (const auto &Record : Functions) {
5340+
NameVals.push_back(Record.GUID);
5341+
NameVals.push_back(StrtabBuilder.add(Record.Name));
5342+
NameVals.push_back(Record.Name.size());
53345343
}
53355344
Stream.EmitRecord(Code, NameVals);
53365345
NameVals.clear();

llvm/lib/IR/AutoUpgrade.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/IR/DebugInfoMetadata.h"
2727
#include "llvm/IR/DiagnosticInfo.h"
2828
#include "llvm/IR/Function.h"
29+
#include "llvm/IR/GlobalValue.h"
2930
#include "llvm/IR/IRBuilder.h"
3031
#include "llvm/IR/InstVisitor.h"
3132
#include "llvm/IR/Instruction.h"
@@ -6359,6 +6360,46 @@ bool llvm::UpgradeModuleFlags(Module &M) {
63596360
return Changed;
63606361
}
63616362

6363+
bool llvm::UpgradeCFIFunctionsMetadata(Module &M) {
6364+
NamedMDNode *CFIConsts = M.getNamedMetadata("cfi.functions");
6365+
if (!CFIConsts)
6366+
return false;
6367+
6368+
bool Changed = false;
6369+
for (unsigned I = 0, E = CFIConsts->getNumOperands(); I != E; ++I) {
6370+
MDNode *Op = CFIConsts->getOperand(I);
6371+
if (Op->getNumOperands() >= 3 &&
6372+
isa<ConstantAsMetadata>(Op->getOperand(2)) &&
6373+
cast<ConstantAsMetadata>(Op->getOperand(2))->getType()->isIntegerTy(64))
6374+
continue;
6375+
6376+
if (Op->getNumOperands() < 2)
6377+
continue;
6378+
6379+
MDString *NameMD = dyn_cast_or_null<MDString>(Op->getOperand(0));
6380+
if (!NameMD)
6381+
continue;
6382+
6383+
StringRef Name = NameMD->getString();
6384+
GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage(
6385+
GlobalValue::dropLLVMManglingEscape(Name));
6386+
6387+
SmallVector<Metadata *, 4> Elts;
6388+
Elts.push_back(Op->getOperand(0));
6389+
Elts.push_back(Op->getOperand(1));
6390+
Elts.push_back(ConstantAsMetadata::get(
6391+
ConstantInt::get(Type::getInt64Ty(M.getContext()), GUID)));
6392+
6393+
for (unsigned J = 2, EJ = Op->getNumOperands(); J != EJ; ++J)
6394+
Elts.push_back(Op->getOperand(J));
6395+
6396+
CFIConsts->setOperand(I, MDNode::get(M.getContext(), Elts));
6397+
Changed = true;
6398+
}
6399+
6400+
return Changed;
6401+
}
6402+
63626403
void llvm::UpgradeSectionAttributes(Module &M) {
63636404
auto TrimSpaces = [](StringRef Section) -> std::string {
63646405
SmallVector<StringRef, 5> Components;

0 commit comments

Comments
 (0)