[llvm] [C API] Add blockaddress getters to C API (PR #77390)

Benji Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 8 14:55:56 PST 2024


https://github.com/Benjins created https://github.com/llvm/llvm-project/pull/77390

Exposes getters for the function and basic block associated with blockaddress constants to the C API. Tests for them are added, which required a tweak to llvm-c-test to declare basic blocks ahead of any actual function cloning, since the blockaddress constants may reference basic blocks in arbitrary other functions

----------------------------

This PR is split into two commits for reviewing sake. The first commit is the refactor of `echo.cpp` to pre-declare all basic blocks in `declare_symbols` along with the functions. The second commit contains the pertinent change to the C API

>From 43db89c2bc2a42ff1e88deb99b7214e3e37e317c Mon Sep 17 00:00:00 2001
From: Benji Smith <6193112+Benjins at users.noreply.github.com>
Date: Sun, 7 Jan 2024 20:16:25 -0500
Subject: [PATCH 1/2] Refactor llvm-c-test to pre-declare all basic blocks for
 all functions

This is necessary for being able to clone blockaddress values, since they can
reference basic blocks in other functions. We declare all basic blocks up front
similar to how all functions are declared, and find them when the function
itself is cloned
---
 llvm/tools/llvm-c-test/echo.cpp | 46 +++++++++++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 2 deletions(-)

diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index bc708e2d472edd..5d9e26f875e5da 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -238,6 +238,20 @@ static LLVMValueRef clone_constant(LLVMValueRef Cst, LLVMModuleRef M) {
   return Ret;
 }
 
+static LLVMBasicBlockRef find_bb_in_func(LLVMValueRef Fn, const char *BBName) {
+  LLVMBasicBlockRef CurBB = LLVMGetFirstBasicBlock(Fn);
+  while (CurBB != nullptr) {
+
+    const char *CurBBName = LLVMGetBasicBlockName(CurBB);
+    if (strcmp(CurBBName, BBName) == 0)
+      return CurBB;
+
+    CurBB = LLVMGetNextBasicBlock(CurBB);
+  }
+
+  return nullptr;
+}
+
 static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
   if (!LLVMIsAConstant(Cst))
     report_fatal_error("Expected a constant");
@@ -432,6 +446,17 @@ static LLVMValueRef clone_inline_asm(LLVMValueRef Asm, LLVMModuleRef M) {
                           CanUnwind);
 }
 
