Skip to content

Commit 0a422d9

Browse files
committed
Check for functions's LocalLinkage when applying norecurse attribute
1 parent 8d1a31c commit 0a422d9

11 files changed

+171
-243
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,6 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
20712071
SmallPtrSet<Function *, 8> &Changed,
20722072
bool NoFunctionsAddressIsTaken) {
20732073
// Try and identify functions that do not recurse.
2074-
20752074
// If the SCC contains multiple nodes we know for sure there is recursion.
20762075
if (SCCNodes.size() != 1)
20772076
return;
@@ -2080,19 +2079,13 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
20802079
if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
20812080
return;
20822081

2083-
Module *M = F->getParent();
2084-
llvm::TargetLibraryInfoImpl TLII(llvm::Triple(M->getTargetTriple()));
2085-
llvm::TargetLibraryInfo TLI(TLII);
20862082
// If all of the calls in F are identifiable and can be proven to not
20872083
// callback F, F is norecurse. This check also detects self-recursion
20882084
// as F is not currently marked norecurse, so any call from F to F
20892085
// will not be marked norecurse.
20902086
for (auto &BB : *F) {
20912087
for (auto &I : BB.instructionsWithoutDebug()) {
20922088
if (auto *CB = dyn_cast<CallBase>(&I)) {
2093-
if (F->hasAddressTaken())
2094-
return;
2095-
20962089
Function *Callee = CB->getCalledFunction();
20972090

20982091
if (!Callee || Callee == F)
@@ -2101,21 +2094,25 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
21012094
if (Callee->doesNotRecurse())
21022095
continue;
21032096

2104-
LibFunc LF;
21052097
if (Callee->isDeclaration()) {
21062098
if (Callee->hasFnAttribute(Attribute::NoCallback) ||
2107-
(NoFunctionsAddressIsTaken &&
2108-
TLI.getLibFunc(Callee->getName(), LF)))
2099+
NoFunctionsAddressIsTaken)
21092100
continue;
21102101
return;
2102+
} else if (F->hasAddressTaken() || !F->hasLocalLinkage()) {
2103+
// Control reaches here only for callees which are defined in this
2104+
// module and do not satisfy conditions for norecurse attribute.
2105+
// In such a case, if function F has external linkage or address
2106+
// taken, conversatively avoid adding norecurse.
2107+
return;
21112108
}
21122109
}
21132110
}
21142111
}
21152112

21162113
// Every call was either to an external function guaranteed to not make a
2117-
// call to this function or a direct call to internal function and we have no
2118-
// indirect recursion as the SCC size is one. This function cannot recurse.
2114+
// call to this function or a direct call to internal function. Also, SCC is
2115+
// one. Together, the above checks ensures, this function cannot norecurse.
21192116
F->setDoesNotRecurse();
21202117
++NumNoRecurse;
21212118
Changed.insert(F);

llvm/test/Other/cgscc-iterate-function-mutation.ll

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ declare void @reference_function_pointer(ptr) nofree nosync readnone
99
; and the RefSCCs that those functions are in, we re-run the CGSCC passes to
1010
; observe the refined call graph structure.
1111

