Skip to content

Commit fa9b1be

Browse files
[ThinLTO]Mark referencers of local ifunc not eligible for import (#92431)
If an ifunc has local linkage, do not add it into ref edges and mark its referencer (a function or global variable) not eligible for import. An ifunc doesn't have summary and ThinLTO cannot promote it. Importing the referencer may cause linkage errors. To reference a similar fix, https://reviews.llvm.org/D158961 marks callers of local ifunc not eligible for import to fix #58740
1 parent fe4d5f0 commit fa9b1be

File tree

2 files changed

+81
-13
lines changed

2 files changed

+81
-13
lines changed

llvm/lib/Analysis/ModuleSummaryAnalysis.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,12 @@ extern cl::opt<unsigned> MaxNumVTableAnnotations;
9595
// global vars at all. When importing function we aren't interested if any
9696
// instruction in it takes an address of any basic block, because instruction
9797
// can only take an address of basic block located in the same function.
98+
// Set `RefLocalLinkageIFunc` to true if the analyzed value references a
99+
// local-linkage ifunc.
98100
static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
99101
SetVector<ValueInfo, std::vector<ValueInfo>> &RefEdges,
100-
SmallPtrSet<const User *, 8> &Visited) {
102+
SmallPtrSet<const User *, 8> &Visited,
103+
bool &RefLocalLinkageIFunc) {
101104
bool HasBlockAddress = false;
102105
SmallVector<const User *, 32> Worklist;
103106
if (Visited.insert(CurUser).second)
@@ -119,8 +122,18 @@ static bool findRefEdges(ModuleSummaryIndex &Index, const User *CurUser,
119122
// We have a reference to a global value. This should be added to
120123
// the reference set unless it is a callee. Callees are handled
121124
// specially by WriteFunction and are added to a separate list.
122-
if (!(CB && CB->isCallee(&OI)))
125+
if (!(CB && CB->isCallee(&OI))) {
126+
// If an ifunc has local linkage, do not add it into ref edges, and
127+
// sets `RefLocalLinkageIFunc` to true. The referencer is not eligible
128+
// for import. An ifunc doesn't have summary and ThinLTO cannot
129+
// promote it; importing the referencer may cause linkage errors.
130+
if (auto *GI = dyn_cast_if_present<GlobalIFunc>(GV);
131+
GI && GI->hasLocalLinkage()) {
132+
RefLocalLinkageIFunc = true;
133+
continue;
134+
}
123135
RefEdges.insert(Index.getOrInsertValueInfo(GV));
136+
}
124137
continue;
125138
}
126139
if (Visited.insert(Operand).second)
@@ -313,7 +326,8 @@ static void computeFunctionSummary(
313326

314327
// Add personality function, prefix data and prologue data to function's ref
315328
// list.
316-
findRefEdges(Index, &F, RefEdges, Visited);
329+
bool HasLocalIFuncCallOrRef = false;
330+
findRefEdges(Index, &F, RefEdges, Visited, HasLocalIFuncCallOrRef);
317331
std::vector<const Instruction *> NonVolatileLoads;
318332
std::vector<const Instruction *> NonVolatileStores;
319333

@@ -326,7 +340,6 @@ static void computeFunctionSummary(
326340

327341
bool HasInlineAsmMaybeReferencingInternal = false;
328342
bool HasIndirBranchToBlockAddress = false;
329-
bool HasIFuncCall = false;
330343
bool HasUnknownCall = false;
331344
bool MayThrow = false;
332345
for (const BasicBlock &BB : F) {
@@ -372,11 +385,11 @@ static void computeFunctionSummary(
372385
// of calling it we should add GV to RefEdges directly.
373386
RefEdges.insert(Index.getOrInsertValueInfo(GV));
374387
else if (auto *U = dyn_cast<User>(Stored))
375-
findRefEdges(Index, U, RefEdges, Visited);
388+
findRefEdges(Index, U, RefEdges, Visited, HasLocalIFuncCallOrRef);
376389
continue;
377390
}
378391
}
379-
findRefEdges(Index, &I, RefEdges, Visited);
392+
findRefEdges(Index, &I, RefEdges, Visited, HasLocalIFuncCallOrRef);
380393
const auto *CB = dyn_cast<CallBase>(&I);
381394
if (!CB) {
382395
if (I.mayThrow())
@@ -450,7 +463,7 @@ static void computeFunctionSummary(
450463
// Non-local ifunc is not cloned and does not have the issue.
451464
if (auto *GI = dyn_cast_if_present<GlobalIFunc>(CalledValue))
452465
if (GI->hasLocalLinkage())
453-
HasIFuncCall = true;
466+
HasLocalIFuncCallOrRef = true;
454467
// Skip inline assembly calls.
455468
if (CI && CI->isInlineAsm())
456469
continue;
@@ -555,7 +568,7 @@ static void computeFunctionSummary(
555568
SmallPtrSet<const User *, 8> &Cache) {
556569
for (const auto *I : Instrs) {
557570
Cache.erase(I);
558-
findRefEdges(Index, I, Edges, Cache);
571+
findRefEdges(Index, I, Edges, Cache, HasLocalIFuncCallOrRef);
559572
}
560573
};
561574

@@ -631,9 +644,9 @@ static void computeFunctionSummary(
631644
#endif
632645

633646
bool NonRenamableLocal = isNonRenamableLocal(F);
634-
bool NotEligibleForImport = NonRenamableLocal ||
635-
HasInlineAsmMaybeReferencingInternal ||
636-
HasIndirBranchToBlockAddress || HasIFuncCall;
647+
bool NotEligibleForImport =
648+
NonRenamableLocal || HasInlineAsmMaybeReferencingInternal ||
649+
HasIndirBranchToBlockAddress || HasLocalIFuncCallOrRef;
637650
GlobalValueSummary::GVFlags Flags(
638651
F.getLinkage(), F.getVisibility(), NotEligibleForImport,
639652
/* Live = */ false, F.isDSOLocal(), F.canBeOmittedFromSymbolTable(),
@@ -787,7 +800,10 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
787800
SmallVectorImpl<MDNode *> &Types) {
788801
SetVector<ValueInfo, std::vector<ValueInfo>> RefEdges;
789802
SmallPtrSet<const User *, 8> Visited;
790-
bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited);
803+
bool RefLocalIFunc = false;
804+
bool HasBlockAddress =
805+
findRefEdges(Index, &V, RefEdges, Visited, RefLocalIFunc);
806+
const bool NotEligibleForImport = (HasBlockAddress || RefLocalIFunc);
791807
bool NonRenamableLocal = isNonRenamableLocal(V);
792808
GlobalValueSummary::GVFlags Flags(
793809
V.getLinkage(), V.getVisibility(), NonRenamableLocal,
@@ -821,7 +837,7 @@ static void computeVariableSummary(ModuleSummaryIndex &Index,
821837
RefEdges.takeVector());
822838
if (NonRenamableLocal)
823839
CantBePromoted.insert(V.getGUID());
824-
if (HasBlockAddress)
840+
if (NotEligibleForImport)
825841
GVarSummary->setNotEligibleToImport();
826842
if (!VTableFuncs.empty())
827843
GVarSummary->setVTableFuncs(VTableFuncs);

llvm/test/ThinLTO/X86/ref-ifunc.ll

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
; RUN: opt -module-summary %s -o %t.bc
2+
3+
; RUN: llvm-dis %t.bc -o - | FileCheck %s
4+
5+
; Tests that var and caller are not eligible to import and they don't have refs to ifunc 'callee'
6+
7+
; CHECK: gv: (name: "var", summaries: (variable: ({{.*}}, flags: ({{.*}}notEligibleToImport: 1
8+
; CHECK-NOT: refs
9+
; CHECK-SAME: guid = 7919382516565939378
10+
11+
; CHECK: gv: (name: "caller", summaries: (function: ({{.*}}, flags: ({{.*}}notEligibleToImport: 1
12+
; CHECK-NOT: refs
13+
; CHECK-SAME: guid = 16677772384402303968
14+
15+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
16+
target triple = "x86_64-unknown-linux-gnu"
17+
18+
@__cpu_model = external global { i32, i32, i32, [1 x i32] }
19+
20+
@callee = internal ifunc void(), ptr @callee.resolver
21+
22+
@var = constant { [1 x ptr] } { [1 x ptr] [ptr @callee]}
23+
24+
define void @dispatch(ptr %func) {
25+
tail call void %func()
26+
ret void
27+
}
28+
29+
define void @caller() {
30+
tail call void @dispatch(ptr @callee)
31+
ret void
32+
}
33+
34+
define internal ptr @callee.resolver() {
35+
resolver_entry:
36+
tail call void @__cpu_indicator_init()
37+
%0 = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i64 0, i32 3, i64 0)
38+
%1 = and i32 %0, 1024
39+
%.not = icmp eq i32 %1, 0
40+
%func_sel = select i1 %.not, ptr @callee.default.1, ptr @callee.avx2.0
41+
ret ptr %func_sel
42+
}
43+
44+
define internal void @callee.default.1(i32 %a) {
45+
ret void
46+
}
47+
48+
define internal void @callee.avx2.0(i32 %a) {
49+
ret void
50+
}
51+
52+
declare void @__cpu_indicator_init()

0 commit comments

Comments
 (0)