[llvm] 0a67e77 - CallGraph: Fix IgnoreAssumeLikeCalls option to Function::hasAddressTaken

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 5 18:42:05 PST 2022


Author: Matt Arsenault
Date: 2022-12-05T21:41:59-05:00
New Revision: 0a67e771f6d21b1232c40f226c4eee48c3527210

URL: https://github.com/llvm/llvm-project/commit/0a67e771f6d21b1232c40f226c4eee48c3527210
DIFF: https://github.com/llvm/llvm-project/commit/0a67e771f6d21b1232c40f226c4eee48c3527210.diff

LOG: CallGraph: Fix IgnoreAssumeLikeCalls option to Function::hasAddressTaken

This was added in 29e2d9461a91b and likely never worked in a useful
way.

The test added for it fails when converted to opaque pointers, since
the lifetime intrinsic now directly uses the address. The code was
only trying to handle a user indirectly through a bitcast
instruction. That would never have been useful; a bitcast of a global
value would be folded to a ConstantExpr cast.

I also don't understand why it was special casing use_empty on the
cast. Relax the check to be either BitCastOperator or
AddrSpaceCastOperator. In practice, BitCastOperator won't appear
today.

I believe the change in parallel_deletion_cg_update is a correct
improvement but I didn't fully follow it. .omp_outlined..0 is used in
a constant expression cast to a call which ends up getting deleted.

Added: 
    

Modified: 
    llvm/lib/IR/Function.cpp
    llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll
    llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 9912e1a9b7eab..792e714b62fc0 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -1876,6 +1876,10 @@ std::optional<Function *> Intrinsic::remangleIntrinsicFunction(Function *F) {
   return NewDecl;
 }
 
+static bool isPointerCastOperator(const User *U) {
+  return isa<AddrSpaceCastOperator>(U) || isa<BitCastOperator>(U);
+}
+
 /// hasAddressTaken - returns true if there are any uses of this function
 /// other than direct calls or invokes to it. Optionally ignores callback
 /// uses, assume like pointer annotation calls, and references in llvm.used
