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

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


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Benji Smith (Benjins)

<details>
<summary>Changes</summary>

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

---
Full diff: https://github.com/llvm/llvm-project/pull/77390.diff


5 Files Affected:

- (modified) llvm/docs/ReleaseNotes.rst (+3) 
- (modified) llvm/include/llvm-c/Core.h (+10) 
- (modified) llvm/lib/IR/Core.cpp (+8) 
- (modified) llvm/test/Bindings/llvm-c/echo.ll (+26) 
- (modified) llvm/tools/llvm-c-test/echo.cpp (+60-2) 


``````````diff
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 bc708e2d472edd..153001e0a23931 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");
@@ -373,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))
@@ -432,6 +462,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 +1083,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 +1236,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)

``````````

</details>


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


More information about the llvm-commits mailing list