diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -1771,6 +1771,7 @@ 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. */ @@ -2915,6 +2916,14 @@ */ 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); diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -989,6 +989,13 @@ return nullptr; } +LLVMValueRef LLVMIsAValueAsMetadata(LLVMValueRef Val) { + if (auto *MD = dyn_cast_or_null(unwrap(Val))) + if (isa(MD->getMetadata())) + return Val; + return nullptr; +} + LLVMValueRef LLVMIsAMDString(LLVMValueRef Val) { if (auto *MD = dyn_cast_or_null(unwrap(Val))) if (isa(MD->getMetadata())) @@ -1248,6 +1255,13 @@ Dest[i] = getMDNodeOperandImpl(Context, N, i); } +void LLVMReplaceMDNodeOperandWith(LLVMValueRef V, unsigned Index, + LLVMMetadataRef Replacement) { + auto *MD = cast(unwrap(V)); + auto *N = cast(MD->getMetadata()); + N->replaceOperandWith(Index, unwrap(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 --- /dev/null +++ b/llvm/test/Bindings/llvm-c/is_a_value_as_metadata.ll @@ -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 --- /dev/null +++ b/llvm/test/Bindings/llvm-c/replace_md_operand.ll @@ -0,0 +1,2 @@ +; RUN: llvm-c-test --replace-md-operand < /dev/null +; This used to trigger an assertion diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h --- a/llvm/tools/llvm-c-test/llvm-c-test.h +++ b/llvm/tools/llvm-c-test/llvm-c-test.h @@ -41,6 +41,8 @@ // 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); diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c --- a/llvm/tools/llvm-c-test/main.c +++ b/llvm/tools/llvm-c-test/main.c @@ -44,6 +44,11 @@ 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 @@ 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")) { diff --git a/llvm/tools/llvm-c-test/metadata.c b/llvm/tools/llvm-c-test/metadata.c --- a/llvm/tools/llvm-c-test/metadata.c +++ b/llvm/tools/llvm-c-test/metadata.c @@ -14,6 +14,9 @@ #include "llvm-c-test.h" +#include +#include + int llvm_add_named_metadata_operand(void) { LLVMModuleRef m = LLVMModuleCreateWithName("Mod"); LLVMValueRef values[] = { LLVMConstInt(LLVMInt32Type(), 0, 0) }; @@ -39,3 +42,38 @@ 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; +}