@@ -1897,17 +1901,15 @@ bool Function::hasAddressTaken(const User **PutOffender,
 
     const auto *Call = dyn_cast<CallBase>(FU);
     if (!Call) {
-      if (IgnoreAssumeLikeCalls) {
-        if (const auto *FI = dyn_cast<Instruction>(FU)) {
-          if (FI->isCast() && !FI->user_empty() &&
-              llvm::all_of(FU->users(), [](const User *U) {
-                if (const auto *I = dyn_cast<IntrinsicInst>(U))
-                  return I->isAssumeLikeIntrinsic();
-                return false;
-              }))
-            continue;
-        }
+      if (IgnoreAssumeLikeCalls && isPointerCastOperator(FU) &&
+          all_of(FU->users(), [](const User *U) {
+            if (const auto *I = dyn_cast<IntrinsicInst>(U))
+              return I->isAssumeLikeIntrinsic();
+            return false;
+          })) {
+        continue;
       }
+
       if (IgnoreLLVMUsed && !FU->user_empty()) {
         const User *FUU = FU;
         if (isa<BitCastOperator>(FU) && FU->hasOneUse() &&
@@ -1926,6 +1928,13 @@ bool Function::hasAddressTaken(const User **PutOffender,
         *PutOffender = FU;
       return true;
     }
+
+    if (IgnoreAssumeLikeCalls) {
+      if (const auto *I = dyn_cast<IntrinsicInst>(Call))
+        if (I->isAssumeLikeIntrinsic())
+          continue;
+    }
+
     if (!Call->isCallee(&U) || Call->getFunctionType() != getFunctionType()) {
       if (IgnoreARCAttachedCall &&
           Call->isOperandBundleOfType(LLVMContext::OB_clang_arc_attachedcall,

diff  --git a/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll
index 4bacec43782f2..1c559f2345447 100644
--- a/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll
+++ b/llvm/test/Analysis/CallGraph/ignore-assumelike-calls.ll
@@ -1,26 +1,63 @@
 ; RUN: opt < %s -print-callgraph -disable-output 2>&1 | FileCheck %s
 ; CHECK: Call graph node <<null function>><<{{.*}}>>  #uses=0
-; CHECK-NEXT:   CS<None> calls function 'cast_only'
-; CHECK-NEXT:   CS<None> calls function 'llvm.lifetime.start.p0i8'
+; CHECK-NEXT:   CS<None> calls function 'other_intrinsic_use'
+; CHECK-NEXT:   CS<None> calls function 'other_cast_intrinsic_use'
+; CHECK-NEXT:   CS<None> calls function 'llvm.lifetime.start.p0'
+; CHECK-NEXT:   CS<None> calls function 'llvm.memset.p0.i64'
+; CHECK-NEXT:   CS<None> calls function 'llvm.memset.p1.i64'
 ; CHECK-EMPTY:
-; CHECK-NEXT:   Call graph node for function: 'cast_only'<<{{.*}}>>  #uses=1
+; CHECK-NEXT:   Call graph node for function: 'addrspacecast_only'<<{{.*}}>>  #uses=0
 ; CHECK-EMPTY:
-; CHECK-NEXT:   Call graph node for function: 'llvm.lifetime.start.p0i8'<<{{.*}}>>  #uses=1
+; CHECK-NEXT:   Call graph node for function: 'bitcast_only'<<{{.*}}>>  #uses=0
+; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'llvm.lifetime.start.p0'<<{{.*}}>>  #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'llvm.memset.p0.i64'<<{{.*}}>>  #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'llvm.memset.p1.i64'<<{{.*}}>>  #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'other_cast_intrinsic_use'<<{{.*}}>>  #uses=1
+; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'other_intrinsic_use'<<{{.*}}>>  #uses=1
 ; CHECK-EMPTY:
 ; CHECK-NEXT:   Call graph node for function: 'used_by_lifetime'<<{{.*}}>>  #uses=0
 ; CHECK-EMPTY:
+; CHECK-NEXT:   Call graph node for function: 'used_by_lifetime_cast'<<{{.*}}>>  #uses=0
+; CHECK-EMPTY:
 
 define internal void @used_by_lifetime() {
 entry:
-  %c = bitcast void()* @used_by_lifetime to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %c)
+  call void @llvm.lifetime.start.p0(i64 4, ptr @used_by_lifetime)
   ret void
 }
 
-define internal void @cast_only() {
+define internal void @used_by_lifetime_cast() addrspace(1) {
+  call void @llvm.lifetime.start.p0(i64 4, ptr addrspacecast (ptr addrspace(1) @used_by_lifetime_cast to ptr))
+  ret void
+}
+
+define internal void @bitcast_only() {
 entry:
-  %c = bitcast void()* @cast_only to i8*
+  %c = bitcast ptr @bitcast_only to ptr
+  ret void
+}
+
+define internal void @addrspacecast_only() addrspace(1) {
+entry:
+  %c = addrspacecast ptr addrspace(1) @addrspacecast_only to ptr
+  ret void
+}
+
+define internal void @other_intrinsic_use() {
+  call void @llvm.memset.p0.i64(ptr @other_intrinsic_use, i8 0, i64 1024, i1 false)
+  ret void
+}
+
+define internal void @other_cast_intrinsic_use() {
+  call void @llvm.memset.p1.i64(ptr addrspace(1) addrspacecast (ptr @other_cast_intrinsic_use to ptr addrspace(1)), i8 0, i64 1024, i1 false)
   ret void
 }
 
-declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
+declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
+declare void @llvm.memset.p0.i64(ptr, i8, i64, i1 immarg)
+declare void @llvm.memset.p1.i64(ptr addrspace(1), i8, i64, i1 immarg)

diff  --git a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
index 3e3efee594ec4..17db5d08dbad1 100644
--- a/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
+++ b/llvm/test/Transforms/OpenMP/parallel_deletion_cg_update.ll
@@ -1,15 +1,14 @@
 ; RUN: opt < %s -passes='function(instcombine),cgscc(attributor-cgscc),print-callgraph' -disable-output 2>&1 | FileCheck %s
 
 ; CHECK: Call graph node <<null function>><<{{.*}}>>  #uses=0
-; CHECK:   CS<None> calls function 'dead_fork_call'
-; CHECK:   CS<None> calls function '.omp_outlined..0'
-; CHECK:   CS<None> calls function '__kmpc_fork_call'
-; CHECK:   CS<None> calls function 'live_fork_call'
-; CHECK:   CS<None> calls function '.omp_outlined..1'
-; CHECK:   CS<None> calls function 'd'
+; CHECK-NEXT:   CS<None> calls function 'dead_fork_call'
+; CHECK-NEXT:   CS<None> calls function '__kmpc_fork_call'
+; CHECK-NEXT:   CS<None> calls function 'live_fork_call'
+; CHECK-NEXT:   CS<None> calls function '.omp_outlined..1'
+; CHECK-NEXT:   CS<None> calls function 'd'
+;
+; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>>  #uses=0
 ;
-; CHECK: Call graph node for function: '.omp_outlined..0'<<{{.*}}>>  #uses=1
-; 
 ; CHECK: Call graph node for function: '.omp_outlined..1'<<{{.*}}>>  #uses=3
 ; CHECK:   CS<{{.*}}> calls function 'd'
 ;


        


More information about the llvm-commits mailing list