12-
; CHECK: define void @test1_a() #1 {
12+
; CHECK: define void @test1_a() {
1313
define void @test1_a() {
1414
call void @test1_b1()
1515
call void @test1_b2()
@@ -128,7 +128,7 @@ exit:
128128
; multiple layers that have to be traversed in the correct order instead of
129129
; a single node.
130130

131-
; CHECK: define void @test3_a() #1 {
131+
; CHECK: define void @test3_a() {
132132
define void @test3_a() {
133133
call void @test3_b11()
134134
call void @test3_b21()
@@ -137,13 +137,13 @@ define void @test3_a() {
137137
ret void
138138
}
139139

140-
; CHECK: define void @test3_b11() #2 {
140+
; CHECK: define void @test3_b11() #0 {
141141
define void @test3_b11() {
142142
call void @test3_b12()
143143
ret void
144144
}
145145

146-
; CHECK: define void @test3_b12() #2 {
146+
; CHECK: define void @test3_b12() #0 {
147147
define void @test3_b12() {
148148
call void @test3_b13()
149149
ret void
@@ -155,13 +155,13 @@ define void @test3_b13() {
155155
ret void
156156
}
157157

158-
; CHECK: define void @test3_b21() #2 {
158+
; CHECK: define void @test3_b21() #0 {
159159
define void @test3_b21() {
160160
call void @test3_b22()
161161
ret void
162162
}
163163

164-
; CHECK: define void @test3_b22() #2 {
164+
; CHECK: define void @test3_b22() #0 {
165165
define void @test3_b22() {
166166
call void @test3_b23()
167167
ret void
@@ -180,13 +180,13 @@ exit:
180180
ret void
181181
}
182182

183-
; CHECK: define void @test3_b31() #1 {
183+
; CHECK: define void @test3_b31() {
184184
define void @test3_b31() {
185185
call void @test3_b32()
186186
ret void
187187
}
188188

189-
; CHECK: define void @test3_b32() #1 {
189+
; CHECK: define void @test3_b32() {
190190
define void @test3_b32() {
191191
call void @test3_b33()
192192
ret void
@@ -205,13 +205,13 @@ exit:
205205
ret void
206206
}
207207

208-
; CHECK: define void @test3_b41() #2 {
208+
; CHECK: define void @test3_b41() #0 {
209209
define void @test3_b41() {
210210
call void @test3_b42()
211211
ret void
212212
}
213213

214-
; CHECK: define void @test3_b42() #2 {
214+
; CHECK: define void @test3_b42() #0 {
215215
define void @test3_b42() {
216216
call void @test3_b43()
217217
ret void
@@ -244,13 +244,13 @@ define void @test4_a() {
244244
ret void
245245
}
246246

247-
; CHECK: define void @test4_b11() #2 {
247+
; CHECK: define void @test4_b11() #0 {
248248
define void @test4_b11() {
249249
call void @test4_b12()
250250
ret void
251251
}
252252

253-
; CHECK: define void @test4_b12() #2 {
253+
; CHECK: define void @test4_b12() #0 {
254254
define void @test4_b12() {
255255
call void @test4_b13()
256256
ret void
@@ -262,20 +262,20 @@ define void @test4_b13() {
262262
ret void
263263
}
264264

265-
; CHECK: define void @test4_b21() #2 {
265+
; CHECK: define void @test4_b21() #0 {
266266
define void @test4_b21() {
267267
call void @test4_b22()
268268
ret void
269269
}
270270

271-
; CHECK: define void @test4_b22() #2 {
271+
; CHECK: define void @test4_b22() #0 {
272272
define void @test4_b22() {
273273
call void @test4_b23()
274274
ret void
275275
}
276276

277277
; CHECK: define void @test4_b23() #0 {
278-
define void @test4_b23() #0 {
278+
define void @test4_b23() {
279279
call void @reference_function_pointer(ptr @test4_a)
280280
br i1 false, label %dead, label %exit
281281

@@ -287,13 +287,13 @@ exit:
287287
ret void
288288
}
289289

290-
; CHECK: define void @test4_b31() #1 {
290+
; CHECK: define void @test4_b31() {
291291
define void @test4_b31() {
292292
call void @test4_b32()
293293
ret void
294294
}
295295

296-
; CHECK: define void @test4_b32() #1 {
296+
; CHECK: define void @test4_b32() {
297297
define void @test4_b32() {
298298
call void @test4_b33()
299299
ret void
@@ -313,13 +313,13 @@ exit:
313313
ret void
314314
}
315315

316-
; CHECK: define void @test4_b41() #2 {
316+
; CHECK: define void @test4_b41() #0 {
317317
define void @test4_b41() {
318318
call void @test4_b42()
319319
ret void
320320
}
321321

322-
; CHECK: define void @test4_b42() #2 {
322+
; CHECK: define void @test4_b42() #0 {
323323
define void @test4_b42() {
324324
call void @test4_b43()
325325
ret void
@@ -339,5 +339,3 @@ exit:
339339
}
340340

341341
; CHECK: attributes #0 = { nofree nosync memory(none) }
342-
; CHECK: attributes #1 = { norecurse }
343-
; CHECK: attributes #2 = { nofree norecurse nosync memory(none) }

llvm/test/Transforms/FunctionAttrs/nofree-attributor.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,9 @@ define void @f1() #0 {
250250
}
251251

252252
define void @f2() #0 {
253-
; FNATTR: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable
253+
; FNATTR: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
254254
; FNATTR-LABEL: define {{[^@]+}}@f2
255-
; FNATTR-SAME: () #[[ATTR7:[0-9]+]] {
255+
; FNATTR-SAME: () #[[ATTR4]] {
256256
; FNATTR-NEXT: tail call void @f1()
257257
; FNATTR-NEXT: ret void
258258
;

llvm/test/Transforms/FunctionAttrs/nonnull.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ define internal void @optnone(ptr dereferenceable(4) %a) optnone noinline {
11051105
}
11061106
define void @make_live(ptr nonnull dereferenceable(8) %a) {
11071107
; FNATTRS-LABEL: define void @make_live(
1108-
; FNATTRS-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) #[[ATTR13:[0-9]+]] {
1108+
; FNATTRS-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) {
11091109
; FNATTRS-NEXT: call void @naked(ptr nonnull align 16 dereferenceable(8) [[A]])
11101110
; FNATTRS-NEXT: call void @control(ptr nonnull align 16 dereferenceable(8) [[A]])
11111111
; FNATTRS-NEXT: call void @optnone(ptr nonnull align 16 dereferenceable(8) [[A]])

llvm/test/Transforms/FunctionAttrs/norecurse_multiSCC_indirect_recursion.ll

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
44
target triple = "aarch64-unknown-linux-gnu"
55

6-
; This test includes a call graph with multiple SCCs. The purpose of this is
7-
; to check that norecurse is not added when a function is part of non-singular
6+
; This test includes a call graph with multiple SCCs. The purpose of this is
7+
; to check that norecurse is not added when a function is part of non-singular
88
; SCC.
99
; There are three different SCCs in this test:
1010
; SCC#1: main, foo, bar, foo1, bar1
@@ -13,9 +13,9 @@ target triple = "aarch64-unknown-linux-gnu"
1313
; None of these functions should be marked as norecurse
1414

1515
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
16-
define dso_local void @bar1() local_unnamed_addr #0 {
16+
define internal void @bar1() local_unnamed_addr #0 {
1717
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
18-
; CHECK-LABEL: define dso_local void @bar1(
18+
; CHECK-LABEL: define internal void @bar1(
1919
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0:[0-9]+]] {
2020
; CHECK-NEXT: [[ENTRY:.*:]]
2121
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @main()
@@ -45,9 +45,9 @@ entry:
4545
}
4646

4747
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
48-
define dso_local void @foo1() local_unnamed_addr #0 {
48+
define internal void @foo1() local_unnamed_addr #0 {
4949
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
50-
; CHECK-LABEL: define dso_local void @foo1(
50+
; CHECK-LABEL: define internal void @foo1(
5151
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
5252
; CHECK-NEXT: [[ENTRY:.*:]]
5353
; CHECK-NEXT: tail call void @bar1()
@@ -59,9 +59,9 @@ entry:
5959
}
6060

6161
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
62-
define dso_local void @bar() local_unnamed_addr #0 {
62+
define internal void @bar() local_unnamed_addr #0 {
6363
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
64-
; CHECK-LABEL: define dso_local void @bar(
64+
; CHECK-LABEL: define internal void @bar(
6565
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
6666
; CHECK-NEXT: [[ENTRY:.*:]]
6767
; CHECK-NEXT: tail call void @foo1()
@@ -73,9 +73,9 @@ entry:
7373
}
7474

7575
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
76-
define dso_local void @foo() local_unnamed_addr #0 {
76+
define internal void @foo() local_unnamed_addr #0 {
7777
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
78-
; CHECK-LABEL: define dso_local void @foo(
78+
; CHECK-LABEL: define internal void @foo(
7979
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
8080
; CHECK-NEXT: [[ENTRY:.*:]]
8181
; CHECK-NEXT: tail call void @bar()
@@ -87,9 +87,9 @@ entry:
8787
}
8888

8989
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
90-
define dso_local void @bar4() local_unnamed_addr #0 {
90+
define internal void @bar4() local_unnamed_addr #0 {
9191
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
92-
; CHECK-LABEL: define dso_local void @bar4(
92+
; CHECK-LABEL: define internal void @bar4(
9393
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
9494
; CHECK-NEXT: [[ENTRY:.*:]]
9595
; CHECK-NEXT: tail call void @bar2()
@@ -101,9 +101,9 @@ entry:
101101
}
102102

103103
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
104-
define dso_local void @bar2() local_unnamed_addr #0 {
104+
define internal void @bar2() local_unnamed_addr #0 {
105105
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
106-
; CHECK-LABEL: define dso_local void @bar2(
106+
; CHECK-LABEL: define internal void @bar2(
107107
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
108108
; CHECK-NEXT: [[ENTRY:.*:]]
109109
; CHECK-NEXT: tail call void @bar3()
@@ -115,9 +115,9 @@ entry:
115115
}
116116

117117
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
118-
define dso_local void @bar3() local_unnamed_addr #0 {
118+
define internal void @bar3() local_unnamed_addr #0 {
119119
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
120-
; CHECK-LABEL: define dso_local void @bar3(
120+
; CHECK-LABEL: define internal void @bar3(
121121
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
122122
; CHECK-NEXT: [[ENTRY:.*:]]
123123
; CHECK-NEXT: tail call void @bar4()
@@ -129,9 +129,9 @@ entry:
129129
}
130130

131131
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
132-
define dso_local void @fun() local_unnamed_addr #0 {
132+
define internal void @fun() local_unnamed_addr #0 {
133133
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
134-
; CHECK-LABEL: define dso_local void @fun(
134+
; CHECK-LABEL: define internal void @fun(
135135
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
136136
; CHECK-NEXT: [[ENTRY:.*:]]
137137
; CHECK-NEXT: tail call void @baz()
@@ -143,9 +143,9 @@ entry:
143143
}
144144

145145
; Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
146-
define dso_local void @baz() local_unnamed_addr #0 {
146+
define internal void @baz() local_unnamed_addr #0 {
147147
; CHECK: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable
148-
; CHECK-LABEL: define dso_local void @baz(
148+
; CHECK-LABEL: define internal void @baz(
149149
; CHECK-SAME: ) local_unnamed_addr #[[ATTR0]] {
150150
; CHECK-NEXT: [[ENTRY:.*:]]
151151
; CHECK-NEXT: tail call void @fun()

0 commit comments

Comments
 (0)