[llvm] dbb3a65 - [Attributor][FIX] Do not replace a value with a non-dominating instruction

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 10 14:09:46 PDT 2021


Author: Johannes Doerfert
Date: 2021-07-10T16:09:30-05:00
New Revision: dbb3a65f5b30ff78e0a7165b377180a00e580f8c

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

LOG: [Attributor][FIX] Do not replace a value with a non-dominating instruction

We have to be careful when we replace values to not use a non-dominating
instruction. It makes sense that simplification offers those as
"simplified values" but we can't manifest them in the IR without PHI
nodes. In the future we should consider potentially adding those PHI
nodes.

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/IPConstantProp/PR16052.ll
    llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll
    llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
    llvm/test/Transforms/Attributor/heap_to_stack.ll
    llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll
    llvm/test/Transforms/Attributor/memory_locations.ll
    llvm/test/Transforms/Attributor/noalias.ll
    llvm/test/Transforms/Attributor/nonnull.ll
    llvm/test/Transforms/Attributor/value-simplify.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 03e1abd665d6..3dd7cf662a5b 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -142,6 +142,12 @@ namespace AA {
 /// instruction/argument of \p Scope.
 bool isValidInScope(const Value &V, const Function *Scope);
 
+/// Return true if \p V is a valid value at position \p CtxI, that is a
+/// constant, an argument of the same function as \p CtxI, or an instruction in
+/// that function that dominates \p CtxI.
+bool isValidAtPosition(const Value &V, const Instruction &CtxI,
+                       InformationCache &InfoCache);
+
 /// Try to convert \p V to type \p Ty without introducing new instructions. If
 /// this is not possible return `nullptr`. Note: this function basically knows
 /// how to cast various constants.

diff  --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 6f98ec0c5928..2933b1e2c3ee 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -176,6 +176,22 @@ bool AA::isValidInScope(const Value &V, const Function *Scope) {
   return false;
 }
 
+bool AA::isValidAtPosition(const Value &V, const Instruction &CtxI,
+                           InformationCache &InfoCache) {
+  if (isa<Constant>(V))
+    return true;
+  const Function *Scope = CtxI.getFunction();
+  if (auto *A = dyn_cast<Argument>(&V))
+    return A->getParent() == Scope;
+  if (auto *I = dyn_cast<Instruction>(&V))
+    if (I->getFunction() == Scope) {
+      const DominatorTree *DT =
+          InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*Scope);
+      return DT && DT->dominates(I, &CtxI);
+    }
+  return false;
+}
+
 Value *AA::getWithType(Value &V, Type &Ty) {
   if (V.getType() == &Ty)
     return &V;

diff  --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index deb32c72920b..ee664f923dbd 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -4385,7 +4385,7 @@ struct AAValueSimplifyImpl : AAValueSimplify {
 
   /// Return a value we can use as replacement for the associated one, or
   /// nullptr if we don't have one that makes sense.
-  virtual Value *getReplacementValue() const {
+  Value *getReplacementValue(Attributor &A) const {
     Value *NewV;
     NewV = SimplifiedAssociatedValue.hasValue()
                ? SimplifiedAssociatedValue.getValue()
@@ -4393,8 +4393,12 @@ struct AAValueSimplifyImpl : AAValueSimplify {
     if (!NewV)
       return nullptr;
     NewV = AA::getWithType(*NewV, *getAssociatedType());
-    if (!NewV || NewV == &getAssociatedValue() ||
-        !AA::isValidInScope(*NewV, getAnchorScope()))
+    if (!NewV || NewV == &getAssociatedValue())
+      return nullptr;
+    const Instruction *CtxI = getCtxI();
+    if (CtxI && !AA::isValidAtPosition(*NewV, *CtxI, A.getInfoCache()))
+      return nullptr;
+    if (!CtxI && !AA::isValidInScope(*NewV, getAnchorScope()))
       return nullptr;
     return NewV;
   }
@@ -4449,7 +4453,7 @@ struct AAValueSimplifyImpl : AAValueSimplify {
     if (getAssociatedValue().user_empty())
       return Changed;
 
-    if (auto *NewV = getReplacementValue()) {
+    if (auto *NewV = getReplacementValue(A)) {
       LLVM_DEBUG(dbgs() << "[ValueSimplify] " << getAssociatedValue() << " -> "
                         << *NewV << " :: " << *this << "\n");
       if (A.changeValueAfterManifest(getAssociatedValue(), *NewV))
@@ -4596,7 +4600,7 @@ struct AAValueSimplifyReturned : AAValueSimplifyImpl {
   ChangeStatus manifest(Attributor &A) override {
     ChangeStatus Changed = ChangeStatus::UNCHANGED;
 
-    if (auto *NewV = getReplacementValue()) {
+    if (auto *NewV = getReplacementValue(A)) {
       auto PredForReturned =
           [&](Value &, const SmallSetVector<ReturnInst *, 4> &RetInsts) {
             for (ReturnInst *RI : RetInsts) {
@@ -4821,7 +4825,7 @@ struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {
   ChangeStatus manifest(Attributor &A) override {
     ChangeStatus Changed = ChangeStatus::UNCHANGED;
 
-    if (auto *NewV = getReplacementValue()) {
+    if (auto *NewV = getReplacementValue(A)) {
       Use &U = cast<CallBase>(&getAnchorValue())
                    ->getArgOperandUse(getCallSiteArgNo());
       if (A.changeUseAfterManifest(U, *NewV))

diff  --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
index 824f01ff5589..a5765ed3e9d7 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR16052.ll
@@ -32,21 +32,39 @@ entry:
 
 define i64 @fn2b(i32 %arg) {
 ;
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2b
-; IS__TUNIT____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
-; IS__TUNIT____-NEXT:  entry:
-; IS__TUNIT____-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
-; IS__TUNIT____-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
-; IS__TUNIT____-NEXT:    ret i64 [[DIV]]
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn2b
+; IS__TUNIT_OPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
+; IS__TUNIT_OPM-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__TUNIT_OPM-NEXT:    [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #[[ATTR0]]
+; IS__TUNIT_OPM-NEXT:    ret i64 [[CALL2]]
 ;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2b
-; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
-; IS__CGSCC____-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
-; IS__CGSCC____-NEXT:    ret i64 [[DIV]]
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2b
+; IS__TUNIT_NPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
+; IS__TUNIT_NPM-NEXT:  entry:
+; IS__TUNIT_NPM-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
+; IS__TUNIT_NPM-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__TUNIT_NPM-NEXT:    ret i64 [[DIV]]
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2b
+; IS__CGSCC_OPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
+; IS__CGSCC_OPM-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__CGSCC_OPM-NEXT:    [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]]) #[[ATTR1:[0-9]+]]
+; IS__CGSCC_OPM-NEXT:    ret i64 [[CALL2]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2b
+; IS__CGSCC_NPM-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    [[CONV:%.*]] = sext i32 [[ARG]] to i64
+; IS__CGSCC_NPM-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__CGSCC_NPM-NEXT:    ret i64 [[DIV]]
 ;
 entry:
   %conv = sext i32 %arg to i64
@@ -83,11 +101,23 @@ entry:
 }
 
 define internal i64 @fn1(i64 %p1) {
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn1
-; IS__CGSCC____-SAME: (i64 [[P1:%.*]]) #[[ATTR0]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    ret i64 undef
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn1
+; IS__TUNIT_OPM-SAME: (i64 returned [[P1:%.*]]) #[[ATTR0]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    ret i64 [[P1]]
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn1
+; IS__CGSCC_OPM-SAME: (i64 returned [[P1:%.*]]) #[[ATTR0]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    ret i64 [[P1]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn1
+; IS__CGSCC_NPM-SAME: (i64 [[P1:%.*]]) #[[ATTR0]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    ret i64 undef
 ;
 entry:
   %tobool = icmp ne i64 %p1, 0
@@ -97,5 +127,8 @@ entry:
 ;.
 ; IS__TUNIT____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
 ;.
-; IS__CGSCC____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
+; IS__CGSCC_OPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
+; IS__CGSCC_OPM: attributes #[[ATTR1]] = { readnone willreturn }
+;.
+; IS__CGSCC_NPM: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll
index f1d3dce74acb..0a96ff4852df 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/PR26044.ll
@@ -8,35 +8,67 @@ target triple = "x86_64-unknown-linux-gnu"
 
 define void @fn2(i32* %P, i1 %C) {
 ;
-; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind
-; IS__TUNIT____-LABEL: define {{[^@]+}}@fn2
-; IS__TUNIT____-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-; IS__TUNIT____-NEXT:  entry:
-; IS__TUNIT____-NEXT:    br label [[IF_END:%.*]]
-; IS__TUNIT____:       for.cond1:
-; IS__TUNIT____-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
-; IS__TUNIT____:       if.end:
-; IS__TUNIT____-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
-; IS__TUNIT____-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
-; IS__TUNIT____-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
-; IS__TUNIT____-NEXT:    br label [[FOR_COND1]]
-; IS__TUNIT____:       exit:
-; IS__TUNIT____-NEXT:    ret void
-;
-; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2
-; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    br label [[IF_END:%.*]]
-; IS__CGSCC____:       for.cond1:
-; IS__CGSCC____-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
-; IS__CGSCC____:       if.end:
-; IS__CGSCC____-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
-; IS__CGSCC____-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
-; IS__CGSCC____-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
-; IS__CGSCC____-NEXT:    br label [[FOR_COND1]]
-; IS__CGSCC____:       exit:
-; IS__CGSCC____-NEXT:    ret void
+; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn2
+; IS__TUNIT_OPM-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    br label [[IF_END:%.*]]
+; IS__TUNIT_OPM:       for.cond1:
+; IS__TUNIT_OPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__TUNIT_OPM:       if.end:
+; IS__TUNIT_OPM-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__TUNIT_OPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
+; IS__TUNIT_OPM-NEXT:    [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]]) #[[ATTR3:[0-9]+]]
+; IS__TUNIT_OPM-NEXT:    store i32 [[CALL]], i32* [[P]], align 4
+; IS__TUNIT_OPM-NEXT:    br label [[FOR_COND1]]
+; IS__TUNIT_OPM:       exit:
+; IS__TUNIT_OPM-NEXT:    ret void
+;
+; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn2
+; IS__TUNIT_NPM-SAME: (i32* nocapture nofree [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__TUNIT_NPM-NEXT:  entry:
+; IS__TUNIT_NPM-NEXT:    br label [[IF_END:%.*]]
+; IS__TUNIT_NPM:       for.cond1:
+; IS__TUNIT_NPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__TUNIT_NPM:       if.end:
+; IS__TUNIT_NPM-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__TUNIT_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
+; IS__TUNIT_NPM-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
+; IS__TUNIT_NPM-NEXT:    br label [[FOR_COND1]]
+; IS__TUNIT_NPM:       exit:
+; IS__TUNIT_NPM-NEXT:    ret void
+;
+; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2
+; IS__CGSCC_OPM-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    br label [[IF_END:%.*]]
+; IS__CGSCC_OPM:       for.cond1:
+; IS__CGSCC_OPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__CGSCC_OPM:       if.end:
+; IS__CGSCC_OPM-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__CGSCC_OPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
+; IS__CGSCC_OPM-NEXT:    [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
+; IS__CGSCC_OPM-NEXT:    store i32 [[CALL]], i32* [[P]], align 4
+; IS__CGSCC_OPM-NEXT:    br label [[FOR_COND1]]
+; IS__CGSCC_OPM:       exit:
+; IS__CGSCC_OPM-NEXT:    ret void
+;
+; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2
+; IS__CGSCC_NPM-SAME: (i32* nocapture nofree nonnull align 4 dereferenceable(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    br label [[IF_END:%.*]]
+; IS__CGSCC_NPM:       for.cond1:
+; IS__CGSCC_NPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__CGSCC_NPM:       if.end:
+; IS__CGSCC_NPM-NEXT:    [[E_2:%.*]] = phi i32* [ [[P]], [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* [[E_2]], align 4
+; IS__CGSCC_NPM-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
+; IS__CGSCC_NPM-NEXT:    br label [[FOR_COND1]]
+; IS__CGSCC_NPM:       exit:
+; IS__CGSCC_NPM-NEXT:    ret void
 ;
 entry:
   br label %if.end
@@ -55,11 +87,23 @@ exit:
 }
 
 define internal i32 @fn1(i32 %p1) {
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn1
-; IS__CGSCC____-SAME: (i32 [[P1:%.*]]) #[[ATTR1:[0-9]+]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    ret i32 undef
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn1
+; IS__TUNIT_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    ret i32 [[P1]]
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn1
+; IS__CGSCC_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    ret i32 [[P1]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn1
+; IS__CGSCC_NPM-SAME: (i32 [[P1:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    ret i32 undef
 ;
 entry:
   %tobool = icmp ne i32 %p1, 0
@@ -69,35 +113,67 @@ entry:
 
 define void @fn_no_null_opt(i32* %P, i1 %C) null_pointer_is_valid {
 ;
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind null_pointer_is_valid
-; IS__TUNIT____-LABEL: define {{[^@]+}}@fn_no_null_opt
-; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] {
-; IS__TUNIT____-NEXT:  entry:
-; IS__TUNIT____-NEXT:    br label [[IF_END:%.*]]
-; IS__TUNIT____:       for.cond1:
-; IS__TUNIT____-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
-; IS__TUNIT____:       if.end:
-; IS__TUNIT____-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
-; IS__TUNIT____-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
-; IS__TUNIT____-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
-; IS__TUNIT____-NEXT:    br label [[FOR_COND1]]
-; IS__TUNIT____:       exit:
-; IS__TUNIT____-NEXT:    ret void
-;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn_no_null_opt
-; IS__CGSCC____-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    br label [[IF_END:%.*]]
-; IS__CGSCC____:       for.cond1:
-; IS__CGSCC____-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
-; IS__CGSCC____:       if.end:
-; IS__CGSCC____-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
-; IS__CGSCC____-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
-; IS__CGSCC____-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
-; IS__CGSCC____-NEXT:    br label [[FOR_COND1]]
-; IS__CGSCC____:       exit:
-; IS__CGSCC____-NEXT:    ret void
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind null_pointer_is_valid
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn_no_null_opt
+; IS__TUNIT_OPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    br label [[IF_END:%.*]]
+; IS__TUNIT_OPM:       for.cond1:
+; IS__TUNIT_OPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__TUNIT_OPM:       if.end:
+; IS__TUNIT_OPM-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__TUNIT_OPM-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
+; IS__TUNIT_OPM-NEXT:    [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]]) #[[ATTR3]]
+; IS__TUNIT_OPM-NEXT:    store i32 [[CALL]], i32* [[P]], align 4
+; IS__TUNIT_OPM-NEXT:    br label [[FOR_COND1]]
+; IS__TUNIT_OPM:       exit:
+; IS__TUNIT_OPM-NEXT:    ret void
+;
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind null_pointer_is_valid
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@fn_no_null_opt
+; IS__TUNIT_NPM-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i1 [[C:%.*]]) #[[ATTR1:[0-9]+]] {
+; IS__TUNIT_NPM-NEXT:  entry:
+; IS__TUNIT_NPM-NEXT:    br label [[IF_END:%.*]]
+; IS__TUNIT_NPM:       for.cond1:
+; IS__TUNIT_NPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__TUNIT_NPM:       if.end:
+; IS__TUNIT_NPM-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__TUNIT_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
+; IS__TUNIT_NPM-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
+; IS__TUNIT_NPM-NEXT:    br label [[FOR_COND1]]
+; IS__TUNIT_NPM:       exit:
+; IS__TUNIT_NPM-NEXT:    ret void
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn_no_null_opt
+; IS__CGSCC_OPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    br label [[IF_END:%.*]]
+; IS__CGSCC_OPM:       for.cond1:
+; IS__CGSCC_OPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__CGSCC_OPM:       if.end:
+; IS__CGSCC_OPM-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__CGSCC_OPM-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
+; IS__CGSCC_OPM-NEXT:    [[CALL:%.*]] = call i32 @fn0(i32 [[TMP0]])
+; IS__CGSCC_OPM-NEXT:    store i32 [[CALL]], i32* [[P]], align 4
+; IS__CGSCC_OPM-NEXT:    br label [[FOR_COND1]]
+; IS__CGSCC_OPM:       exit:
+; IS__CGSCC_OPM-NEXT:    ret void
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind null_pointer_is_valid
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn_no_null_opt
+; IS__CGSCC_NPM-SAME: (i32* nocapture nofree writeonly align 4 dereferenceable_or_null(4) [[P:%.*]], i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    br label [[IF_END:%.*]]
+; IS__CGSCC_NPM:       for.cond1:
+; IS__CGSCC_NPM-NEXT:    br i1 [[C]], label [[IF_END]], label [[EXIT:%.*]]
+; IS__CGSCC_NPM:       if.end:
+; IS__CGSCC_NPM-NEXT:    [[E_2:%.*]] = phi i32* [ undef, [[ENTRY:%.*]] ], [ null, [[FOR_COND1:%.*]] ]
+; IS__CGSCC_NPM-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
+; IS__CGSCC_NPM-NEXT:    store i32 [[TMP0]], i32* [[P]], align 4
+; IS__CGSCC_NPM-NEXT:    br label [[FOR_COND1]]
+; IS__CGSCC_NPM:       exit:
+; IS__CGSCC_NPM-NEXT:    ret void
 ;
 entry:
   br label %if.end
@@ -116,11 +192,23 @@ exit:
 }
 
 define internal i32 @fn0(i32 %p1) {
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn0
-; IS__CGSCC____-SAME: (i32 [[P1:%.*]]) #[[ATTR1]] {
-; IS__CGSCC____-NEXT:  entry:
-; IS__CGSCC____-NEXT:    ret i32 undef
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@fn0
+; IS__TUNIT_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1]] {
+; IS__TUNIT_OPM-NEXT:  entry:
+; IS__TUNIT_OPM-NEXT:    ret i32 [[P1]]
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn0
+; IS__CGSCC_OPM-SAME: (i32 returned [[P1:%.*]]) #[[ATTR1]] {
+; IS__CGSCC_OPM-NEXT:  entry:
+; IS__CGSCC_OPM-NEXT:    ret i32 [[P1]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn0
+; IS__CGSCC_NPM-SAME: (i32 [[P1:%.*]]) #[[ATTR1]] {
+; IS__CGSCC_NPM-NEXT:  entry:
+; IS__CGSCC_NPM-NEXT:    ret i32 undef
 ;
 entry:
   %tobool = icmp ne i32 %p1, 0
@@ -128,10 +216,15 @@ entry:
   ret i32 %cond
 }
 ;.
-; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind }
-; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid }
+; IS__TUNIT_OPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind }
+; IS__TUNIT_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }
+; IS__TUNIT_OPM: attributes #[[ATTR2]] = { nofree nosync nounwind null_pointer_is_valid }
+; IS__TUNIT_OPM: attributes #[[ATTR3]] = { nofree nosync nounwind readnone }
+;.
+; IS__TUNIT_NPM: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind }
+; IS__TUNIT_NPM: attributes #[[ATTR1]] = { nofree nosync nounwind null_pointer_is_valid }
 ;.
-; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind }
-; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn }
-; IS__CGSCC____: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind null_pointer_is_valid }
+; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind }
+; IS__CGSCC____: attributes #[[ATTR1:[0-9]+]] = { nofree norecurse nosync nounwind readnone willreturn }
+; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nofree norecurse nosync nounwind null_pointer_is_valid }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
index c81fd9ed5940..d59605ef299f 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
@@ -20,19 +20,33 @@ define internal i32* @incdec(i1 %C, i32* %V) {
 ; IS__TUNIT____-NEXT:    store i32 [[X2]], i32* [[V]], align 4
 ; IS__TUNIT____-NEXT:    ret i32* [[V]]
 ;
-; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@incdec
-; IS__CGSCC____-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] {
-; IS__CGSCC____-NEXT:    [[X:%.*]] = load i32, i32* [[V]], align 4
-; IS__CGSCC____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
-; IS__CGSCC____:       T:
-; IS__CGSCC____-NEXT:    [[X1:%.*]] = add i32 [[X]], 1
-; IS__CGSCC____-NEXT:    store i32 [[X1]], i32* [[V]], align 4
-; IS__CGSCC____-NEXT:    ret i32* undef
-; IS__CGSCC____:       F:
-; IS__CGSCC____-NEXT:    [[X2:%.*]] = sub i32 [[X]], 1
-; IS__CGSCC____-NEXT:    store i32 [[X2]], i32* [[V]], align 4
-; IS__CGSCC____-NEXT:    ret i32* undef
+; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@incdec
+; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT:    [[X:%.*]] = load i32, i32* [[V]], align 4
+; IS__CGSCC_OPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_OPM:       T:
+; IS__CGSCC_OPM-NEXT:    [[X1:%.*]] = add i32 [[X]], 1
+; IS__CGSCC_OPM-NEXT:    store i32 [[X1]], i32* [[V]], align 4
+; IS__CGSCC_OPM-NEXT:    ret i32* [[V]]
+; IS__CGSCC_OPM:       F:
+; IS__CGSCC_OPM-NEXT:    [[X2:%.*]] = sub i32 [[X]], 1
+; IS__CGSCC_OPM-NEXT:    store i32 [[X2]], i32* [[V]], align 4
+; IS__CGSCC_OPM-NEXT:    ret i32* [[V]]
+;
+; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@incdec
+; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[V:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT:    [[X:%.*]] = load i32, i32* [[V]], align 4
+; IS__CGSCC_NPM-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; IS__CGSCC_NPM:       T:
+; IS__CGSCC_NPM-NEXT:    [[X1:%.*]] = add i32 [[X]], 1
+; IS__CGSCC_NPM-NEXT:    store i32 [[X1]], i32* [[V]], align 4
+; IS__CGSCC_NPM-NEXT:    ret i32* undef
+; IS__CGSCC_NPM:       F:
+; IS__CGSCC_NPM-NEXT:    [[X2:%.*]] = sub i32 [[X]], 1
+; IS__CGSCC_NPM-NEXT:    store i32 [[X2]], i32* [[V]], align 4
+; IS__CGSCC_NPM-NEXT:    ret i32* undef
 ;
   %X = load i32, i32* %V
   br i1 %C, label %T, label %F
@@ -74,43 +88,81 @@ define internal { i32, i32 } @foo(i32 %A, i32 %B) {
 }
 
 define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn
-; IS__TUNIT____-LABEL: define {{[^@]+}}@caller
-; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 {
-; IS__TUNIT____-NEXT:    [[Q:%.*]] = alloca i32, align 4
-; IS__TUNIT____-NEXT:    [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]]
-; IS__TUNIT____-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]]
-; IS__TUNIT____-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
-; IS__TUNIT____-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]]
-; IS__TUNIT____-NEXT:    br label [[OK:%.*]]
-; IS__TUNIT____:       OK:
-; IS__TUNIT____-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
-; IS__TUNIT____-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
-; IS__TUNIT____-NEXT:    store i32 [[Z]], i32* [[Q]], align 4
-; IS__TUNIT____-NEXT:    br label [[RET:%.*]]
-; IS__TUNIT____:       LPAD:
-; IS__TUNIT____-NEXT:    unreachable
-; IS__TUNIT____:       RET:
-; IS__TUNIT____-NEXT:    ret void
+; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind willreturn
+; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@caller
+; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 {
+; IS__TUNIT_OPM-NEXT:    [[Q:%.*]] = alloca i32, align 4
+; IS__TUNIT_OPM-NEXT:    [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]]
+; IS__TUNIT_OPM-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]]
+; IS__TUNIT_OPM-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
+; IS__TUNIT_OPM-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]]
+; IS__TUNIT_OPM-NEXT:    br label [[OK:%.*]]
+; IS__TUNIT_OPM:       OK:
+; IS__TUNIT_OPM-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
+; IS__TUNIT_OPM-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
+; IS__TUNIT_OPM-NEXT:    store i32 [[Z]], i32* [[W]], align 4
+; IS__TUNIT_OPM-NEXT:    br label [[RET:%.*]]
+; IS__TUNIT_OPM:       LPAD:
+; IS__TUNIT_OPM-NEXT:    unreachable
+; IS__TUNIT_OPM:       RET:
+; IS__TUNIT_OPM-NEXT:    ret void
 ;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@caller
-; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 {
-; IS__CGSCC____-NEXT:    [[Q:%.*]] = alloca i32, align 4
-; IS__CGSCC____-NEXT:    [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]]
-; IS__CGSCC____-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]]
-; IS__CGSCC____-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
-; IS__CGSCC____-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]]
-; IS__CGSCC____-NEXT:    br label [[OK:%.*]]
-; IS__CGSCC____:       OK:
-; IS__CGSCC____-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
-; IS__CGSCC____-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
-; IS__CGSCC____-NEXT:    store i32 [[Z]], i32* [[Q]], align 4
-; IS__CGSCC____-NEXT:    br label [[RET:%.*]]
-; IS__CGSCC____:       LPAD:
-; IS__CGSCC____-NEXT:    unreachable
-; IS__CGSCC____:       RET:
-; IS__CGSCC____-NEXT:    ret void
+; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind willreturn
+; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@caller
+; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 {
+; IS__TUNIT_NPM-NEXT:    [[Q:%.*]] = alloca i32, align 4
+; IS__TUNIT_NPM-NEXT:    [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]]
+; IS__TUNIT_NPM-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]]
+; IS__TUNIT_NPM-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
+; IS__TUNIT_NPM-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]]
+; IS__TUNIT_NPM-NEXT:    br label [[OK:%.*]]
+; IS__TUNIT_NPM:       OK:
+; IS__TUNIT_NPM-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
+; IS__TUNIT_NPM-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
+; IS__TUNIT_NPM-NEXT:    store i32 [[Z]], i32* [[Q]], align 4
+; IS__TUNIT_NPM-NEXT:    br label [[RET:%.*]]
+; IS__TUNIT_NPM:       LPAD:
+; IS__TUNIT_NPM-NEXT:    unreachable
+; IS__TUNIT_NPM:       RET:
+; IS__TUNIT_NPM-NEXT:    ret void
+;
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@caller
+; IS__CGSCC_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 {
+; IS__CGSCC_OPM-NEXT:    [[Q:%.*]] = alloca i32, align 4
+; IS__CGSCC_OPM-NEXT:    [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_OPM-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]]
+; IS__CGSCC_OPM-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
+; IS__CGSCC_OPM-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]]
+; IS__CGSCC_OPM-NEXT:    br label [[OK:%.*]]
+; IS__CGSCC_OPM:       OK:
+; IS__CGSCC_OPM-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
+; IS__CGSCC_OPM-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
+; IS__CGSCC_OPM-NEXT:    store i32 [[Z]], i32* [[W]], align 4
+; IS__CGSCC_OPM-NEXT:    br label [[RET:%.*]]
+; IS__CGSCC_OPM:       LPAD:
+; IS__CGSCC_OPM-NEXT:    unreachable
+; IS__CGSCC_OPM:       RET:
+; IS__CGSCC_OPM-NEXT:    ret void
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@caller
+; IS__CGSCC_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 {
+; IS__CGSCC_NPM-NEXT:    [[Q:%.*]] = alloca i32, align 4
+; IS__CGSCC_NPM-NEXT:    [[W:%.*]] = call i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR3:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0
+; IS__CGSCC_NPM-NEXT:    [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR4:[0-9]+]]
+; IS__CGSCC_NPM-NEXT:    br label [[OK:%.*]]
+; IS__CGSCC_NPM:       OK:
+; IS__CGSCC_NPM-NEXT:    [[X2:%.*]] = extractvalue { i32, i32 } [[S2]], 0
+; IS__CGSCC_NPM-NEXT:    [[Z:%.*]] = add i32 [[X1]], [[X2]]
+; IS__CGSCC_NPM-NEXT:    store i32 [[Z]], i32* [[Q]], align 4
+; IS__CGSCC_NPM-NEXT:    br label [[RET:%.*]]
+; IS__CGSCC_NPM:       LPAD:
+; IS__CGSCC_NPM-NEXT:    unreachable
+; IS__CGSCC_NPM:       RET:
+; IS__CGSCC_NPM-NEXT:    ret void
 ;
   %Q = alloca i32
   ;; Call incdec to see if %W is properly replaced by %Q
