[llvm] 821a0f2 - [AssumeBundles] Prevent generation of some redundant assumes

via llvm-commits llvm-commits at lists.llvm.org
Sun May 10 10:24:11 PDT 2020


Author: Tyker
Date: 2020-05-10T19:23:59+02:00
New Revision: 821a0f23d83921bf32a0a290b5f267f3514d09df

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

LOG: [AssumeBundles] Prevent generation of some redundant assumes

Summary: with this patch the assume salvageKnowledge will not generate assume if all knowledge is already available in an assume with valid context. assume bulider can also in some cases update an existing assume with better information.

Reviewers: jdoerfert

Reviewed By: jdoerfert

Subscribers: hiraditya, llvm-commits

Tags: #llvm

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

Added: 
    

Modified: 
    llvm/include/llvm/Analysis/AssumeBundleQueries.h
    llvm/include/llvm/Transforms/Utils/AssumeBundleBuilder.h
    llvm/lib/Analysis/AssumeBundleQueries.cpp
    llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
    llvm/test/Analysis/BasicAA/featuretest.ll
    llvm/test/Transforms/EarlyCSE/guards.ll
    llvm/test/Transforms/EarlyCSE/invariant-loads.ll
    llvm/test/Transforms/Util/assume-builder.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/AssumeBundleQueries.h b/llvm/include/llvm/Analysis/AssumeBundleQueries.h
index 4c01717fa1b3..3810ee595e8e 100644
--- a/llvm/include/llvm/Analysis/AssumeBundleQueries.h
+++ b/llvm/include/llvm/Analysis/AssumeBundleQueries.h
@@ -142,8 +142,9 @@ RetainedKnowledge getKnowledgeFromUse(const Use *U,
 RetainedKnowledge getKnowledgeForValue(
     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
     AssumptionCache *AC = nullptr,
-    function_ref<bool(RetainedKnowledge, Instruction *)> Filter =
-        [](RetainedKnowledge, Instruction *) { return true; });
+    function_ref<bool(RetainedKnowledge, Instruction *,
+                            const CallBase::BundleOpInfo *)>
+        Filter = [](auto...) { return true; });
 
 /// Return a valid Knowledge associated to the Value V if its Attribute kind is
 /// in AttrKinds and the knowledge is suitable to be used in the context of

diff  --git a/llvm/include/llvm/Transforms/Utils/AssumeBundleBuilder.h b/llvm/include/llvm/Transforms/Utils/AssumeBundleBuilder.h
index f1cd0239b008..e50bd761aff4 100644
--- a/llvm/include/llvm/Transforms/Utils/AssumeBundleBuilder.h
+++ b/llvm/include/llvm/Transforms/Utils/AssumeBundleBuilder.h
@@ -23,6 +23,7 @@
 namespace llvm {
 class IntrinsicInst;
 class AssumptionCache;
+class DominatorTree;
 
 /// Build a call to llvm.assume to preserve informations that can be derived
 /// from the given instruction.
@@ -33,7 +34,12 @@ IntrinsicInst *buildAssumeFromInst(Instruction *I);
 /// Calls BuildAssumeFromInst and if the resulting llvm.assume is valid insert
 /// if before I. This is usually what need to be done to salvage the knowledge
 /// contained in the instruction I.
-void salvageKnowledge(Instruction *I, AssumptionCache *AC = nullptr);
+/// The AssumptionCache must be provided if it is available or the cache may
+/// become silently be invalid.
+/// The DominatorTree can optionally be provided to enable cross-block
+/// reasoning.
+void salvageKnowledge(Instruction *I, AssumptionCache *AC = nullptr,
+                      DominatorTree *DT = nullptr);
 
 /// This pass will try to build an llvm.assume for every instruction in the
 /// function. Its main purpose is testing.

diff  --git a/llvm/lib/Analysis/AssumeBundleQueries.cpp b/llvm/lib/Analysis/AssumeBundleQueries.cpp
index ec1eb6804846..7cd7536b34ea 100644
--- a/llvm/lib/Analysis/AssumeBundleQueries.cpp
+++ b/llvm/lib/Analysis/AssumeBundleQueries.cpp
@@ -120,25 +120,35 @@ bool llvm::isAssumeWithEmptyBundle(CallInst &CI) {
                  });
 }
 
