From d5444ccf17cb016779c6ace75e41826173497361 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 5 Feb 2019 18:05:44 +0000 Subject: [PATCH] [LLVM-C] Add Bindings to GlobalIFunc Summary: Adds the standard gauntlet of accessors for global indirect functions and updates the echo test. Now it would be nice to have a target abstraction so one could know if they have access to a suitable ELF linker and runtime. Reviewers: whitequark, deadalnix Reviewed By: whitequark Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D56177 llvm-svn: 353193 --- llvm/include/llvm-c/Core.h | 97 +++++++++++++++++++++++++++++++++++++++ llvm/lib/IR/Core.cpp | 65 ++++++++++++++++++++++++++ llvm/test/Bindings/llvm-c/echo.ll | 7 +++ llvm/tools/llvm-c-test/echo.cpp | 78 ++++++++++++++++++++++++++++++- 4 files changed, 245 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h index 0dec14f..d84a3a1 100644 --- a/llvm/include/llvm-c/Core.h +++ b/llvm/include/llvm-c/Core.h @@ -2612,6 +2612,103 @@ void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned Align); */ /** + * @defgroup LLVMCCoreValueGlobalIFunc IFuncs + * + * Functions in this group relate to indirect functions. + * + * Functions in this group expect LLVMValueRef instances that correspond + * to llvm::GlobalIFunc instances. + * + * @{ + */ + +/** + * Add a global indirect function to a module under a specified name. + * + * @see llvm::GlobalIFunc::create() + */ +LLVMValueRef LLVMAddGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen, + LLVMTypeRef Ty, unsigned AddrSpace, + LLVMValueRef Resolver); + +/** + * Obtain a GlobalIFunc value from a Module by its name. + * + * The returned value corresponds to a llvm::GlobalIFunc value. + * + * @see llvm::Module::getNamedIFunc() + */ +LLVMValueRef LLVMGetNamedGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen); + +/** + * Obtain an iterator to the first GlobalIFunc in a Module. + * + * @see llvm::Module::ifunc_begin() + */ +LLVMValueRef LLVMGetFirstGlobalIFunc(LLVMModuleRef M); + +/** + * Obtain an iterator to the last GlobalIFunc in a Module. + * + * @see llvm::Module::ifunc_end() + */ +LLVMValueRef LLVMGetLastGlobalIFunc(LLVMModuleRef M); + +/** + * Advance a GlobalIFunc iterator to the next GlobalIFunc. + * + * Returns NULL if the iterator was already at the end and there are no more + * global aliases. + */ +LLVMValueRef LLVMGetNextGlobalIFunc(LLVMValueRef IFunc); + +/** + * Decrement a GlobalIFunc iterator to the previous GlobalIFunc. + * + * Returns NULL if the iterator was already at the beginning and there are + * no previous global aliases. + */ +LLVMValueRef LLVMGetPreviousGlobalIFunc(LLVMValueRef IFunc); + +/** + * Retrieves the resolver function associated with this indirect function, or + * NULL if it doesn't not exist. + * + * @see llvm::GlobalIFunc::getResolver() + */ +LLVMValueRef LLVMGetGlobalIFuncResolver(LLVMValueRef IFunc); + +/** + * Sets the resolver function associated with this indirect function. + * + * @see llvm::GlobalIFunc::setResolver() + */ +void LLVMSetGlobalIFuncResolver(LLVMValueRef IFunc, LLVMValueRef Resolver); + +/** + * Remove a global indirect function from its parent module and delete it. + * + * @see llvm::GlobalIFunc::eraseFromParent() + */ +void LLVMEraseGlobalIFunc(LLVMValueRef IFunc); + +/** + * Remove a global indirect function from its parent module. + * + * This unlinks the global indirect function from its containing module but + * keeps it alive. + * + * @see llvm::GlobalIFunc::removeFromParent() + */ +void LLVMRemoveGlobalIFunc(LLVMValueRef IFunc); + +/** + * @} + */ + +/** * @} */ diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp index 2171178..1b8ad48 100644 --- a/llvm/lib/IR/Core.cpp +++ b/llvm/lib/IR/Core.cpp @@ -2463,6 +2463,71 @@ void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned align) { A->addAttr(Attribute::getWithAlignment(A->getContext(), align)); } +/*--.. Operations on ifuncs ................................................--*/ + +LLVMValueRef LLVMAddGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen, + LLVMTypeRef Ty, unsigned AddrSpace, + LLVMValueRef Resolver) { + return wrap(GlobalIFunc::create(unwrap(Ty), AddrSpace, + GlobalValue::ExternalLinkage, + StringRef(Name, NameLen), + unwrap(Resolver), unwrap(M))); +} + +LLVMValueRef LLVMGetNamedGlobalIFunc(LLVMModuleRef M, + const char *Name, size_t NameLen) { + return wrap(unwrap(M)->getNamedIFunc(StringRef(Name, NameLen))); +} + +LLVMValueRef LLVMGetFirstGlobalIFunc(LLVMModuleRef M) { + Module *Mod = unwrap(M); + Module::ifunc_iterator I = Mod->ifunc_begin(); + if (I == Mod->ifunc_end()) + return nullptr; + return wrap(&*I); +} + +LLVMValueRef LLVMGetLastGlobalIFunc(LLVMModuleRef M) { + Module *Mod = unwrap(M); + Module::ifunc_iterator I = Mod->ifunc_end(); + if (I == Mod->ifunc_begin()) + return nullptr; + return wrap(&*--I); +} + +LLVMValueRef LLVMGetNextGlobalIFunc(LLVMValueRef IFunc) { + GlobalIFunc *GIF = unwrap(IFunc); + Module::ifunc_iterator I(GIF); + if (++I == GIF->getParent()->ifunc_end()) + return nullptr; + return wrap(&*I); +} + +LLVMValueRef LLVMGetPreviousGlobalIFunc(LLVMValueRef IFunc) { + GlobalIFunc *GIF = unwrap(IFunc); + Module::ifunc_iterator I(GIF); + if (I == GIF->getParent()->ifunc_begin()) + return nullptr; + return wrap(&*--I); +} + +LLVMValueRef LLVMGetGlobalIFuncResolver(LLVMValueRef IFunc) { + return wrap(unwrap(IFunc)->getResolver()); +} + +void LLVMSetGlobalIFuncResolver(LLVMValueRef IFunc, LLVMValueRef Resolver) { + unwrap(IFunc)->setResolver(unwrap(Resolver)); +} + +void LLVMEraseGlobalIFunc(LLVMValueRef IFunc) { + unwrap(IFunc)->eraseFromParent(); +} + +void LLVMRemoveGlobalIFunc(LLVMValueRef IFunc) { + unwrap(IFunc)->removeFromParent(); +} + /*--.. Operations on basic blocks ..........................................--*/ LLVMValueRef LLVMBasicBlockAsValue(LLVMBasicBlockRef BB) { diff --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll index 118f822..bb6556e 100644 --- a/llvm/test/Bindings/llvm-c/echo.ll +++ b/llvm/test/Bindings/llvm-c/echo.ll @@ -28,6 +28,13 @@ module asm "classical GAS" @aliased4 = weak alias i32, i32* @var @aliased5 = weak_odr alias i32, i32* @var +@ifunc = ifunc i32 (i32), i64 ()* @ifunc_resolver + +define i64 @ifunc_resolver() { +entry: + ret i64 0 +} + define { i64, %S* } @unpackrepack(%S %s) { %1 = extractvalue %S %s, 0 %2 = extractvalue %S %s, 1 diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp index 73da1ee..8341b11 100644 --- a/llvm/tools/llvm-c-test/echo.cpp +++ b/llvm/tools/llvm-c-test/echo.cpp @@ -939,7 +939,7 @@ AliasDecl: if (!Begin) { if (End != nullptr) report_fatal_error("Range has an end but no beginning"); - goto NamedMDDecl; + goto GlobalIFuncDecl; } Cur = Begin; @@ -967,6 +967,41 @@ AliasDecl: Cur = Next; } +GlobalIFuncDecl: + Begin = LLVMGetFirstGlobalIFunc(Src); + End = LLVMGetLastGlobalIFunc(Src); + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no beginning"); + goto NamedMDDecl; + } + + Cur = Begin; + Next = nullptr; + while (true) { + size_t NameLen; + const char *Name = LLVMGetValueName2(Cur, &NameLen); + if (LLVMGetNamedGlobalIFunc(M, Name, NameLen)) + report_fatal_error("Global ifunc already cloned"); + LLVMTypeRef CurType = TypeCloner(M).Clone(LLVMGlobalGetValueType(Cur)); + // FIXME: Allow NULL resolver. + LLVMAddGlobalIFunc(M, Name, NameLen, + CurType, /*addressSpace*/ 0, LLVMGetUndef(CurType)); + + Next = LLVMGetNextGlobalIFunc(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error(""); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousGlobalIFunc(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous global is not Current"); + + Cur = Next; + } + NamedMDDecl: LLVMNamedMDNodeRef BeginMD = LLVMGetFirstNamedMetadata(Src); LLVMNamedMDNodeRef EndMD = LLVMGetLastNamedMetadata(Src); @@ -1114,7 +1149,7 @@ AliasClone: if (!Begin) { if (End != nullptr) report_fatal_error("Range has an end but no beginning"); - goto NamedMDClone; + goto GlobalIFuncClone; } Cur = Begin; @@ -1147,6 +1182,45 @@ AliasClone: Cur = Next; } +GlobalIFuncClone: + Begin = LLVMGetFirstGlobalIFunc(Src); + End = LLVMGetLastGlobalIFunc(Src); + if (!Begin) { + if (End != nullptr) + report_fatal_error("Range has an end but no beginning"); + goto NamedMDClone; + } + + Cur = Begin; + Next = nullptr; + while (true) { + size_t NameLen; + const char *Name = LLVMGetValueName2(Cur, &NameLen); + LLVMValueRef IFunc = LLVMGetNamedGlobalIFunc(M, Name, NameLen); + if (!IFunc) + report_fatal_error("Global ifunc must have been declared already"); + + if (LLVMValueRef Resolver = LLVMGetGlobalIFuncResolver(Cur)) { + LLVMSetGlobalIFuncResolver(IFunc, clone_constant(Resolver, M)); + } + + LLVMSetLinkage(IFunc, LLVMGetLinkage(Cur)); + LLVMSetUnnamedAddress(IFunc, LLVMGetUnnamedAddress(Cur)); + + Next = LLVMGetNextGlobalIFunc(Cur); + if (Next == nullptr) { + if (Cur != End) + report_fatal_error("Last global alias does not match End"); + break; + } + + LLVMValueRef Prev = LLVMGetPreviousGlobalIFunc(Next); + if (Prev != Cur) + report_fatal_error("Next.Previous global alias is not Current"); + + Cur = Next; + } + NamedMDClone: LLVMNamedMDNodeRef BeginMD = LLVMGetFirstNamedMetadata(Src); LLVMNamedMDNodeRef EndMD = LLVMGetLastNamedMetadata(Src); -- 2.7.4