[llvm] 86509e8 - [Attributor] Use assumed information to determine side-effects

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 12 15:39:37 PST 2020


Author: Johannes Doerfert
Date: 2020-02-12T17:36:38-06:00
New Revision: 86509e8c3b846ec8f5264be8b3f53a4bef8e83e8

URL: https://github.com/llvm/llvm-project/commit/86509e8c3b846ec8f5264be8b3f53a4bef8e83e8
DIFF: https://github.com/llvm/llvm-project/commit/86509e8c3b846ec8f5264be8b3f53a4bef8e83e8.diff

LOG: [Attributor] Use assumed information to determine side-effects

We relied on wouldInstructionBeTriviallyDead before but that functions
does not take assumed information, especially for calls, into account.
The replacement, AAIsDead::isAssumeSideEffectFree, does.

This change makes AAIsDeadCallSiteReturn more complex as we can have
a dead call or only dead users.

The test have been modified to include a side effect where there was
none in order to keep the coverage.

Reviewed By: sstefan1

Differential Revision: https://reviews.llvm.org/D73311

Added: 
    

Modified: 
    llvm/lib/Transforms/IPO/Attributor.cpp
    llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
    llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll
    llvm/test/Transforms/Attributor/align.ll
    llvm/test/Transforms/Attributor/liveness.ll
    llvm/test/Transforms/Attributor/misc.ll
    llvm/test/Transforms/Attributor/noalias.ll
    llvm/test/Transforms/Attributor/nonnull.ll
    llvm/test/Transforms/Attributor/noreturn_async.ll
    llvm/test/Transforms/Attributor/noreturn_sync.ll
    llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
    llvm/test/Transforms/Attributor/willreturn.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 86968d1f7761..1d0e82c45d88 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -2820,29 +2820,16 @@ struct AAIsDeadValueImpl : public AAIsDead {
 
   /// See AAIsDead::isKnownDead(Instruction *I).
   bool isKnownDead(const Instruction *I) const override {
-    return I == getCtxI() && getKnown();
+    return isAssumedDead(I) && getKnown();
   }
 
   /// See AbstractAttribute::getAsStr().
   const std::string getAsStr() const override {
     return isAssumedDead() ? "assumed-dead" : "assumed-live";
   }
-};
-
-struct AAIsDeadFloating : public AAIsDeadValueImpl {
-  AAIsDeadFloating(const IRPosition &IRP) : AAIsDeadValueImpl(IRP) {}
 
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {
-    if (Instruction *I = dyn_cast<Instruction>(&getAssociatedValue()))
-      if (!wouldInstructionBeTriviallyDead(I))
-        indicatePessimisticFixpoint();
-    if (isa<UndefValue>(getAssociatedValue()))
-      indicatePessimisticFixpoint();
-  }
-
-  /// See AbstractAttribute::updateImpl(...).
-  ChangeStatus updateImpl(Attributor &A) override {
+  /// Check if all uses are assumed dead.
+  bool areAllUsesAssumedDead(Attributor &A) {
     auto UsePred = [&](const Use &U, bool &Follow) {
       Instruction *UserI = cast<Instruction>(U.getUser());
       if (CallSite CS = CallSite(UserI)) {
@@ -2862,7 +2849,53 @@ struct AAIsDeadFloating : public AAIsDeadValueImpl {
       return wouldInstructionBeTriviallyDead(UserI);
     };
 
-    if (!A.checkForAllUses(UsePred, *this, getAssociatedValue()))
+    return A.checkForAllUses(UsePred, *this, getAssociatedValue());
+  }
+
+  /// Determine if \p I is assumed to be side-effect free.
+  bool isAssumedSideEffectFree(Attributor &A, Instruction *I) {
+    if (!I || wouldInstructionBeTriviallyDead(I))
+      return true;
+
+    auto *CB = dyn_cast<CallBase>(I);
+    if (!CB || isa<IntrinsicInst>(CB))
+      return false;
+
+    const IRPosition &CallIRP = IRPosition::callsite_function(*CB);
+    const auto &NoUnwindAA = A.getAAFor<AANoUnwind>(*this, CallIRP);
+    if (!NoUnwindAA.isAssumedNoUnwind())
+      return false;
+
+    const auto &MemBehaviorAA = A.getAAFor<AAMemoryBehavior>(*this, CallIRP);
+    if (!MemBehaviorAA.isAssumedReadOnly())
+      return false;
+
+    return true;
+  }
+};
+
+struct AAIsDeadFloating : public AAIsDeadValueImpl {
+  AAIsDeadFloating(const IRPosition &IRP) : AAIsDeadValueImpl(IRP) {}
+
+  /// See AbstractAttribute::initialize(...).
+  void initialize(Attributor &A) override {
+    if (isa<UndefValue>(getAssociatedValue())) {
+      indicatePessimisticFixpoint();
+      return;
+    }
+
+    Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());
+    if (!isAssumedSideEffectFree(A, I))
+      indicatePessimisticFixpoint();
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  ChangeStatus updateImpl(Attributor &A) override {
+    Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());
+    if (!isAssumedSideEffectFree(A, I))
+      return indicatePessimisticFixpoint();
+
+    if (!areAllUsesAssumedDead(A))
       return indicatePessimisticFixpoint();
     return ChangeStatus::UNCHANGED;
   }
@@ -2870,12 +2903,16 @@ struct AAIsDeadFloating : public AAIsDeadValueImpl {
   /// See AbstractAttribute::manifest(...).
   ChangeStatus manifest(Attributor &A) override {
     Value &V = getAssociatedValue();
-    if (auto *I = dyn_cast<Instruction>(&V))
-      if (wouldInstructionBeTriviallyDead(I)) {
+    if (auto *I = dyn_cast<Instruction>(&V)) {
+      // If we get here we basically know the users are all dead. We check if
+      // isAssumedSideEffectFree returns true here again because it might not be
+      // the case and only the users are dead but the instruction (=call) is
+      // still needed.
+      if (isAssumedSideEffectFree(A, I) && !isa<InvokeInst>(I)) {
         A.deleteAfterManifest(*I);
         return ChangeStatus::CHANGED;
       }
-
+    }
     if (V.use_empty())
       return ChangeStatus::UNCHANGED;
 
@@ -2956,6 +2993,69 @@ struct AAIsDeadCallSiteArgument : public AAIsDeadValueImpl {
   void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(IsDead) }
 };
 
+struct AAIsDeadCallSiteReturned : public AAIsDeadFloating {
+  AAIsDeadCallSiteReturned(const IRPosition &IRP)
+      : AAIsDeadFloating(IRP), IsAssumedSideEffectFree(true) {}
+
+  /// See AAIsDead::isAssumedDead().
+  bool isAssumedDead() const override {
+    return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;
+  }
+
+  /// Return true if all users are assumed dead.
+  bool hasOnlyAssumedDeadUses() const { return getAssumed(); }
+
+  /// See AbstractAttribute::initialize(...).
+  void initialize(Attributor &A) override {
+    if (isa<UndefValue>(getAssociatedValue())) {
+      indicatePessimisticFixpoint();
+      return;
+    }
+
+    // We track this separately as a secondary state.
+    IsAssumedSideEffectFree = isAssumedSideEffectFree(A, getCtxI());
+  }
+
+  /// See AbstractAttribute::updateImpl(...).
+  ChangeStatus updateImpl(Attributor &A) override {
+    ChangeStatus Changed = ChangeStatus::UNCHANGED;
+    if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(A, getCtxI())) {
+      IsAssumedSideEffectFree = false;
+      Changed = ChangeStatus::CHANGED;
+    }
+
+    if (!areAllUsesAssumedDead(A))
+      return indicatePessimisticFixpoint();
+    return Changed;
+  }
+
+  /// See AbstractAttribute::manifest(...).
+  ChangeStatus manifest(Attributor &A) override {
+    if (auto *CI = dyn_cast<CallInst>(&getAssociatedValue()))
+      if (CI->isMustTailCall())
+        return ChangeStatus::UNCHANGED;
+    return AAIsDeadFloating::manifest(A);
+  }
+
+  /// See AbstractAttribute::trackStatistics()
+  void trackStatistics() const override {
+    if (IsAssumedSideEffectFree)
+      STATS_DECLTRACK_CSRET_ATTR(IsDead)
+    else
+      STATS_DECLTRACK_CSRET_ATTR(UnusedResult)
+  }
+
+  /// See AbstractAttribute::getAsStr().
+  const std::string getAsStr() const override {
+    return isAssumedDead()
+               ? "assumed-dead"
+               : (getAssumed() ? "assumed-dead-users" : "assumed-live");
+  }
+
+private:
+  bool IsAssumedSideEffectFree;
+};
+
 struct AAIsDeadReturned : public AAIsDeadValueImpl {
   AAIsDeadReturned(const IRPosition &IRP) : AAIsDeadValueImpl(IRP) {}
 
@@ -2970,7 +3070,8 @@ struct AAIsDeadReturned : public AAIsDeadValueImpl {
           IRPosition::callsite_returned(ACS.getCallSite());
       const auto &RetIsDeadAA = A.getAAFor<AAIsDead>(*this, CSRetPos);
       AllKnownDead &= RetIsDeadAA.isKnownDead();
-      return RetIsDeadAA.isAssumedDead();
+      return static_cast<const AAIsDeadCallSiteReturned &>(RetIsDeadAA)
+          .hasOnlyAssumedDeadUses();
     };
 
     bool AllCallSitesKnown;
@@ -3003,16 +3104,6 @@ struct AAIsDeadReturned : public AAIsDeadValueImpl {
   void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(IsDead) }
 };
 
-struct AAIsDeadCallSiteReturned : public AAIsDeadFloating {
-  AAIsDeadCallSiteReturned(const IRPosition &IRP) : AAIsDeadFloating(IRP) {}
-
-  /// See AbstractAttribute::initialize(...).
-  void initialize(Attributor &A) override {}
-
-  /// See AbstractAttribute::trackStatistics()
-  void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(IsDead) }
-};
-
 struct AAIsDeadFunction : public AAIsDead {
   AAIsDeadFunction(const IRPosition &IRP) : AAIsDead(IRP) {}
 
@@ -7530,6 +7621,12 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
 
   auto CallSitePred = [&](Instruction &I) -> bool {
     CallSite CS(&I);
+    IRPosition CSRetPos = IRPosition::callsite_returned(CS);
+
+    // Call sites might be dead if they do not have side effects and no live
+    // users. The return value might be dead if there are no live users.
+    getOrCreateAAFor<AAIsDead>(CSRetPos);
+
     if (Function *Callee = CS.getCalledFunction()) {
       // Skip declerations except if annotations on their call sites were
       // explicitly requested.
@@ -7541,13 +7638,9 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) {
 
         IRPosition CSRetPos = IRPosition::callsite_returned(CS);
 
-        // Call site return values might be dead.
-        getOrCreateAAFor<AAIsDead>(CSRetPos);
-
         // Call site return integer values might be limited by a constant range.
-        if (Callee->getReturnType()->isIntegerTy()) {
+        if (Callee->getReturnType()->isIntegerTy())
           getOrCreateAAFor<AAValueConstantRange>(CSRetPos);
-        }
       }
 
       for (int i = 0, e = CS.getNumArgOperands(); i < e; i++) {

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
index a76a1c9578fd..94dad3737ba9 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
@@ -21,8 +21,10 @@ define internal void @test(i32** %X) !dbg !2 {
 
 define internal void @test_byval(%struct.pair* byval %P) {
 ; CHECK-LABEL: define {{[^@]+}}@test_byval()
+; CHECK-NEXT:    call void @sink(i32 0)
 ; CHECK-NEXT:    ret void
 ;
+  call void @sink(i32 0)
   ret void
 }
 

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
index 8ce8789bb8cc..b637d39a50de 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
@@ -31,8 +31,12 @@ define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture rea
 ; CHECK-LABEL: define {{[^@]+}}@callee_t0f
 ; CHECK-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...)
 ; CHECK-NEXT:  entry:
+; CHECK-NEXT:    call void @sink(i32 0)
 ; CHECK-NEXT:    ret void
 ;
 entry:
+  call void @sink(i32 0)
   ret void
 }
+
+declare void @sink(i32)

diff  --git a/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll b/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll
index ddb0e4430210..3a3f0fe210f5 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/multiple_callbacks.ll
@@ -60,7 +60,6 @@ define internal i32 @cb2(i32 %unknown) {
 ; CHECK-LABEL: define {{[^@]+}}@cb2
 ; CHECK-SAME: (i32 returned [[UNKNOWN:%.*]])
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CALL:%.*]] = call i32 @cb0(i32 0)
 ; CHECK-NEXT:    ret i32 [[UNKNOWN]]
 ;
 entry:
@@ -91,8 +90,6 @@ entry:
 define void @foo() {
 ; CHECK-LABEL: define {{[^@]+}}@foo()
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CALL:%.*]] = call i32 @cb0(i32 0)
-; CHECK-NEXT:    [[CALL1:%.*]] = call i32 @cb3(i32 1)
 ; CHECK-NEXT:    call void @broker(i32 (i32)* nonnull @cb0, i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb0, i32 0, i32 1)
 ; CHECK-NEXT:    call void @broker(i32 (i32)* nonnull @cb1, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb2, i32 0, i32 1)
 ; CHECK-NEXT:    call void @broker(i32 (i32)* nonnull @cb3, i32 (i32)* nonnull @cb2, i32 (i32)* nonnull @cb3, i32 0, i32 1)

diff  --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll
index 3d4a761d0812..baa7fe9cb70c 100644
--- a/llvm/test/Transforms/Attributor/align.ll
+++ b/llvm/test/Transforms/Attributor/align.ll
@@ -1,8 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes --turn off
-; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
-; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
-; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
-; RUN: opt -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
+; RUN: opt -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
+; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
+; RUN: opt -passes=attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_MODULE
+; RUN: opt -passes=attributor-cgscc -attributor-manifest-internal -attributor-disable=false -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ATTRIBUTOR_CGSCC
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -137,18 +137,18 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
 
 ; TEST 7
 ; Better than IR information
-define align 4 i32* @test7(i32* align 32 %p) #0 {
+define align 4 i8* @test7() #0 {
 ; ATTRIBUTOR_MODULE-LABEL: define {{[^@]+}}@test7
-; ATTRIBUTOR_MODULE-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
-; ATTRIBUTOR_MODULE-NEXT:    ret i32* [[P]]
+; ATTRIBUTOR_MODULE-NEXT:    [[C:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
+; ATTRIBUTOR_MODULE-NEXT:    ret i8* [[C]]
 ;
 ; ATTRIBUTOR_CGSCC-LABEL: define {{[^@]+}}@test7
-; ATTRIBUTOR_CGSCC-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]])
-; ATTRIBUTOR_CGSCC-NEXT:    [[TMP1:%.*]] = tail call i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
-; ATTRIBUTOR_CGSCC-NEXT:    ret i32* [[P]]
+; ATTRIBUTOR_CGSCC-SAME: ()
+; ATTRIBUTOR_CGSCC-NEXT:    [[C:%.*]] = tail call nonnull align 8 dereferenceable(1) i8* @f1(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1)
+; ATTRIBUTOR_CGSCC-NEXT:    ret i8* [[C]]
 ;
-  tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
-  ret i32* %p
+  %c = tail call i8* @f1(i8* align 8 dereferenceable(1) @a1)
+  ret i8* %c
 }
 
 ; TEST 7b
@@ -281,7 +281,7 @@ define void @test8_helper() {
   ret void
 }
 
-declare void @user_i32_ptr(i32*) readnone nounwind
+declare void @user_i32_ptr(i32* nocapture readnone) nounwind
 define internal void @test8(i32* %a, i32* %b, i32* %c) {
 ; ATTRIBUTOR_MODULE: define internal void @test8(i32* noalias nocapture readnone align 4 %a, i32* noalias nocapture readnone align 4 %b, i32* noalias nocapture readnone %c)
 ; ATTRIBUTOR_CGSCC: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c)

diff  --git a/llvm/test/Transforms/Attributor/liveness.ll b/llvm/test/Transforms/Attributor/liveness.ll
index 92142f06d4ee..cbd5484e9797 100644
--- a/llvm/test/Transforms/Attributor/liveness.ll
+++ b/llvm/test/Transforms/Attributor/liveness.ll
@@ -8,7 +8,7 @@
 ; ALL_BUT_OLD_CGSCCC: @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* inttoptr (i32 1 to i8*), i8* inttoptr (i32 1 to i8*)]
 @dead_with_blockaddress_users.l = constant [2 x i8*] [i8* blockaddress(@dead_with_blockaddress_users, %lab0), i8* blockaddress(@dead_with_blockaddress_users, %end)]
 
