[llvm] [ValueTracking] Conservative NoSync check prevents vectorization (PR #199002)

Kshitij Paranjape via llvm-commits llvm-commits at lists.llvm.org
Sat May 30 05:00:25 PDT 2026


https://github.com/kshitijvp updated https://github.com/llvm/llvm-project/pull/199002

>From a45e23bbab455d49a1fd40234f89130fe4191a1f Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Thu, 21 May 2026 16:22:20 +0530
Subject: [PATCH 01/11] [ValueTracking] Conservative NoSync check prevents
 vectorization

Conservative nosync check in ValueTracking.cpp returns false
causing potentially faulting load preventing vectorization.
Instead check if any instructions between Assume Instruction
and Ctx Instruction are synchronizing.
---
 llvm/include/llvm/Analysis/ValueTracking.h |  2 +-
 llvm/lib/Analysis/ValueTracking.cpp        | 22 +++++++++++++++++-----
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index b2f664a9c9c0d..79ff896779ce2 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -639,7 +639,7 @@ inline bool isValidAssumeForContext(const Instruction *I,
 }
 
 /// Returns true, if no instruction between \p Assume and \p CtxI may free
-/// memory and the function is marked as NoSync. The latter ensures the current
+/// or synchronize memory. The latter ensures the current
 /// function cannot arrange for another thread to free on its behalf.
 LLVM_ABI bool willNotFreeBetween(const Instruction *Assume,
                                  const Instruction *CtxI);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 3be0db5ad9c7e..b59bed0cc7f23 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -703,14 +703,26 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
 
 bool llvm::willNotFreeBetween(const Instruction *Assume,
                               const Instruction *CtxI) {
-  // Helper to check if there are any calls in the range that may free memory.
+  // Helper to make sure the current function cannot arrange for
+  // another thread to free on its behalf and to check if there
+  // are any calls in the range that may free memory.
   auto hasNoFreeCalls = [](auto Range) {
     for (const auto &[Idx, I] : enumerate(Range)) {
       if (Idx > MaxInstrsToCheckForFree)
         return false;
-      if (const auto *CB = dyn_cast<CallBase>(&I))
-        if (!CB->hasFnAttr(Attribute::NoFree))
-          return false;
+      if (I.isVolatile())
+        return false;
+
+      if (I.maySynchronize())
+        return false;
+
+      auto *CB = dyn_cast<CallBase>(&I);
+      if (CB) {
+        // Non call site cases covered by the two checks above
+        if (!CB->hasFnAttr(Attribute::NoSync) ||
+            !CB->hasFnAttr(Attribute::NoFree))
+            return false;
+      }
     }
     return true;
   };
@@ -739,7 +751,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
   }
 
   // Check if there are any calls between Assume and CtxIter that may free
-  // memory.
+  // memory or synchronize.
   return hasNoFreeCalls(make_range(Assume->getIterator(), CtxIter));
 }
 

>From 291b92878379ea769cf514495eb52448b2f9cc05 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Thu, 21 May 2026 16:42:53 +0530
Subject: [PATCH 02/11] Nitpick

---
 llvm/lib/Analysis/ValueTracking.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index b59bed0cc7f23..09c74166d929f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -721,7 +721,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
         // Non call site cases covered by the two checks above
         if (!CB->hasFnAttr(Attribute::NoSync) ||
             !CB->hasFnAttr(Attribute::NoFree))
-            return false;
+          return false;
       }
     }
     return true;

>From 7ef20bd4fa3d3221e756b3fddeae9227ad29cedc Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Fri, 22 May 2026 00:41:33 +0530
Subject: [PATCH 03/11] Added cleaned Tests

---
 llvm/lib/Analysis/ValueTracking.cpp           |   5 -
 ...able-info-from-assumption-constant-size.ll | 369 ++++++++++++++++--
 2 files changed, 347 insertions(+), 27 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 09c74166d929f..705eebc1e35fd 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -727,11 +727,6 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
     return true;
   };
 
-  // Make sure the current function cannot arrange for another thread to free on
-  // its behalf.
-  if (!CtxI->getFunction()->hasNoSync())
-    return false;
-
   // Handle cross-block case: CtxI in a successor of Assume's block.
   const BasicBlock *CtxBB = CtxI->getParent();
   const BasicBlock *AssumeBB = Assume->getParent();
diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
index fe758c3ed21e3..53f274a1a8fa7 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
@@ -1307,30 +1307,13 @@ define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_b
 ; CHECK:       [[VECTOR_PH]]:
 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
 ; CHECK:       [[VECTOR_BODY]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
-; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i64 0
-; CHECK-NEXT:    br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
-; CHECK:       [[PRED_LOAD_IF]]:
-; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
-; CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i64 0
-; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE]]
-; CHECK:       [[PRED_LOAD_CONTINUE]]:
-; CHECK-NEXT:    [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
-; CHECK-NEXT:    [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i64 1
-; CHECK-NEXT:    br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
-; CHECK:       [[PRED_LOAD_IF1]]:
-; CHECK-NEXT:    [[TMP9:%.*]] = add i64 [[INDEX]], 1
-; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
-; CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
-; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i64 1
-; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE2]]
-; CHECK:       [[PRED_LOAD_CONTINUE2]]:
-; CHECK-NEXT:    [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
-; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge <2 x i32> [[WIDE_LOAD]], zeroinitializer
+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <2 x i32>, ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[WIDE_LOAD]], <2 x i32> [[WIDE_LOAD1]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
 ; CHECK-NEXT:    store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
@@ -1456,4 +1439,346 @@ exit:
   ret void
 }
 
