Skip to content

Commit df61923

Browse files
committed
decouple cfi from thinlto
1 parent b29bf9f commit df61923

25 files changed

Lines changed: 335 additions & 162 deletions

llvm/include/llvm/IR/ModuleSummaryIndex.h

Lines changed: 53 additions & 48 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

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/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8146,17 +8146,23 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
81468146

81478147
case bitc::FS_CFI_FUNCTION_DEFS: {
81488148
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]));
8149+
for (unsigned I = 0; I != Record.size(); I += 3) {
8150+
GlobalValue::GUID ThinLTOGUID = Record[I];
8151+
StringRef Name(Strtab.data() + Record[I + 1],
8152+
static_cast<size_t>(Record[I + 2]));
8153+
CfiFunctionDefs.addSymbolWithThinLTOGUID(Name, ThinLTOGUID);
8154+
}
81528155
break;
81538156
}
81548157

81558158
case bitc::FS_CFI_FUNCTION_DECLS: {
81568159
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]));
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+
CfiFunctionDecls.addSymbolWithThinLTOGUID(Name, ThinLTOGUID);
8165+
}
81608166
break;
81618167
}
81628168

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/LTO/LTO.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,9 +1580,9 @@ class CGThinBackend : public ThinBackendProc {
15801580
OnWrite, ShouldEmitImportsFiles, ThinLTOParallelism),
15811581
ShouldEmitIndexFiles(ShouldEmitIndexFiles) {
15821582
auto &Defs = CombinedIndex.cfiFunctionDefs();
1583-
CfiFunctionDefs.insert_range(Defs.guids());
1583+
CfiFunctionDefs.insert_range(Defs.getExportedThinLTOGUIDs());
15841584
auto &Decls = CombinedIndex.cfiFunctionDecls();
1585-
CfiFunctionDecls.insert_range(Decls.guids());
1585+
CfiFunctionDecls.insert_range(Decls.getExportedThinLTOGUIDs());
15861586
}
15871587
};
15881588

@@ -2156,9 +2156,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
21562156
// Any functions referenced by the jump table in the regular LTO object must
21572157
// be exported.
21582158
auto &Defs = ThinLTO.CombinedIndex.cfiFunctionDefs();
2159-
ExportedGUIDs.insert(Defs.guid_begin(), Defs.guid_end());
2159+
ExportedGUIDs.insert(Defs.getExportedThinLTOGUIDs().begin(),
2160+
Defs.getExportedThinLTOGUIDs().end());
21602161
auto &Decls = ThinLTO.CombinedIndex.cfiFunctionDecls();
2161-
ExportedGUIDs.insert(Decls.guid_begin(), Decls.guid_end());
2162+
ExportedGUIDs.insert(Decls.getExportedThinLTOGUIDs().begin(),
2163+
Decls.getExportedThinLTOGUIDs().end());
21622164