+static CallInst::BundleOpInfo *getBundleFromUse(const Use *U) {
+  auto *Intr = dyn_cast<IntrinsicInst>(U->getUser());
+  if (!match(U->getUser(),
+             m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
+    return nullptr;
+  return &Intr->getBundleOpInfoForOperand(U->getOperandNo());
+}
+
 RetainedKnowledge
 llvm::getKnowledgeFromUse(const Use *U,
                           ArrayRef<Attribute::AttrKind> AttrKinds) {
-  if (!match(U->getUser(),
-             m_Intrinsic<Intrinsic::assume>(m_Unless(m_Specific(U->get())))))
+  CallInst::BundleOpInfo* Bundle = getBundleFromUse(U);
+  if (!Bundle)
     return RetainedKnowledge::none();
-  auto *Intr = cast<IntrinsicInst>(U->getUser());
   RetainedKnowledge RK =
-      getKnowledgeFromOperandInAssume(*Intr, U->getOperandNo());
+      getKnowledgeFromBundle(*cast<CallInst>(U->getUser()), *Bundle);
   for (auto Attr : AttrKinds)
     if (Attr == RK.AttrKind)
       return RK;
   return RetainedKnowledge::none();
 }
 
-RetainedKnowledge llvm::getKnowledgeForValue(
-    const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
-    AssumptionCache *AC,
-    function_ref<bool(RetainedKnowledge, Instruction *)> Filter) {
+RetainedKnowledge
+llvm::getKnowledgeForValue(const Value *V,
+                           ArrayRef<Attribute::AttrKind> AttrKinds,
+                           AssumptionCache *AC,
+                           function_ref<bool(RetainedKnowledge, Instruction *,
+                                             const CallBase::BundleOpInfo *)>
+                               Filter) {
   if (AC) {
 #ifndef NDEBUG
     RetainedKnowledge RKCheck =
@@ -150,7 +160,8 @@ RetainedKnowledge llvm::getKnowledgeForValue(
         continue;
       if (RetainedKnowledge RK = getKnowledgeFromBundle(
               *II, II->bundle_op_info_begin()[Elem.Index]))
-        if (is_contained(AttrKinds, RK.AttrKind) && Filter(RK, II)) {
+        if (is_contained(AttrKinds, RK.AttrKind) &&
+            Filter(RK, II, &II->bundle_op_info_begin()[Elem.Index])) {
           assert(!!RKCheck && "invalid Assumption cache");
           return RK;
         }
@@ -159,8 +170,13 @@ RetainedKnowledge llvm::getKnowledgeForValue(
     return RetainedKnowledge::none();
   }
   for (auto &U : V->uses()) {
-    if (RetainedKnowledge RK = getKnowledgeFromUse(&U, AttrKinds))
-      if (Filter(RK, cast<Instruction>(U.getUser())))
+    CallInst::BundleOpInfo* Bundle = getBundleFromUse(&U);
+    if (!Bundle)
+      continue;
+    if (RetainedKnowledge RK =
+            getKnowledgeFromBundle(*cast<CallInst>(U.getUser()), *Bundle))
+      if (is_contained(AttrKinds, RK.AttrKind) &&
+          Filter(RK, cast<Instruction>(U.getUser()), Bundle))
         return RK;
   }
   return RetainedKnowledge::none();
@@ -170,7 +186,7 @@ RetainedKnowledge llvm::getKnowledgeValidInContext(
     const Value *V, ArrayRef<Attribute::AttrKind> AttrKinds,
     const Instruction *CtxI, const DominatorTree *DT, AssumptionCache *AC) {
   return getKnowledgeForValue(V, AttrKinds, AC,
-                              [&](RetainedKnowledge, Instruction *I) {
+                              [&](auto, Instruction *I, auto) {
                                 return isValidAssumeForContext(I, CtxI, DT);
                               });
 }

diff  --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
index ab82950bc24c..55b9ce7f4c56 100644
--- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
+++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp
@@ -9,7 +9,8 @@
 #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
 #include "llvm/Analysis/AssumeBundleQueries.h"
 #include "llvm/Analysis/AssumptionCache.h"
-#include "llvm/ADT/DenseSet.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/Dominators.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/InstIterator.h"
 #include "llvm/IR/IntrinsicInst.h"
@@ -74,10 +75,45 @@ struct AssumeBuilderState {
   using MapKey = std::pair<Value *, Attribute::AttrKind>;
   SmallDenseMap<MapKey, unsigned, 8> AssumedKnowledgeMap;
   Instruction *InsertBeforeInstruction = nullptr;
+  AssumptionCache* AC = nullptr;
+  DominatorTree* DT = nullptr;
 
-  AssumeBuilderState(Module *M) : M(M) {}
+  AssumeBuilderState(Module *M, Instruction *I = nullptr,
+                     AssumptionCache *AC = nullptr, DominatorTree *DT = nullptr)
+      : M(M), InsertBeforeInstruction(I), AC(AC), DT(DT) {}
+
+  bool tryToPreserveWithoutAddingAssume(RetainedKnowledge RK) {
+    if (!InsertBeforeInstruction || !AC || !RK.WasOn)
+      return false;
+    bool HasBeenPreserved = false;
+    Use* ToUpdate = nullptr;
+    getKnowledgeForValue(
+        RK.WasOn, {RK.AttrKind}, AC,
+        [&](RetainedKnowledge RKOther, Instruction *Assume,
+            const CallInst::BundleOpInfo *Bundle) {
+          if (!isValidAssumeForContext(Assume, InsertBeforeInstruction, DT))
+            return false;
+          if (RKOther.ArgValue >= RK.ArgValue) {
+            HasBeenPreserved = true;
+            return true;
+          } else if (isValidAssumeForContext(InsertBeforeInstruction, Assume,
+                                             DT)) {
+            HasBeenPreserved = true;
+            IntrinsicInst *Intr = cast<IntrinsicInst>(Assume);
+            ToUpdate = &Intr->op_begin()[Bundle->Begin + ABA_Argument];
+            return true;
+          }
+          return false;
+        });
+    if (ToUpdate)
+      ToUpdate->set(
+          ConstantInt::get(Type::getInt64Ty(M->getContext()), RK.ArgValue));
+    return HasBeenPreserved;
+  }
 
   void addKnowledge(RetainedKnowledge RK) {
+    if (tryToPreserveWithoutAddingAssume(RK))
+      return;
     MapKey Key{RK.WasOn, RK.AttrKind};
     auto Lookup = AssumedKnowledgeMap.find(Key);
     if (Lookup == AssumedKnowledgeMap.end()) {
@@ -185,11 +221,10 @@ IntrinsicInst *llvm::buildAssumeFromInst(Instruction *I) {
   return Builder.build();
 }
 
-void llvm::salvageKnowledge(Instruction *I, AssumptionCache *AC) {
+void llvm::salvageKnowledge(Instruction *I, AssumptionCache *AC, DominatorTree* DT) {
   if (!EnableKnowledgeRetention)
     return;
-  AssumeBuilderState Builder(I->getModule());
-  Builder.InsertBeforeInstruction = I;
+  AssumeBuilderState Builder(I->getModule(), I, AC, DT);
   Builder.addInstruction(I);
   if (IntrinsicInst *Intr = Builder.build()) {
     Intr->insertBefore(I);
@@ -200,8 +235,9 @@ void llvm::salvageKnowledge(Instruction *I, AssumptionCache *AC) {
 
 PreservedAnalyses AssumeBuilderPass::run(Function &F,
                                          FunctionAnalysisManager &AM) {
+  AssumptionCache* AC = AM.getCachedResult<AssumptionAnalysis>(F);
+  DominatorTree* DT = AM.getCachedResult<DominatorTreeAnalysis>(F);
   for (Instruction &I : instructions(F))
-    if (Instruction *Assume = buildAssumeFromInst(&I))
-      Assume->insertBefore(&I);
+    salvageKnowledge(&I, AC, DT);
   return PreservedAnalyses::all();
 }

diff  --git a/llvm/test/Analysis/BasicAA/featuretest.ll b/llvm/test/Analysis/BasicAA/featuretest.ll
index 7e061f62bd76..401b709e539b 100644
--- a/llvm/test/Analysis/BasicAA/featuretest.ll
+++ b/llvm/test/Analysis/BasicAA/featuretest.ll
@@ -36,7 +36,6 @@ define i32 @
diff erent_array_test(i64 %A, i64 %B) {
 ; USE_ASSUME-NEXT:    call void @external(i32* nonnull [[ARRAY11_SUB]])
 ; USE_ASSUME-NEXT:    call void @external(i32* nonnull [[ARRAY22_SUB]])
 ; USE_ASSUME-NEXT:    [[POINTER:%.*]] = getelementptr [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 [[A:%.*]]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
 ; USE_ASSUME-NEXT:    [[POINTER2:%.*]] = getelementptr [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 [[B:%.*]]
 ; USE_ASSUME-NEXT:    store i32 7, i32* [[POINTER2]], align 4
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
@@ -78,7 +77,6 @@ define i32 @constant_array_index_test() {
 ; USE_ASSUME-NEXT:    call void @external(i32* nonnull [[ARRAY1_SUB]])
 ; USE_ASSUME-NEXT:    [[P1:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 7
 ; USE_ASSUME-NEXT:    [[P2:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 6
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
 ; USE_ASSUME-NEXT:    store i32 1, i32* [[P2]], align 4
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
 ; USE_ASSUME-NEXT:    ret i32 0
@@ -105,8 +103,7 @@ define i32 @gep_distance_test(i32* %A) {
 ; NO_ASSUME-NEXT:    ret i32 0
 ;
 ; USE_ASSUME-LABEL: @gep_distance_test(
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
-; USE_ASSUME-NEXT:    [[B:%.*]] = getelementptr i32, i32* [[A]], i64 2
+; USE_ASSUME-NEXT:    [[B:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 2
 ; USE_ASSUME-NEXT:    store i32 7, i32* [[B]], align 4
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
 ; USE_ASSUME-NEXT:    ret i32 0
@@ -129,7 +126,6 @@ define i32 @gep_distance_test2({i32,i32}* %A, i64 %distance) {
 ;
 ; USE_ASSUME-LABEL: @gep_distance_test2(
 ; USE_ASSUME-NEXT:    [[A1:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A:%.*]], i64 0, i32 0
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
 ; USE_ASSUME-NEXT:    [[B:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A]], i64 [[DISTANCE:%.*]], i32 1
 ; USE_ASSUME-NEXT:    store i32 7, i32* [[B]], align 4
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
@@ -154,8 +150,7 @@ define i32 @gep_distance_test3(i32 * %A) {
 ; NO_ASSUME-NEXT:    ret i32 0
 ;
 ; USE_ASSUME-LABEL: @gep_distance_test3(
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
-; USE_ASSUME-NEXT:    [[C1:%.*]] = getelementptr i32, i32* [[A]], i64 1
+; USE_ASSUME-NEXT:    [[C1:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 1
 ; USE_ASSUME-NEXT:    [[C:%.*]] = bitcast i32* [[C1]] to i8*
 ; USE_ASSUME-NEXT:    store i8 42, i8* [[C]], align 1
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
@@ -181,7 +176,6 @@ define i32 @constexpr_test() {
 ; USE_ASSUME-LABEL: @constexpr_test(
 ; USE_ASSUME-NEXT:    [[X:%.*]] = alloca i32, align 4
 ; USE_ASSUME-NEXT:    call void @external(i32* nonnull [[X]])
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
 ; USE_ASSUME-NEXT:    store i32 5, i32* getelementptr inbounds ({ i32 }, { i32 }* @Global, i64 0, i32 0), align 4
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
 ; USE_ASSUME-NEXT:    ret i32 0

diff  --git a/llvm/test/Transforms/EarlyCSE/guards.ll b/llvm/test/Transforms/EarlyCSE/guards.ll
index 3f162bd44b35..f266e5ee8418 100644
--- a/llvm/test/Transforms/EarlyCSE/guards.ll
+++ b/llvm/test/Transforms/EarlyCSE/guards.ll
@@ -229,7 +229,6 @@ define void @test08(i32 %a, i32 %b, i32* %ptr) {
 ; USE_ASSUME-NEXT:    store i32 100, i32* [[PTR:%.*]]
 ; USE_ASSUME-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CMP]]) [ "deopt"() ]
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    store i32 400, i32* [[PTR]]
 ; USE_ASSUME-NEXT:    ret void
 ;
@@ -271,7 +270,6 @@ define void @test09(i32 %a, i32 %b, i1 %c, i32* %ptr) {
 ; USE_ASSUME-NEXT:    store i32 100, i32* [[PTR:%.*]]
 ; USE_ASSUME-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[CMP]]) [ "deopt"() ]
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    store i32 400, i32* [[PTR]]
 ; USE_ASSUME-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; USE_ASSUME:       if.true:
@@ -410,8 +408,6 @@ define void @test13(i32 %a, i32 %b, i32* %ptr) {
 ; USE_ASSUME-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 [[CMP]])
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR:%.*]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    store i32 400, i32* [[PTR]]
 ; USE_ASSUME-NEXT:    ret void
 ;
@@ -452,8 +448,6 @@ define void @test14(i32 %a, i32 %b, i1 %c, i32* %ptr) {
 ; USE_ASSUME-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 [[CMP]])
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR:%.*]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    store i32 400, i32* [[PTR]]
 ; USE_ASSUME-NEXT:    br i1 [[C:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
 ; USE_ASSUME:       if.true:

diff  --git a/llvm/test/Transforms/EarlyCSE/invariant-loads.ll b/llvm/test/Transforms/EarlyCSE/invariant-loads.ll
index d20521afa8a6..393103c9dc34 100644
--- a/llvm/test/Transforms/EarlyCSE/invariant-loads.ll
+++ b/llvm/test/Transforms/EarlyCSE/invariant-loads.ll
@@ -18,7 +18,6 @@ define void @f_0(i32* %ptr) {
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[PTR]], i64 4), "nonnull"(i32* [[PTR]]) ]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[VAL0]])
 ; USE_ASSUME-NEXT:    ret void
 ;
@@ -194,7 +193,6 @@ define void @test_scope_start_without_load(i32* %p) {
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
 ; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
 ; USE_ASSUME-NEXT:    ret void
 ;
@@ -225,7 +223,6 @@ define void @test_scope_restart(i32* %p) {
 ; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
 ; USE_ASSUME-NEXT:    [[ADD:%.*]] = add i32 [[V1]], [[V1]]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[ADD]])
-; USE_ASSUME-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
 ; USE_ASSUME-NEXT:    call void @clobber_and_use(i32 [[V1]])
 ; USE_ASSUME-NEXT:    ret void
 ;

diff  --git a/llvm/test/Transforms/Util/assume-builder.ll b/llvm/test/Transforms/Util/assume-builder.ll
index 8e6d2ec34d1b..513d6d8d8ae4 100644
--- a/llvm/test/Transforms/Util/assume-builder.ll
+++ b/llvm/test/Transforms/Util/assume-builder.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=BASIC
 ; RUN: opt -passes='assume-builder,verify' --enable-knowledge-retention --assume-preserve-all -S %s | FileCheck %s --check-prefixes=ALL
+; RUN: opt -passes='require<assumptions>,assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=WITH-AC
+; RUN: opt -passes='require<domtree>,require<assumptions>,assume-builder,verify' --enable-knowledge-retention -S %s | FileCheck %s --check-prefixes=CROSS-BLOCK
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 
@@ -22,8 +24,8 @@ define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {
 ; BASIC-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]])
 ; BASIC-NEXT:    call void @func(i32* [[P1]], i32* [[P]])
 ; BASIC-NEXT:    call void @func_strbool(i32* [[P1]])
-; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 16) ]
-; BASIC-NEXT:    call void @func(i32* dereferenceable(16) [[P]], i32* dereferenceable(8) [[P]])
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 32) ]
+; BASIC-NEXT:    call void @func(i32* dereferenceable(32) [[P]], i32* dereferenceable(8) [[P]])
 ; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8) ]
 ; BASIC-NEXT:    call void @func_many(i32* align 8 [[P1]])
 ; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P2:%.*]], i64 8), "nonnull"(i32* [[P3:%.*]]) ]
@@ -43,8 +45,8 @@ define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {
 ; ALL-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]])
 ; ALL-NEXT:    call void @func(i32* [[P1]], i32* [[P]])
 ; ALL-NEXT:    call void @func_strbool(i32* [[P1]])
-; ALL-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 16) ]
-; ALL-NEXT:    call void @func(i32* dereferenceable(16) [[P]], i32* dereferenceable(8) [[P]])
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 32) ]
+; ALL-NEXT:    call void @func(i32* dereferenceable(32) [[P]], i32* dereferenceable(8) [[P]])
 ; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8), "norecurse"(), "nounwind"(), "willreturn"() ]
 ; ALL-NEXT:    call void @func_many(i32* align 8 [[P1]])
 ; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P2:%.*]], i64 8), "nonnull"(i32* [[P3:%.*]]), "nounwind"() ]
@@ -53,13 +55,56 @@ define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {
 ; ALL-NEXT:    call void @func(i32* nonnull [[P1]], i32* nonnull [[P]])
 ; ALL-NEXT:    ret void
 ;
+; WITH-AC-LABEL: @test(
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P:%.*]], i64 16), "nonnull"(i32* [[P]]) ]
+; WITH-AC-NEXT:    call void @func(i32* nonnull dereferenceable(16) [[P]], i32* null)
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1:%.*]], i64 12) ]
+; WITH-AC-NEXT:    call void @func(i32* dereferenceable(12) [[P1]], i32* nonnull [[P]])
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "cold"() ]
+; WITH-AC-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]]) #0
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "cold"() ]
+; WITH-AC-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]])
+; WITH-AC-NEXT:    call void @func(i32* [[P1]], i32* [[P]])
+; WITH-AC-NEXT:    call void @func_strbool(i32* [[P1]])
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 32) ]
+; WITH-AC-NEXT:    call void @func(i32* dereferenceable(32) [[P]], i32* dereferenceable(8) [[P]])
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8) ]
+; WITH-AC-NEXT:    call void @func_many(i32* align 8 [[P1]])
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P2:%.*]], i64 8), "nonnull"(i32* [[P3:%.*]]) ]
+; WITH-AC-NEXT:    call void @func_argattr(i32* [[P2]], i32* [[P3]])
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(i32* [[P1]]) ]
+; WITH-AC-NEXT:    call void @func(i32* nonnull [[P1]], i32* nonnull [[P]])
+; WITH-AC-NEXT:    ret void
+;
+; CROSS-BLOCK-LABEL: @test(
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P:%.*]], i64 16), "nonnull"(i32* [[P]]) ]
+; CROSS-BLOCK-NEXT:    call void @func(i32* nonnull dereferenceable(16) [[P]], i32* null)
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1:%.*]], i64 12) ]
+; CROSS-BLOCK-NEXT:    call void @func(i32* dereferenceable(12) [[P1]], i32* nonnull [[P]])
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "cold"() ]
+; CROSS-BLOCK-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]]) #0
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "cold"() ]
+; CROSS-BLOCK-NEXT:    call void @func_cold(i32* dereferenceable(12) [[P1]])
+; CROSS-BLOCK-NEXT:    call void @func(i32* [[P1]], i32* [[P]])
+; CROSS-BLOCK-NEXT:    call void @func_strbool(i32* [[P1]])
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P]], i64 32) ]
+; CROSS-BLOCK-NEXT:    call void @func(i32* dereferenceable(32) [[P]], i32* dereferenceable(8) [[P]])
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8) ]
+; CROSS-BLOCK-NEXT:    call void @func_many(i32* align 8 [[P1]])
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P2:%.*]], i64 8), "nonnull"(i32* [[P3:%.*]]) ]
+; CROSS-BLOCK-NEXT:    call void @func_argattr(i32* [[P2]], i32* [[P3]])
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "nonnull"(i32* [[P1]]) ]
+; CROSS-BLOCK-NEXT:    call void @func(i32* nonnull [[P1]], i32* nonnull [[P]])
+; CROSS-BLOCK-NEXT:    ret void
+;
+
   call void @func(i32* nonnull dereferenceable(16) %P, i32* null)
   call void @func(i32* dereferenceable(12) %P1, i32* nonnull %P)
   call void @func_cold(i32* dereferenceable(12) %P1) cold
   call void @func_cold(i32* dereferenceable(12) %P1)
   call void @func(i32* %P1, i32* %P)
   call void @func_strbool(i32* %P1)