-declare void @no_return_call() nofree noreturn nounwind readnone
+declare void @no_return_call() nofree noreturn nounwind nosync
 
 declare void @normal_call() readnone
 
@@ -547,9 +547,11 @@ define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
 declare void @sink() nofree nosync nounwind willreturn
 define void @test_unreachable() {
 ; CHECK:       define void @test_unreachable()
+; CHECK-NEXT:    call void @sink()
 ; CHECK-NEXT:    call void @test_unreachable()
 ; CHECK-NEXT:    unreachable
 ; CHECK-NEXT:  }
+  call void @sink()
   call void @test_unreachable()
   unreachable
 }
@@ -664,70 +666,262 @@ define linkonce_odr void @non_exact3() {
 ; CHECK-NEXT:   %nr = call i32 @foo_noreturn()
 ; CHECK-NEXT:   unreachable
 
-define internal void @non_dead_a0() { ret void }
-define internal void @non_dead_a1() { ret void }
-define internal void @non_dead_a2() { ret void }
-define internal void @non_dead_a3() { ret void }
-define internal void @non_dead_a4() { ret void }
-define internal void @non_dead_a5() { ret void }
-define internal void @non_dead_a6() { ret void }
-define internal void @non_dead_a7() { ret void }
-define internal void @non_dead_a8() { ret void }
-define internal void @non_dead_a9() { ret void }
-define internal void @non_dead_a10() { ret void }
-define internal void @non_dead_a11() { ret void }
-define internal void @non_dead_a12() { ret void }
-define internal void @non_dead_a13() { ret void }
-define internal void @non_dead_a14() { ret void }
-define internal void @non_dead_a15() { ret void }
-define internal void @non_dead_b0() { ret void }
-define internal void @non_dead_b1() { ret void }
-define internal void @non_dead_b2() { ret void }
-define internal void @non_dead_b3() { ret void }
-define internal void @non_dead_b4() { ret void }
-define internal void @non_dead_b5() { ret void }
-define internal void @non_dead_b6() { ret void }
-define internal void @non_dead_b7() { ret void }
-define internal void @non_dead_b8() { ret void }
-define internal void @non_dead_b9() { ret void }
-define internal void @non_dead_b10() { ret void }
-define internal void @non_dead_b11() { ret void }
-define internal void @non_dead_b12() { ret void }
-define internal void @non_dead_b13() { ret void }
-define internal void @non_dead_b14() { ret void }
-define internal void @non_dead_b15() { ret void }
-define internal void @non_dead_c0() { ret void }
-define internal void @non_dead_c1() { ret void }
-define internal void @non_dead_c2() { ret void }
-define internal void @non_dead_c3() { ret void }
-define internal void @non_dead_c4() { ret void }
-define internal void @non_dead_c5() { ret void }
-define internal void @non_dead_c6() { ret void }
-define internal void @non_dead_c7() { ret void }
-define internal void @non_dead_c8() { ret void }
-define internal void @non_dead_c9() { ret void }
-define internal void @non_dead_c10() { ret void }
-define internal void @non_dead_c11() { ret void }
-define internal void @non_dead_c12() { ret void }
-define internal void @non_dead_c13() { ret void }
-define internal void @non_dead_c14() { ret void }
-define internal void @non_dead_c15() { ret void }
-define internal void @non_dead_d0() { ret void }
-define internal void @non_dead_d1() { ret void }
-define internal void @non_dead_d2() { ret void }
-define internal void @non_dead_d3() { ret void }
-define internal void @non_dead_d4() { ret void }
-define internal void @non_dead_d5() { ret void }
-define internal void @non_dead_d6() { ret void }
-define internal void @non_dead_d7() { ret void }
-define internal void @non_dead_d8() { ret void }
-define internal void @non_dead_d9() { ret void }
-define internal void @non_dead_d10() { ret void }
-define internal void @non_dead_d11() { ret void }
-define internal void @non_dead_d12() { ret void }
-define internal void @non_dead_d13() { ret void }
-define internal void @non_dead_d14() { ret void }
-define internal void @non_dead_d15() { ret void }
+define internal void @non_dead_a0() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a1() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a2() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a3() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a4() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a5() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a6() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a7() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a8() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a9() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a10() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a11() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a12() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a13() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a14() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_a15() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b0() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b1() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b2() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b3() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b4() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b5() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b6() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b7() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b8() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b9() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b10() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b11() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b12() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b13() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b14() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_b15() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c0() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c1() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c2() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c3() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c4() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c5() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c6() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c7() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c8() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c9() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c10() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c11() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c12() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c13() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c14() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_c15() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d0() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d1() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d2() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d3() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d4() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d5() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d6() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d7() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d8() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d9() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d10() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d11() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d12() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d13() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d14() {
+  call void @sink()
+  ret void
+}
+define internal void @non_dead_d15() {
+  call void @sink()
+  ret void
+}
 define internal void @dead_e0() { call void @dead_e1() ret void }
 define internal void @dead_e1() { call void @dead_e2() ret void }
 define internal void @dead_e2() { ret void }
@@ -796,10 +990,10 @@ define internal void @dead_e2() { ret void }
 ; CHECK: define internal void @non_dead_d13()
 ; CHECK: define internal void @non_dead_d14()
 ; Verify we actually deduce information for these functions.
-; MODULE: Function Attrs: nofree nosync nounwind readnone willreturn
+; MODULE: Function Attrs: nofree nosync nounwind willreturn
 ; MODULE-NEXT: define internal void @non_dead_d15()
 ; MODULE-NOT: define internal void @dead_e
-; CGSCC: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CGSCC: Function Attrs: nofree nosync nounwind willreturn
 ; CGSCC-NEXT: define internal void @non_dead_d15()
 
 declare void @blowup() noreturn
@@ -860,6 +1054,7 @@ live_with_dead_entry:
 ; MODULE: define internal void @useless_arg_sink()
 ; CGSCC: define internal void @useless_arg_sink(i32*{{.*}} %a)
 define internal void @useless_arg_sink(i32* %a) {
+  call void @sink()
   ret void
 }
 
@@ -867,7 +1062,7 @@ define internal void @useless_arg_sink(i32* %a) {
 ; CGSCC: define internal void @useless_arg_almost_sink(i32*{{.*}} %a)
 define internal void @useless_arg_almost_sink(i32* %a) {
 ; MODULE: call void @useless_arg_sink()
-; CGSCC: call void @useless_arg_sink(i32* noalias nofree readnone %a)
+; CGSCC: call void @useless_arg_sink(i32* noalias nocapture nofree readnone %a)
   call void @useless_arg_sink(i32* %a)
   ret void
 }

diff  --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll
index 4fdb0bc280d3..cb7757915232 100644
--- a/llvm/test/Transforms/Attributor/misc.ll
+++ b/llvm/test/Transforms/Attributor/misc.ll
@@ -10,7 +10,7 @@ define internal void @internal(void (i8*)* %fp) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; CHECK-NEXT:    [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; CHECK-NEXT:    call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
+; CHECK-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; CHECK-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; CHECK-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; CHECK-NEXT:    call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
@@ -24,7 +24,7 @@ define internal void @internal(void (i8*)* %fp) {
 ; DECL_CS-NEXT:  entry:
 ; DECL_CS-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; DECL_CS-NEXT:    [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; DECL_CS-NEXT:    call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
+; DECL_CS-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; DECL_CS-NEXT:    call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
 ; DECL_CS-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
@@ -52,7 +52,7 @@ define void @external(void (i8*)* %fp) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; CHECK-NEXT:    [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; CHECK-NEXT:    call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
+; CHECK-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; CHECK-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; CHECK-NEXT:    call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*))
 ; CHECK-NEXT:    call void @callback2(void (i8*)* [[FP]])
@@ -67,7 +67,7 @@ define void @external(void (i8*)* %fp) {
 ; DECL_CS-NEXT:  entry:
 ; DECL_CS-NEXT:    [[A:%.*]] = alloca i32, align 4
 ; DECL_CS-NEXT:    [[TMP:%.*]] = bitcast i32* [[A]] to i8*
-; DECL_CS-NEXT:    call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef)
+; DECL_CS-NEXT:    call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]])
 ; DECL_CS-NEXT:    call void @callback1(void (i32*)* nonnull @foo)
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*))
 ; DECL_CS-NEXT:    call void @callback2(void (i8*)* [[FP]])