+static LLVMBasicBlockRef declare_bb_in_func(LLVMValueRef DstFn,
+                                            LLVMBasicBlockRef Src) {
+  const char *Name = LLVMGetBasicBlockName(Src);
+
+  if (find_bb_in_func(DstFn, Name) != nullptr)
+    report_fatal_error("Trying to re-declare existing basic block");
+
+  LLVMBasicBlockRef DstBB = LLVMAppendBasicBlock(DstFn, Name);
+  return DstBB;
+}
+
 struct FunCloner {
   LLVMValueRef Fun;
   LLVMModuleRef M;
@@ -1042,8 +1067,15 @@ struct FunCloner {
     if (Name != VName)
       report_fatal_error("Basic block name mismatch");
 
-    LLVMBasicBlockRef BB = LLVMAppendBasicBlock(Fun, Name);
-    return BBMap[Src] = BB;
+    // Scan for existing basic blocks that we forward-declared
+    // If a basic block is not cached in BBMap already, then it should exist
+    // in Fun, since we should have pre-declared all basic blocks earlier in
+    // declare_symbols
+    if (LLVMBasicBlockRef ExistingBB = find_bb_in_func(Fun, Name))
+      return BBMap[Src] = ExistingBB;
+
+    report_fatal_error("Trying to declare new basic block");
+    return nullptr;
   }
 
   LLVMBasicBlockRef CloneBB(LLVMBasicBlockRef Src) {
@@ -1188,6 +1220,16 @@ static void declare_symbols(LLVMModuleRef Src, LLVMModuleRef M) {
       }
     }
 
+    // Declare any basic blocks in this function:
+    // We need to do this here, in case any blockaddress value's are used,
+    // in which case we may reference basic blocks in any function
+    // Therefore, declare them before actually cloning any function
+    LLVMBasicBlockRef CurSrcBB = LLVMGetFirstBasicBlock(Cur);
+    while (CurSrcBB != nullptr) {
+      declare_bb_in_func(F, CurSrcBB);
+      CurSrcBB = LLVMGetNextBasicBlock(CurSrcBB);
+    }
+
     Next = LLVMGetNextFunction(Cur);
     if (Next == nullptr) {
       if (Cur != End)

>From 68a433cdda2cc5e310f36a424b37feaf93052e96 Mon Sep 17 00:00:00 2001
From: Benji Smith <6193112+Benjins at users.noreply.github.com>
Date: Sun, 7 Jan 2024 20:43:25 -0500
Subject: [PATCH 2/2] Add LLVMGetBlockAddressFunction and
 LLVMGetBlockAddressBasicBlock getters

This allows for accessing the function/basic block that a blockaddress constant
refers to

Tests are added for it in the llvm-c-test echo.ll file
---
 llvm/docs/ReleaseNotes.rst        |  3 +++
 llvm/include/llvm-c/Core.h        | 10 ++++++++++
 llvm/lib/IR/Core.cpp              |  8 ++++++++
 llvm/test/Bindings/llvm-c/echo.ll | 26 ++++++++++++++++++++++++++
 llvm/tools/llvm-c-test/echo.cpp   | 16 ++++++++++++++++
 5 files changed, 63 insertions(+)

diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 52610e7de18751..24dc9614d97dc5 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -246,6 +246,9 @@ Changes to the C API
   the fast-math flags of an instruction, as well as ``LLVMCanValueUseFastMathFlags``
   for checking if an instruction can use such flags
 
+* Added ``LLVMGetBlockAddressFunction`` and ``LLVMGetBlockAddressBasicBlock``
+  functions for accessing the values in a blockaddress constant
+
 Changes to the CodeGen infrastructure
 -------------------------------------
 
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 83530ae7b51324..1b9683a1d490ad 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -2328,6 +2328,16 @@ LLVMValueRef LLVMConstShuffleVector(LLVMValueRef VectorAConstant,
                                     LLVMValueRef MaskConstant);
 LLVMValueRef LLVMBlockAddress(LLVMValueRef F, LLVMBasicBlockRef BB);
 
+/**
+ * Gets the function associated with a given BlockAddress constant value
+ */
+LLVMValueRef LLVMGetBlockAddressFunction(LLVMValueRef BlockAddr);
+
+/**
+ * Gets the basic block associated with a given BlockAddress constant value
+ */
+LLVMBasicBlockRef LLVMGetBlockAddressBasicBlock(LLVMValueRef BlockAddr);
+
 /** Deprecated: Use LLVMGetInlineAsm instead. */
 LLVMValueRef LLVMConstInlineAsm(LLVMTypeRef Ty,
                                 const char *AsmString, const char *Constraints,
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index fb30fbce0ba22e..d6d159ab8b9e83 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -1805,6 +1805,14 @@ LLVMValueRef LLVMBlockAddress(LLVMValueRef F, LLVMBasicBlockRef BB) {
   return wrap(BlockAddress::get(unwrap<Function>(F), unwrap(BB)));
 }
 
+LLVMValueRef LLVMGetBlockAddressFunction(LLVMValueRef BlockAddr) {
+  return wrap(unwrap<BlockAddress>(BlockAddr)->getFunction());
+}
+
+LLVMBasicBlockRef LLVMGetBlockAddressBasicBlock(LLVMValueRef BlockAddr) {
+  return wrap(unwrap<BlockAddress>(BlockAddr)->getBasicBlock());
+}
+
 /*--.. Operations on global variables, functions, and aliases (globals) ....--*/
 
 LLVMModuleRef LLVMGetGlobalParent(LLVMValueRef Global) {
diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index be0207599478b8..c69c921823a510 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -334,6 +334,32 @@ define void @test_fast_math_flags_call_outer(float %a) {
   ret void
 }
 
+define ptr @test_block_address_01() {
+entry:
+  br label %block_0
+block_0:
+  ret ptr blockaddress(@test_block_address_01, %block_0)
+}
+
+define ptr @test_block_address_02() {
+entry:
+  ret ptr blockaddress(@test_block_address_01, %block_0)
+}
+
+define ptr @test_block_address_03() {
+entry:
+  br label %block_1
+block_1:
+  ret ptr blockaddress(@test_block_address_04, %block_2)
+}
+
+define ptr @test_block_address_04() {
+entry:
+  br label %block_2
+block_2:
+  ret ptr blockaddress(@test_block_address_03, %block_1)
+}
+
 !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 5d9e26f875e5da..153001e0a23931 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -387,6 +387,22 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
     return LLVMConstVector(Elts.data(), EltCount);
   }
 
+  if (LLVMIsABlockAddress(Cst)) {
+    check_value_kind(Cst, LLVMBlockAddressValueKind);
+    LLVMValueRef SrcFunc = LLVMGetBlockAddressFunction(Cst);
+    LLVMBasicBlockRef SrcBB = LLVMGetBlockAddressBasicBlock(Cst);
+
+    LLVMValueRef DstFunc = clone_constant(SrcFunc, M);
+
+    LLVMBasicBlockRef DstBB =
+        find_bb_in_func(DstFunc, LLVMGetBasicBlockName(SrcBB));
+    if (DstBB == nullptr)
+      report_fatal_error(
+          "Could not find basic block with expected name for blockaddress");
+
+    return LLVMBlockAddress(DstFunc, DstBB);
+  }
+
   // At this point, if it's not a constant expression, it's a kind of constant
   // which is not supported
   if (!LLVMIsAConstantExpr(Cst))



More information about the llvm-commits mailing list