+define i64 @VectorizingWithoutNoSyncAttributeTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @VectorizingWithoutNoSyncAttributeTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], [[EXIT:label %.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
+; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
+; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
+; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
+; CHECK-NEXT:    [[C_2:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
+; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    br i1 [[TMP10]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP24:![0-9]+]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], [[LOOP_COMP1:label %.*]], label %[[SCALAR_PH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
+; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
+; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
+; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
+; CHECK-NEXT:    br [[LOOP_EARLY_EXIT1:label %.*]]
+; CHECK:       [[SCALAR_PH]]:
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %merge, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv = phi ptr [ %merge, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @volatileNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @volatileNotVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    [[VOLATILE:%.*]] = load volatile ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  %volatile = load volatile ptr, ptr %v, align 8                          ; Volatile Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %merge, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv = phi ptr [ %merge, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @fenceNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @fenceNotVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    fence seq_cst
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  fence seq_cst                                                           ; Fence Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %merge, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
 
+loop.early.exit:
+  %iv = phi ptr [ %merge, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @atomicNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @atomicNotVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    [[ATOMIC:%.*]] = load atomic ptr, ptr [[V]] seq_cst, align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  %atomic = load atomic ptr, ptr %v seq_cst, align 8                      ; Atomic Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %merge, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv = phi ptr [ %merge, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}

>From 8752bd7b8b0d5beadfd81db39e03ac8c033cc1ac Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Fri, 22 May 2026 10:44:00 +0530
Subject: [PATCH 04/11] Update Test

---
 .../SimplifyCFG/speculate-derefable-load.ll   | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/llvm/test/Transforms/SimplifyCFG/speculate-derefable-load.ll b/llvm/test/Transforms/SimplifyCFG/speculate-derefable-load.ll
index b8c999d700aa7..693da976d1752 100644
--- a/llvm/test/Transforms/SimplifyCFG/speculate-derefable-load.ll
+++ b/llvm/test/Transforms/SimplifyCFG/speculate-derefable-load.ll
@@ -4,14 +4,10 @@
 define i64 @align_deref_align(i1 %c, ptr %p) {
 ; CHECK-LABEL: define i64 @align_deref_align(
 ; CHECK-SAME: i1 [[C:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
-; CHECK-NEXT:    br i1 [[C]], label %[[IF:.*]], label %[[EXIT:.*]]
-; CHECK:       [[IF]]:
 ; CHECK-NEXT:    [[V:%.*]] = load i64, ptr [[P]], align 8
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[RES:%.*]] = phi i64 [ [[V]], %[[IF]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[C]], i64 [[V]], i64 0
 ; CHECK-NEXT:    ret i64 [[RES]]
 ;
 entry:
@@ -52,17 +48,12 @@ exit:
 define i64 @assume_deref_align2(i1 %c1, i32 %x, ptr %p) {
 ; CHECK-LABEL: define i64 @assume_deref_align2(
 ; CHECK-SAME: i1 [[C1:%.*]], i32 [[X:%.*]], ptr [[P:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[P]], i64 8), "align"(ptr [[P]], i64 8) ]
-; CHECK-NEXT:    br i1 [[C1]], label %[[IF1:.*]], label %[[EXIT:.*]]
-; CHECK:       [[IF1]]:
 ; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i32 [[X]], 10
-; CHECK-NEXT:    br i1 [[C2]], label %[[IF2:.*]], label %[[EXIT]]
-; CHECK:       [[IF2]]:
 ; CHECK-NEXT:    [[V:%.*]] = load i64, ptr [[P]], align 8
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[RES:%.*]] = phi i64 [ [[V]], %[[IF2]] ], [ 1, %[[IF1]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C2]], i64 [[V]], i64 1
+; CHECK-NEXT:    [[RES:%.*]] = select i1 [[C1]], i64 [[SPEC_SELECT]], i64 0
 ; CHECK-NEXT:    ret i64 [[RES]]
 ;
 entry:

>From cc94ce58fd1dfe841874836b6012b99b29b4ad0f Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Fri, 22 May 2026 10:49:35 +0530
Subject: [PATCH 05/11] Nitpick

---
 llvm/lib/Analysis/ValueTracking.cpp | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 705eebc1e35fd..04dc7744b1c54 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -703,9 +703,7 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
 
 bool llvm::willNotFreeBetween(const Instruction *Assume,
                               const Instruction *CtxI) {
-  // Helper to make sure the current function cannot arrange for
-  // another thread to free on its behalf and to check if there
-  // are any calls in the range that may free memory.
+  // Helper to check if there are any calls in the range that may free memory.
   auto hasNoFreeCalls = [](auto Range) {
     for (const auto &[Idx, I] : enumerate(Range)) {
       if (Idx > MaxInstrsToCheckForFree)
@@ -746,7 +744,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
   }
 
   // Check if there are any calls between Assume and CtxIter that may free
-  // memory or synchronize.
+  // memory.
   return hasNoFreeCalls(make_range(Assume->getIterator(), CtxIter));
 }
 

>From 8fd490349d1ec31285069843ce3cd1caa2596ca2 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Mon, 25 May 2026 11:59:32 +0530
Subject: [PATCH 06/11] Remove Volatile Check

---
 llvm/lib/Analysis/ValueTracking.cpp           |  2 -
 ...able-info-from-assumption-constant-size.ll | 64 ++++++++++++-------
 2 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 04dc7744b1c54..c685956288139 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -708,8 +708,6 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
     for (const auto &[Idx, I] : enumerate(Range)) {
       if (Idx > MaxInstrsToCheckForFree)
         return false;
-      if (I.isVolatile())
-        return false;
 
       if (I.maySynchronize())
         return false;
diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
index 53f274a1a8fa7..e609cbc07e409 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
@@ -1537,10 +1537,10 @@ exit:
   ret i64 %mer
 }
 
-define i64 @volatileNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
-; CHECK-LABEL: define i64 @volatileNotVectorizingTest(
+define i64 @volatileVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @volatileVectorizingTest(
 ; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
 ; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
@@ -1554,27 +1554,45 @@ define i64 @volatileNotVectorizingTest(ptr noundef nonnull readonly align 8 capt
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
 ; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK-NEXT:    br i1 [[C_1]], [[EXIT:label %.*]], label %[[LOOP_PREHEADER:.*]]
 ; CHECK:       [[LOOP_PREHEADER]]:
-; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
-; CHECK:       [[LOOP_HEADER]]:
-; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
-; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
-; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
-; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
-; CHECK:       [[LOOP_EARLY_EXIT]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
-; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[LOOP_LATCH]]:
-; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
-; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
-; CHECK:       [[LOOP_COMP]]:
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
-; CHECK-NEXT:    ret i64 [[MER]]
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
+; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
+; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
+; CHECK:       [[VECTOR_BODY]]:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
+; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
+; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
+; CHECK-NEXT:    [[TMP9:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
+; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[TMP9]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK:       [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT:    br i1 [[TMP10]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP26:![0-9]+]]
+; CHECK:       [[MIDDLE_BLOCK]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], [[LOOP_COMP:label %.*]], label %[[SCALAR_PH]]
+; CHECK:       [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
+; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
+; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
+; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
+; CHECK-NEXT:    br [[LOOP_EARLY_EXIT:label %.*]]
+; CHECK:       [[SCALAR_PH]]:
 ;
 entry:
   %l.v = load ptr, ptr %v, align 8

>From bd85427968c7506ac58a33381492df2b9627c9d0 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Sat, 30 May 2026 13:04:15 +0530
Subject: [PATCH 07/11] Nitpick

---
 llvm/include/llvm/Analysis/ValueTracking.h |  2 +-
 llvm/lib/Analysis/ValueTracking.cpp        | 13 ++++---------
 2 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 79ff896779ce2..05f610d523021 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -639,7 +639,7 @@ inline bool isValidAssumeForContext(const Instruction *I,
 }
 
 /// Returns true, if no instruction between \p Assume and \p CtxI may free
-/// or synchronize memory. The latter ensures the current
+/// (including through synchronization). The latter ensures the current
 /// function cannot arrange for another thread to free on its behalf.
 LLVM_ABI bool willNotFreeBetween(const Instruction *Assume,
                                  const Instruction *CtxI);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index c685956288139..d18278760a1c4 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -709,16 +709,11 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
       if (Idx > MaxInstrsToCheckForFree)
         return false;
 
-      if (I.maySynchronize())
-        return false;
-
-      auto *CB = dyn_cast<CallBase>(&I);
-      if (CB) {
-        // Non call site cases covered by the two checks above
-        if (!CB->hasFnAttr(Attribute::NoSync) ||
-            !CB->hasFnAttr(Attribute::NoFree))
+      if (auto *CB = dyn_cast<CallBase>(&I)) {
+        if (!CB->hasFnAttr(Attribute::NoFree))
           return false;
-      }
+      } else if (I.maySynchronize())
+        return false;
     }
     return true;
   };

>From cb5f6a7fd96cb6d4c90122d6d7147a8e7fa7b130 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Sat, 30 May 2026 14:10:53 +0530
Subject: [PATCH 08/11] Nitpick

---
 ...able-info-from-assumption-constant-size.ll | 27 +++++++++++++++----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
index e609cbc07e409..e94c320eb76d4 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
@@ -1307,13 +1307,30 @@ define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_b
 ; CHECK:       [[VECTOR_PH]]:
 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
 ; CHECK:       [[VECTOR_BODY]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
 ; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge <2 x i32> [[WIDE_LOAD]], zeroinitializer
-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <2 x i32>, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[WIDE_LOAD]], <2 x i32> [[WIDE_LOAD1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i64 0
+; CHECK-NEXT:    br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
+; CHECK:       [[PRED_LOAD_IF]]:
+; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
+; CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
+; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i64 0
+; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE]]
+; CHECK:       [[PRED_LOAD_CONTINUE]]:
+; CHECK-NEXT:    [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
+; CHECK-NEXT:    [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i64 1
+; CHECK-NEXT:    br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
+; CHECK:       [[PRED_LOAD_IF1]]:
+; CHECK-NEXT:    [[TMP9:%.*]] = add i64 [[INDEX]], 1
+; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
+; CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i64 1
+; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE2]]
+; CHECK:       [[PRED_LOAD_CONTINUE2]]:
+; CHECK-NEXT:    [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
+; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
 ; CHECK-NEXT:    store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2

>From 615daab422e952f12ed7f75ed78155d0bf411ac4 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Sat, 30 May 2026 16:37:10 +0530
Subject: [PATCH 09/11] Nitpick

---
 llvm/include/llvm/Analysis/ValueTracking.h    |   3 +-
 ...able-info-from-assumption-constant-size.ll | 389 +----------------
 ...able-info-from-assumption-variable-size.ll | 394 ++++++++++++++++++
 3 files changed, 400 insertions(+), 386 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 05f610d523021..684c22fdab2e4 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -639,8 +639,7 @@ inline bool isValidAssumeForContext(const Instruction *I,
 }
 
 /// Returns true, if no instruction between \p Assume and \p CtxI may free
-/// (including through synchronization). The latter ensures the current
-/// function cannot arrange for another thread to free on its behalf.
+/// (including through synchronization).
 LLVM_ABI bool willNotFreeBetween(const Instruction *Assume,
                                  const Instruction *CtxI);
 
diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
index e94c320eb76d4..875fa0d69cfe3 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
@@ -1307,30 +1307,13 @@ define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_b
 ; CHECK:       [[VECTOR_PH]]:
 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
 ; CHECK:       [[VECTOR_BODY]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
-; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i64 0
-; CHECK-NEXT:    br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
-; CHECK:       [[PRED_LOAD_IF]]:
-; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
-; CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i64 0
-; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE]]
-; CHECK:       [[PRED_LOAD_CONTINUE]]:
-; CHECK-NEXT:    [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
-; CHECK-NEXT:    [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i64 1
-; CHECK-NEXT:    br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
-; CHECK:       [[PRED_LOAD_IF1]]:
-; CHECK-NEXT:    [[TMP9:%.*]] = add i64 [[INDEX]], 1
-; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
-; CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
-; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i64 1
-; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE2]]
-; CHECK:       [[PRED_LOAD_CONTINUE2]]:
-; CHECK-NEXT:    [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
-; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge <2 x i32> [[WIDE_LOAD]], zeroinitializer
+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <2 x i32>, ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[WIDE_LOAD]], <2 x i32> [[WIDE_LOAD1]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
 ; CHECK-NEXT:    store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
@@ -1455,365 +1438,3 @@ loop.latch:
 exit:
   ret void
 }
-
-define i64 @VectorizingWithoutNoSyncAttributeTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
-; CHECK-LABEL: define i64 @VectorizingWithoutNoSyncAttributeTest(
-; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
-; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
-; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
-; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_1]], [[EXIT:label %.*]], label %[[LOOP_PREHEADER:.*]]
-; CHECK:       [[LOOP_PREHEADER]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
-; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
-; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
-; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
-; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
-; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; CHECK:       [[VECTOR_PH]]:
-; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
-; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
-; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
-; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
-; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
-; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
-; CHECK:       [[LOOP_HEADER]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
-; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
-; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
-; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
-; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
-; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
-; CHECK-NEXT:    [[C_2:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
-; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
-; CHECK:       [[LOOP_LATCH]]:
-; CHECK-NEXT:    br i1 [[TMP10]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP24:![0-9]+]]
-; CHECK:       [[LOOP_COMP]]:
-; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
-; CHECK-NEXT:    br i1 [[CMP_N]], [[LOOP_COMP1:label %.*]], label %[[SCALAR_PH]]
-; CHECK:       [[LOOP_EARLY_EXIT]]:
-; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
-; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
-; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
-; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
-; CHECK-NEXT:    br [[LOOP_EARLY_EXIT1:label %.*]]
-; CHECK:       [[SCALAR_PH]]:
-;
-entry:
-  %l.v = load ptr, ptr %v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  %pi.l.v = ptrtoint ptr %l.v to i64
-  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
-  %l.gep.v = load ptr, ptr %gep.v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
-  %sub = sub i64 %pi.l.gep.v, %pi.l.v
-  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %c.1 = icmp eq ptr %l.v, %l.gep.v
-  br i1 %c.1, label %exit, label %loop.preheader
-
-loop.preheader:
-  br label %loop.header
-
-loop.header:
-  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
-  %val = load i32, ptr %merge, align 4
-  %c.2 = icmp slt i32 %val, %n
-  br i1 %c.2, label %loop.early.exit, label %loop.latch
-
-loop.early.exit:
-  %iv = phi ptr [ %merge, %loop.header ]
-  %pi.iv = ptrtoint ptr %iv to i64
-  br label %exit
-
-loop.latch:
-  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
-  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
-  br i1 %c.3, label %loop.comp, label %loop.header
-
-loop.comp:
-  br label %exit
-
-exit:
-  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
-  ret i64 %mer
-}
-
-define i64 @volatileVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
-; CHECK-LABEL: define i64 @volatileVectorizingTest(
-; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
-; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
-; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
-; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
-; CHECK-NEXT:    [[VOLATILE:%.*]] = load volatile ptr, ptr [[V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_1]], [[EXIT:label %.*]], label %[[LOOP_PREHEADER:.*]]
-; CHECK:       [[LOOP_PREHEADER]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
-; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
-; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
-; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
-; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
-; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
-; CHECK:       [[VECTOR_PH]]:
-; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
-; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
-; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
-; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
-; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
-; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
-; CHECK:       [[VECTOR_BODY]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
-; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
-; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
-; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
-; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
-; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
-; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
-; CHECK-NEXT:    [[TMP9:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
-; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT:    br i1 [[TMP9]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
-; CHECK:       [[VECTOR_BODY_INTERIM]]:
-; CHECK-NEXT:    br i1 [[TMP10]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP26:![0-9]+]]
-; CHECK:       [[MIDDLE_BLOCK]]:
-; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
-; CHECK-NEXT:    br i1 [[CMP_N]], [[LOOP_COMP:label %.*]], label %[[SCALAR_PH]]
-; CHECK:       [[VECTOR_EARLY_EXIT]]:
-; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
-; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
-; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
-; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
-; CHECK-NEXT:    br [[LOOP_EARLY_EXIT:label %.*]]
-; CHECK:       [[SCALAR_PH]]:
-;
-entry:
-  %l.v = load ptr, ptr %v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  %pi.l.v = ptrtoint ptr %l.v to i64
-  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
-  %l.gep.v = load ptr, ptr %gep.v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
-  %sub = sub i64 %pi.l.gep.v, %pi.l.v
-  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
-  %volatile = load volatile ptr, ptr %v, align 8                          ; Volatile Instruction
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %c.1 = icmp eq ptr %l.v, %l.gep.v
-  br i1 %c.1, label %exit, label %loop.preheader
-
-loop.preheader:
-  br label %loop.header
-
-loop.header:
-  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
-  %val = load i32, ptr %merge, align 4
-  %c.2 = icmp slt i32 %val, %n
-  br i1 %c.2, label %loop.early.exit, label %loop.latch
-
-loop.early.exit:
-  %iv = phi ptr [ %merge, %loop.header ]
-  %pi.iv = ptrtoint ptr %iv to i64
-  br label %exit
-
-loop.latch:
-  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
-  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
-  br i1 %c.3, label %loop.comp, label %loop.header
-
-loop.comp:
-  br label %exit
-
-exit:
-  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
-  ret i64 %mer
-}
-
-define i64 @fenceNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
-; CHECK-LABEL: define i64 @fenceNotVectorizingTest(
-; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
-; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
-; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
-; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
-; CHECK-NEXT:    fence seq_cst
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
-; CHECK:       [[LOOP_PREHEADER]]:
-; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
-; CHECK:       [[LOOP_HEADER]]:
-; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
-; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
-; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
-; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
-; CHECK:       [[LOOP_EARLY_EXIT]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
-; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[LOOP_LATCH]]:
-; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
-; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
-; CHECK:       [[LOOP_COMP]]:
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
-; CHECK-NEXT:    ret i64 [[MER]]
-;
-entry:
-  %l.v = load ptr, ptr %v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  %pi.l.v = ptrtoint ptr %l.v to i64
-  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
-  %l.gep.v = load ptr, ptr %gep.v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
-  %sub = sub i64 %pi.l.gep.v, %pi.l.v
-  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
-  fence seq_cst                                                           ; Fence Instruction
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %c.1 = icmp eq ptr %l.v, %l.gep.v
-  br i1 %c.1, label %exit, label %loop.preheader
-
-loop.preheader:
-  br label %loop.header
-
-loop.header:
-  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
-  %val = load i32, ptr %merge, align 4
-  %c.2 = icmp slt i32 %val, %n
-  br i1 %c.2, label %loop.early.exit, label %loop.latch
-
-loop.early.exit:
-  %iv = phi ptr [ %merge, %loop.header ]
-  %pi.iv = ptrtoint ptr %iv to i64
-  br label %exit
-
-loop.latch:
-  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
-  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
-  br i1 %c.3, label %loop.comp, label %loop.header
-
-loop.comp:
-  br label %exit
-
-exit:
-  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
-  ret i64 %mer
-}
-
-define i64 @atomicNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
-; CHECK-LABEL: define i64 @atomicNotVectorizingTest(
-; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
-; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
-; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
-; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
-; CHECK-NEXT:    [[ATOMIC:%.*]] = load atomic ptr, ptr [[V]] seq_cst, align 8
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
-; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
-; CHECK:       [[LOOP_PREHEADER]]:
-; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
-; CHECK:       [[LOOP_HEADER]]:
-; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
-; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
-; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
-; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
-; CHECK:       [[LOOP_EARLY_EXIT]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
-; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[LOOP_LATCH]]:
-; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
-; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
-; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
-; CHECK:       [[LOOP_COMP]]:
-; CHECK-NEXT:    br label %[[EXIT]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
-; CHECK-NEXT:    ret i64 [[MER]]
-;
-entry:
-  %l.v = load ptr, ptr %v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  %pi.l.v = ptrtoint ptr %l.v to i64
-  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
-  %l.gep.v = load ptr, ptr %gep.v, align 8
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
-  %sub = sub i64 %pi.l.gep.v, %pi.l.v
-  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
-  %atomic = load atomic ptr, ptr %v seq_cst, align 8                      ; Atomic Instruction
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
-  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
-  %c.1 = icmp eq ptr %l.v, %l.gep.v
-  br i1 %c.1, label %exit, label %loop.preheader
-
-loop.preheader:
-  br label %loop.header
-
-loop.header:
-  %merge = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
-  %val = load i32, ptr %merge, align 4
-  %c.2 = icmp slt i32 %val, %n
-  br i1 %c.2, label %loop.early.exit, label %loop.latch
-
-loop.early.exit:
-  %iv = phi ptr [ %merge, %loop.header ]
-  %pi.iv = ptrtoint ptr %iv to i64
-  br label %exit
-
-loop.latch:
-  %gep.merge = getelementptr inbounds nuw i8, ptr %merge, i64 4
-  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
-  br i1 %c.3, label %loop.comp, label %loop.header
-
-loop.comp:
-  br label %exit
-
-exit:
-  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
-  ret i64 %mer
-}
diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-variable-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-variable-size.ll
index 90ecd7e65cb5a..876c21d81a72a 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-variable-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-variable-size.ll
@@ -805,3 +805,397 @@ for.inc:
 exit:
   ret void
 }
+
+define i64 @VectorizingWithoutNoSyncAttributeTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @VectorizingWithoutNoSyncAttributeTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
+; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
+; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
+; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
+; CHECK-NEXT:    [[C_2:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
+; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    br i1 [[TMP10]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP18:![0-9]+]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[LOOP_COMP1:.*]], label %[[SCALAR_PH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
+; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
+; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
+; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
+; CHECK-NEXT:    br label %[[LOOP_EARLY_EXIT1:.*]]
+; CHECK:       [[SCALAR_PH]]:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi ptr [ [[TMP5]], %[[LOOP_COMP]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[LOOP_HEADER1:.*]]
+; CHECK:       [[LOOP_HEADER1]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH1:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_4:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_4]], label %[[LOOP_EARLY_EXIT1]], label %[[LOOP_LATCH1]]
+; CHECK:       [[LOOP_EARLY_EXIT1]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER1]] ], [ [[TMP14]], %[[LOOP_EARLY_EXIT]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH1]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP1]], label %[[LOOP_HEADER1]], !llvm.loop [[LOOP19:![0-9]+]]
+; CHECK:       [[LOOP_COMP1]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT1]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP1]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %iv = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %iv, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv.1 = phi ptr [ %iv, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv.1 to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %iv, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @volatileVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @volatileVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    [[VOLATILE:%.*]] = load volatile ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[PI_L_GEP_V]], -4
+; CHECK-NEXT:    [[TMP1:%.*]] = sub i64 [[TMP0]], [[PI_L_V]]
+; CHECK-NEXT:    [[TMP2:%.*]] = lshr i64 [[TMP1]], 2
+; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 1
+; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 2
+; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK:       [[VECTOR_PH]]:
+; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 2
+; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
+; CHECK-NEXT:    [[TMP4:%.*]] = shl i64 [[N_VEC]], 2
+; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP4]]
+; CHECK-NEXT:    [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x i32> poison, i32 [[N]], i64 0
+; CHECK-NEXT:    [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x i32> [[BROADCAST_SPLATINSERT]], <2 x i32> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
+; CHECK:       [[VECTOR_BODY]]:
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ]
+; CHECK-NEXT:    [[TMP6:%.*]] = shl i64 [[INDEX]], 2
+; CHECK-NEXT:    [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP6]]
+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[NEXT_GEP]], align 4
+; CHECK-NEXT:    [[TMP7:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], [[BROADCAST_SPLAT]]
+; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
+; CHECK-NEXT:    [[TMP8:%.*]] = freeze <2 x i1> [[TMP7]]
+; CHECK-NEXT:    [[TMP9:%.*]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[TMP8]])
+; CHECK-NEXT:    [[TMP10:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[TMP9]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK:       [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT:    br i1 [[TMP10]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP20:![0-9]+]]
+; CHECK:       [[MIDDLE_BLOCK]]:
+; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[LOOP_COMP:.*]], label %[[SCALAR_PH]]
+; CHECK:       [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT:    [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v2i1(<2 x i1> [[TMP7]], i1 false)
+; CHECK-NEXT:    [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
+; CHECK-NEXT:    [[TMP13:%.*]] = shl i64 [[TMP12]], 2
+; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr i8, ptr [[L_V]], i64 [[TMP13]]
+; CHECK-NEXT:    br label %[[LOOP_EARLY_EXIT:.*]]
+; CHECK:       [[SCALAR_PH]]:
+; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi ptr [ [[TMP5]], %[[MIDDLE_BLOCK]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ], [ [[TMP14]], %[[VECTOR_EARLY_EXIT]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP21:![0-9]+]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  %volatile = load volatile ptr, ptr %v, align 8                          ; Volatile Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %iv = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %iv, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv.1 = phi ptr [ %iv, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv.1 to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %iv, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @fenceNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @fenceNotVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    fence seq_cst
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  fence seq_cst                                                           ; Fence Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %iv = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %iv, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv.1 = phi ptr [ %iv, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv.1 to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %iv, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}
+
+define i64 @atomicNotVectorizingTest(ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) %v, i32 noundef %n) {
+; CHECK-LABEL: define i64 @atomicNotVectorizingTest(
+; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(24) [[V:%.*]], i32 noundef [[N:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[L_V:%.*]] = load ptr, ptr [[V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_V:%.*]] = ptrtoint ptr [[L_V]] to i64
+; CHECK-NEXT:    [[GEP_V:%.*]] = getelementptr inbounds nuw i8, ptr [[V]], i64 8
+; CHECK-NEXT:    [[L_GEP_V:%.*]] = load ptr, ptr [[GEP_V]], align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_GEP_V]], i64 4) ]
+; CHECK-NEXT:    [[PI_L_GEP_V:%.*]] = ptrtoint ptr [[L_GEP_V]] to i64
+; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[PI_L_GEP_V]], [[PI_L_V]]
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[L_V]], i64 [[SUB]]) ]
+; CHECK-NEXT:    [[ATOMIC:%.*]] = load atomic ptr, ptr [[V]] seq_cst, align 8
+; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[L_V]], i64 4) ]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq ptr [[L_V]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_1]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
+; CHECK:       [[LOOP_PREHEADER]]:
+; CHECK-NEXT:    br label %[[LOOP_HEADER:.*]]
+; CHECK:       [[LOOP_HEADER]]:
+; CHECK-NEXT:    [[MERGE:%.*]] = phi ptr [ [[GEP_MERGE:%.*]], %[[LOOP_LATCH:.*]] ], [ [[L_V]], %[[LOOP_PREHEADER]] ]
+; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[MERGE]], align 4
+; CHECK-NEXT:    [[C_2:%.*]] = icmp slt i32 [[VAL]], [[N]]
+; CHECK-NEXT:    br i1 [[C_2]], label %[[LOOP_EARLY_EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK:       [[LOOP_EARLY_EXIT]]:
+; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[MERGE]], %[[LOOP_HEADER]] ]
+; CHECK-NEXT:    [[PI_IV:%.*]] = ptrtoint ptr [[IV]] to i64
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[LOOP_LATCH]]:
+; CHECK-NEXT:    [[GEP_MERGE]] = getelementptr inbounds nuw i8, ptr [[MERGE]], i64 4
+; CHECK-NEXT:    [[C_3:%.*]] = icmp eq ptr [[GEP_MERGE]], [[L_GEP_V]]
+; CHECK-NEXT:    br i1 [[C_3]], label %[[LOOP_COMP:.*]], label %[[LOOP_HEADER]]
+; CHECK:       [[LOOP_COMP]]:
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[MER:%.*]] = phi i64 [ [[PI_L_GEP_V]], %[[ENTRY]] ], [ [[PI_IV]], %[[LOOP_EARLY_EXIT]] ], [ [[PI_L_GEP_V]], %[[LOOP_COMP]] ]
+; CHECK-NEXT:    ret i64 [[MER]]
+;
+entry:
+  %l.v = load ptr, ptr %v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %pi.l.v = ptrtoint ptr %l.v to i64
+  %gep.v = getelementptr inbounds nuw i8, ptr %v, i64 8
+  %l.gep.v = load ptr, ptr %gep.v, align 8
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.gep.v, i64 4) ]
+  %pi.l.gep.v = ptrtoint ptr %l.gep.v to i64
+  %sub = sub i64 %pi.l.gep.v, %pi.l.v
+  call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %l.v, i64 %sub) ]
+  %atomic = load atomic ptr, ptr %v seq_cst, align 8                      ; Atomic Instruction
+  call void @llvm.assume(i1 true) [ "align"(ptr %l.v, i64 4) ]
+  %c.1 = icmp eq ptr %l.v, %l.gep.v
+  br i1 %c.1, label %exit, label %loop.preheader
+
+loop.preheader:
+  br label %loop.header
+
+loop.header:
+  %iv = phi ptr [ %gep.merge, %loop.latch ], [ %l.v, %loop.preheader ]
+  %val = load i32, ptr %iv, align 4
+  %c.2 = icmp slt i32 %val, %n
+  br i1 %c.2, label %loop.early.exit, label %loop.latch
+
+loop.early.exit:
+  %iv.1 = phi ptr [ %iv, %loop.header ]
+  %pi.iv = ptrtoint ptr %iv.1 to i64
+  br label %exit
+
+loop.latch:
+  %gep.merge = getelementptr inbounds nuw i8, ptr %iv, i64 4
+  %c.3 = icmp eq ptr %gep.merge, %l.gep.v
+  br i1 %c.3, label %loop.comp, label %loop.header
+
+loop.comp:
+  br label %exit
+
+exit:
+  %mer = phi i64 [ %pi.l.gep.v, %entry ], [ %pi.iv, %loop.early.exit ], [ %pi.l.gep.v, %loop.comp ]
+  ret i64 %mer
+}

>From a247f2ccd73ddd784017faf590d42fd9faba1a98 Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Sat, 30 May 2026 17:00:36 +0530
Subject: [PATCH 10/11] Nitpick

---
 llvm/lib/Analysis/ValueTracking.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index d18278760a1c4..cb9f507b78cc4 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -704,7 +704,7 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
 bool llvm::willNotFreeBetween(const Instruction *Assume,
                               const Instruction *CtxI) {
   // Helper to check if there are any calls in the range that may free memory.
-  auto hasNoFreeCalls = [](auto Range) {
+  auto hasNoFreeInRange = [](auto Range) {
     for (const auto &[Idx, I] : enumerate(Range)) {
       if (Idx > MaxInstrsToCheckForFree)
         return false;
@@ -726,7 +726,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
     if (CtxBB->getSinglePredecessor() != AssumeBB)
       return false;
 
-    if (!hasNoFreeCalls(make_range(CtxBB->begin(), CtxIter)))
+    if (!hasNoFreeInRange(make_range(CtxBB->begin(), CtxIter)))
       return false;
 
     CtxIter = AssumeBB->end();
@@ -738,7 +738,7 @@ bool llvm::willNotFreeBetween(const Instruction *Assume,
 
   // Check if there are any calls between Assume and CtxIter that may free
   // memory.
-  return hasNoFreeCalls(make_range(Assume->getIterator(), CtxIter));
+  return hasNoFreeInRange(make_range(Assume->getIterator(), CtxIter));
 }
 
 // TODO: cmpExcludesZero misses many cases where `RHS` is non-constant but

>From 03fdf5015dc8456d193e38500c3d4a7ace4bc6ec Mon Sep 17 00:00:00 2001
From: Kshitij Paranjape <kshitijvparanjape at gmail.com>
Date: Sat, 30 May 2026 17:29:47 +0530
Subject: [PATCH 11/11] Modify Test

---
 ...able-info-from-assumption-constant-size.ll | 27 +++++++++++++++----
 1 file changed, 22 insertions(+), 5 deletions(-)

diff --git a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
index 875fa0d69cfe3..e7d3448e74ada 100644
--- a/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
+++ b/llvm/test/Transforms/LoopVectorize/dereferenceable-info-from-assumption-constant-size.ll
@@ -1307,13 +1307,30 @@ define void @deref_assumption_in_header_constant_trip_count_nofree_via_context_b
 ; CHECK:       [[VECTOR_PH]]:
 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]
 ; CHECK:       [[VECTOR_BODY]]:
-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
+; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[PRED_LOAD_CONTINUE2:.*]] ]
 ; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <2 x i32>, ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = icmp sge <2 x i32> [[WIDE_LOAD]], zeroinitializer
-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <2 x i32>, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i32> [[WIDE_LOAD]], <2 x i32> [[WIDE_LOAD1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i32> [[WIDE_LOAD]], zeroinitializer
+; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <2 x i1> [[TMP1]], i64 0
+; CHECK-NEXT:    br i1 [[TMP2]], label %[[PRED_LOAD_IF:.*]], label %[[PRED_LOAD_CONTINUE:.*]]
+; CHECK:       [[PRED_LOAD_IF]]:
+; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr i32, ptr [[A]], i64 [[INDEX]]
+; CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
+; CHECK-NEXT:    [[TMP6:%.*]] = insertelement <2 x i32> poison, i32 [[TMP5]], i64 0
+; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE]]
+; CHECK:       [[PRED_LOAD_CONTINUE]]:
+; CHECK-NEXT:    [[TMP7:%.*]] = phi <2 x i32> [ poison, %[[VECTOR_BODY]] ], [ [[TMP6]], %[[PRED_LOAD_IF]] ]
+; CHECK-NEXT:    [[TMP8:%.*]] = extractelement <2 x i1> [[TMP1]], i64 1
+; CHECK-NEXT:    br i1 [[TMP8]], label %[[PRED_LOAD_IF1:.*]], label %[[PRED_LOAD_CONTINUE2]]
+; CHECK:       [[PRED_LOAD_IF1]]:
+; CHECK-NEXT:    [[TMP9:%.*]] = add i64 [[INDEX]], 1
+; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr i32, ptr [[A]], i64 [[TMP9]]
+; CHECK-NEXT:    [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+; CHECK-NEXT:    [[TMP12:%.*]] = insertelement <2 x i32> [[TMP7]], i32 [[TMP11]], i64 1
+; CHECK-NEXT:    br label %[[PRED_LOAD_CONTINUE2]]
+; CHECK:       [[PRED_LOAD_CONTINUE2]]:
+; CHECK-NEXT:    [[TMP13:%.*]] = phi <2 x i32> [ [[TMP7]], %[[PRED_LOAD_CONTINUE]] ], [ [[TMP12]], %[[PRED_LOAD_IF1]] ]
+; CHECK-NEXT:    [[PREDPHI:%.*]] = select <2 x i1> [[TMP1]], <2 x i32> [[TMP13]], <2 x i32> [[WIDE_LOAD]]
 ; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds i32, ptr [[C]], i64 [[INDEX]]
 ; CHECK-NEXT:    store <2 x i32> [[PREDPHI]], ptr [[TMP14]], align 4
 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2



More information about the llvm-commits mailing list