[llvm-c] add LLVMReplaceMDNodeOperandWith
authorDavide Bertola <bertola.davide@gmail.com>
Tue, 31 Jan 2023 17:02:50 +0000 (09:02 -0800)
committerAdrian Prantl <aprantl@apple.com>
Tue, 31 Jan 2023 17:58:03 +0000 (09:58 -0800)
I'm working on a tool that visits debug info and massages it using the
llvm-c API. I noticed that LLVMGetOperand special cases MDNodes so I
can get their operands, but I can't replace them. This patch adds
LLVMReplaceMDNodeOperandWith which boils down to
MDNode::replaceOperandWith.

The name was chosen for consistency with LLVMGetMDNodeOperands and
LLVMGetMDNodeNumOperands.

Differential Revision: https://reviews.llvm.org/D136637

llvm/include/llvm-c/Core.h
llvm/lib/IR/Core.cpp
llvm/test/Bindings/llvm-c/is_a_value_as_metadata.ll [new file with mode: 0644]
llvm/test/Bindings/llvm-c/replace_md_operand.ll [new file with mode: 0644]
llvm/tools/llvm-c-test/llvm-c-test.h
llvm/tools/llvm-c-test/main.c
llvm/tools/llvm-c-test/metadata.c

index 21cc1f8..94a25ff 100644 (file)
@@ -1785,6 +1785,7 @@ LLVMBool LLVMIsPoison(LLVMValueRef Val);
 LLVM_FOR_EACH_VALUE_SUBCLASS(LLVM_DECLARE_VALUE_CAST)
 
 LLVMValueRef LLVMIsAMDNode(LLVMValueRef Val);
+LLVMValueRef LLVMIsAValueAsMetadata(LLVMValueRef Val);
 LLVMValueRef LLVMIsAMDString(LLVMValueRef Val);
 
 /** Deprecated: Use LLVMGetValueName2 instead. */
@@ -2914,6 +2915,14 @@ unsigned LLVMGetMDNodeNumOperands(LLVMValueRef V);
  */
 void LLVMGetMDNodeOperands(LLVMValueRef V, LLVMValueRef *Dest);
 
+/**
+ * Replace an operand at a specific index in a llvm::MDNode value.
+ *
+ * @see llvm::MDNode::replaceOperandWith()
+ */
+void LLVMReplaceMDNodeOperandWith(LLVMValueRef V, unsigned Index,
+                                  LLVMMetadataRef Replacement);
+
 /** Deprecated: Use LLVMMDStringInContext2 instead. */
 LLVMValueRef LLVMMDStringInContext(LLVMContextRef C, const char *Str,
                                    unsigned SLen);
index b12c483..a93fc85 100644 (file)
@@ -1009,6 +1009,13 @@ LLVMValueRef LLVMIsAMDNode(LLVMValueRef Val) {
   return nullptr;
 }
 