-  call void @func(i32* dereferenceable(16) %P, i32* dereferenceable(8) %P)
+  call void @func(i32* dereferenceable(32) %P, i32* dereferenceable(8) %P)
   call void @func_many(i32* align 8 %P1)
   call void @func_argattr(i32* %P2, i32* %P3)
   call void @func(i32* nonnull %P1, i32* nonnull %P)
@@ -162,6 +207,90 @@ define i32 @test2(%struct.S* %0, i32* %1, i8* %2) {
 ; ALL-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
 ; ALL-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
 ; ALL-NEXT:    ret i32 [[TMP28]]
+;
+; WITH-AC-LABEL: @test2(
+; WITH-AC-NEXT:    [[TMP4:%.*]] = alloca %struct.S*, align 8
+; WITH-AC-NEXT:    [[TMP5:%.*]] = alloca i32*, align 8
+; WITH-AC-NEXT:    [[TMP6:%.*]] = alloca i8*, align 8
+; WITH-AC-NEXT:    [[TMP7:%.*]] = alloca [[STRUCT_S:%.*]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8), "nonnull"(%struct.S** [[TMP4]]) ]
+; WITH-AC-NEXT:    store %struct.S* [[TMP0:%.*]], %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP5]], i64 8), "dereferenceable"(i32** [[TMP5]], i64 8), "nonnull"(i32** [[TMP5]]) ]
+; WITH-AC-NEXT:    store i32* [[TMP1:%.*]], i32** [[TMP5]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8** [[TMP6]], i64 8), "nonnull"(i8** [[TMP6]]) ]
+; WITH-AC-NEXT:    store i8* [[TMP2:%.*]], i8** [[TMP6]]
+; WITH-AC-NEXT:    [[TMP8:%.*]] = load i32*, i32** [[TMP5]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP8]], i64 4), "dereferenceable"(i32* [[TMP8]], i64 4), "nonnull"(i32* [[TMP8]]) ]
+; WITH-AC-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP8]], align 4
+; WITH-AC-NEXT:    [[TMP10:%.*]] = trunc i32 [[TMP9]] to i8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8** [[TMP6]], i64 8) ]
+; WITH-AC-NEXT:    [[TMP11:%.*]] = load i8*, i8** [[TMP6]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1), "nonnull"(i8* [[TMP11]]) ]
+; WITH-AC-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
+; WITH-AC-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; WITH-AC-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]]
+; WITH-AC-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
+; WITH-AC-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; WITH-AC-NEXT:    [[TMP16:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP16]], i32 0, i32 0
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP17]], i64 8), "dereferenceable"(i32* [[TMP17]], i64 4), "nonnull"(i32* [[TMP17]]) ]
+; WITH-AC-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP17]], align 8
+; WITH-AC-NEXT:    [[TMP19:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP20:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP19]], i32 0, i32 1
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8* [[TMP20]], i64 4), "dereferenceable"(i8* [[TMP20]], i64 1), "nonnull"(i8* [[TMP20]]) ]
+; WITH-AC-NEXT:    [[TMP21:%.*]] = load i8, i8* [[TMP20]], align 4
+; WITH-AC-NEXT:    [[TMP22:%.*]] = sext i8 [[TMP21]] to i32
+; WITH-AC-NEXT:    [[TMP23:%.*]] = add nsw i32 [[TMP18]], [[TMP22]]
+; WITH-AC-NEXT:    [[TMP24:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP24]], i32 0, i32 2
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP25]], i64 8), "dereferenceable"(i32** [[TMP25]], i64 8), "nonnull"(i32** [[TMP25]]) ]
+; WITH-AC-NEXT:    [[TMP26:%.*]] = load i32*, i32** [[TMP25]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP26]], i64 4), "dereferenceable"(i32* [[TMP26]], i64 4), "nonnull"(i32* [[TMP26]]) ]
+; WITH-AC-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
+; WITH-AC-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
+; WITH-AC-NEXT:    ret i32 [[TMP28]]
+;
+; CROSS-BLOCK-LABEL: @test2(
+; CROSS-BLOCK-NEXT:    [[TMP4:%.*]] = alloca %struct.S*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP5:%.*]] = alloca i32*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP6:%.*]] = alloca i8*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP7:%.*]] = alloca [[STRUCT_S:%.*]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8), "nonnull"(%struct.S** [[TMP4]]) ]
+; CROSS-BLOCK-NEXT:    store %struct.S* [[TMP0:%.*]], %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP5]], i64 8), "dereferenceable"(i32** [[TMP5]], i64 8), "nonnull"(i32** [[TMP5]]) ]
+; CROSS-BLOCK-NEXT:    store i32* [[TMP1:%.*]], i32** [[TMP5]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8** [[TMP6]], i64 8), "nonnull"(i8** [[TMP6]]) ]
+; CROSS-BLOCK-NEXT:    store i8* [[TMP2:%.*]], i8** [[TMP6]]
+; CROSS-BLOCK-NEXT:    [[TMP8:%.*]] = load i32*, i32** [[TMP5]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP8]], i64 4), "dereferenceable"(i32* [[TMP8]], i64 4), "nonnull"(i32* [[TMP8]]) ]
+; CROSS-BLOCK-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP8]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP10:%.*]] = trunc i32 [[TMP9]] to i8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8** [[TMP6]], i64 8) ]
+; CROSS-BLOCK-NEXT:    [[TMP11:%.*]] = load i8*, i8** [[TMP6]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1), "nonnull"(i8* [[TMP11]]) ]
+; CROSS-BLOCK-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
+; CROSS-BLOCK-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]]
+; CROSS-BLOCK-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP16:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP16]], i32 0, i32 0
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP17]], i64 8), "dereferenceable"(i32* [[TMP17]], i64 4), "nonnull"(i32* [[TMP17]]) ]
+; CROSS-BLOCK-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP17]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP19:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP20:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP19]], i32 0, i32 1
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8* [[TMP20]], i64 4), "dereferenceable"(i8* [[TMP20]], i64 1), "nonnull"(i8* [[TMP20]]) ]
+; CROSS-BLOCK-NEXT:    [[TMP21:%.*]] = load i8, i8* [[TMP20]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP22:%.*]] = sext i8 [[TMP21]] to i32
+; CROSS-BLOCK-NEXT:    [[TMP23:%.*]] = add nsw i32 [[TMP18]], [[TMP22]]
+; CROSS-BLOCK-NEXT:    [[TMP24:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP24]], i32 0, i32 2
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP25]], i64 8), "dereferenceable"(i32** [[TMP25]], i64 8), "nonnull"(i32** [[TMP25]]) ]
+; CROSS-BLOCK-NEXT:    [[TMP26:%.*]] = load i32*, i32** [[TMP25]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP26]], i64 4), "dereferenceable"(i32* [[TMP26]], i64 4), "nonnull"(i32* [[TMP26]]) ]
+; CROSS-BLOCK-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
+; CROSS-BLOCK-NEXT:    ret i32 [[TMP28]]
 ;
   %4 = alloca %struct.S*, align 8
   %5 = alloca i32*, align 8