21632165
auto isExported = [&](StringRef ModuleIdentifier, ValueInfo VI) {
21642166
const auto &ExportList = ExportLists.find(ModuleIdentifier);

llvm/lib/Transforms/IPO/CrossDSOCFI.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ void CrossDSOCFI::buildCFICheck(Module &M) {
7373
NamedMDNode *CfiFunctionsMD = M.getNamedMetadata("cfi.functions");
7474
if (CfiFunctionsMD) {
7575
for (auto *Func : CfiFunctionsMD->operands()) {
76-
assert(Func->getNumOperands() >= 2);
77-
for (unsigned I = 2; I < Func->getNumOperands(); ++I)
76+
assert(Func->getNumOperands() >= 3);
77+
assert(isa<ConstantAsMetadata>(Func->getOperand(2)));
78+
for (unsigned I = 3; I < Func->getNumOperands(); ++I)
7879
if (ConstantInt *TypeId =
7980
extractNumericTypeId(cast<MDNode>(Func->getOperand(I).get())))
8081
TypeIds.insert(TypeId->getZExtValue());

llvm/lib/Transforms/IPO/LowerTypeTests.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,10 +1788,15 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
17881788
}
17891789

17901790
if (IsExported) {
1791+
// TODO: use F->getGUID() once #184065 is relanded.
1792+
GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage(
1793+
GlobalValue::dropLLVMManglingEscape(F->getName()));
17911794
if (IsJumpTableCanonical)
1792-
ExportSummary->cfiFunctionDefs().emplace(F->getName());
1795+
ExportSummary->cfiFunctionDefs().addSymbolWithThinLTOGUID(F->getName(),
1796+
GUID);
17931797
else
1794-
ExportSummary->cfiFunctionDecls().emplace(F->getName());
1798+
ExportSummary->cfiFunctionDecls().addSymbolWithThinLTOGUID(F->getName(),
1799+
GUID);
17951800
}
17961801

17971802
if (!IsJumpTableCanonical) {
@@ -2123,9 +2128,9 @@ bool LowerTypeTestsModule::lower() {
21232128
// have the same name, but it's not the one we are looking for.
21242129
if (F.hasLocalLinkage())
21252130
continue;
2126-
if (ImportSummary->cfiFunctionDefs().count(F.getName()))
2131+
if (ImportSummary->cfiFunctionDefs().contains(F.getName()))
21272132
Defs.push_back(&F);
2128-
else if (ImportSummary->cfiFunctionDecls().count(F.getName()))
2133+
else if (ImportSummary->cfiFunctionDecls().contains(F.getName()))
21292134
Decls.push_back(&F);
21302135
}
21312136

@@ -2208,8 +2213,10 @@ bool LowerTypeTestsModule::lower() {
22082213
->getUniqueInteger()
22092214
.getZExtValue());
22102215
const GlobalValue::GUID GUID =
2211-
GlobalValue::getGUIDAssumingExternalLinkage(
2212-
GlobalValue::dropLLVMManglingEscape(FunctionName));
2216+
cast<ConstantAsMetadata>(FuncMD->getOperand(2))
2217+
->getValue()
2218+
->getUniqueInteger()
2219+
.getZExtValue();
22132220
// Do not emit jumptable entries for functions that are not-live and
22142221
// have no live references (and are not exported with cross-DSO CFI.)
22152222
if (!ExportSummary->isGUIDLive(GUID))
@@ -2280,7 +2287,7 @@ bool LowerTypeTestsModule::lower() {
22802287
F->setLinkage(GlobalValue::ExternalWeakLinkage);
22812288

22822289
F->eraseMetadata(LLVMContext::MD_type);
2283-
for (unsigned I = 2; I < FuncMD->getNumOperands(); ++I)
2290+
for (unsigned I = 3; I < FuncMD->getNumOperands(); ++I)
22842291
F->addMetadata(LLVMContext::MD_type,
22852292
*cast<MDNode>(FuncMD->getOperand(I).get()));
22862293
}

llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,11 @@ void splitAndWriteThinLTOBitcode(
436436
Linkage = CFL_Declaration;
437437
Elts.push_back(ConstantAsMetadata::get(
438438
llvm::ConstantInt::get(Type::getInt8Ty(Ctx), Linkage)));
439+
// TODO: use F->getGUID() once #184065 is relanded.
440+
GlobalValue::GUID GUID = GlobalValue::getGUIDAssumingExternalLinkage(
441+
GlobalValue::dropLLVMManglingEscape(V->getName()));
442+
Elts.push_back(ConstantAsMetadata::get(
443+
llvm::ConstantInt::get(Type::getInt64Ty(Ctx), GUID)));
439444
append_range(Elts, Types);
440445
CfiFunctionMDs.push_back(MDTuple::get(Ctx, Elts));
441446
}

llvm/test/ThinLTO/X86/cfi-icall-only-defuse.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ define i8 @f(i1 %i, ptr %p) {
4040
!0 = !{i64 0, !"t1"}
4141

4242
; FOOBAZ: <GLOBALVAL_SUMMARY_BLOCK
43-
; FOOBAZ: <CFI_FUNCTION_DEFS op0=0 op1=3 op2=3 op3=3 op4=6 op5=3/>
43+
; FOOBAZ: <CFI_FUNCTION_DEFS op0={{.*}} op1=0 op2=3 op3={{.*}} op4=3 op5=3 op6={{.*}} op7=6 op8=3/>
4444
; FOOBAZ: <TYPE_ID op0=9 op1=2 op2=4 op3=7 op4=0 op5=0 op6=0 op7=0/>
4545
; FOOBAZ: </GLOBALVAL_SUMMARY_BLOCK>
4646
; FOOBAZ: <STRTAB_BLOCK
4747
; FOOBAZ-NEXT: <BLOB abbrevid=4/> blob data = 'barbazfoot1'
4848
; FOOBAZ-NEXT: </STRTAB_BLOCK>
4949

5050
; BARQUX: <GLOBALVAL_SUMMARY_BLOCK
51-
; BARQUX: <CFI_FUNCTION_DEFS op0=0 op1=3 op2=3 op3=3 op4=6 op5=3/>
51+
; BARQUX: <CFI_FUNCTION_DEFS op0={{.*}} op1=0 op2=3 op3={{.*}} op4=3 op5=3 op6={{.*}} op7=6 op8=3/>
5252
; BARQUX: <TYPE_ID op0=9 op1=2 op2=4 op3=7 op4=0 op5=0 op6=0 op7=0/>
5353
; BARQUX: </GLOBALVAL_SUMMARY_BLOCK>
5454
; BARQUX: <STRTAB_BLOCK

0 commit comments

Comments
 (0)