[llvm] 62f7888 - [Attributor] Dominating must-write accesses allow unknown initial values

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 21 21:09:37 PDT 2022


Author: Johannes Doerfert
Date: 2022-07-21T23:08:43-05:00
New Revision: 62f7888d6d9d98481a1373db1d7804b49c69ec12

URL: https://github.com/llvm/llvm-project/commit/62f7888d6d9d98481a1373db1d7804b49c69ec12
DIFF: https://github.com/llvm/llvm-project/commit/62f7888d6d9d98481a1373db1d7804b49c69ec12.diff

LOG: [Attributor] Dominating must-write accesses allow unknown initial values

If we have a dominating must-write access we do not need to know the
initial value of some object to perform reasoning about the potential
values. The dominating must-write has overwritten the initial value.

Added: 
    

Modified: 
    llvm/include/llvm/Transforms/IPO/Attributor.h
    llvm/lib/Transforms/IPO/Attributor.cpp
    llvm/lib/Transforms/IPO/AttributorAttributes.cpp
    llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll
    llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
    llvm/test/Transforms/Attributor/internal-noalias.ll
    llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
    llvm/test/Transforms/Attributor/wrapper.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index adfd0bc0556ca..d8b671f45bca4 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -4913,19 +4913,36 @@ struct AAPointerInfo : public AbstractAttribute {
   AAPointerInfo(const IRPosition &IRP) : AbstractAttribute(IRP) {}
 
   enum AccessKind {
-    AK_READ = 1 << 0,
-    AK_WRITE = 1 << 1,
-    AK_READ_WRITE = AK_READ | AK_WRITE,
+    // First two bits to distinguish may and must accesses
+    AK_MUST = 1 << 0,
+    AK_MAY = 1 << 1,
+
+    // Then two bits for read and write. These are not exclusive.
+    AK_R = 1 << 2,
+    AK_W = 1 << 3,
+    AK_RW = AK_R | AK_W,
+
+    // Helper for easy access.
+    AK_MAY_READ = AK_MAY | AK_R,
+    AK_MAY_WRITE = AK_MAY | AK_W,
+    AK_MAY_READ_WRITE = AK_MAY | AK_R | AK_W,
+    AK_MUST_READ = AK_MUST | AK_R,
+    AK_MUST_WRITE = AK_MUST | AK_W,
+    AK_MUST_READ_WRITE = AK_MUST | AK_R | AK_W,
   };
 
   /// An access description.
   struct Access {
     Access(Instruction *I, Optional<Value *> Content, AccessKind Kind, Type *Ty)
-        : LocalI(I), RemoteI(I), Content(Content), Kind(Kind), Ty(Ty) {}
+        : LocalI(I), RemoteI(I), Content(Content), Kind(Kind), Ty(Ty) {
+      verify();
+    }
     Access(Instruction *LocalI, Instruction *RemoteI, Optional<Value *> Content,
            AccessKind Kind, Type *Ty)
         : LocalI(LocalI), RemoteI(RemoteI), Content(Content), Kind(Kind),
-          Ty(Ty) {}
+          Ty(Ty) {
+      verify();
+    }
     Access(const Access &Other) = default;
     Access(const Access &&Other)
         : LocalI(Other.LocalI), RemoteI(Other.RemoteI), Content(Other.Content),
@@ -4946,14 +4963,22 @@ struct AAPointerInfo : public AbstractAttribute {
       return *this;
     }
 
+    void verify() {
+      assert(isMustAccess() + isMayAccess() == 1 &&
+             "Expect must or may access, not both.");
+    }
+
     /// Return the access kind.
     AccessKind getKind() const { return Kind; }
 
     /// Return true if this is a read access.
-    bool isRead() const { return Kind & AK_READ; }
+    bool isRead() const { return Kind & AK_R; }
 
     /// Return true if this is a write access.
-    bool isWrite() const { return Kind & AK_WRITE; }
+    bool isWrite() const { return Kind & AK_W; }
+
+    bool isMustAccess() const { return Kind & AK_MUST; }
+    bool isMayAccess() const { return Kind & AK_MAY; }
 
     /// Return the instruction that causes the access with respect to the local
     /// scope of the associated attribute.
@@ -5057,10 +5082,14 @@ struct AAPointerInfo : public AbstractAttribute {
   /// return true if all such accesses were known and the callback returned true
   /// for all of them, false otherwise. In contrast to forallInterferingAccesses
   /// this function will perform reasoning to exclude write accesses that cannot
-  /// affect the load even if they on the surface look as if they would.
-  virtual bool forallInterferingAccesses(
-      Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,
-      function_ref<bool(const Access &, bool)> CB) const = 0;
+  /// affect the load even if they on the surface look as if they would. The
+  /// flag \p HasBeenWrittenTo will be set to true if we know that \p I does not
+  /// read the intial value of the underlying memory.
+  virtual bool
+  forallInterferingAccesses(Attributor &A, const AbstractAttribute &QueryingAA,
+                            Instruction &I,
+                            function_ref<bool(const Access &, bool)> CB,
+                            bool &HasBeenWrittenTo) const = 0;
 
   /// This function should return true if the type of the \p AA is AAPointerInfo
   static bool classof(const AbstractAttribute *AA) {

diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 952c188a582d0..83029cf1b8949 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -389,17 +389,6 @@ static bool getPotentialCopiesOfMemoryValue(
         NullOnly = false;
     };
 
-    if (IsLoad) {
-      Value *InitialValue = AA::getInitialValueForObj(*Obj, *I.getType(), TLI);
-      if (!InitialValue) {
-        LLVM_DEBUG(dbgs() << "Failed to get initial value: " << *Obj << "\n");
-        return false;
-      }
-      CheckForNullOnlyAndUndef(InitialValue, /* IsExact */ true);
-      NewCopies.push_back(InitialValue);
-      NewCopyOrigins.push_back(nullptr);
-    }
-
     auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) {
       if ((IsLoad && !Acc.isWrite()) || (!IsLoad && !Acc.isRead()))
         return true;
@@ -448,15 +437,36 @@ static bool getPotentialCopiesOfMemoryValue(
       return true;
     };
 
+    // If the value has been written to we don't need the initial value of the
+    // object.
+    bool HasBeenWrittenTo = false;
+
     auto &PI = A.getAAFor<AAPointerInfo>(QueryingAA, IRPosition::value(*Obj),
                                          DepClassTy::NONE);
-    if (!PI.forallInterferingAccesses(A, QueryingAA, I, CheckAccess)) {
+    if (!PI.forallInterferingAccesses(A, QueryingAA, I, CheckAccess,
+                                      HasBeenWrittenTo)) {
       LLVM_DEBUG(
           dbgs()
           << "Failed to verify all interfering accesses for underlying object: "
           << *Obj << "\n");
       return false;
     }
+
+    if (IsLoad && !HasBeenWrittenTo) {
+      Value *InitialValue = AA::getInitialValueForObj(*Obj, *I.getType(), TLI);
+      if (!InitialValue)
+        return false;
+      CheckForNullOnlyAndUndef(InitialValue, /* IsExact */ true);
+      if (NullRequired && !NullOnly) {
+        LLVM_DEBUG(dbgs() << "Non exact access but initial value that is not "
+                             "null or undef, abort!\n");
+        return false;
+      }
+
+      NewCopies.push_back(InitialValue);
+      NewCopyOrigins.push_back(nullptr);
+    }
+
     PIs.push_back(&PI);
   }
 

diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index e9c928c28c7e9..e478c543f8bad 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -961,9 +961,14 @@ struct AAPointerInfoImpl
       const override {
     return State::forallInterferingAccesses(OAS, CB);
   }
-  bool forallInterferingAccesses(
-      Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,
-      function_ref<bool(const Access &, bool)> UserCB) const override {
+
+  bool
+  forallInterferingAccesses(Attributor &A, const AbstractAttribute &QueryingAA,
+                            Instruction &I,
+                            function_ref<bool(const Access &, bool)> UserCB,
+                            bool &HasBeenWrittenTo) const override {
+    HasBeenWrittenTo = false;
+
     SmallPtrSet<const Access *, 8> DominatingWrites;
     SmallVector<std::pair<const Access *, bool>, 8> InterferingAccesses;
 
@@ -999,14 +1004,12 @@ struct AAPointerInfoImpl
 
     const bool FindInterferingWrites = I.mayReadFromMemory();
     const bool FindInterferingReads = I.mayWriteToMemory();
-    const bool UseDominanceReasoning = FindInterferingWrites;
+    const bool UseDominanceReasoning =
+        FindInterferingWrites && NoRecurseAA.isKnownNoRecurse();
     const bool CanUseCFGResoning = CanIgnoreThreading(I);
     InformationCache &InfoCache = A.getInfoCache();
     const DominatorTree *DT =
-        NoRecurseAA.isKnownNoRecurse() && UseDominanceReasoning
-            ? InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
-                  Scope)
-            : nullptr;
+        InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(Scope);
 
     enum GPUAddressSpace : unsigned {
       Generic = 0,
@@ -1063,6 +1066,12 @@ struct AAPointerInfoImpl
           (!FindInterferingReads || !Acc.isRead()))
         return true;
 
+      bool Dominates = DT && Exact && Acc.isMustAccess() &&
+                       (Acc.getLocalInst()->getFunction() == &Scope) &&
+                       DT->dominates(Acc.getRemoteInst(), &I);
+      if (Dominates)
+        HasBeenWrittenTo = true;
+
       // For now we only filter accesses based on CFG reasoning which does not
       // work yet if we have threading effects, or the access is complicated.
       if (CanUseCFGResoning) {
@@ -1073,11 +1082,8 @@ struct AAPointerInfoImpl
              !AA::isPotentiallyReachable(A, I, *Acc.getLocalInst(), QueryingAA,
                                          IsLiveInCalleeCB)))
           return true;
-        if (DT && Exact && (Acc.getLocalInst()->getFunction() == &Scope) &&
-            IsSameThreadAsLoad(Acc)) {
-          if (DT->dominates(Acc.getLocalInst(), &I))
-            DominatingWrites.insert(&Acc);
-        }
+        if (Dominates && UseDominanceReasoning && IsSameThreadAsLoad(Acc))
+          DominatingWrites.insert(&Acc);
       }
 
       InterferingAccesses.push_back({&Acc, Exact});
@@ -1120,7 +1126,8 @@ struct AAPointerInfoImpl
     // succeeded for all or not.
     unsigned NumInterferingAccesses = InterferingAccesses.size();
     for (auto &It : InterferingAccesses) {
-      if (!DT || NumInterferingAccesses > MaxInterferingAccesses ||
+      if (!DT || !UseDominanceReasoning ||
+          NumInterferingAccesses > MaxInterferingAccesses ||
           !CanSkipAccess(*It.first, It.second)) {
         if (!UserCB(*It.first, It.second))
           return false;
@@ -1156,8 +1163,9 @@ struct AAPointerInfoImpl
         if (FromCallee) {
           Content = A.translateArgumentToCallSiteContent(
               RAcc.getContent(), CB, *this, UsedAssumedInformation);
-          AK = AccessKind(
-              AK & (IsByval ? AccessKind::AK_READ : AccessKind::AK_READ_WRITE));
+          AK =
+              AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));
+          AK = AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));
         }
         Changed =
             Changed | addAccess(A, OAS.getOffset(), OAS.getSize(), CB, Content,
@@ -1345,21 +1353,37 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
         return true;
       }
 
-      if (auto *LoadI = dyn_cast<LoadInst>(Usr))
-        return handleAccess(A, *LoadI, *CurPtr, /* Content */ nullptr,
-                            AccessKind::AK_READ, OffsetInfoMap[CurPtr].Offset,
-                            Changed, LoadI->getType());
+      if (auto *LoadI = dyn_cast<LoadInst>(Usr)) {
+        // If the access is to a pointer that may or may not be the associated
+        // value, e.g. due to a PHI, we cannot assume it will be read.
+        AccessKind AK = AccessKind::AK_R;
+        if (getUnderlyingObject(CurPtr) == &AssociatedValue)
+          AK = AccessKind(AK | AccessKind::AK_MUST);
+        else
+          AK = AccessKind(AK | AccessKind::AK_MAY);
+        return handleAccess(A, *LoadI, *CurPtr, /* Content */ nullptr, AK,
+                            OffsetInfoMap[CurPtr].Offset, Changed,
+                            LoadI->getType());
+      }
+
       if (auto *StoreI = dyn_cast<StoreInst>(Usr)) {
         if (StoreI->getValueOperand() == CurPtr) {
           LLVM_DEBUG(dbgs() << "[AAPointerInfo] Escaping use in store "
                             << *StoreI << "\n");
           return false;
         }
+        // If the access is to a pointer that may or may not be the associated
+        // value, e.g. due to a PHI, we cannot assume it will be written.
+        AccessKind AK = AccessKind::AK_W;
+        if (getUnderlyingObject(CurPtr) == &AssociatedValue)
+          AK = AccessKind(AK | AccessKind::AK_MUST);
+        else
+          AK = AccessKind(AK | AccessKind::AK_MAY);
         bool UsedAssumedInformation = false;
         Optional<Value *> Content =
             A.getAssumedSimplified(*StoreI->getValueOperand(), *this,
                                    UsedAssumedInformation, AA::Interprocedural);
-        return handleAccess(A, *StoreI, *CurPtr, Content, AccessKind::AK_WRITE,
+        return handleAccess(A, *StoreI, *CurPtr, Content, AK,
                             OffsetInfoMap[CurPtr].Offset, Changed,
                             StoreI->getValueOperand()->getType());
       }
@@ -1474,10 +1498,10 @@ struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
       unsigned ArgNo = getIRPosition().getCallSiteArgNo();
       ChangeStatus Changed = ChangeStatus::UNCHANGED;
       if (ArgNo == 0) {
-        handleAccess(A, *MI, Ptr, nullptr, AccessKind::AK_WRITE, 0, Changed,
-                     nullptr, LengthVal);
+        handleAccess(A, *MI, Ptr, nullptr, AccessKind::AK_MUST_WRITE, 0,
+                     Changed, nullptr, LengthVal);
       } else if (ArgNo == 1) {
-        handleAccess(A, *MI, Ptr, nullptr, AccessKind::AK_READ, 0, Changed,
+        handleAccess(A, *MI, Ptr, nullptr, AccessKind::AK_MUST_READ, 0, Changed,
                      nullptr, LengthVal);
       } else {
         LLVM_DEBUG(dbgs() << "[AAPointerInfo] Unhandled memory intrinsic "

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
index e49e90a0388e2..5eea4d2aa00ea 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/aggregate-promote.ll
@@ -1,6 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
+; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal  -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
 ; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
 ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal  -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
 

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll
index 023bdc7b31294..d4e6dc1486a0c 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/alignment.ll
@@ -110,7 +110,7 @@ define internal i32 @caller(i32* %A) {
 ; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR1:[0-9]+]] {
 ; IS__CGSCC_NPM-NEXT:    [[A_PRIV:%.*]] = alloca i32, align 4
 ; IS__CGSCC_NPM-NEXT:    store i32 [[TMP0]], i32* [[A_PRIV]], align 4
-; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A_PRIV]], i64 1) #[[ATTR3:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A_PRIV]], i64 noundef 1) #[[ATTR3:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[C]]
 ;
   %B = alloca i64
@@ -137,7 +137,7 @@ define i32 @callercaller() {
 ; IS__CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@callercaller
 ; IS__CGSCC_NPM-SAME: () #[[ATTR2:[0-9]+]] {
-; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @caller(i32 2) #[[ATTR4:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @caller(i32 noundef 2) #[[ATTR4:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[X]]
 ;
   %B = alloca i32

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll
index 31295fc3f73f0..95cba52ea1977 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/attrs.ll
@@ -105,7 +105,7 @@ define i32 @test(i32* %X) {
 ; IS__CGSCC_NPM-NEXT:    [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
 ; IS__CGSCC_NPM-NEXT:    [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
 ; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[X]], align 4
-; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @f(i32 1, i64 2, i32 [[TMP0]]) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @f(i32 noundef 1, i64 noundef 2, i32 [[TMP0]]) #[[ATTR2:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[C]]
 ;
 entry:

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll
index 28f621500ed5c..ba1e3668403b5 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/basictest.ll
@@ -44,7 +44,7 @@ define internal i32 @caller(i32* %B) {
 ; IS__CGSCC_NPM-SAME: (i32 [[TMP0:%.*]]) #[[ATTR1:[0-9]+]] {
 ; IS__CGSCC_NPM-NEXT:    [[B_PRIV:%.*]] = alloca i32, align 4
 ; IS__CGSCC_NPM-NEXT:    store i32 [[TMP0]], i32* [[B_PRIV]], align 4
-; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @test(i32 1, i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B_PRIV]]) #[[ATTR3:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[C:%.*]] = call i32 @test(i32 noundef 1, i32* noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B_PRIV]]) #[[ATTR3:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[C]]
 ;
   %A = alloca i32
@@ -71,7 +71,7 @@ define i32 @callercaller() {
 ; IS__CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@callercaller
 ; IS__CGSCC_NPM-SAME: () #[[ATTR2:[0-9]+]] {
-; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @caller(i32 2) #[[ATTR4:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @caller(i32 noundef 2) #[[ATTR4:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[X]]
 ;
   %B = alloca i32

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
index 9ae184452d773..e0966f97eac34 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
@@ -95,7 +95,7 @@ define i32 @test(i32* %X) {
 ; IS__CGSCC_NPM-NEXT:    [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
 ; IS__CGSCC_NPM-NEXT:    [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
 ; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[X]], align 4
-; IS__CGSCC_NPM-NEXT:    call void @f(i32 1, i64 2, i32 [[TMP0]]) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    call void @f(i32 noundef 1, i64 noundef 2, i32 [[TMP0]]) #[[ATTR2:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 0
 ;
 entry:

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll
index f49d30b8ee522..063acfbf2121a 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/byval.ll
@@ -134,8 +134,8 @@ define i32 @main() nounwind  {
 ; IS__CGSCC_NPM-NEXT:    [[S:%.*]] = alloca [[STRUCT_SS:%.*]], align 4
 ; IS__CGSCC_NPM-NEXT:    [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
 ; IS__CGSCC_NPM-NEXT:    [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
-; IS__CGSCC_NPM-NEXT:    [[C0:%.*]] = call i32 @f(i32 1, i64 2) #[[ATTR2:[0-9]+]]
-; IS__CGSCC_NPM-NEXT:    [[C1:%.*]] = call i32 @g(i32 1, i64 2) #[[ATTR2]]
+; IS__CGSCC_NPM-NEXT:    [[C0:%.*]] = call i32 @f(i32 noundef 1, i64 noundef 2) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[C1:%.*]] = call i32 @g(i32 noundef 1, i64 noundef 2) #[[ATTR2]]
 ; IS__CGSCC_NPM-NEXT:    [[A:%.*]] = add i32 [[C0]], [[C1]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[A]]
 ;

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll
index 0dac5c3195a33..112f70c824d48 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow2.ll
@@ -57,7 +57,7 @@ define i32 @foo() {
 ; IS__CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@foo
 ; IS__CGSCC_NPM-SAME: () #[[ATTR1:[0-9]+]] {
-; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @callee(i32 17) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = call i32 @callee(i32 noundef 17) #[[ATTR2:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[X]]
 ;
   %A = alloca i32         ; <i32*> [#uses=2]

diff  --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
index 20f7d0dd65378..2b5829e759d4b 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
@@ -22,7 +22,7 @@ define void @caller() #0 {
 ; IS__TUNIT_NPM-NEXT:    ret void
 ;
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller() {
-; IS__CGSCC_NPM-NEXT:    call void @promote_i32_ptr(i32 42), !prof [[PROF0:![0-9]+]]
+; IS__CGSCC_NPM-NEXT:    call void @promote_i32_ptr(i32 noundef 42), !prof [[PROF0:![0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret void
 ;
   %x = alloca i32

diff  --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll
index a9b4bb4d178c5..60df30cd37705 100644
--- a/llvm/test/Transforms/Attributor/internal-noalias.ll
+++ b/llvm/test/Transforms/Attributor/internal-noalias.ll
@@ -166,7 +166,7 @@ define i32 @visible_local_2() {
 ; IS__CGSCC_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@visible_local_2
 ; IS__CGSCC_NPM-SAME: () #[[ATTR3:[0-9]+]] {
-; IS__CGSCC_NPM-NEXT:    [[CALL:%.*]] = call i32 @noalias_args_argmem_ro(i32 5, i32 5) #[[ATTR6:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[CALL:%.*]] = call i32 @noalias_args_argmem_ro(i32 noundef 5, i32 noundef 5) #[[ATTR6:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret i32 [[CALL]]
 ;
   %B = alloca i32, align 4

diff  --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index e99886f8b3b46..eb5d3fa78bc72 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -1599,19 +1599,24 @@ for.end35:                                        ; preds = %for.cond.cleanup27
 ;      return Flag3;
 ;    }
 define i32 @static_global_simplifiable_3() {
-; NOT_TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
-; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@static_global_simplifiable_3
-; NOT_TUNIT_NPM-SAME: () #[[ATTR5:[0-9]+]] {
-; NOT_TUNIT_NPM-NEXT:    store i32 1, i32* @Flag3, align 4, !tbaa [[TBAA3]]
-; NOT_TUNIT_NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]]
-; NOT_TUNIT_NPM-NEXT:    ret i32 [[I]]
+; IS________OPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; IS________OPM-LABEL: define {{[^@]+}}@static_global_simplifiable_3
+; IS________OPM-SAME: () #[[ATTR5:[0-9]+]] {
+; IS________OPM-NEXT:    store i32 1, i32* @Flag3, align 4, !tbaa [[TBAA3]]
+; IS________OPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]]
+; IS________OPM-NEXT:    ret i32 [[I]]
 ;
-; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@static_global_simplifiable_3
-; IS__TUNIT_NPM-SAME: () #[[ATTR3]] {
+; IS__TUNIT_NPM-SAME: () #[[ATTR5]] {
 ; IS__TUNIT_NPM-NEXT:    store i32 1, i32* @Flag3, align 4, !tbaa [[TBAA3]]
-; IS__TUNIT_NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]]
-; IS__TUNIT_NPM-NEXT:    ret i32 [[I]]
+; IS__TUNIT_NPM-NEXT:    ret i32 1
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@static_global_simplifiable_3
+; IS__CGSCC_NPM-SAME: () #[[ATTR6:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT:    store i32 1, i32* @Flag3, align 4, !tbaa [[TBAA3]]
+; IS__CGSCC_NPM-NEXT:    ret i32 1
 ;
   store i32 1, i32* @Flag3, align 4, !tbaa !3
   %i = load i32, i32* @Flag3, align 4, !tbaa !3
@@ -2555,19 +2560,19 @@ define i32 @global_not_simplifiable_1(i32 %cnd) {
 ; IS__TUNIT_OPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]]
 ; IS__TUNIT_OPM-NEXT:    ret i32 [[I]]
 ;
-; IS________NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS________NPM-LABEL: define {{[^@]+}}@global_not_simplifiable_1
-; IS________NPM-SAME: (i32 [[CND:%.*]]) #[[ATTR6:[0-9]+]] {
-; IS________NPM-NEXT:  entry:
-; IS________NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]]
-; IS________NPM-NEXT:    ret i32 [[I]]
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@global_not_simplifiable_1
+; IS__TUNIT_NPM-SAME: (i32 [[CND:%.*]]) #[[ATTR6:[0-9]+]] {
+; IS__TUNIT_NPM-NEXT:  entry:
+; IS__TUNIT_NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]]
+; IS__TUNIT_NPM-NEXT:    ret i32 [[I]]
 ;
-; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@global_not_simplifiable_1
-; IS__CGSCC_OPM-SAME: (i32 [[CND:%.*]]) #[[ATTR7:[0-9]+]] {
-; IS__CGSCC_OPM-NEXT:  entry:
-; IS__CGSCC_OPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]]
-; IS__CGSCC_OPM-NEXT:    ret i32 [[I]]
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@global_not_simplifiable_1
+; IS__CGSCC____-SAME: (i32 [[CND:%.*]]) #[[ATTR7:[0-9]+]] {
+; IS__CGSCC____-NEXT:  entry:
+; IS__CGSCC____-NEXT:    [[I:%.*]] = load i32, i32* @Flag0, align 4, !tbaa [[TBAA3]]
+; IS__CGSCC____-NEXT:    ret i32 [[I]]
 ;
 entry:
   %i = load i32, i32* @Flag0, align 4, !tbaa !3
@@ -2637,6 +2642,31 @@ entry:
   ret i32 %i
 }
 
+; Similiar to static_global_simplifiable_3 but with a may-store.
+define i32 @static_global_not_simplifiable_3(i1 %c, i32* %p) {
+; NOT_TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@static_global_not_simplifiable_3
+; NOT_TUNIT_NPM-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR5:[0-9]+]] {
+; NOT_TUNIT_NPM-NEXT:    [[SEL:%.*]] = select i1 [[C]], i32* @Flag3, i32* [[P]]
+; NOT_TUNIT_NPM-NEXT:    store i32 1, i32* [[SEL]], align 4, !tbaa [[TBAA3]]
+; NOT_TUNIT_NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]]
+; NOT_TUNIT_NPM-NEXT:    ret i32 [[I]]
+;
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@static_global_not_simplifiable_3
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]], i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR3]] {
+; IS__TUNIT_NPM-NEXT:    [[SEL:%.*]] = select i1 [[C]], i32* @Flag3, i32* [[P]]
+; IS__TUNIT_NPM-NEXT:    store i32 1, i32* [[SEL]], align 4, !tbaa [[TBAA3]]
+; IS__TUNIT_NPM-NEXT:    [[I:%.*]] = load i32, i32* @Flag3, align 4, !tbaa [[TBAA3]]
+; IS__TUNIT_NPM-NEXT:    ret i32 [[I]]
+;
+  %sel = select i1 %c, i32* @Flag3, i32* %p
+  store i32 1, i32* %sel, align 4, !tbaa !3
+  %i = load i32, i32* @Flag3, align 4, !tbaa !3
+  ret i32 %i
+}
+
+
 ;    int write_read{,_static,_static_undef}_global(void) {
 ;      Gint{,static,_static_undef}1 = 7;
 ;      return Gint1;
@@ -2689,7 +2719,7 @@ define void @write_global() {
 ;
 ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@write_global
-; IS__CGSCC_NPM-SAME: () #[[ATTR7:[0-9]+]] {
+; IS__CGSCC_NPM-SAME: () #[[ATTR6]] {
 ; IS__CGSCC_NPM-NEXT:    store i32 7, i32* @Gint2, align 4
 ; IS__CGSCC_NPM-NEXT:    ret void
 ;
@@ -2703,36 +2733,38 @@ define i32 @read_global() {
 ; IS__TUNIT_OPM-NEXT:    [[L:%.*]] = load i32, i32* @Gint2, align 4
 ; IS__TUNIT_OPM-NEXT:    ret i32 [[L]]
 ;
-; IS________NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS________NPM-LABEL: define {{[^@]+}}@read_global
-; IS________NPM-SAME: () #[[ATTR6]] {
-; IS________NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gint2, align 4
-; IS________NPM-NEXT:    ret i32 [[L]]
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@read_global
+; IS__TUNIT_NPM-SAME: () #[[ATTR6]] {
+; IS__TUNIT_NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gint2, align 4
+; IS__TUNIT_NPM-NEXT:    ret i32 [[L]]
 ;
-; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@read_global
-; IS__CGSCC_OPM-SAME: () #[[ATTR7]] {
-; IS__CGSCC_OPM-NEXT:    [[L:%.*]] = load i32, i32* @Gint2, align 4
-; IS__CGSCC_OPM-NEXT:    ret i32 [[L]]
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@read_global
+; IS__CGSCC____-SAME: () #[[ATTR7]] {
+; IS__CGSCC____-NEXT:    [[L:%.*]] = load i32, i32* @Gint2, align 4
+; IS__CGSCC____-NEXT:    ret i32 [[L]]
 ;
   %l = load i32, i32* @Gint2
   ret i32 %l
 }
-; FIXME: We could replace these loads.
 define i32 @write_read_static_global() {
-; NOT_TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
-; NOT_TUNIT_NPM-LABEL: define {{[^@]+}}@write_read_static_global
-; NOT_TUNIT_NPM-SAME: () #[[ATTR5]] {
-; NOT_TUNIT_NPM-NEXT:    store i32 7, i32* @Gstatic_int1, align 4
-; NOT_TUNIT_NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int1, align 4
-; NOT_TUNIT_NPM-NEXT:    ret i32 [[L]]
+; IS________OPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; IS________OPM-LABEL: define {{[^@]+}}@write_read_static_global
+; IS________OPM-SAME: () #[[ATTR5]] {
+; IS________OPM-NEXT:    store i32 7, i32* @Gstatic_int1, align 4
+; IS________OPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int1, align 4
+; IS________OPM-NEXT:    ret i32 [[L]]
 ;
-; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@write_read_static_global
-; IS__TUNIT_NPM-SAME: () #[[ATTR3]] {
-; IS__TUNIT_NPM-NEXT:    store i32 7, i32* @Gstatic_int1, align 4
-; IS__TUNIT_NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int1, align 4
-; IS__TUNIT_NPM-NEXT:    ret i32 [[L]]
+; IS__TUNIT_NPM-SAME: () #[[ATTR5]] {
+; IS__TUNIT_NPM-NEXT:    ret i32 7
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@write_read_static_global
+; IS__CGSCC_NPM-SAME: () #[[ATTR6]] {
+; IS__CGSCC_NPM-NEXT:    ret i32 7
 ;
   store i32 7, i32* @Gstatic_int1
   %l = load i32, i32* @Gstatic_int1
@@ -2759,7 +2791,7 @@ define void @write_static_global() {
 ;
 ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@write_static_global
-; IS__CGSCC_NPM-SAME: () #[[ATTR7]] {
+; IS__CGSCC_NPM-SAME: () #[[ATTR6]] {
 ; IS__CGSCC_NPM-NEXT:    store i32 7, i32* @Gstatic_int2, align 4
 ; IS__CGSCC_NPM-NEXT:    ret void
 ;
@@ -2773,17 +2805,17 @@ define i32 @read_static_global() {
 ; IS__TUNIT_OPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4
 ; IS__TUNIT_OPM-NEXT:    ret i32 [[L]]
 ;
-; IS________NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS________NPM-LABEL: define {{[^@]+}}@read_static_global
-; IS________NPM-SAME: () #[[ATTR6]] {
-; IS________NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4
-; IS________NPM-NEXT:    ret i32 [[L]]
+; IS__TUNIT_NPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@read_static_global
+; IS__TUNIT_NPM-SAME: () #[[ATTR6]] {
+; IS__TUNIT_NPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4
+; IS__TUNIT_NPM-NEXT:    ret i32 [[L]]
 ;
-; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
-; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@read_static_global
-; IS__CGSCC_OPM-SAME: () #[[ATTR7]] {
-; IS__CGSCC_OPM-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4
-; IS__CGSCC_OPM-NEXT:    ret i32 [[L]]
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@read_static_global
+; IS__CGSCC____-SAME: () #[[ATTR7]] {
+; IS__CGSCC____-NEXT:    [[L:%.*]] = load i32, i32* @Gstatic_int2, align 4
+; IS__CGSCC____-NEXT:    ret i32 [[L]]
 ;
   %l = load i32, i32* @Gstatic_int2
   ret i32 %l
@@ -2806,7 +2838,7 @@ define i32 @write_read_static_undef_global() {
 ;
 ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@write_read_static_undef_global
-; IS__CGSCC_NPM-SAME: () #[[ATTR7]] {
+; IS__CGSCC_NPM-SAME: () #[[ATTR6]] {
 ; IS__CGSCC_NPM-NEXT:    ret i32 7
 ;
   store i32 7, i32* @Gstatic_undef_int1
@@ -2832,7 +2864,7 @@ define void @write_static_undef_global() {
 ;
 ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly
 ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@write_static_undef_global
-; IS__CGSCC_NPM-SAME: () #[[ATTR7]] {
+; IS__CGSCC_NPM-SAME: () #[[ATTR6]] {
 ; IS__CGSCC_NPM-NEXT:    store i32 7, i32* @Gstatic_undef_int2, align 4
 ; IS__CGSCC_NPM-NEXT:    ret void
 ;
@@ -3516,14 +3548,13 @@ define dso_local i32 @round_trip_calloc(i32 %x) {
 ; IS__TUNIT_OPM-NEXT:    ret i32 [[TMP1]]
 ;
 ; IS________NPM-LABEL: define {{[^@]+}}@round_trip_calloc
-; IS________NPM-SAME: (i32 [[X:%.*]]) {
+; IS________NPM-SAME: (i32 returned [[X:%.*]]) {
 ; IS________NPM-NEXT:  entry:
 ; IS________NPM-NEXT:    [[CALL_H2S:%.*]] = alloca i8, i64 4, align 1
 ; IS________NPM-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[CALL_H2S]], i8 0, i64 4, i1 false)
 ; IS________NPM-NEXT:    [[TMP0:%.*]] = bitcast i8* [[CALL_H2S]] to i32*
 ; IS________NPM-NEXT:    store i32 [[X]], i32* [[TMP0]], align 4
-; IS________NPM-NEXT:    [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
-; IS________NPM-NEXT:    ret i32 [[TMP1]]
+; IS________NPM-NEXT:    ret i32 [[X]]
 ;
 ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@round_trip_calloc
 ; IS__CGSCC_OPM-SAME: (i32 [[X:%.*]]) {
@@ -3555,10 +3586,7 @@ define dso_local i32 @round_trip_calloc_constant() {
 ; IS________NPM-NEXT:  entry:
 ; IS________NPM-NEXT:    [[CALL_H2S:%.*]] = alloca i8, i64 4, align 1
 ; IS________NPM-NEXT:    call void @llvm.memset.p0i8.i64(i8* [[CALL_H2S]], i8 0, i64 4, i1 false)
-; IS________NPM-NEXT:    [[TMP0:%.*]] = bitcast i8* [[CALL_H2S]] to i32*
-; IS________NPM-NEXT:    store i32 11, i32* [[TMP0]], align 4
-; IS________NPM-NEXT:    [[TMP1:%.*]] = load i32, i32* [[TMP0]], align 4
-; IS________NPM-NEXT:    ret i32 [[TMP1]]
+; IS________NPM-NEXT:    ret i32 11
 ;
 ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@round_trip_calloc_constant() {
 ; IS__CGSCC_OPM-NEXT:  entry:
@@ -3994,7 +4022,7 @@ define dso_local void @test_nested_memory(float* %dst, double* %src) {
 ; IS__CGSCC_NPM-NEXT:    [[TMP1:%.*]] = bitcast i8* [[SRC2]] to double**
 ; IS__CGSCC_NPM-NEXT:    store double* [[SRC]], double** [[TMP1]], align 8
 ; IS__CGSCC_NPM-NEXT:    store i8* [[CALL]], i8** bitcast (%struct.STy** getelementptr inbounds ([[STRUCT_STY]], %struct.STy* @global, i64 0, i32 2) to i8**), align 8
-; IS__CGSCC_NPM-NEXT:    call fastcc void @nested_memory_callee(float* nofree nonnull align 4294967296 undef, double* nofree nonnull align 4294967296 undef, %struct.STy* nofree nonnull align 8 @global) #[[ATTR17:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    call fastcc void @nested_memory_callee(float* nofree nonnull align 4294967296 undef, double* nofree nonnull align 4294967296 undef, %struct.STy* nofree noundef nonnull align 8 dereferenceable(24) @global) #[[ATTR17:[0-9]+]]
 ; IS__CGSCC_NPM-NEXT:    ret void
 ;
 entry:
@@ -4534,8 +4562,8 @@ define i1 @alloca_non_unique_caller(i32 %in, i1 %c) {
 ; IS__CGSCC_NPM: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn }
 ; IS__CGSCC_NPM: attributes #[[ATTR4]] = { nofree norecurse nosync nounwind readnone willreturn }
 ; IS__CGSCC_NPM: attributes #[[ATTR5]] = { nofree norecurse nosync nounwind willreturn }
-; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nofree norecurse nosync nounwind readonly willreturn }
-; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind willreturn writeonly }
+; IS__CGSCC_NPM: attributes #[[ATTR6]] = { nofree norecurse nosync nounwind willreturn writeonly }
+; IS__CGSCC_NPM: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind readonly willreturn }
 ; IS__CGSCC_NPM: attributes #[[ATTR8]] = { nofree norecurse nosync nounwind writeonly }
 ; IS__CGSCC_NPM: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind willreturn uwtable }
 ; IS__CGSCC_NPM: attributes #[[ATTR10]] = { argmemonly nofree norecurse nosync nounwind willreturn }

diff  --git a/llvm/test/Transforms/Attributor/wrapper.ll b/llvm/test/Transforms/Attributor/wrapper.ll
index 5a0f68f507537..85bf78a69d2ea 100644
--- a/llvm/test/Transforms/Attributor/wrapper.ll
+++ b/llvm/test/Transforms/Attributor/wrapper.ll
@@ -9,7 +9,7 @@
 ;
 ; Check the original function, which is wrapped and becomes anonymous
 ; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; CHECK: define internal i32 @0()
+; CHECK: define internal noundef i32 @0()
 ; CHECK: ret i32 1
 define linkonce i32 @inner1() {
 entry:


        


More information about the llvm-commits mailing list