Skip to content

Commit b51fa88

Browse files
committed
Bail without adding norecurse if address of function is taken as it could be called back in
1 parent 41c6eaa commit b51fa88

File tree

10 files changed

+186
-159
lines changed

10 files changed

+186
-159
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,49 +2067,8 @@ static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
20672067
AI.run(SCCNodes, Changed);
20682068
}
20692069

2070-
/// Returns true if N or any function it (transitively) calls makes a call
2071-
/// to an unknown external function: either an indirect call or a declaration
2072-
/// without the NoCallback attribute.
2073-
static bool callsUnknownExternal(LazyCallGraph::Node *N) {
2074-
std::deque<LazyCallGraph::Node *> Worklist;
2075-
DenseSet<LazyCallGraph::Node *> Visited;
2076-
Worklist.push_back(N);
2077-
Visited.insert(N);
2078-
2079-
while (!Worklist.empty()) {
2080-
auto *Cur = Worklist.front();
2081-
Worklist.pop_front();
2082-
2083-
Function &F = Cur->getFunction();
2084-
for (auto &BB : F) {
2085-
for (auto &I : BB.instructionsWithoutDebug()) {
2086-
if (auto *CB = dyn_cast<CallBase>(&I)) {
2087-
const Function *Callee = CB->getCalledFunction();
2088-
// Indirect call, treat as unknown external function.
2089-
if (!Callee)
2090-
return true;
2091-
// Extern declaration without NoCallback attribute
2092-
if (Callee->isDeclaration() &&
2093-
!Callee->hasFnAttribute(Attribute::NoCallback))
2094-
return true;
2095-
}
2096-
}
2097-
}
2098-
2099-
// Enqueue all direct call-edge successors for further scanning
2100-
for (auto &Edge : Cur->populate().calls()) {
2101-
LazyCallGraph::Node *Succ = &Edge.getNode();
2102-
if (Visited.insert(Succ).second)
2103-
Worklist.push_back(Succ);
2104-
}
2105-
}
2106-
2107-
return false;
2108-
}
2109-
21102070
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
2111-
SmallPtrSet<Function *, 8> &Changed,
2112-
LazyCallGraph &CG) {
2071+
SmallPtrSet<Function *, 8> &Changed) {
21132072
// Try and identify functions that do not recurse.
21142073

21152074
// If the SCC contains multiple nodes we know for sure there is recursion.
@@ -2120,6 +2079,8 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
21202079
if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
21212080
return;
21222081

2082+
if (F->hasAddressTaken())
2083+
return;
21232084
// If all of the calls in F are identifiable and can be proven to not
21242085
// callback F, F is norecurse. This check also detects self-recursion
21252086
// as F is not currently marked norecurse, so any call from F to F
@@ -2141,10 +2102,6 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
21412102
continue;
21422103
return;
21432104
}
2144-
2145-
if (auto *CNode = CG.lookup(*Callee))
2146-
if (callsUnknownExternal(CNode))
2147-
return;
21482105
}
21492106
}
21502107
}
@@ -2295,7 +2252,7 @@ static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
22952252
template <typename AARGetterT>
22962253
static SmallPtrSet<Function *, 8>
22972254
deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
2298-
bool ArgAttrsOnly, LazyCallGraph &CG) {
2255+
bool ArgAttrsOnly) {
22992256
SCCNodesResult Nodes = createSCCNodeSet(Functions);
23002257

23012258
// Bail if the SCC only contains optnone functions.
@@ -2325,7 +2282,7 @@ deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter,
23252282
addNoAliasAttrs(Nodes.SCCNodes, Changed);
23262283
addNonNullAttrs(Nodes.SCCNodes, Changed);
23272284
inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
2328-
addNoRecurseAttrs(Nodes.SCCNodes, Changed, CG);
2285+
addNoRecurseAttrs(Nodes.SCCNodes, Changed);
23292286

23302287
// Finally, infer the maximal set of attributes from the ones we've inferred
23312288
// above. This is handling the cases where one attribute on a signature
@@ -2368,7 +2325,7 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
23682325
}
23692326

