[llvm] [FunctionAttrs] Handle ConstantRange overflow in memset initializes inference (PR #145739)

Shivam Gupta via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 25 11:12:13 PDT 2025


https://github.com/xgupta updated https://github.com/llvm/llvm-project/pull/145739

>From 27e2d77af5495718618d66ae2fe71ff562283774 Mon Sep 17 00:00:00 2001
From: Shivam Gupta <shivam98.tkg at gmail.com>
Date: Wed, 25 Jun 2025 21:29:41 +0530
Subject: [PATCH 1/2] [FunctionAttrs] Handle ConstantRange overflow in memset
 initializes inference

Avoid constructing invalid ConstantRange when Offset + Length in
memset overflows signed 64-bit integer space. This prevents
assertion failures when inferring the initializes attribute.

Fixes #140345
---
 llvm/lib/Transforms/IPO/FunctionAttrs.cpp     | 19 ++++++++++++++-----
 .../Transforms/FunctionAttrs/initializes.ll   | 14 ++++++++++++++
 2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index f918d7e059b63..76e74a148625c 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -57,6 +57,7 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Utils/Local.h"
@@ -675,11 +676,19 @@ ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I,
       [](Value *Length,
          std::optional<int64_t> Offset) -> std::optional<ConstantRange> {
     auto *ConstantLength = dyn_cast<ConstantInt>(Length);
-    if (ConstantLength && Offset &&
-        ConstantLength->getValue().isStrictlyPositive()) {
-      return ConstantRange(
-          APInt(64, *Offset, true),
-          APInt(64, *Offset + ConstantLength->getSExtValue(), true));
+    if (ConstantLength && Offset) {
+      int64_t Off = *Offset;
+      int64_t Len = ConstantLength->getSExtValue();
+
+      // Reject zero or negative lengths
+      if (Len <= 0)
+        return std::nullopt;
+
+      int64_t High;
+      if (llvm::AddOverflow(Off, Len, High))
+        return std::nullopt;
+
+      return ConstantRange(APInt(64, Off, true), APInt(64, High, true));
     }
     return std::nullopt;
   };
diff --git a/llvm/test/Transforms/FunctionAttrs/initializes.ll b/llvm/test/Transforms/FunctionAttrs/initializes.ll
index 5800bc1ca7864..193d0fd589884 100644
--- a/llvm/test/Transforms/FunctionAttrs/initializes.ll
+++ b/llvm/test/Transforms/FunctionAttrs/initializes.ll
@@ -649,3 +649,17 @@ define void @range_overflows_signed_64_bit_int(ptr %arg) {
   store i32 0, ptr %getelementptr
   ret void
 }
+
+; We should bail if the memset range overflows a signed 64-bit int.
+define void @memset_large_offset_nonzero_size(ptr %dst) {
+; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
+; CHECK-LABEL: define void @memset_large_offset_nonzero_size(
+; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 9223372036854775805
+; CHECK-NEXT:    call void @llvm.memset.p0.i64(ptr [[OFFSET]], i8 0, i64 3, i1 false)
+; CHECK-NEXT:    ret void
+;
+  %offset = getelementptr inbounds i8, ptr %dst, i64 9223372036854775805
+  call void @llvm.memset.p0.i64(ptr %offset, i8 0, i64 3, i1 false)
+  ret void
+}

>From 29777114e360fce543f572e374d191bae017e111 Mon Sep 17 00:00:00 2001
From: Shivam Gupta <shivam98.tkg at gmail.com>
Date: Wed, 25 Jun 2025 23:41:41 +0530
Subject: [PATCH 2/2] make it consistent with GetTypeAccessRange

---
 llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 76e74a148625c..f43202eea6306 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -57,7 +57,6 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Utils/Local.h"
@@ -677,21 +676,23 @@ ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I,
          std::optional<int64_t> Offset) -> std::optional<ConstantRange> {
     auto *ConstantLength = dyn_cast<ConstantInt>(Length);
     if (ConstantLength && Offset) {
-      int64_t Off = *Offset;
       int64_t Len = ConstantLength->getSExtValue();
 
       // Reject zero or negative lengths
       if (Len <= 0)
         return std::nullopt;
 
-      int64_t High;
-      if (llvm::AddOverflow(Off, Len, High))
+      APInt Low(64, *Offset, true);
+      bool Overflow;
+      APInt High = Low.sadd_ov(APInt(64, Len, true), Overflow);
+      if (Overflow)
         return std::nullopt;
 
-      return ConstantRange(APInt(64, Off, true), APInt(64, High, true));
+      return ConstantRange(Low, High);
     }
     return std::nullopt;
   };
+
   if (auto *SI = dyn_cast<StoreInst>(I)) {
     if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) {
       // Get the fixed type size of "SI". Since the access range of a write



More information about the llvm-commits mailing list