summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Eubanks <aeubanks@google.com>2021-10-20 12:05:53 -0700
committerTom Stellard <tstellar@redhat.com>2021-12-20 10:20:54 -0800
commitcd4ebb2918ae6cd938aabc3e95d5739b4d067f83 (patch)
tree2b7acceaf8b485ac22f89d1e5ef8a44ae02d2511
parentd4a57c84834c1e4db116fa3623918ed43d3bf13b (diff)
downloadllvm-cd4ebb2918ae6cd938aabc3e95d5739b4d067f83.tar.gz
[LazyCallGraph] Skip blockaddresses
blockaddresses do not participate in the call graph since the only instructions that use them must all return to someplace within the current function. And passes cannot retrieve a function address from a blockaddress. This was suggested by efriedma in D58260. Fixes PR50881. Reviewed By: nickdesaulniers Differential Revision: https://reviews.llvm.org/D112178 (cherry picked from commit 029f1a53448979365ab965572356b83edc82f755)
-rw-r--r--llvm/include/llvm/Analysis/LazyCallGraph.h24
-rw-r--r--llvm/test/Analysis/LazyCallGraph/blockaddress.ll28
-rw-r--r--llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll58
-rw-r--r--llvm/test/Transforms/Attributor/liveness.ll12
-rw-r--r--llvm/unittests/Analysis/LazyCallGraphTest.cpp3
5 files changed, 61 insertions, 64 deletions
diff --git a/llvm/include/llvm/Analysis/LazyCallGraph.h b/llvm/include/llvm/Analysis/LazyCallGraph.h
index 81500905c0f5..148be34aa73b 100644
--- a/llvm/include/llvm/Analysis/LazyCallGraph.h
+++ b/llvm/include/llvm/Analysis/LazyCallGraph.h
@@ -1098,28 +1098,10 @@ public:
continue;
}
- // The blockaddress constant expression is a weird special case, we can't
- // generically walk its operands the way we do for all other constants.
- if (BlockAddress *BA = dyn_cast<BlockAddress>(C)) {
- // If we've already visited the function referred to by the block
- // address, we don't need to revisit it.
- if (Visited.count(BA->getFunction()))
- continue;
-
- // If all of the blockaddress' users are instructions within the
- // referred to function, we don't need to insert a cycle.
- if (llvm::all_of(BA->users(), [&](User *U) {
- if (Instruction *I = dyn_cast<Instruction>(U))
- return I->getFunction() == BA->getFunction();
- return false;
- }))
- continue;
-
- // Otherwise we should go visit the referred to function.
- Visited.insert(BA->getFunction());
- Worklist.push_back(BA->getFunction());
+ // blockaddresses are weird and don't participate in the call graph anyway,
+ // skip them.
+ if (isa<BlockAddress>(C))
continue;
- }
for (Value *Op : C->operand_values())
if (Visited.insert(cast<Constant>(Op)).second)
diff --git a/llvm/test/Analysis/LazyCallGraph/blockaddress.ll b/llvm/test/Analysis/LazyCallGraph/blockaddress.ll
new file mode 100644
index 000000000000..cf2d00bce6db
--- /dev/null
+++ b/llvm/test/Analysis/LazyCallGraph/blockaddress.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes="cgscc(function(sccp,simplifycfg))" < %s -S | FileCheck %s
+
+define i32 @baz(i32 %y, i1 %b) {
+; CHECK-LABEL: @baz(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br i1 [[B:%.*]], label [[LAB:%.*]], label [[FOR_COND:%.*]]
+; CHECK: for.cond:
+; CHECK-NEXT: [[P_0:%.*]] = phi i8* [ null, [[FOR_COND]] ], [ blockaddress(@baz, [[LAB]]), [[ENTRY:%.*]] ]
+; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i8, i8* [[P_0]], i64 1
+; CHECK-NEXT: br label [[FOR_COND]]
+; CHECK: lab:
+; CHECK-NEXT: ret i32 0
+;
+entry:
+ br i1 %b, label %lab, label %for.cond.preheader
+
+for.cond.preheader:
+ br label %for.cond
+
+for.cond:
+ %p.0 = phi i8* [ null, %for.cond ], [ blockaddress(@baz, %lab), %for.cond.preheader ]
+ %incdec.ptr = getelementptr inbounds i8, i8* %p.0, i64 1
+ br label %for.cond
+
+lab:
+ ret i32 0
+}
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll b/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll
index 3ddf81dfc1ac..c4ae94bdd910 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/dangling-block-address.ll
@@ -34,37 +34,23 @@ entry:
}
define internal void @bar(i32* nocapture %pc) nounwind readonly {
-; IS__CGSCC_OPM: Function Attrs: nounwind readonly
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@bar
-; IS__CGSCC_OPM-SAME: (i32* nocapture [[PC:%.*]]) #[[ATTR1:[0-9]+]] {
-; IS__CGSCC_OPM-NEXT: entry:
-; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO:%.*]]
-; IS__CGSCC_OPM: lab0:
-; IS__CGSCC_OPM-NEXT: [[INDVAR_NEXT:%.*]] = add i32 [[INDVAR:%.*]], 1
-; IS__CGSCC_OPM-NEXT: br label [[INDIRECTGOTO]]
-; IS__CGSCC_OPM: end:
-; IS__CGSCC_OPM-NEXT: ret void
-; IS__CGSCC_OPM: indirectgoto:
-; IS__CGSCC_OPM-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
-; IS__CGSCC_OPM-NEXT: [[PC_ADDR_0:%.*]] = getelementptr i32, i32* [[PC]], i32 [[INDVAR]]
-; IS__CGSCC_OPM-NEXT: [[TMP1_PN:%.*]] = load i32, i32* [[PC_ADDR_0]], align 4
-; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST_IN:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @bar.l, i32 0, i32 [[TMP1_PN]]
-; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]], align 8
-; IS__CGSCC_OPM-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
-;
-; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone
-; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@bar
-; IS__CGSCC_NPM-SAME: () #[[ATTR1:[0-9]+]] {
-; IS__CGSCC_NPM-NEXT: entry:
-; IS__CGSCC_NPM-NEXT: br label [[INDIRECTGOTO:%.*]]
-; IS__CGSCC_NPM: lab0:
-; IS__CGSCC_NPM-NEXT: [[INDVAR_NEXT:%.*]] = add i32 [[INDVAR:%.*]], 1
-; IS__CGSCC_NPM-NEXT: br label [[INDIRECTGOTO]]
-; IS__CGSCC_NPM: end:
-; IS__CGSCC_NPM-NEXT: ret void
-; IS__CGSCC_NPM: indirectgoto:
-; IS__CGSCC_NPM-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
-; IS__CGSCC_NPM-NEXT: indirectbr i8* undef, [label [[LAB0]], label %end]
+; IS__CGSCC____: Function Attrs: nounwind readonly
+; IS__CGSCC____-LABEL: define {{[^@]+}}@bar
+; IS__CGSCC____-SAME: (i32* nocapture [[PC:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__CGSCC____-NEXT: entry:
+; IS__CGSCC____-NEXT: br label [[INDIRECTGOTO:%.*]]
+; IS__CGSCC____: lab0:
+; IS__CGSCC____-NEXT: [[INDVAR_NEXT:%.*]] = add i32 [[INDVAR:%.*]], 1
+; IS__CGSCC____-NEXT: br label [[INDIRECTGOTO]]
+; IS__CGSCC____: end:
+; IS__CGSCC____-NEXT: ret void
+; IS__CGSCC____: indirectgoto:
+; IS__CGSCC____-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
+; IS__CGSCC____-NEXT: [[PC_ADDR_0:%.*]] = getelementptr i32, i32* [[PC]], i32 [[INDVAR]]
+; IS__CGSCC____-NEXT: [[TMP1_PN:%.*]] = load i32, i32* [[PC_ADDR_0]], align 4
+; IS__CGSCC____-NEXT: [[INDIRECT_GOTO_DEST_IN:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @bar.l, i32 0, i32 [[TMP1_PN]]
+; IS__CGSCC____-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]], align 8
+; IS__CGSCC____-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
;
entry:
br label %indirectgoto
@@ -104,11 +90,7 @@ entry:
;.
; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
;.
-; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nounwind readnone }
-; IS__CGSCC_OPM: attributes #[[ATTR1]] = { nounwind readonly }
-; IS__CGSCC_OPM: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn }
-;.
-; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nounwind readnone }
-; IS__CGSCC_NPM: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone }
-; IS__CGSCC_NPM: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn }
+; IS__CGSCC____: attributes #[[ATTR0]] = { nounwind readnone }
+; IS__CGSCC____: attributes #[[ATTR1]] = { nounwind readonly }
+; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind readnone willreturn }
;.
diff --git a/llvm/test/Transforms/Attributor/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll
index 8370d7810a29..49c6babe6089 100644
--- a/llvm/test/Transforms/Attributor/liveness.ll
+++ b/llvm/test/Transforms/Attributor/liveness.ll
@@ -2432,9 +2432,9 @@ define internal void @dead_with_blockaddress_users(i32* nocapture %pc) nounwind
; IS__CGSCC_OPM-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]]
; IS__CGSCC_OPM-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone
+; IS__CGSCC____: Function Attrs: nounwind readonly
; IS__CGSCC____-LABEL: define {{[^@]+}}@dead_with_blockaddress_users
-; IS__CGSCC____-SAME: () #[[ATTR14:[0-9]+]] {
+; IS__CGSCC____-SAME: (i32* nocapture [[PC:%.*]]) #[[ATTR14:[0-9]+]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: br label [[INDIRECTGOTO:%.*]]
; IS__CGSCC____: lab0:
@@ -2444,7 +2444,11 @@ define internal void @dead_with_blockaddress_users(i32* nocapture %pc) nounwind
; IS__CGSCC____-NEXT: ret void
; IS__CGSCC____: indirectgoto:
; IS__CGSCC____-NEXT: [[INDVAR]] = phi i32 [ [[INDVAR_NEXT]], [[LAB0:%.*]] ], [ 0, [[ENTRY:%.*]] ]
-; IS__CGSCC____-NEXT: indirectbr i8* undef, [label [[LAB0]], label %end]
+; IS__CGSCC____-NEXT: [[PC_ADDR_0:%.*]] = getelementptr i32, i32* [[PC]], i32 [[INDVAR]]
+; IS__CGSCC____-NEXT: [[TMP1_PN:%.*]] = load i32, i32* [[PC_ADDR_0]], align 4
+; IS__CGSCC____-NEXT: [[INDIRECT_GOTO_DEST_IN:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* @dead_with_blockaddress_users.l, i32 0, i32 [[TMP1_PN]]
+; IS__CGSCC____-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = load i8*, i8** [[INDIRECT_GOTO_DEST_IN]], align 8
+; IS__CGSCC____-NEXT: indirectbr i8* [[INDIRECT_GOTO_DEST]], [label [[LAB0]], label %end]
;
entry:
br label %indirectgoto
@@ -2655,7 +2659,7 @@ declare void @llvm.lifetime.end.p0i8(i64 %0, i8* %1)
; IS__CGSCC____: attributes #[[ATTR11]] = { nofree norecurse noreturn nosync nounwind readnone }
; IS__CGSCC____: attributes #[[ATTR12]] = { nofree norecurse noreturn nosync nounwind readnone willreturn }
; IS__CGSCC____: attributes #[[ATTR13]] = { nofree nosync nounwind willreturn }
-; IS__CGSCC____: attributes #[[ATTR14]] = { nofree norecurse nosync nounwind readnone }
+; IS__CGSCC____: attributes #[[ATTR14]] = { nounwind readonly }
; IS__CGSCC____: attributes #[[ATTR15]] = { nofree nosync nounwind readnone willreturn }
; IS__CGSCC____: attributes #[[ATTR16:[0-9]+]] = { argmemonly nofree nosync nounwind willreturn }
; IS__CGSCC____: attributes #[[ATTR17]] = { nounwind willreturn }
diff --git a/llvm/unittests/Analysis/LazyCallGraphTest.cpp b/llvm/unittests/Analysis/LazyCallGraphTest.cpp
index b154c6f29088..d6e73f3a95f2 100644
--- a/llvm/unittests/Analysis/LazyCallGraphTest.cpp
+++ b/llvm/unittests/Analysis/LazyCallGraphTest.cpp
@@ -1978,7 +1978,8 @@ TEST(LazyCallGraphTest, HandleBlockAddress) {
LazyCallGraph::Node &G = *CG.lookup(lookupFunction(*M, "g"));
EXPECT_EQ(&FRC, CG.lookupRefSCC(F));
EXPECT_EQ(&GRC, CG.lookupRefSCC(G));
- EXPECT_TRUE(GRC.isParentOf(FRC));
+ EXPECT_FALSE(GRC.isParentOf(FRC));
+ EXPECT_FALSE(FRC.isParentOf(GRC));
}
// Test that a blockaddress that refers to itself creates no new RefSCC