@@ -217,8 +346,8 @@ define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true"
 ; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1) ]
 ; BASIC-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
 ; BASIC-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
-; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
-; BASIC-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 32), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
+; BASIC-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 32
 ; BASIC-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
 ; BASIC-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
 ; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
@@ -264,8 +393,8 @@ define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true"
 ; ALL-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1) ]
 ; ALL-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
 ; ALL-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
-; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
-; ALL-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 32), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
+; ALL-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 32
 ; ALL-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
 ; ALL-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
 ; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 8), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
@@ -289,6 +418,88 @@ define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true"
 ; ALL-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
 ; ALL-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
 ; ALL-NEXT:    ret i32 [[TMP28]]
+;
+; WITH-AC-LABEL: @test3(
+; WITH-AC-NEXT:    [[TMP4:%.*]] = alloca %struct.S*, align 8
+; WITH-AC-NEXT:    [[TMP5:%.*]] = alloca i32*, align 8
+; WITH-AC-NEXT:    [[TMP6:%.*]] = alloca i8*, align 8
+; WITH-AC-NEXT:    [[TMP7:%.*]] = alloca [[STRUCT_S:%.*]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 32), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
+; WITH-AC-NEXT:    store %struct.S* [[TMP0:%.*]], %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP5]], i64 8), "dereferenceable"(i32** [[TMP5]], i64 8) ]
+; WITH-AC-NEXT:    store i32* [[TMP1:%.*]], i32** [[TMP5]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8** [[TMP6]], i64 8), "dereferenceable"(i8** [[TMP6]], i64 8) ]
+; WITH-AC-NEXT:    store i8* [[TMP2:%.*]], i8** [[TMP6]], align 8
+; WITH-AC-NEXT:    [[TMP8:%.*]] = load i32*, i32** [[TMP5]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP8]], i64 4), "dereferenceable"(i32* [[TMP8]], i64 4) ]
+; WITH-AC-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP8]], align 4
+; WITH-AC-NEXT:    [[TMP10:%.*]] = trunc i32 [[TMP9]] to i8
+; WITH-AC-NEXT:    [[TMP11:%.*]] = load i8*, i8** [[TMP6]]
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1) ]
+; WITH-AC-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
+; WITH-AC-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; WITH-AC-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 32
+; WITH-AC-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
+; WITH-AC-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; WITH-AC-NEXT:    [[TMP16:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP16]], i32 0, i32 0
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP17]], i64 8), "dereferenceable"(i32* [[TMP17]], i64 4) ]
+; WITH-AC-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP17]], align 8
+; WITH-AC-NEXT:    [[TMP19:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP20:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP19]], i32 0, i32 1
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8* [[TMP20]], i64 4), "dereferenceable"(i8* [[TMP20]], i64 1) ]
+; WITH-AC-NEXT:    [[TMP21:%.*]] = load i8, i8* [[TMP20]], align 4
+; WITH-AC-NEXT:    [[TMP22:%.*]] = sext i8 [[TMP21]] to i32
+; WITH-AC-NEXT:    [[TMP23:%.*]] = add nsw i32 [[TMP18]], [[TMP22]]
+; WITH-AC-NEXT:    [[TMP24:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; WITH-AC-NEXT:    [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP24]], i32 0, i32 2
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32** [[TMP25]], i64 8) ]
+; WITH-AC-NEXT:    [[TMP26:%.*]] = load i32*, i32** [[TMP25]]
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP26]], i64 4), "dereferenceable"(i32* [[TMP26]], i64 4) ]
+; WITH-AC-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
+; WITH-AC-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
+; WITH-AC-NEXT:    ret i32 [[TMP28]]
+;
+; CROSS-BLOCK-LABEL: @test3(
+; CROSS-BLOCK-NEXT:    [[TMP4:%.*]] = alloca %struct.S*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP5:%.*]] = alloca i32*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP6:%.*]] = alloca i8*, align 8
+; CROSS-BLOCK-NEXT:    [[TMP7:%.*]] = alloca [[STRUCT_S:%.*]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(%struct.S** [[TMP4]], i64 32), "dereferenceable"(%struct.S** [[TMP4]], i64 8) ]
+; CROSS-BLOCK-NEXT:    store %struct.S* [[TMP0:%.*]], %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32** [[TMP5]], i64 8), "dereferenceable"(i32** [[TMP5]], i64 8) ]
+; CROSS-BLOCK-NEXT:    store i32* [[TMP1:%.*]], i32** [[TMP5]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8** [[TMP6]], i64 8), "dereferenceable"(i8** [[TMP6]], i64 8) ]
+; CROSS-BLOCK-NEXT:    store i8* [[TMP2:%.*]], i8** [[TMP6]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP8:%.*]] = load i32*, i32** [[TMP5]], align 8
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP8]], i64 4), "dereferenceable"(i32* [[TMP8]], i64 4) ]
+; CROSS-BLOCK-NEXT:    [[TMP9:%.*]] = load i32, i32* [[TMP8]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP10:%.*]] = trunc i32 [[TMP9]] to i8
+; CROSS-BLOCK-NEXT:    [[TMP11:%.*]] = load i8*, i8** [[TMP6]]
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i8* [[TMP11]], i64 1) ]
+; CROSS-BLOCK-NEXT:    store i8 [[TMP10]], i8* [[TMP11]], align 1
+; CROSS-BLOCK-NEXT:    [[TMP12:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP13:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 32
+; CROSS-BLOCK-NEXT:    [[TMP14:%.*]] = bitcast %struct.S* [[TMP13]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP15:%.*]] = bitcast %struct.S* [[TMP7]] to i8*
+; CROSS-BLOCK-NEXT:    [[TMP16:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP16]], i32 0, i32 0
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP17]], i64 8), "dereferenceable"(i32* [[TMP17]], i64 4) ]
+; CROSS-BLOCK-NEXT:    [[TMP18:%.*]] = load i32, i32* [[TMP17]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP19:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP20:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP19]], i32 0, i32 1
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i8* [[TMP20]], i64 4), "dereferenceable"(i8* [[TMP20]], i64 1) ]
+; CROSS-BLOCK-NEXT:    [[TMP21:%.*]] = load i8, i8* [[TMP20]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP22:%.*]] = sext i8 [[TMP21]] to i32
+; CROSS-BLOCK-NEXT:    [[TMP23:%.*]] = add nsw i32 [[TMP18]], [[TMP22]]
+; CROSS-BLOCK-NEXT:    [[TMP24:%.*]] = load %struct.S*, %struct.S** [[TMP4]], align 8
+; CROSS-BLOCK-NEXT:    [[TMP25:%.*]] = getelementptr inbounds [[STRUCT_S]], %struct.S* [[TMP24]], i32 0, i32 2
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(i32** [[TMP25]], i64 8) ]
+; CROSS-BLOCK-NEXT:    [[TMP26:%.*]] = load i32*, i32** [[TMP25]]
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[TMP26]], i64 4), "dereferenceable"(i32* [[TMP26]], i64 4) ]
+; CROSS-BLOCK-NEXT:    [[TMP27:%.*]] = load i32, i32* [[TMP26]], align 4
+; CROSS-BLOCK-NEXT:    [[TMP28:%.*]] = add nsw i32 [[TMP23]], [[TMP27]]
+; CROSS-BLOCK-NEXT:    ret i32 [[TMP28]]
 ;
   %4 = alloca %struct.S*, align 8
   %5 = alloca i32*, align 8