23702327
auto ChangedFunctions =
2371-
deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly, CG);
2328+
deriveAttrsInPostOrder(Functions, AARGetter, ArgAttrsOnly);
23722329
if (ChangedFunctions.empty())
23732330
return PreservedAnalyses::all();
23742331

llvm/test/CodeGen/AMDGPU/amdgpu-simplify-libcall-sincos.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ entry:
725725

726726
define void @sincos_f32_value_is_different_constexpr(ptr addrspace(1) nocapture writeonly %sin_out, ptr addrspace(1) nocapture writeonly %cos_out) {
727727
; CHECK-LABEL: define void @sincos_f32_value_is_different_constexpr
728-
; CHECK-SAME: (ptr addrspace(1) writeonly captures(none) initializes((0, 4)) [[SIN_OUT:%.*]], ptr addrspace(1) writeonly captures(none) initializes((0, 4)) [[COS_OUT:%.*]]) #[[ATTR2]] {
728+
; CHECK-SAME: (ptr addrspace(1) writeonly captures(none) initializes((0, 4)) [[SIN_OUT:%.*]], ptr addrspace(1) writeonly captures(none) initializes((0, 4)) [[COS_OUT:%.*]]) #[[ATTR6:[0-9]+]] {
729729
; CHECK-NEXT: entry:
730730
; CHECK-NEXT: [[CALL:%.*]] = tail call contract float @_Z3sinf(float bitcast (i32 ptrtoint (ptr @func to i32) to float))
731731
; CHECK-NEXT: store float [[CALL]], ptr addrspace(1) [[SIN_OUT]], align 4
@@ -881,7 +881,7 @@ entry:
881881

882882
define float @sincos_f32_unused_result_cos(float %x) {
883883
; CHECK-LABEL: define float @sincos_f32_unused_result_cos
884-
; CHECK-SAME: (float [[X:%.*]]) local_unnamed_addr #[[ATTR6:[0-9]+]] {
884+
; CHECK-SAME: (float [[X:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
885885
; CHECK-NEXT: entry:
886886
; CHECK-NEXT: [[SIN:%.*]] = tail call contract float @_Z3sinf(float [[X]])
887887
; CHECK-NEXT: ret float [[SIN]]
@@ -896,7 +896,7 @@ entry:
896896

897897
define float @sincos_f32_unused_result_sin(float %x) {
898898
; CHECK-LABEL: define float @sincos_f32_unused_result_sin
899-
; CHECK-SAME: (float [[X:%.*]]) local_unnamed_addr #[[ATTR6]] {
899+
; CHECK-SAME: (float [[X:%.*]]) local_unnamed_addr #[[ATTR7]] {
900900
; CHECK-NEXT: entry:
901901
; CHECK-NEXT: [[COS:%.*]] = tail call contract float @_Z3cosf(float [[X]])
902902
; CHECK-NEXT: ret float [[COS]]
@@ -911,7 +911,7 @@ entry:
911911

912912
define void @sincos_f32_repeated_uses(float %x, ptr addrspace(1) %sin_out, ptr addrspace(1) %cos_out) {
913913
; CHECK-LABEL: define void @sincos_f32_repeated_uses
914-
; CHECK-SAME: (float [[X:%.*]], ptr addrspace(1) [[SIN_OUT:%.*]], ptr addrspace(1) [[COS_OUT:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
914+
; CHECK-SAME: (float [[X:%.*]], ptr addrspace(1) [[SIN_OUT:%.*]], ptr addrspace(1) [[COS_OUT:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
915915
; CHECK-NEXT: entry:
916916
; CHECK-NEXT: [[__SINCOS_:%.*]] = alloca float, align 4, addrspace(5)
917917
; CHECK-NEXT: [[TMP0:%.*]] = call contract float @_Z6sincosfPU3AS5f(float [[X]], ptr addrspace(5) [[__SINCOS_]])

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

Lines changed: 21 additions & 19 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() {
12+
; CHECK: define void @test1_a() #1 {
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() {
131+
; CHECK: define void @test3_a() #1 {
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() #0 {
140+
; CHECK: define void @test3_b11() #2 {
141141
define void @test3_b11() {
142142
call void @test3_b12()
143143
ret void
144144
}
145145

146-
; CHECK: define void @test3_b12() #0 {
146+
; CHECK: define void @test3_b12() #2 {
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() #0 {
158+
; CHECK: define void @test3_b21() #2 {
159159
define void @test3_b21() {
160160
call void @test3_b22()
161161
ret void
162162
}
163163

164-
; CHECK: define void @test3_b22() #0 {
164+
; CHECK: define void @test3_b22() #2 {
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() {
183+
; CHECK: define void @test3_b31() #1 {
184184
define void @test3_b31() {
185185
call void @test3_b32()
186186
ret void
187187
}
188188

189-
; CHECK: define void @test3_b32() {
189+
; CHECK: define void @test3_b32() #1 {
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() #0 {
208+
; CHECK: define void @test3_b41() #2 {
209209
define void @test3_b41() {
210210
call void @test3_b42()
211211
ret void
212212
}
213213

214-
; CHECK: define void @test3_b42() #0 {
214+
; CHECK: define void @test3_b42() #2 {
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() #0 {
247+
; CHECK: define void @test4_b11() #2 {
248248
define void @test4_b11() {
249249
call void @test4_b12()
250250
ret void
251251
}
252252

253-
; CHECK: define void @test4_b12() #0 {
253+
; CHECK: define void @test4_b12() #2 {
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() #0 {
265+
; CHECK: define void @test4_b21() #2 {
266266
define void @test4_b21() {
267267
call void @test4_b22()
268268
ret void
269269
}
270270

271-
; CHECK: define void @test4_b22() #0 {
271+
; CHECK: define void @test4_b22() #2 {
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() {
278+
define void @test4_b23() #0 {
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() {
290+
; CHECK: define void @test4_b31() #1 {
291291
define void @test4_b31() {
292292
call void @test4_b32()
293293
ret void
294294
}
295295

296-
; CHECK: define void @test4_b32() {
296+
; CHECK: define void @test4_b32() #1 {
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() #0 {
316+
; CHECK: define void @test4_b41() #2 {
317317
define void @test4_b41() {
318318
call void @test4_b42()
319319
ret void
320320
}
321321

322-
; CHECK: define void @test4_b42() #0 {
322+
; CHECK: define void @test4_b42() #2 {
323323
define void @test4_b42() {
324324
call void @test4_b43()
325325
ret void
@@ -339,3 +339,5 @@ 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 nosync nounwind memory(none) uwtable
253+
; FNATTR: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable
254254
; FNATTR-LABEL: define {{[^@]+}}@f2
255-
; FNATTR-SAME: () #[[ATTR4]] {
255+
; FNATTR-SAME: () #[[ATTR7:[0-9]+]] {
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:%.*]]) {
1108+
; FNATTRS-SAME: ptr nonnull dereferenceable(8) [[A:%.*]]) #[[ATTR13:[0-9]+]] {
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/noreturn.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22

33
declare i32 @f()
44

5-
; CHECK: Function Attrs: noreturn
5+
; CHECK: Function Attrs: {{.*}}noreturn
66
; CHECK-NEXT: @noreturn()
77
declare i32 @noreturn() noreturn
88

9-
; CHECK: Function Attrs: noreturn
9+
; CHECK: Function Attrs: {{.*}}noreturn
1010
; CHECK-NEXT: @caller()
1111
define i32 @caller() {
1212
%c = call i32 @noreturn()
1313
ret i32 %c
1414
}
1515

16-
; CHECK: Function Attrs: noreturn
16+
; CHECK: Function Attrs: {{.*}}noreturn
1717
; CHECK-NEXT: @caller2()
1818
define i32 @caller2() {
1919
%c = call i32 @caller()
2020
ret i32 %c
2121
}
2222

23-
; CHECK: Function Attrs: noreturn
23+
; CHECK: Function Attrs: {{.*}}noreturn
2424
; CHECK-NEXT: @caller3()
2525
define i32 @caller3() {
2626
entry:

0 commit comments

Comments
 (0)