@@ -93,11 +93,13 @@ entry:
 
 define internal void @foo(i32* %a) {
 ; ALL-LABEL: define {{[^@]+}}@foo
-; ALL-SAME: (i32* nocapture nofree readnone [[A:%.*]])
+; ALL-SAME: (i32* nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]])
 ; ALL-NEXT:  entry:
+; ALL-NEXT:    store i32 0, i32* %a
 ; ALL-NEXT:    ret void
 ;
 entry:
+  store i32 0, i32* %a
   ret void
 }
 

diff  --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll
index 0e95d546ea95..14b9fd0e7200 100644
--- a/llvm/test/Transforms/Attributor/noalias.ll
+++ b/llvm/test/Transforms/Attributor/noalias.ll
@@ -162,6 +162,7 @@ define i8* @test8(i32* %0) nounwind uwtable {
 declare void @use_i8(i8* nocapture)
 define internal void @test9a(i8* %a, i8* %b) {
 ; CHECK: define internal void @test9a()
+  call void @use_i8(i8* null)
   ret void
 }
 define internal void @test9b(i8* %a, i8* %b) {

diff  --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index f11f3941aaa8..fbbf0388b323 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -165,7 +165,7 @@ define void @test13_helper() {
   tail call void @test13(i8* %nonnullptr, i8* %maybenullptr, i8* %nonnullptr)
   ret void
 }
-declare void @use_i8_ptr(i8* nofree) readnone nounwind
+declare void @use_i8_ptr(i8* nofree nocapture readnone) nounwind
 define internal void @test13(i8* %a, i8* %b, i8* %c) {
 ; ATTRIBUTOR: define internal void @test13(i8* noalias nocapture nofree nonnull readnone %a, i8* noalias nocapture nofree readnone %b, i8* noalias nocapture nofree readnone %c)
   call void @use_i8_ptr(i8* %a)
@@ -537,7 +537,7 @@ define i32* @g1() {
   ret i32* %c
 }
 
-declare void @use_i32_ptr(i32*) readnone nounwind
+declare void @use_i32_ptr(i32* readnone nocapture) nounwind
 ; ATTRIBUTOR: define internal void @called_by_weak(i32* noalias nocapture nonnull readnone %a)
 define internal void @called_by_weak(i32* %a) {
   call void @use_i32_ptr(i32* %a)

diff  --git a/llvm/test/Transforms/Attributor/noreturn_async.ll b/llvm/test/Transforms/Attributor/noreturn_async.ll
index 9fb99159acf5..de33360d8237 100644
--- a/llvm/test/Transforms/Attributor/noreturn_async.ll
+++ b/llvm/test/Transforms/Attributor/noreturn_async.ll
@@ -1,4 +1,4 @@
-; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
+; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
 ;
 ; This file is the same as noreturn_sync.ll but with a personality which
 ; indicates that the exception handler *can* catch asynchronous exceptions. As
@@ -25,8 +25,10 @@ entry:
 ; CHECK:      Function Attrs: nofree noreturn nosync nounwind
 ; CHECK-NEXT: define
 ; CHECK-NEXT:   entry:
+; CHECK-NEXT:   {{.*}}@printf{{.*}}
 ; CHECK-NEXT:   call void @"?overflow@@YAXXZ"()
 ; CHECK-NEXT:   unreachable
+  %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C at _0BC@NKPAGFFJ at Exception?5caught?6?$AA@", i64 0, i64 0)) nofree nosync nounwind
   call void @"?overflow@@YAXXZ"()
   %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C at _0BC@NKPAGFFJ at Exception?5caught?6?$AA@", i64 0, i64 0))
   ret void

diff  --git a/llvm/test/Transforms/Attributor/noreturn_sync.ll b/llvm/test/Transforms/Attributor/noreturn_sync.ll
index 4e6f13737a7e..cba1faacb036 100644
--- a/llvm/test/Transforms/Attributor/noreturn_sync.ll
+++ b/llvm/test/Transforms/Attributor/noreturn_sync.ll
@@ -1,4 +1,4 @@
-; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s
+; RUN: opt -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s
 ;
 ; This file is the same as noreturn_async.ll but with a personality which
 ; indicates that the exception handler *cannot* catch asynchronous exceptions.
@@ -25,8 +25,10 @@ entry:
 ; CHECK:      Function Attrs: nofree noreturn nosync nounwind
 ; CHECK-NEXT: define
 ; CHECK-NEXT:   entry:
+; CHECK-NEXT:   {{.*}}@printf{{.*}}
 ; CHECK-NEXT:   call void @"?overflow@@YAXXZ"()
 ; CHECK-NEXT:   unreachable
+  %call2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C at _0BC@NKPAGFFJ at Exception?5caught?6?$AA@", i64 0, i64 0)) nofree nosync nounwind
   call void @"?overflow@@YAXXZ"()
   %call3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"??_C at _0BC@NKPAGFFJ at Exception?5caught?6?$AA@", i64 0, i64 0))
   ret void

diff  --git a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
index 72d062b76161..21033beacacb 100644
--- a/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
+++ b/llvm/test/Transforms/Attributor/read_write_returned_arguments_scc.ll
@@ -161,5 +161,5 @@ entry:
 ; CHECK-NOT: attributes #
 ; CHECK: attributes #{{.*}} = { nofree nosync nounwind }
 ; CHECK: attributes #{{.*}} = { nofree norecurse nosync nounwind }
-; CHECK: attributes #{{.*}} = { nosync }
+; CHECK: attributes #{{.*}} = { nosync nounwind }
 ; CHECK-NOT: attributes #

diff  --git a/llvm/test/Transforms/Attributor/willreturn.ll b/llvm/test/Transforms/Attributor/willreturn.ll
index 12b79a4d009f..4cea09b94063 100644
--- a/llvm/test/Transforms/Attributor/willreturn.ll
+++ b/llvm/test/Transforms/Attributor/willreturn.ll
@@ -117,12 +117,15 @@ define i32 @fact_loop(i32 %0) local_unnamed_addr #0 {
 ;     mutual_recursion1();
 ; }
 
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+declare void @sink() nounwind willreturn nosync nofree
+
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NOT: willreturn
 ; ATTRIBUTOR-NEXT: define void @mutual_recursion1(i1 %c)
 define void @mutual_recursion1(i1 %c) #0 {
   br i1 %c, label %rec, label %end
 rec:
+  call void @sink()
   call void @mutual_recursion2(i1 %c)
   br label %end
 end:
@@ -130,7 +133,7 @@ end:
 }
 
 
-; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind readnone uwtable
+; ATTRIBUTOR: Function Attrs: nofree noinline nosync nounwind uwtable
 ; ATTRIBUTOR-NOT: willreturn
 ; ATTRIBUTOR-NEXT: define void @mutual_recursion2(i1 %c)
 define void @mutual_recursion2(i1 %c) #0 {


        


More information about the llvm-commits mailing list