[llvm] [C API] Add accessors for new no-wrap flags on GEP instructions (PR #97970)

Benji Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 8 07:18:17 PDT 2024


https://github.com/Benjins updated https://github.com/llvm/llvm-project/pull/97970

>From 0171a6b03cb62061d304b1e4929ae861d9b540ed Mon Sep 17 00:00:00 2001
From: Benji Smith <benjsith at gmail.com>
Date: Sun, 7 Jul 2024 14:04:26 -0400
Subject: [PATCH 1/2] [C API] Add accessors for new no-wrap flags on GEP
 instructions

Previously, only the inbounds flag was accessible via the C API. This adds
support for any no-wrap related flags (currently nuw and nusw)
---
 llvm/docs/ReleaseNotes.rst        |  6 ++++++
 llvm/include/llvm-c/Core.h        | 28 +++++++++++++++++++++++++
 llvm/lib/IR/Core.cpp              | 34 +++++++++++++++++++++++++++++++
 llvm/test/Bindings/llvm-c/echo.ll |  9 ++++++++
 llvm/tools/llvm-c-test/echo.cpp   |  8 +++-----
 5 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index a6bfd55119398..a0b76a8cb1526 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -293,6 +293,12 @@ They are described in detail in the `debug info migration guide <https://llvm.or
   * ``LLVMGetTargetExtTypeNumTypeParams``/``LLVMGetTargetExtTypeTypeParam``
   * ``LLVMGetTargetExtTypeNumIntParams``/``LLVMGetTargetExtTypeIntParam``
 
+* Added the following functions for accessing/changing the no-wrap flags for a
+  GetElementPtr instruction
+
+  * ``LLVMGEPGetNoWrapFlags``
+  * ``LLVMGEPSetNoWrapFlags``
+
 Changes to the CodeGen infrastructure
 -------------------------------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 9867db4839fe1..db7cebadf20f8 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -510,6 +510,20 @@ enum {
  */
 typedef unsigned LLVMFastMathFlags;
 
+enum {
+  LLVMGEPFlagInBounds = (1 << 0),
+  LLVMGEPFlagNUSW = (1 << 1),
+  LLVMGEPFlagNUW = (1 << 2),
+};
+
+/**
+ * Flags that constrain the allowed wrap semantics of a getelementptr
+ * instruction.
+ *
+ * See https://llvm.org/docs/LangRef.html#getelementptr-instruction
+ */
+typedef unsigned LLVMGEPNoWrapFlags;
+
 /**
  * @}
  */
@@ -3904,6 +3918,20 @@ void LLVMSetIsInBounds(LLVMValueRef GEP, LLVMBool InBounds);
  */
 LLVMTypeRef LLVMGetGEPSourceElementType(LLVMValueRef GEP);
 
+/**
+ * Get the no-wrap related flags for the given GEP instruction.
+ *
+ * @see llvm::GetElementPtrInst::getNoWrapFlags
+ */
+LLVMGEPNoWrapFlags LLVMGEPGetNoWrapFlags(LLVMValueRef GEP);
+
+/**
+ * Get the no-wrap related flags for the given GEP instruction.
+ *
+ * @see llvm::GetElementPtrInst::setNoWrapFlags
+ */
+void LLVMGEPSetNoWrapFlags(LLVMValueRef GEP, LLVMGEPNoWrapFlags WrapFlags);
+
 /**
  * @}
  */
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 9ba7873106043..a9da24e816b2a 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -3090,6 +3090,30 @@ LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca) {
 
 /*--.. Operations on gep instructions (only) ...............................--*/
 
+static GEPNoWrapFlags mapFromLLVMGEPNoWrapFlags(LLVMGEPNoWrapFlags GEPFlags) {
+  GEPNoWrapFlags NewGEPFlags;
+  if ((GEPFlags & LLVMGEPFlagInBounds) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::inBounds();
+  if ((GEPFlags & LLVMGEPFlagNUSW) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::noUnsignedSignedWrap();
+  if ((GEPFlags & LLVMGEPFlagNUW) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::noUnsignedWrap();
+
+  return NewGEPFlags;
+}
+
+static LLVMGEPNoWrapFlags mapToLLVMGEPNoWrapFlags(GEPNoWrapFlags GEPFlags) {
+  LLVMGEPNoWrapFlags NewGEPFlags = 0;
+  if (GEPFlags.isInBounds())
+    NewGEPFlags |= LLVMGEPFlagInBounds;
+  if (GEPFlags.hasNoUnsignedSignedWrap())
+    NewGEPFlags |= LLVMGEPFlagNUSW;
+  if (GEPFlags.hasNoUnsignedWrap())
+    NewGEPFlags |= LLVMGEPFlagNUW;
+
+  return NewGEPFlags;
+}
+
 LLVMBool LLVMIsInBounds(LLVMValueRef GEP) {
   return unwrap<GEPOperator>(GEP)->isInBounds();
 }
@@ -3102,6 +3126,16 @@ LLVMTypeRef LLVMGetGEPSourceElementType(LLVMValueRef GEP) {
   return wrap(unwrap<GEPOperator>(GEP)->getSourceElementType());
 }
 
+LLVMGEPNoWrapFlags LLVMGEPGetNoWrapFlags(LLVMValueRef GEP) {
+  GEPOperator *GEPOp = unwrap<GEPOperator>(GEP);
+  return mapToLLVMGEPNoWrapFlags(GEPOp->getNoWrapFlags());
+}
+
+void LLVMGEPSetNoWrapFlags(LLVMValueRef GEP, LLVMGEPNoWrapFlags WrapFlags) {
+  GetElementPtrInst *GEPInst = unwrap<GetElementPtrInst>(GEP);
+  GEPInst->setNoWrapFlags(mapFromLLVMGEPNoWrapFlags(WrapFlags));
+}
+
 /*--.. Operations on phi nodes .............................................--*/
 
 void LLVMAddIncoming(LLVMValueRef PhiNode, LLVMValueRef *IncomingValues,
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index dc6f2a9e7d206..5dcaa04f4f72c 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -391,6 +391,15 @@ bb_03:
   ret void
 }
 
+define ptr @test_gep_no_wrap_flags(ptr %0) {
+  %gep.1 = getelementptr i8, ptr %0, i32 4
+  %gep.inbounds = getelementptr inbounds i8, ptr %0, i32 4
+  %gep.nuw = getelementptr nuw i8, ptr %0, i32 4
+  %gep.nuw.inbounds = getelementptr inbounds nuw i8, ptr %0, i32 4
+  %gep.nusw = getelementptr nusw i8, ptr %0, i32 4
+  ret ptr %gep.nusw
+}
+
 !llvm.dbg.cu = !{!0, !2}
 !llvm.module.flags = !{!3}
 
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 6fa36421810f0..3c7169efde412 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -767,11 +767,9 @@ struct FunCloner {
         int NumIdx = LLVMGetNumIndices(Src);
         for (int i = 1; i <= NumIdx; i++)
           Idx.push_back(CloneValue(LLVMGetOperand(Src, i)));
-        if (LLVMIsInBounds(Src))
-          Dst = LLVMBuildInBoundsGEP2(Builder, ElemTy, Ptr, Idx.data(), NumIdx,
-                                      Name);
-        else
-          Dst = LLVMBuildGEP2(Builder, ElemTy, Ptr, Idx.data(), NumIdx, Name);
+
+        Dst = LLVMBuildGEP2(Builder, ElemTy, Ptr, Idx.data(), NumIdx, Name);
+        LLVMGEPSetNoWrapFlags(Dst, LLVMGEPGetNoWrapFlags(Src));
         break;
       }
       case LLVMAtomicRMW: {

>From 0aecc8f9beadf4bb8061bee92a2c0bb26f7a6f71 Mon Sep 17 00:00:00 2001
From: Benji Smith <benjsith at gmail.com>
Date: Mon, 8 Jul 2024 10:13:34 -0400
Subject: [PATCH 2/2] Update PR based on feedback: add BuildGEP and ConstGEP
 variants that take an explicit set of GEPNoWrapFlags. Also, actually clone
 the no-wrap flags for constant GEP expressions, and add a test to verify this

---
 llvm/docs/ReleaseNotes.rst        |  4 +-
 llvm/include/llvm-c/Core.h        |  9 ++++
 llvm/lib/IR/Core.cpp              | 71 ++++++++++++++++++++-----------
 llvm/test/Bindings/llvm-c/echo.ll |  3 ++
 llvm/tools/llvm-c-test/echo.cpp   | 12 +++---
 5 files changed, 68 insertions(+), 31 deletions(-)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index a0b76a8cb1526..bceb00981726f 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -293,9 +293,11 @@ They are described in detail in the `debug info migration guide <https://llvm.or
   * ``LLVMGetTargetExtTypeNumTypeParams``/``LLVMGetTargetExtTypeTypeParam``
   * ``LLVMGetTargetExtTypeNumIntParams``/``LLVMGetTargetExtTypeIntParam``
 
-* Added the following functions for accessing/changing the no-wrap flags for a
+* Added the following functions for accessing/setting the no-wrap flags for a
   GetElementPtr instruction
 
+  * ``LLVMBuildGEPWithWrapFlags``
+  * ``LLVMConstGEPWithWrapFlags``
   * ``LLVMGEPGetNoWrapFlags``
   * ``LLVMGEPSetNoWrapFlags``
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index db7cebadf20f8..771032e102198 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -2409,6 +2409,10 @@ LLVMValueRef LLVMConstGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
 LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
                                    LLVMValueRef *ConstantIndices,
                                    unsigned NumIndices);