@@ -303,7 +514,7 @@ define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true"
   %11 = load i8*, i8** %6
   store i8 %10, i8* %11, align 1
   %12 = bitcast %struct.S* %7 to i8*
-  %13 = load %struct.S*, %struct.S** %4, align 8
+  %13 = load %struct.S*, %struct.S** %4, align 32
   %14 = bitcast %struct.S* %13 to i8*
   %15 = bitcast %struct.S* %7 to i8*
   %16 = load %struct.S*, %struct.S** %4, align 8
@@ -321,3 +532,117 @@ define i32 @test3(%struct.S* %0, i32* %1, i8* %2) "null-pointer-is-valid"="true"
   %28 = add nsw i32 %23, %27
   ret i32 %28
 }
+
+define dso_local i32 @_Z6squarePi(i32* %P, i32* %P1, i1 %cond) {
+; BASIC-LABEL: @_Z6squarePi(
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P:%.*]], i64 4), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P]], align 4
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1:%.*]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P1]], align 8
+; BASIC-NEXT:    br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
+; BASIC:       A:
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P]], align 8
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 4), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P1]], align 4
+; BASIC-NEXT:    br i1 [[COND]], label [[C:%.*]], label [[B]]
+; BASIC:       B:
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P]], align 8
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P1]], align 8
+; BASIC-NEXT:    br label [[C]]
+; BASIC:       C:
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 32), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P]], align 32
+; BASIC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 4), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; BASIC-NEXT:    store i32 0, i32* [[P1]], align 4
+; BASIC-NEXT:    ret i32 0
+;
+; ALL-LABEL: @_Z6squarePi(
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P:%.*]], i64 4), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P]], align 4
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1:%.*]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P1]], align 8
+; ALL-NEXT:    br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
+; ALL:       A:
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P]], align 8
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 4), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P1]], align 4
+; ALL-NEXT:    br i1 [[COND]], label [[C:%.*]], label [[B]]
+; ALL:       B:
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P]], align 8
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P1]], align 8
+; ALL-NEXT:    br label [[C]]
+; ALL:       C:
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 32), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P]], align 32
+; ALL-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 4), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; ALL-NEXT:    store i32 0, i32* [[P1]], align 4
+; ALL-NEXT:    ret i32 0
+;
+; WITH-AC-LABEL: @_Z6squarePi(
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P:%.*]], i64 4), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P]], align 4
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1:%.*]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P1]], align 8
+; WITH-AC-NEXT:    br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
+; WITH-AC:       A:
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P]], align 8
+; WITH-AC-NEXT:    store i32 0, i32* [[P1]], align 4
+; WITH-AC-NEXT:    br i1 [[COND]], label [[C:%.*]], label [[B]]
+; WITH-AC:       B:
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P]], align 8
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P1]], align 8
+; WITH-AC-NEXT:    br label [[C]]
+; WITH-AC:       C:
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 32), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P]], align 32
+; WITH-AC-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1]], i64 4), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; WITH-AC-NEXT:    store i32 0, i32* [[P1]], align 4
+; WITH-AC-NEXT:    ret i32 0
+;
+; CROSS-BLOCK-LABEL: @_Z6squarePi(
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P:%.*]], i64 4), "dereferenceable"(i32* [[P]], i64 4), "nonnull"(i32* [[P]]) ]
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P]], align 4
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P1:%.*]], i64 8), "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P1]], align 8
+; CROSS-BLOCK-NEXT:    br i1 [[COND:%.*]], label [[A:%.*]], label [[B:%.*]]
+; CROSS-BLOCK:       A:
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8) ]
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P]], align 8
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P1]], align 4
+; CROSS-BLOCK-NEXT:    br i1 [[COND]], label [[C:%.*]], label [[B]]
+; CROSS-BLOCK:       B:
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 8) ]
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P]], align 8
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P1]], align 8
+; CROSS-BLOCK-NEXT:    br label [[C]]
+; CROSS-BLOCK:       C:
+; CROSS-BLOCK-NEXT:    call void @llvm.assume(i1 true) [ "align"(i32* [[P]], i64 32) ]
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P]], align 32
+; CROSS-BLOCK-NEXT:    store i32 0, i32* [[P1]], align 4
+; CROSS-BLOCK-NEXT:    ret i32 0
+;
+  store i32 0, i32* %P, align 4
+  store i32 0, i32* %P1, align 8
+  br i1 %cond, label %A, label %B
+A:
+  store i32 0, i32* %P, align 8
+  store i32 0, i32* %P1, align 4
+  br i1 %cond, label %C, label %B
+B:
+  store i32 0, i32* %P, align 8
+  store i32 0, i32* %P1, align 8
+  br label %C
+C:
+  store i32 0, i32* %P, align 32
+  store i32 0, i32* %P1, align 4
+  ret i32 0
+}


        


More information about the llvm-commits mailing list