@@ -142,11 +194,11 @@ declare i32 @__gxx_personality_v0(...)
 ;.
 ; IS__TUNIT____: attributes #[[ATTR0]] = { argmemonly nofree nosync nounwind willreturn }
 ; IS__TUNIT____: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }
-; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn }
+; IS__TUNIT____: attributes #[[ATTR2:[0-9]+]] = { nofree nosync nounwind willreturn }
 ;.
-; IS__CGSCC____: attributes #[[ATTR0]] = { argmemonly nofree norecurse nosync nounwind willreturn }
+; IS__CGSCC____: attributes #[[ATTR0:[0-9]+]] = { argmemonly nofree norecurse nosync nounwind willreturn }
 ; IS__CGSCC____: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind readnone willreturn }
-; IS__CGSCC____: attributes #[[ATTR2]] = { nounwind willreturn }
-; IS__CGSCC____: attributes #[[ATTR3]] = { readnone willreturn }
-; IS__CGSCC____: attributes #[[ATTR4]] = { nounwind readnone willreturn }
+; IS__CGSCC____: attributes #[[ATTR2:[0-9]+]] = { nounwind willreturn }
+; IS__CGSCC____: attributes #[[ATTR3:[0-9]+]] = { readnone willreturn }
+; IS__CGSCC____: attributes #[[ATTR4:[0-9]+]] = { nounwind readnone willreturn }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/heap_to_stack.ll b/llvm/test/Transforms/Attributor/heap_to_stack.ll
index aa09f1b8b562..27df244e3889 100644
--- a/llvm/test/Transforms/Attributor/heap_to_stack.ll
+++ b/llvm/test/Transforms/Attributor/heap_to_stack.ll
@@ -41,9 +41,11 @@ define void @h2s_value_simplify_interaction(i1 %c, i8* %A) {
 ; IS________OPM:       f:
 ; IS________OPM-NEXT:    br label [[J:%.*]]
 ; IS________OPM:       f2:
-; IS________OPM-NEXT:    [[L:%.*]] = load i8, i8* [[M]], align 1
+; IS________OPM-NEXT:    [[C1:%.*]] = bitcast i8* [[M]] to i32*
+; IS________OPM-NEXT:    [[C2:%.*]] = bitcast i32* [[C1]] to i8*
+; IS________OPM-NEXT:    [[L:%.*]] = load i8, i8* [[C2]], align 1
 ; IS________OPM-NEXT:    call void @usei8(i8 [[L]])
-; IS________OPM-NEXT:    call void @no_sync_func(i8* nocapture nofree noundef [[M]]) #[[ATTR5:[0-9]+]]
+; IS________OPM-NEXT:    call void @no_sync_func(i8* nocapture nofree noundef [[C2]]) #[[ATTR5:[0-9]+]]
 ; IS________OPM-NEXT:    br label [[J]]
 ; IS________OPM:       dead:
 ; IS________OPM-NEXT:    unreachable
@@ -536,9 +538,10 @@ define i32 @irreducible_cfg(i32 %0) {
 ; IS________OPM-NEXT:    br label [[TMP8]]
 ; IS________OPM:       15:
 ; IS________OPM-NEXT:    [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4
-; IS________OPM-NEXT:    call void @free(i8* nocapture noundef [[TMP2]])
-; IS________OPM-NEXT:    [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4
-; IS________OPM-NEXT:    ret i32 [[TMP17]]
+; IS________OPM-NEXT:    [[TMP17:%.*]] = bitcast i32* [[TMP3]] to i8*
+; IS________OPM-NEXT:    call void @free(i8* nocapture noundef [[TMP17]])
+; IS________OPM-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    ret i32 [[TMP18]]
 ;
 ; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg
 ; IS________NPM-SAME: (i32 [[TMP0:%.*]]) {

diff  --git a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll
index f2fe9ef20818..cb74ed43cd73 100644
--- a/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll
+++ b/llvm/test/Transforms/Attributor/heap_to_stack_gpu.ll
@@ -377,36 +377,68 @@ define void @test11() {
 
 ; TEST 12
 define i32 @irreducible_cfg(i32 %0) {
-; CHECK-LABEL: define {{[^@]+}}@irreducible_cfg
-; CHECK-SAME: (i32 [[TMP0:%.*]]) {
-; CHECK-NEXT:    [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT:    [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
-; CHECK-NEXT:    store i32 10, i32* [[TMP3]], align 4
-; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1
-; CHECK-NEXT:    br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]]
-; CHECK:       5:
-; CHECK-NEXT:    [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5
-; CHECK-NEXT:    br label [[TMP13:%.*]]
-; CHECK:       7:
-; CHECK-NEXT:    br label [[TMP8:%.*]]
-; CHECK:       8:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ]
-; CHECK-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4
-; CHECK-NEXT:    [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1
-; CHECK-NEXT:    store i32 [[TMP10]], i32* [[TMP3]], align 4
-; CHECK-NEXT:    [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0
-; CHECK-NEXT:    br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]]
-; CHECK:       12:
-; CHECK-NEXT:    br label [[TMP13]]
-; CHECK:       13:
-; CHECK-NEXT:    [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ]
-; CHECK-NEXT:    [[TMP14]] = add nsw i32 [[DOT1]], 1
-; CHECK-NEXT:    br label [[TMP8]]
-; CHECK:       15:
-; CHECK-NEXT:    [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4
-; CHECK-NEXT:    call void @free(i8* nocapture noundef [[TMP2]])
-; CHECK-NEXT:    [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4
-; CHECK-NEXT:    ret i32 [[TMP17]]
+; IS________OPM-LABEL: define {{[^@]+}}@irreducible_cfg
+; IS________OPM-SAME: (i32 [[TMP0:%.*]]) {
+; IS________OPM-NEXT:    [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4)
+; IS________OPM-NEXT:    [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+; IS________OPM-NEXT:    store i32 10, i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1
+; IS________OPM-NEXT:    br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]]
+; IS________OPM:       5:
+; IS________OPM-NEXT:    [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5
+; IS________OPM-NEXT:    br label [[TMP13:%.*]]
+; IS________OPM:       7:
+; IS________OPM-NEXT:    br label [[TMP8:%.*]]
+; IS________OPM:       8:
+; IS________OPM-NEXT:    [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ]
+; IS________OPM-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1
+; IS________OPM-NEXT:    store i32 [[TMP10]], i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0
+; IS________OPM-NEXT:    br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]]
+; IS________OPM:       12:
+; IS________OPM-NEXT:    br label [[TMP13]]
+; IS________OPM:       13:
+; IS________OPM-NEXT:    [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ]
+; IS________OPM-NEXT:    [[TMP14]] = add nsw i32 [[DOT1]], 1
+; IS________OPM-NEXT:    br label [[TMP8]]
+; IS________OPM:       15:
+; IS________OPM-NEXT:    [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    [[TMP17:%.*]] = bitcast i32* [[TMP3]] to i8*
+; IS________OPM-NEXT:    call void @free(i8* nocapture noundef [[TMP17]])
+; IS________OPM-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________OPM-NEXT:    ret i32 [[TMP18]]
+;
+; IS________NPM-LABEL: define {{[^@]+}}@irreducible_cfg
+; IS________NPM-SAME: (i32 [[TMP0:%.*]]) {
+; IS________NPM-NEXT:    [[TMP2:%.*]] = call noalias i8* @malloc(i64 noundef 4)
+; IS________NPM-NEXT:    [[TMP3:%.*]] = bitcast i8* [[TMP2]] to i32*
+; IS________NPM-NEXT:    store i32 10, i32* [[TMP3]], align 4
+; IS________NPM-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[TMP0]], 1
+; IS________NPM-NEXT:    br i1 [[TMP4]], label [[TMP5:%.*]], label [[TMP7:%.*]]
+; IS________NPM:       5:
+; IS________NPM-NEXT:    [[TMP6:%.*]] = add nsw i32 [[TMP0]], 5
+; IS________NPM-NEXT:    br label [[TMP13:%.*]]
+; IS________NPM:       7:
+; IS________NPM-NEXT:    br label [[TMP8:%.*]]
+; IS________NPM:       8:
+; IS________NPM-NEXT:    [[DOT0:%.*]] = phi i32 [ [[TMP14:%.*]], [[TMP13]] ], [ 1, [[TMP7]] ]
+; IS________NPM-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________NPM-NEXT:    [[TMP10:%.*]] = add nsw i32 [[TMP9]], -1
+; IS________NPM-NEXT:    store i32 [[TMP10]], i32* [[TMP3]], align 4
+; IS________NPM-NEXT:    [[TMP11:%.*]] = icmp ne i32 [[TMP9]], 0
+; IS________NPM-NEXT:    br i1 [[TMP11]], label [[TMP12:%.*]], label [[TMP15:%.*]]
+; IS________NPM:       12:
+; IS________NPM-NEXT:    br label [[TMP13]]
+; IS________NPM:       13:
+; IS________NPM-NEXT:    [[DOT1:%.*]] = phi i32 [ [[TMP6]], [[TMP5]] ], [ [[DOT0]], [[TMP12]] ]
+; IS________NPM-NEXT:    [[TMP14]] = add nsw i32 [[DOT1]], 1
+; IS________NPM-NEXT:    br label [[TMP8]]
+; IS________NPM:       15:
+; IS________NPM-NEXT:    [[TMP16:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________NPM-NEXT:    call void @free(i8* nocapture noundef [[TMP2]])
+; IS________NPM-NEXT:    [[TMP17:%.*]] = load i32, i32* [[TMP3]], align 4
+; IS________NPM-NEXT:    ret i32 [[TMP17]]
 ;
   %2 = call noalias i8* @malloc(i64 4)
   %3 = bitcast i8* %2 to i32*

diff  --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll
index a28de51ed839..60cf10019c16 100644
--- a/llvm/test/Transforms/Attributor/memory_locations.ll
+++ b/llvm/test/Transforms/Attributor/memory_locations.ll
@@ -639,20 +639,20 @@ define internal i8 @recursive_not_readnone_internal2(i8* %ptr, i1 %c) {
 ; IS__TUNIT____-NEXT:    [[R:%.*]] = load i8, i8* [[ALLOC]], align 1
 ; IS__TUNIT____-NEXT:    ret i8 [[R]]
 ; IS__TUNIT____:       f:
-; IS__TUNIT____-NEXT:    store i8 1, i8* [[ALLOC]], align 1
+; IS__TUNIT____-NEXT:    store i8 1, i8* [[PTR]], align 1
 ; IS__TUNIT____-NEXT:    ret i8 0
 ;
-; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
+; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal2
-; IS__CGSCC____-SAME: (i8* noalias nocapture nofree nonnull readnone [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR9]] {
+; IS__CGSCC____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] {
 ; IS__CGSCC____-NEXT:    [[ALLOC:%.*]] = alloca i8, align 1
 ; IS__CGSCC____-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
 ; IS__CGSCC____:       t:
-; IS__CGSCC____-NEXT:    [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree nonnull readnone dereferenceable(1) undef, i1 noundef false) #[[ATTR9]]
+; IS__CGSCC____-NEXT:    [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]]
 ; IS__CGSCC____-NEXT:    [[R:%.*]] = load i8, i8* [[ALLOC]], align 1
 ; IS__CGSCC____-NEXT:    ret i8 [[R]]
 ; IS__CGSCC____:       f:
-; IS__CGSCC____-NEXT:    store i8 1, i8* [[ALLOC]], align 1
+; IS__CGSCC____-NEXT:    store i8 1, i8* [[PTR]], align 1
 ; IS__CGSCC____-NEXT:    ret i8 0
 ;
   %alloc = alloca i8
@@ -676,7 +676,7 @@ define i8 @readnone_caller2(i1 %c) {
 ; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone
 ; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2
 ; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] {
-; IS__CGSCC____-NEXT:    [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR13:[0-9]+]]
+; IS__CGSCC____-NEXT:    [[R:%.*]] = call i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR12]]
 ; IS__CGSCC____-NEXT:    ret i8 [[R]]
 ;
   %r = call i8 @recursive_not_readnone_internal2(i8* undef, i1 %c)
@@ -742,5 +742,4 @@ define void @argmemonky_caller() {
 ; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind willreturn writeonly }
 ; IS__CGSCC____: attributes #[[ATTR11]] = { nofree nosync nounwind }
 ; IS__CGSCC____: attributes #[[ATTR12]] = { nounwind }
-; IS__CGSCC____: attributes #[[ATTR13]] = { nounwind readnone }
 ;.

diff  --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll
index 60ec42913ff3..e28fd41c7eec 100644
--- a/llvm/test/Transforms/Attributor/noalias.ll
+++ b/llvm/test/Transforms/Attributor/noalias.ll
@@ -417,11 +417,13 @@ define void @test12_4(){
 ; IS________OPM-LABEL: define {{[^@]+}}@test12_4() {
 ; IS________OPM-NEXT:    [[A:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
 ; IS________OPM-NEXT:    [[B:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
+; IS________OPM-NEXT:    [[A_0:%.*]] = getelementptr i8, i8* [[A]], i64 0
 ; IS________OPM-NEXT:    [[A_1:%.*]] = getelementptr i8, i8* [[A]], i64 1
+; IS________OPM-NEXT:    [[B_0:%.*]] = getelementptr i8, i8* [[B]], i64 0
 ; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[B]])
-; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A]])
+; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_0]])
 ; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[A_1]])
-; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A]], i8* nocapture [[B]])
+; IS________OPM-NEXT:    tail call void @two_args(i8* nocapture [[A_0]], i8* nocapture [[B_0]])
 ; IS________OPM-NEXT:    ret void
 ;
 ; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test12_4() {
@@ -463,10 +465,17 @@ define void @use_i8_internal(i8* %a) {
 }
 
 define void @test13_use_noalias(){
-; CHECK-LABEL: define {{[^@]+}}@test13_use_noalias() {
-; CHECK-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT:    call void @use_i8_internal(i8* noalias nocapture [[M1]])
-; CHECK-NEXT:    ret void
+; IS________OPM-LABEL: define {{[^@]+}}@test13_use_noalias() {
+; IS________OPM-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
+; IS________OPM-NEXT:    [[C1:%.*]] = bitcast i8* [[M1]] to i16*
+; IS________OPM-NEXT:    [[C2:%.*]] = bitcast i16* [[C1]] to i8*
+; IS________OPM-NEXT:    call void @use_i8_internal(i8* noalias nocapture [[C2]])
+; IS________OPM-NEXT:    ret void
+;
+; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test13_use_noalias() {
+; NOT_TUNIT_OPM-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
+; NOT_TUNIT_OPM-NEXT:    call void @use_i8_internal(i8* noalias nocapture [[M1]])
+; NOT_TUNIT_OPM-NEXT:    ret void
 ;
 ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@test13_use_noalias()
 ; IS__CGSCC_OPM-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 4)
@@ -482,11 +491,20 @@ define void @test13_use_noalias(){
 }
 
 define void @test13_use_alias(){
-; CHECK-LABEL: define {{[^@]+}}@test13_use_alias() {
-; CHECK-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
-; CHECK-NEXT:    call void @use_i8_internal(i8* nocapture [[M1]])
-; CHECK-NEXT:    call void @use_i8_internal(i8* nocapture [[M1]])
-; CHECK-NEXT:    ret void
+; IS________OPM-LABEL: define {{[^@]+}}@test13_use_alias() {
+; IS________OPM-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
+; IS________OPM-NEXT:    [[C1:%.*]] = bitcast i8* [[M1]] to i16*
+; IS________OPM-NEXT:    [[C2A:%.*]] = bitcast i16* [[C1]] to i8*
+; IS________OPM-NEXT:    [[C2B:%.*]] = bitcast i16* [[C1]] to i8*
+; IS________OPM-NEXT:    call void @use_i8_internal(i8* nocapture [[C2A]])
+; IS________OPM-NEXT:    call void @use_i8_internal(i8* nocapture [[C2B]])
+; IS________OPM-NEXT:    ret void
+;
+; NOT_TUNIT_OPM-LABEL: define {{[^@]+}}@test13_use_alias() {
+; NOT_TUNIT_OPM-NEXT:    [[M1:%.*]] = tail call noalias i8* @malloc(i64 noundef 4)
+; NOT_TUNIT_OPM-NEXT:    call void @use_i8_internal(i8* nocapture [[M1]])
+; NOT_TUNIT_OPM-NEXT:    call void @use_i8_internal(i8* nocapture [[M1]])
+; NOT_TUNIT_OPM-NEXT:    ret void
 ;
   %m1 = tail call noalias i8* @malloc(i64 4)
   %c1 = bitcast i8* %m1 to i16*

diff  --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll
index d3f73c3a2650..f1b0de6499b9 100644
--- a/llvm/test/Transforms/Attributor/nonnull.ll
+++ b/llvm/test/Transforms/Attributor/nonnull.ll
@@ -276,7 +276,7 @@ define i8* @test6b(i1 %c) {
 ; CHECK-NEXT:    [[PHI:%.*]] = phi i8* [ [[RET]], [[ENTRY:%.*]] ], [ [[PHI]], [[LOOP]] ]
 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
 ; CHECK:       exit:
-; CHECK-NEXT:    ret i8* [[RET]]
+; CHECK-NEXT:    ret i8* [[PHI]]
 ;
 entry:
   %ret = call i8* @ret_nonnull()

diff  --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll
index 1d23a20890c4..78575c343dba 100644
--- a/llvm/test/Transforms/Attributor/value-simplify.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify.ll
@@ -1224,6 +1224,47 @@ define internal i1 @cmp_null_after_cast(i32 %a, i8 %b) {
   ret i1 %c
 }
 
+
+declare i8* @m()
+
+define i32 @test(i1 %c) {
+; CHECK-LABEL: define {{[^@]+}}@test
+; CHECK-SAME: (i1 [[C:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ctx_test(i1 [[C]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ctx_test(i1 %c)
+  ret i32 %r
+}
+
+define internal i32 @ctx_test(i1 %c) {
+; CHECK-LABEL: define {{[^@]+}}@ctx_test
+; CHECK-SAME: (i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
+; CHECK:       then:
+; CHECK-NEXT:    [[M:%.*]] = tail call i8* @m()
+; CHECK-NEXT:    [[I:%.*]] = ptrtoint i8* [[M]] to i64
+; CHECK-NEXT:    br label [[JOIN]]
+; CHECK:       join:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[RET:%.*]] = trunc i64 [[PHI]] to i32
+; CHECK-NEXT:    ret i32 [[RET]]
+;
+entry:
+  br i1 %c, label %then, label %join
+
+then:
+  %m = tail call i8* @m()
+  %i = ptrtoint i8* %m to i64
+  br label %join
+
+join:
+  %phi = phi i64 [ %i, %then ], [ undef, %entry ]
+  %ret = trunc i64 %phi to i32
+  ret i32 %ret
+}
+
 ;.
 ; IS__TUNIT_OPM: attributes #[[ATTR0]] = { nofree nosync nounwind willreturn }
 ; IS__TUNIT_OPM: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }


        


More information about the llvm-commits mailing list