+LLVMValueRef LLVMConstGEPWithWrapFlags(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+                                       LLVMValueRef *ConstantIndices,
+                                       unsigned NumIndices,
+                                       LLVMGEPNoWrapFlags WrapFlags);
 LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
 LLVMValueRef LLVMConstPtrToInt(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
 LLVMValueRef LLVMConstIntToPtr(LLVMValueRef ConstantVal, LLVMTypeRef ToType);
@@ -4391,6 +4395,11 @@ LLVMValueRef LLVMBuildGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
 LLVMValueRef LLVMBuildInBoundsGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
                                    LLVMValueRef Pointer, LLVMValueRef *Indices,
                                    unsigned NumIndices, const char *Name);
+LLVMValueRef LLVMBuildGEPWithWrapFlags(LLVMBuilderRef B, LLVMTypeRef Ty,
+                                       LLVMValueRef Pointer,
+                                       LLVMValueRef *Indices,
+                                       unsigned NumIndices, const char *Name,
+                                       LLVMGEPNoWrapFlags WrapFlags);
 LLVMValueRef LLVMBuildStructGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
                                  LLVMValueRef Pointer, unsigned Idx,
                                  const char *Name);
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index a9da24e816b2a..61b81df1f7ab4 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -1685,6 +1685,32 @@ static int map_from_llvmopcode(LLVMOpcode code)
     llvm_unreachable("Unhandled Opcode.");
 }
 