+LLVMValueRef LLVMIsAValueAsMetadata(LLVMValueRef Val) {
+  if (auto *MD = dyn_cast_or_null<MetadataAsValue>(unwrap(Val)))
+    if (isa<ValueAsMetadata>(MD->getMetadata()))
+      return Val;
+  return nullptr;
+}
+
 LLVMValueRef LLVMIsAMDString(LLVMValueRef Val) {
   if (auto *MD = dyn_cast_or_null<MetadataAsValue>(unwrap(Val)))
     if (isa<MDString>(MD->getMetadata()))
@@ -1268,6 +1275,13 @@ void LLVMGetMDNodeOperands(LLVMValueRef V, LLVMValueRef *Dest) {
     Dest[i] = getMDNodeOperandImpl(Context, N, i);
 }
 
+void LLVMReplaceMDNodeOperandWith(LLVMValueRef V, unsigned Index,
+                                  LLVMMetadataRef Replacement) {
+  auto *MD = cast<MetadataAsValue>(unwrap(V));
+  auto *N = cast<MDNode>(MD->getMetadata());
+  N->replaceOperandWith(Index, unwrap<Metadata>(Replacement));
+}
+
 unsigned LLVMGetNamedMetadataNumOperands(LLVMModuleRef M, const char *Name) {
   if (NamedMDNode *N = unwrap(M)->getNamedMetadata(Name)) {
     return N->getNumOperands();
diff --git a/llvm/test/Bindings/llvm-c/is_a_value_as_metadata.ll b/llvm/test/Bindings/llvm-c/is_a_value_as_metadata.ll
new file mode 100644 (file)
index 0000000..f3165e2
--- /dev/null
@@ -0,0 +1,2 @@
+; RUN: llvm-c-test --is-a-value-as-metadata < /dev/null
+; This used to trigger an assertion
diff --git a/llvm/test/Bindings/llvm-c/replace_md_operand.ll b/llvm/test/Bindings/llvm-c/replace_md_operand.ll
new file mode 100644 (file)
index 0000000..758b055
--- /dev/null
@@ -0,0 +1,2 @@
+; RUN: llvm-c-test --replace-md-operand < /dev/null
+; This used to trigger an assertion
index b828a82..5e5b355 100644 (file)
@@ -41,6 +41,8 @@ int llvm_test_dibuilder(void);
 // metadata.c
 int llvm_add_named_metadata_operand(void);
 int llvm_set_metadata(void);
+int llvm_replace_md_operand(void);
+int llvm_is_a_value_as_metadata(void);
 
 // object.c
 int llvm_object_list_sections(void);
index 89a43db..79a56f7 100644 (file)
@@ -44,6 +44,11 @@ static void print_usage(void) {
   fprintf(stderr, "    Read lines of triple, hex ascii machine code from stdin "
                   "- print disassembly\n\n");
   fprintf(stderr, "  * --calc\n");
+  fprintf(stderr, "  * --replace-md-operand\n");
+  fprintf(stderr, "    Run test for replacing MDNode operands\n");
+  fprintf(stderr, "  * --is-a-value-as-metadata\n");
+  fprintf(stderr,
+          "    Run test for checking if LLVMValueRef is a ValueAsMetadata\n");
   fprintf(
       stderr,
       "    Read lines of name, rpn from stdin - print generated module\n\n");
@@ -91,6 +96,10 @@ int main(int argc, char **argv) {
     return llvm_add_named_metadata_operand();
   } else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) {
     return llvm_set_metadata();
+  } else if (argc == 2 && !strcmp(argv[1], "--replace-md-operand")) {
+    return llvm_replace_md_operand();
+  } else if (argc == 2 && !strcmp(argv[1], "--is-a-value-as-metadata")) {
+    return llvm_is_a_value_as_metadata();
   } else if (argc == 2 && !strcmp(argv[1], "--test-function-attributes")) {
     return llvm_test_function_attributes();
   } else if (argc == 2 && !strcmp(argv[1], "--test-callsite-attributes")) {
index b1d7608..e8861c3 100644 (file)
@@ -14,6 +14,9 @@
 
 #include "llvm-c-test.h"
 
+#include <assert.h>
+#include <string.h>
+
 int llvm_add_named_metadata_operand(void) {
   LLVMModuleRef m = LLVMModuleCreateWithName("Mod");
   LLVMValueRef values[] = { LLVMConstInt(LLVMInt32Type(), 0, 0) };
@@ -39,3 +42,38 @@ int llvm_set_metadata(void) {
 
   return 0;
 }
+
+int llvm_replace_md_operand(void) {
+  LLVMModuleRef m = LLVMModuleCreateWithName("Mod");
+  LLVMContextRef context = LLVMGetModuleContext(m);
+  unsigned int tmp = 0;
+
+  LLVMMetadataRef metas[] = {LLVMMDStringInContext2(context, "foo", 3)};
+  LLVMValueRef md =
+      LLVMMetadataAsValue(context, LLVMMDNodeInContext2(context, metas, 1));
+
+  LLVMReplaceMDNodeOperandWith(md, 0,
+                               LLVMMDStringInContext2(context, "bar", 3));
+
+  assert(!strncmp(LLVMGetMDString(LLVMGetOperand(md, 0), &tmp), "bar", 0));
+
+  LLVMDisposeModule(m);
+
+  return 0;
+}
+
+int llvm_is_a_value_as_metadata(void) {
+  LLVMModuleRef m = LLVMModuleCreateWithName("Mod");
+  LLVMContextRef context = LLVMGetModuleContext(m);
+
+  LLVMValueRef values[] = {LLVMConstInt(LLVMInt32Type(), 0, 0)};
+  LLVMValueRef md = LLVMMDNode(values, 1);
+  assert(LLVMIsAValueAsMetadata(md) == md);
+
+  LLVMMetadataRef metas[] = {LLVMMDStringInContext2(context, "foo", 3)};
+  LLVMValueRef md2 =
+      LLVMMetadataAsValue(context, LLVMMDNodeInContext2(context, metas, 1));
+  assert(LLVMIsAValueAsMetadata(md2) == NULL);
+
+  return 0;
+}