Skip to content

Commit

Permalink
[LazyCallGraph] Skip blockaddresses
Browse files Browse the repository at this point in the history
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
  • Loading branch information
aeubanks committed Nov 1, 2021
1 parent a82a844 commit 029f1a5
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 64 deletions.
24 changes: 3 additions & 21 deletions llvm/lib/Analysis/LazyCallGraph.cpp
Expand Up @@ -1973,28 +1973,10 @@ void LazyCallGraph::visitReferences(SmallVectorImpl<Constant *> &Worklist,
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)
Expand Down
28 changes: 28 additions & 0 deletions 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
}
Expand Up @@ -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
Expand Down Expand Up @@ -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 }
;.
12 changes: 8 additions & 4 deletions llvm/test/Transforms/Attributor/liveness.ll
Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -2681,7 +2685,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 }
Expand Down
3 changes: 2 additions & 1 deletion llvm/unittests/Analysis/LazyCallGraphTest.cpp
Expand Up @@ -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
Expand Down

0 comments on commit 029f1a5

Please sign in to comment.