[llvm] [llvm-c][ocaml] Deprecate/replace constexpr GEP APIs (PR #228998)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 5 02:08:11 PDT 2026


https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/228998

>From 82937b1704d9d46eafd7f9e7a0baeceab99912e0 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 30 Sep 2026 12:14:44 +0200
Subject: [PATCH 1/4] [llvm-c][ocaml] Deprecate/replace constexpr GEP APIs

In the C API, this deprecates LLVMConstGEP and LLVMConstInBoundsGEP.
The replacement APIs are LLVMConstPtrAdd and LLVMConstPtrAddFromIndices.
The latter exposes the DataLayout-aware `getGetElementPtr()` API,
and only exists for the sake of convience.

Similarly, in the OCaml API, remove const_gep and const_inbounds_gep
in favor of const_ptradd and const_ptradd_from_indices, which mirror
the C APIs translated to OCaml.

Unlike the older APIs, the new ones work directly on GEPNoWrapFlags
instead of providing (an incomplete set of) separate APIs for
different flavors.
---
 llvm/bindings/ocaml/llvm/llvm.ml      | 16 +++++---
 llvm/bindings/ocaml/llvm/llvm.mli     | 30 ++++++++++-----
 llvm/bindings/ocaml/llvm/llvm_ocaml.c | 26 +++++++------
 llvm/docs/ReleaseNotes.md             | 13 +++++++
 llvm/include/llvm-c/Core.h            | 53 +++++++++++++++++++--------
 llvm/lib/IR/Core.cpp                  | 19 ++++++++++
 llvm/test/Bindings/OCaml/core.ml      | 24 ++++++++++--
 llvm/test/Bindings/llvm-c/echo.ll     | 10 ++---
 llvm/tools/llvm-c-test/echo.cpp       |  5 ++-
 llvm/unittests/IR/ConstantsTest.cpp   | 28 ++++++++++++++
 10 files changed, 171 insertions(+), 53 deletions(-)

diff --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml
index 48bd48b9e4eba..f1a985be81aa0 100644
--- a/llvm/bindings/ocaml/llvm/llvm.ml
+++ b/llvm/bindings/ocaml/llvm/llvm.ml
@@ -355,6 +355,12 @@ module ModuleFlagBehavior = struct
   | AppendUnique
 end
 
+module GEPNoWrapFlags = struct
+  let inbounds = 1
+  let nusw = 2
+  let nuw = 4
+end
+
 module Endian = struct
   type t =
   | Big
@@ -394,7 +400,6 @@ module DataLayout = struct
                              = "llvm_datalayout_offset_of_element"
 end
 
-
 exception IoError of string
 
 let () = Callback.register_exception "Llvm.IoError" (IoError "")
@@ -697,10 +702,11 @@ external const_sub : llvalue -> llvalue -> llvalue = "llvm_const_sub"
 external const_nsw_sub : llvalue -> llvalue -> llvalue = "llvm_const_nsw_sub"
 external const_nuw_sub : llvalue -> llvalue -> llvalue = "llvm_const_nuw_sub"
 external const_xor : llvalue -> llvalue -> llvalue = "llvm_const_xor"
-external const_gep : lltype -> llvalue -> llvalue array -> llvalue
-                   = "llvm_const_gep"
-external const_in_bounds_gep : lltype -> llvalue -> llvalue array -> llvalue
-                             = "llvm_const_in_bounds_gep"
+external const_ptradd : llvalue -> llvalue -> int -> llvalue
+                      = "llvm_const_ptradd"
+external const_ptradd_from_indices : DataLayout.t -> lltype -> llvalue ->
+                                     llvalue array -> int -> llvalue option
+                                   = "llvm_const_ptradd_from_indices"
 external const_trunc : llvalue -> lltype -> llvalue = "llvm_const_trunc"
 external const_ptrtoint : llvalue -> lltype -> llvalue = "llvm_const_ptrtoint"
 external const_inttoptr : llvalue -> lltype -> llvalue = "llvm_const_inttoptr"
diff --git a/llvm/bindings/ocaml/llvm/llvm.mli b/llvm/bindings/ocaml/llvm/llvm.mli
index 294f88c70f8f1..25104ed53e1e1 100644
--- a/llvm/bindings/ocaml/llvm/llvm.mli
+++ b/llvm/bindings/ocaml/llvm/llvm.mli
@@ -394,6 +394,12 @@ module ModuleFlagBehavior :sig
   | AppendUnique
 end
 
+module GEPNoWrapFlags : sig
+  val inbounds : int
+  val nusw : int
+  val nuw : int
+end
+
 (** {6 Data Layout} *)
 
 module Endian : sig
@@ -472,7 +478,6 @@ module DataLayout : sig
   val offset_of_element : lltype -> int -> t -> Int64.t
 end
 
-
 (** {6 Iteration} *)
 
 (** [Before b] and [At_end a] specify positions from the start of the ['b] list
@@ -1199,16 +1204,21 @@ val const_nuw_sub : llvalue -> llvalue -> llvalue
     See the method [llvm::ConstantExpr::getXor]. *)
 val const_xor : llvalue -> llvalue -> llvalue
 
-(** [const_gep srcty pc indices] returns the constant [getElementPtr] of [pc]
-    with source element type [srcty] and the constant integers indices from the
-    array [indices].
+(** [const_ptradd pc offset flags] returns the constant ptradd
+    (getelementptr i8) of [pc] with constant [offset] and the given
+    {!GEPNoWrapFlags} no-wrap flags (combined with [lor], or [0] for none).
+    See the method [llvm::ConstantExpr::getPtrAdd]. *)
+val const_ptradd : llvalue -> llvalue -> int -> llvalue
+
+(** [const_ptradd_from_indices dl srcty pc indices flags] returns the constant
+    ptradd of [pc] with the offset derived from the data layout [dl], the
+    source element type [srcty] and the constant integers indices from the
+    array [indices]. The flags are {!GEPNoWrapFlags} (combined with [lor], or
+    [0] for none). The result may be [None] if the indices cannot be converted
+    to ptradd representation.
     See the method [llvm::ConstantExpr::getGetElementPtr]. *)
-val const_gep : lltype -> llvalue -> llvalue array -> llvalue
-
-(** [const_in_bounds_gep ty pc indices] returns the constant [getElementPtr] of
-    [pc] with the constant integers indices from the array [indices].
-    See the method [llvm::ConstantExpr::getInBoundsGetElementPtr]. *)
-val const_in_bounds_gep : lltype -> llvalue -> llvalue array -> llvalue
+val const_ptradd_from_indices : DataLayout.t -> lltype -> llvalue ->
+                                llvalue array -> int -> llvalue option
 
 (** [const_trunc c ty] returns the constant truncation of integer constant [c]
     to the smaller integer type [ty].
diff --git a/llvm/bindings/ocaml/llvm/llvm_ocaml.c b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
index e08797cf0e3d9..75ae700de70ed 100644
--- a/llvm/bindings/ocaml/llvm/llvm_ocaml.c
+++ b/llvm/bindings/ocaml/llvm/llvm_ocaml.c
@@ -1195,24 +1195,26 @@ value llvm_const_xor(value LHS, value RHS) {
   return to_val(Value);
 }
 
-/* lltype -> llvalue -> llvalue array -> llvalue */
-value llvm_const_gep(value Ty, value ConstantVal, value Indices) {
-  mlsize_t Length = Wosize_val(Indices);
-  LLVMValueRef *Temp = from_val_array(Indices);
-  LLVMValueRef Value =
-      LLVMConstGEP2(Type_val(Ty), Value_val(ConstantVal), Temp, Length);
-  free(Temp);
+/* llvalue -> llvalue -> int -> llvalue */
+value llvm_const_ptradd(value ConstantVal, value ConstantOffset,
+                        value NoWrapFlags) {
+  LLVMValueRef Value = LLVMConstPtrAdd(
+      Value_val(ConstantVal), Value_val(ConstantOffset), Int_val(NoWrapFlags));
   return to_val(Value);
 }
 
-/* lltype -> llvalue -> llvalue array -> llvalue */
-value llvm_const_in_bounds_gep(value Ty, value ConstantVal, value Indices) {
+/* DataLayout.t -> lltype -> llvalue -> llvalue array -> int ->
+ * llvalue option */
+value llvm_const_ptradd_from_indices(value DataLayout, value Ty,
+                                     value ConstantVal, value Indices,
+                                     value NoWrapFlags) {
   mlsize_t Length = Wosize_val(Indices);
   LLVMValueRef *Temp = from_val_array(Indices);
-  LLVMValueRef Value =
-      LLVMConstInBoundsGEP2(Type_val(Ty), Value_val(ConstantVal), Temp, Length);
+  LLVMValueRef Value = LLVMConstPtrAddFromIndices(
+      DataLayout_val(DataLayout), Type_val(Ty), Value_val(ConstantVal), Temp,
+      Length, Int_val(NoWrapFlags));
   free(Temp);
-  return to_val(Value);
+  return ptr_to_option(Value);
 }
 
 /* llvalue -> lltype -> llvalue */
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 93674c1825367..d1797ef165f06 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -314,6 +314,12 @@ Makes programs 10x faster by doing Special New Thing.
   `set_data_layout` now accepts a `DataLayout` instead of a `string`. You can
   use `DataLayout.of_string` and `DataLayout.as_string` to convert between them.
 
+* `const_gep` and `const_inbounds_gep` have been removed in favor of
+  `const_ptradd` and `const_ptradd_from_indices`. Both create `getelementptr i8`
+  constant expressions, the former using an integero ffset, and the latter using
+  a data layout, base type and index sequence. The latter API returns an option,
+  as it may fail if the indices cannot be converted into ptradd representation.
+
 ### Changes to the Python bindings
 
 ### Changes to the C API
@@ -325,6 +331,13 @@ Makes programs 10x faster by doing Special New Thing.
 * Bindings operating on data layout (`LLVMTargetDataRef`) have been moved
   from `Target.h` (`Target` library) to `Core.h` (`IR` library).
 
+* `LLVMConstGEP2()` and `LLVMConstInBoundsGEP2()` have been deprecated.
+  `LLVMConstPtrAdd()` and `LLVMConstPtrAddFromIndices()` can be used instead.
+  Both create `getelementptr i8` constant expressions, the former using an
+  integer offset, and the latter using a data layout, base type and index
+  sequence. The latter API may fail if the indices cannot be converted into
+  ptradd representation.
+
 ### Changes to the CodeGen infrastructure
 
 * Fixed a crash
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index ecff14ee644ce..b359267543e73 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -19,7 +19,6 @@
 #include "llvm-c/ErrorHandling.h"
 #include "llvm-c/ExternC.h"
 #include "llvm-c/Visibility.h"
-
 #include "llvm-c/Types.h"
 
 LLVM_C_EXTERN_C_BEGIN
@@ -32,6 +31,8 @@ LLVM_C_EXTERN_C_BEGIN
  * @{
  */
 
+typedef struct LLVMOpaqueTargetData *LLVMTargetDataRef;
+
 /**
  * @defgroup LLVMCTransforms Transforms
  */
@@ -2777,22 +2778,46 @@ LLVM_C_ABI LLVMValueRef LLVMConstNUWSub(LLVMValueRef LHSConstant,
                                         LLVMValueRef RHSConstant);
 LLVM_C_ABI LLVMValueRef LLVMConstXor(LLVMValueRef LHSConstant,
                                      LLVMValueRef RHSConstant);
-LLVM_C_ABI LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
-                                      LLVMValueRef *ConstantIndices,
-                                      unsigned NumIndices);
-LLVM_C_ABI LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty,
-                                              LLVMValueRef ConstantVal,
-                                              LLVMValueRef *ConstantIndices,
-                                              unsigned NumIndices);
+
+LLVM_C_ABI LLVM_ATTRIBUTE_C_DEPRECATED(
+    LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+                               LLVMValueRef *ConstantIndices,
+                               unsigned NumIndices),
+    "Use LLVMConstPtrAdd() or LLVMConstPtrAddFromIndices() instead");
+LLVM_C_ABI LLVM_ATTRIBUTE_C_DEPRECATED(
+    LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+                                       LLVMValueRef *ConstantIndices,
+                                       unsigned NumIndices),
+    "Use LLVMConstPtrAdd() or LLVMConstPtrAddFromIndices() instead");
+LLVM_C_ABI LLVM_ATTRIBUTE_C_DEPRECATED(
+    LLVMValueRef LLVMConstGEPWithNoWrapFlags(
+        LLVMTypeRef Ty, LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices,
+        unsigned NumIndices, LLVMGEPNoWrapFlags NoWrapFlags),
+    "Use LLVMConstPtrAdd() or LLVMConstPtrAddFromIndices() instead");
+
 /**
- * Creates a constant GetElementPtr expression. Similar to LLVMConstGEP2, but
- * allows specifying the no-wrap flags.
+ * Creates a constant ptradd expression (getelementptr i8).
+ *
+ * @see llvm::ConstantExpr::getPtrAdd()
+ */
+LLVM_C_ABI LLVMValueRef LLVMConstPtrAdd(LLVMValueRef ConstantVal,
+                                        LLVMValueRef ConstantOffset,
+                                        LLVMGEPNoWrapFlags NoWrapFlags);
+
+/**
+ * Creates a constant ptradd expression (getelementptr i8) by converting the
+ * provided GEP indices for the provided source element type into a constant
+ * offset using the provided data layout.
+ *
+ * May return null if the indices are not representable as a constant ptradd.
  *
  * @see llvm::ConstantExpr::getGetElementPtr()
  */
-LLVM_C_ABI LLVMValueRef LLVMConstGEPWithNoWrapFlags(
-    LLVMTypeRef Ty, LLVMValueRef ConstantVal, LLVMValueRef *ConstantIndices,
-    unsigned NumIndices, LLVMGEPNoWrapFlags NoWrapFlags);
+LLVM_C_ABI LLVMValueRef LLVMConstPtrAddFromIndices(
+    LLVMTargetDataRef DataLayout, LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+    LLVMValueRef *ConstantIndices, unsigned NumIndices,
+    LLVMGEPNoWrapFlags NoWrapFlags);
+
 LLVM_C_ABI LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal,
                                        LLVMTypeRef ToType);
 LLVM_C_ABI LLVMValueRef LLVMConstPtrToInt(LLVMValueRef ConstantVal,
@@ -5376,8 +5401,6 @@ LLVM_C_ABI LLVMBool LLVMIsMultithreaded(void);
 
 enum LLVMByteOrdering { LLVMBigEndian, LLVMLittleEndian };
 
-typedef struct LLVMOpaqueTargetData *LLVMTargetDataRef;
-
 /**
  * Obtain the data layout for a module.
  *
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 0025b7b78ccc7..87c1ba389985d 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -1944,6 +1944,25 @@ LLVMValueRef LLVMConstGEPWithNoWrapFlags(LLVMTypeRef Ty,
   LLVM_SUPPRESS_DEPRECATED_DECLARATIONS_POP
 }
 
+LLVMValueRef LLVMConstPtrAdd(LLVMValueRef ConstantVal,
+                             LLVMValueRef ConstantOffset,
+                             LLVMGEPNoWrapFlags NoWrapFlags) {
+  return wrap(ConstantExpr::getPtrAdd(unwrap<Constant>(ConstantVal),
+                                      unwrap<Constant>(ConstantOffset),
+                                      mapFromLLVMGEPNoWrapFlags(NoWrapFlags)));
+}
+
+LLVM_C_ABI LLVMValueRef LLVMConstPtrAddFromIndices(
+    LLVMTargetDataRef DataLayout, LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+    LLVMValueRef *ConstantIndices, unsigned NumIndices,
+    LLVMGEPNoWrapFlags NoWrapFlags) {
+  ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
+                               NumIndices);
+  return wrap(ConstantExpr::getGetElementPtr(
+      *unwrap(DataLayout), unwrap(Ty), unwrap<Constant>(ConstantVal), IdxList,
+      mapFromLLVMGEPNoWrapFlags(NoWrapFlags)));
+}
+
 LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType) {
   return wrap(ConstantExpr::getTrunc(unwrap<Constant>(ConstantVal),
                                      unwrap(ToType)));
diff --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index b44058b2ad25a..7c1a683aa601d 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -297,21 +297,37 @@ let test_constants () =
   ignore (define_global "const_trunc" (const_trunc (const_add foldbomb five)
                                                i8_type) m);
   ignore (define_global "const_ptrtoint" (const_ptrtoint
-    (const_gep i8_type (const_null (pointer_type context))
-               [| const_int i32_type 1 |])
+    (const_ptradd (const_null (pointer_type context)) (const_int i32_type 1) 0)
     i32_type) m);
   ignore (define_global "const_inttoptr" (const_inttoptr (const_add foldbomb five)
                                                   void_ptr) m);
   ignore (define_global "const_bitcast" (const_bitcast foldbomb double_type) m);
 
   group "misc constants";
-  (* CHECK: const_gep{{.*}}getelementptr
+  (* CHECK: const_ptradd = global ptr getelementptr (i8, ptr @FoldBomb, i64 5)
+   * CHECK: const_ptradd_inbounds = global ptr
+   * CHECK-SAME: getelementptr inbounds (i8, ptr @FoldBomb, i64 5)
+   * CHECK: const_ptradd_inbounds_nuw = global ptr
+   * CHECK-SAME: getelementptr inbounds nuw (i8, ptr @FoldBomb, i64 5)
+   * CHECK: const_ptradd_from_indices = global ptr
+   * CHECK-SAME: getelementptr nusw (i8, ptr @FoldBomb, i32 20)
    * CHECK: const_extractelement{{.*}}extractelement
    * CHECK: const_insertelement{{.*}}insertelement
    * CHECK: const_shufflevector = global <4 x i32> <i32 0, i32 1, i32 1, i32 0>
    *)
-  ignore (define_global "const_gep" (const_gep i8_type foldbomb_gv [| five |])
+  ignore (define_global "const_ptradd" (const_ptradd foldbomb_gv five 0) m);
+  ignore (define_global "const_ptradd_inbounds"
+          (const_ptradd foldbomb_gv five GEPNoWrapFlags.inbounds) m);
+  ignore (define_global "const_ptradd_inbounds_nuw"
+          (const_ptradd foldbomb_gv five
+           (GEPNoWrapFlags.inbounds lor GEPNoWrapFlags.nuw)) m);
+  ignore (define_global "const_ptradd_from_indices"
+          (Option.get (const_ptradd_from_indices (data_layout m) i32_type
+                       foldbomb_gv [| five |] GEPNoWrapFlags.nusw))
           m);
+  assert (Option.is_none (const_ptradd_from_indices (data_layout m) i32_type
+                          foldbomb_gv
+                          [| (const_ptrtoint foldbomb_gv i32_type) |] 0));
   let zero = const_int i32_type 0 in
   let one  = const_int i32_type 1 in
   ignore (define_global "const_extractelement" (const_extractelement
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index 285285a55c073..8d8ac9c75dbf8 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -24,11 +24,11 @@ module asm "classical GAS"
 @align = global i32 31, align 4
 @nullptr = global ptr null
 
- at const_gep = global ptr getelementptr (i32, ptr @var, i64 2)
- at const_inbounds_gep = global ptr getelementptr inbounds (i32, ptr @var, i64 1)
- at const_gep_nuw = global ptr getelementptr nuw (i32, ptr @var, i64 1)
- at const_gep_nusw = global ptr getelementptr nusw (i32, ptr @var, i64 1)
- at const_gep_nuw_inbounds = global ptr getelementptr nuw inbounds (i32, ptr @var, i64 1)
+ at const_gep = global ptr getelementptr (i8, ptr @var, i64 8)
+ at const_inbounds_gep = global ptr getelementptr inbounds (i8, ptr @var, i64 4)
+ at const_gep_nuw = global ptr getelementptr nuw (i8, ptr @var, i64 4)
+ at const_gep_nusw = global ptr getelementptr nusw (i8, ptr @var, i64 4)
+ at const_gep_nuw_inbounds = global ptr getelementptr nuw inbounds (i8, ptr @var, i64 4)
 
 @aliased1 = alias i32, ptr @var
 @aliased2 = internal alias i32, ptr @var
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 717722c58a268..b807bef59dcee 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -422,8 +422,9 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
       for (int i = 1; i <= NumIdx; i++)
         Idx.push_back(clone_constant(LLVMGetOperand(Cst, i), M));
 
-      return LLVMConstGEPWithNoWrapFlags(ElemTy, Ptr, Idx.data(), NumIdx,
-                                         LLVMGEPGetNoWrapFlags(Cst));
+      return LLVMConstPtrAddFromIndices(LLVMGetModuleDataLayout(M), ElemTy, Ptr,
+                                        Idx.data(), NumIdx,
+                                        LLVMGEPGetNoWrapFlags(Cst));
     }
     default:
       fprintf(stderr, "%d is not a supported opcode for constant expressions\n",
diff --git a/llvm/unittests/IR/ConstantsTest.cpp b/llvm/unittests/IR/ConstantsTest.cpp
index 0f1cefb234a79..920385c4caaab 100644
--- a/llvm/unittests/IR/ConstantsTest.cpp
+++ b/llvm/unittests/IR/ConstantsTest.cpp
@@ -998,4 +998,32 @@ TEST(ConstantsTest, GetElementPtrDataLayout) {
   EXPECT_EQ(nullptr, ConstantExpr::getGetElementPtr(DL, I8, Ptr, PtrToInt32));
 }
 
+TEST(ConstantsTest, PtrAddCAPI) {
+  LLVMContext Context;
+  DataLayout DL;
+  Module M("", Context);
+
+  Type *I8 = Type::getInt8Ty(Context);
+  Type *I32 = Type::getInt32Ty(Context);
+  Type *I64 = Type::getInt64Ty(Context);
+  Constant *Ptr = M.getOrInsertGlobal("dummy", I8);
+  Constant *PtrToInt = ConstantExpr::getPtrToInt(Ptr, I64);
+  Constant *I64_1 = ConstantInt::get(I64, 1);
+
+  EXPECT_EQ(
+      unwrap(LLVMConstPtrAdd(wrap(Ptr), wrap(I64_1), LLVMGEPFlagNUW)),
+      ConstantExpr::getPtrAdd(Ptr, I64_1, GEPNoWrapFlags::noUnsignedWrap()));
+
+  LLVMValueRef Indices[1] = {wrap(I64_1)};
+  EXPECT_EQ(unwrap(LLVMConstPtrAddFromIndices(wrap(&DL), wrap(I32), wrap(Ptr),
+                                              Indices, 1, LLVMGEPFlagInBounds)),
+            ConstantExpr::getGetElementPtr(DL, I32, Ptr, I64_1,
+                                           GEPNoWrapFlags::inBounds()));
+
+  LLVMValueRef Indices2[1] = {wrap(PtrToInt)};
+  EXPECT_EQ(unwrap(LLVMConstPtrAddFromIndices(wrap(&DL), wrap(I32), wrap(Ptr),
+                                              Indices2, 1, 0)),
+            nullptr);
+}
+
 } // end anonymous namespace

>From 5dc551e9e323e9d9d65019104508510bfd126e17 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 5 Oct 2026 10:19:10 +0200
Subject: [PATCH 2/4] Fixes

---
 llvm/docs/ReleaseNotes.md  |  4 ++--
 llvm/include/llvm-c/Core.h |  2 +-
 llvm/lib/IR/Core.cpp       | 10 ++++++----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index d1797ef165f06..4dd657c0f5843 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -314,9 +314,9 @@ Makes programs 10x faster by doing Special New Thing.
   `set_data_layout` now accepts a `DataLayout` instead of a `string`. You can
   use `DataLayout.of_string` and `DataLayout.as_string` to convert between them.
 
-* `const_gep` and `const_inbounds_gep` have been removed in favor of
+* `const_gep` and `const_in_bounds_gep` have been removed in favor of
   `const_ptradd` and `const_ptradd_from_indices`. Both create `getelementptr i8`
-  constant expressions, the former using an integero ffset, and the latter using
+  constant expressions, the former using an integer offset, and the latter using
   a data layout, base type and index sequence. The latter API returns an option,
   as it may fail if the indices cannot be converted into ptradd representation.
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index b359267543e73..8d55f33e553ae 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -18,8 +18,8 @@
 #include "llvm-c/Deprecated.h"
 #include "llvm-c/ErrorHandling.h"
 #include "llvm-c/ExternC.h"
-#include "llvm-c/Visibility.h"
 #include "llvm-c/Types.h"
+#include "llvm-c/Visibility.h"
 
 LLVM_C_EXTERN_C_BEGIN
 
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 87c1ba389985d..3aab78bdf2d2a 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -1952,10 +1952,12 @@ LLVMValueRef LLVMConstPtrAdd(LLVMValueRef ConstantVal,
                                       mapFromLLVMGEPNoWrapFlags(NoWrapFlags)));
 }
 
-LLVM_C_ABI LLVMValueRef LLVMConstPtrAddFromIndices(
-    LLVMTargetDataRef DataLayout, LLVMTypeRef Ty, LLVMValueRef ConstantVal,
-    LLVMValueRef *ConstantIndices, unsigned NumIndices,
-    LLVMGEPNoWrapFlags NoWrapFlags) {
+LLVMValueRef LLVMConstPtrAddFromIndices(LLVMTargetDataRef DataLayout,
+                                        LLVMTypeRef Ty,
+                                        LLVMValueRef ConstantVal,
+                                        LLVMValueRef *ConstantIndices,
+                                        unsigned NumIndices,
+                                        LLVMGEPNoWrapFlags NoWrapFlags) {
   ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
                                NumIndices);
   return wrap(ConstantExpr::getGetElementPtr(

>From b6542491be95d601304f16c6ac9563f1e8eeb7d4 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 5 Oct 2026 10:22:19 +0200
Subject: [PATCH 3/4] Mention deprecation of LLVMConstGEPWithNoWrapFlags() as
 well

---
 llvm/docs/ReleaseNotes.md | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 4dd657c0f5843..7c09b303442a3 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -331,7 +331,8 @@ Makes programs 10x faster by doing Special New Thing.
 * Bindings operating on data layout (`LLVMTargetDataRef`) have been moved
   from `Target.h` (`Target` library) to `Core.h` (`IR` library).
 
-* `LLVMConstGEP2()` and `LLVMConstInBoundsGEP2()` have been deprecated.
+* `LLVMConstGEP2()`, `LLVMConstInBoundsGEP2()` and
+  `LLVMConstGEPWithNoWrapFlags()` have been deprecated.
   `LLVMConstPtrAdd()` and `LLVMConstPtrAddFromIndices()` can be used instead.
   Both create `getelementptr i8` constant expressions, the former using an
   integer offset, and the latter using a data layout, base type and index

>From d1a7d9c75e26569218d25b37138d1db20564e29a Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Mon, 5 Oct 2026 11:07:43 +0200
Subject: [PATCH 4/4] Add GEPNoWrapFlags.none

---
 llvm/bindings/ocaml/llvm/llvm.ml  | 1 +
 llvm/bindings/ocaml/llvm/llvm.mli | 9 +++++----
 llvm/test/Bindings/OCaml/core.ml  | 9 ++++++---
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/llvm/bindings/ocaml/llvm/llvm.ml b/llvm/bindings/ocaml/llvm/llvm.ml
index f1a985be81aa0..574fa149a47c6 100644
--- a/llvm/bindings/ocaml/llvm/llvm.ml
+++ b/llvm/bindings/ocaml/llvm/llvm.ml
@@ -356,6 +356,7 @@ module ModuleFlagBehavior = struct
 end
 
 module GEPNoWrapFlags = struct
+  let none = 0
   let inbounds = 1
   let nusw = 2
   let nuw = 4
diff --git a/llvm/bindings/ocaml/llvm/llvm.mli b/llvm/bindings/ocaml/llvm/llvm.mli
index 25104ed53e1e1..ca525043caf3f 100644
--- a/llvm/bindings/ocaml/llvm/llvm.mli
+++ b/llvm/bindings/ocaml/llvm/llvm.mli
@@ -395,6 +395,7 @@ module ModuleFlagBehavior :sig
 end
 
 module GEPNoWrapFlags : sig
+  val none : int
   val inbounds : int
   val nusw : int
   val nuw : int
@@ -1206,16 +1207,16 @@ val const_xor : llvalue -> llvalue -> llvalue
 
 (** [const_ptradd pc offset flags] returns the constant ptradd
     (getelementptr i8) of [pc] with constant [offset] and the given
-    {!GEPNoWrapFlags} no-wrap flags (combined with [lor], or [0] for none).
+    {!GEPNoWrapFlags} no-wrap flags (combined with [lor]).
     See the method [llvm::ConstantExpr::getPtrAdd]. *)
 val const_ptradd : llvalue -> llvalue -> int -> llvalue
 
 (** [const_ptradd_from_indices dl srcty pc indices flags] returns the constant
     ptradd of [pc] with the offset derived from the data layout [dl], the
     source element type [srcty] and the constant integers indices from the
-    array [indices]. The flags are {!GEPNoWrapFlags} (combined with [lor], or
-    [0] for none). The result may be [None] if the indices cannot be converted
-    to ptradd representation.
+    array [indices]. The flags are {!GEPNoWrapFlags} (combined with [lor]).
+    The result may be [None] if the indices cannot be converted to ptradd
+    representation.
     See the method [llvm::ConstantExpr::getGetElementPtr]. *)
 val const_ptradd_from_indices : DataLayout.t -> lltype -> llvalue ->
                                 llvalue array -> int -> llvalue option
diff --git a/llvm/test/Bindings/OCaml/core.ml b/llvm/test/Bindings/OCaml/core.ml
index 7c1a683aa601d..31e5dd8ae87ae 100644
--- a/llvm/test/Bindings/OCaml/core.ml
+++ b/llvm/test/Bindings/OCaml/core.ml
@@ -297,7 +297,8 @@ let test_constants () =
   ignore (define_global "const_trunc" (const_trunc (const_add foldbomb five)
                                                i8_type) m);
   ignore (define_global "const_ptrtoint" (const_ptrtoint
-    (const_ptradd (const_null (pointer_type context)) (const_int i32_type 1) 0)
+    (const_ptradd (const_null (pointer_type context)) (const_int i32_type 1)
+                   GEPNoWrapFlags.none)
     i32_type) m);
   ignore (define_global "const_inttoptr" (const_inttoptr (const_add foldbomb five)
                                                   void_ptr) m);
@@ -315,7 +316,8 @@ let test_constants () =
    * CHECK: const_insertelement{{.*}}insertelement
    * CHECK: const_shufflevector = global <4 x i32> <i32 0, i32 1, i32 1, i32 0>
    *)
-  ignore (define_global "const_ptradd" (const_ptradd foldbomb_gv five 0) m);
+  ignore (define_global "const_ptradd"
+          (const_ptradd foldbomb_gv five GEPNoWrapFlags.none) m);
   ignore (define_global "const_ptradd_inbounds"
           (const_ptradd foldbomb_gv five GEPNoWrapFlags.inbounds) m);
   ignore (define_global "const_ptradd_inbounds_nuw"
@@ -327,7 +329,8 @@ let test_constants () =
           m);
   assert (Option.is_none (const_ptradd_from_indices (data_layout m) i32_type
                           foldbomb_gv
-                          [| (const_ptrtoint foldbomb_gv i32_type) |] 0));
+                          [| (const_ptrtoint foldbomb_gv i32_type) |]
+                          GEPNoWrapFlags.none));
   let zero = const_int i32_type 0 in
   let one  = const_int i32_type 1 in
   ignore (define_global "const_extractelement" (const_extractelement



More information about the llvm-commits mailing list