+/*-- GEP wrap flag conversions*/
+
+static GEPNoWrapFlags mapFromLLVMGEPNoWrapFlags(LLVMGEPNoWrapFlags GEPFlags) {
+  GEPNoWrapFlags NewGEPFlags;
+  if ((GEPFlags & LLVMGEPFlagInBounds) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::inBounds();
+  if ((GEPFlags & LLVMGEPFlagNUSW) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::noUnsignedSignedWrap();
+  if ((GEPFlags & LLVMGEPFlagNUW) != 0)
+    NewGEPFlags |= GEPNoWrapFlags::noUnsignedWrap();
+
+  return NewGEPFlags;
+}
+
+static LLVMGEPNoWrapFlags mapToLLVMGEPNoWrapFlags(GEPNoWrapFlags GEPFlags) {
+  LLVMGEPNoWrapFlags NewGEPFlags = 0;
+  if (GEPFlags.isInBounds())
+    NewGEPFlags |= LLVMGEPFlagInBounds;
+  if (GEPFlags.hasNoUnsignedSignedWrap())
+    NewGEPFlags |= LLVMGEPFlagNUSW;
+  if (GEPFlags.hasNoUnsignedWrap())
+    NewGEPFlags |= LLVMGEPFlagNUW;
+
+  return NewGEPFlags;
+}
+
 /*--.. Constant expressions ................................................--*/
 
 LLVMOpcode LLVMGetConstOpcode(LLVMValueRef ConstantVal) {
@@ -1789,6 +1815,17 @@ LLVMValueRef LLVMConstInBoundsGEP2(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
   return wrap(ConstantExpr::getInBoundsGetElementPtr(unwrap(Ty), Val, IdxList));
 }
 
+LLVMValueRef LLVMConstGEPWithWrapFlags(LLVMTypeRef Ty, LLVMValueRef ConstantVal,
+                                       LLVMValueRef *ConstantIndices,
+                                       unsigned NumIndices,
+                                       LLVMGEPNoWrapFlags WrapFlags) {
+  ArrayRef<Constant *> IdxList(unwrap<Constant>(ConstantIndices, NumIndices),
+                               NumIndices);
+  Constant *Val = unwrap<Constant>(ConstantVal);
+  return wrap(ConstantExpr::getGetElementPtr(
+      unwrap(Ty), Val, IdxList, mapFromLLVMGEPNoWrapFlags(WrapFlags)));
+}
+
 LLVMValueRef LLVMConstTrunc(LLVMValueRef ConstantVal, LLVMTypeRef ToType) {
   return wrap(ConstantExpr::getTrunc(unwrap<Constant>(ConstantVal),
                                      unwrap(ToType)));
@@ -3090,30 +3127,6 @@ LLVMTypeRef LLVMGetAllocatedType(LLVMValueRef Alloca) {
 
 /*--.. Operations on gep instructions (only) ...............................--*/
 
-static GEPNoWrapFlags mapFromLLVMGEPNoWrapFlags(LLVMGEPNoWrapFlags GEPFlags) {
-  GEPNoWrapFlags NewGEPFlags;
-  if ((GEPFlags & LLVMGEPFlagInBounds) != 0)
-    NewGEPFlags |= GEPNoWrapFlags::inBounds();
-  if ((GEPFlags & LLVMGEPFlagNUSW) != 0)
-    NewGEPFlags |= GEPNoWrapFlags::noUnsignedSignedWrap();
-  if ((GEPFlags & LLVMGEPFlagNUW) != 0)
-    NewGEPFlags |= GEPNoWrapFlags::noUnsignedWrap();
-
-  return NewGEPFlags;
-}
-
-static LLVMGEPNoWrapFlags mapToLLVMGEPNoWrapFlags(GEPNoWrapFlags GEPFlags) {
-  LLVMGEPNoWrapFlags NewGEPFlags = 0;
-  if (GEPFlags.isInBounds())
-    NewGEPFlags |= LLVMGEPFlagInBounds;
-  if (GEPFlags.hasNoUnsignedSignedWrap())
-    NewGEPFlags |= LLVMGEPFlagNUSW;
-  if (GEPFlags.hasNoUnsignedWrap())
-    NewGEPFlags |= LLVMGEPFlagNUW;
-
-  return NewGEPFlags;
-}
-
 LLVMBool LLVMIsInBounds(LLVMValueRef GEP) {
   return unwrap<GEPOperator>(GEP)->isInBounds();
 }
@@ -3936,6 +3949,16 @@ LLVMValueRef LLVMBuildInBoundsGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
       unwrap(B)->CreateInBoundsGEP(unwrap(Ty), unwrap(Pointer), IdxList, Name));
 }
 
+LLVMValueRef LLVMBuildGEPWithWrapFlags(LLVMBuilderRef B, LLVMTypeRef Ty,
+                                       LLVMValueRef Pointer,
+                                       LLVMValueRef *Indices,
+                                       unsigned NumIndices, const char *Name,
+                                       LLVMGEPNoWrapFlags WrapFlags) {
+  ArrayRef<Value *> IdxList(unwrap(Indices), NumIndices);
+  return wrap(unwrap(B)->CreateGEP(unwrap(Ty), unwrap(Pointer), IdxList, Name,
+                                   mapFromLLVMGEPNoWrapFlags(WrapFlags)));
+}
+
 LLVMValueRef LLVMBuildStructGEP2(LLVMBuilderRef B, LLVMTypeRef Ty,
                                  LLVMValueRef Pointer, unsigned Idx,
                                  const char *Name) {
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index 5dcaa04f4f72c..06e1c44e0c490 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -25,6 +25,9 @@ module asm "classical GAS"
 
 @const_gep = global ptr getelementptr (i32, ptr @var, i64 2)
 @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)
 
 @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 3c7169efde412..d9ae840762a46 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -412,10 +412,9 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
       SmallVector<LLVMValueRef, 8> Idx;
       for (int i = 1; i <= NumIdx; i++)
         Idx.push_back(clone_constant(LLVMGetOperand(Cst, i), M));
-      if (LLVMIsInBounds(Cst))
-        return LLVMConstInBoundsGEP2(ElemTy, Ptr, Idx.data(), NumIdx);
-      else
-        return LLVMConstGEP2(ElemTy, Ptr, Idx.data(), NumIdx);
+
+      return LLVMConstGEPWithWrapFlags(ElemTy, Ptr, Idx.data(), NumIdx,
+                                       LLVMGEPGetNoWrapFlags(Cst));
     }
     default:
       fprintf(stderr, "%d is not a supported opcode for constant expressions\n",
@@ -768,8 +767,9 @@ struct FunCloner {
         for (int i = 1; i <= NumIdx; i++)
           Idx.push_back(CloneValue(LLVMGetOperand(Src, i)));
 
-        Dst = LLVMBuildGEP2(Builder, ElemTy, Ptr, Idx.data(), NumIdx, Name);
-        LLVMGEPSetNoWrapFlags(Dst, LLVMGEPGetNoWrapFlags(Src));
+        Dst =
+            LLVMBuildGEPWithWrapFlags(Builder, ElemTy, Ptr, Idx.data(), NumIdx,
+                                      Name, LLVMGEPGetNoWrapFlags(Src));
         break;
       }
       case LLVMAtomicRMW: {



More information about the llvm-commits mailing list