Index: llvm/trunk/include/llvm-c/Core.h =================================================================== --- llvm/trunk/include/llvm-c/Core.h +++ llvm/trunk/include/llvm-c/Core.h @@ -2612,6 +2612,103 @@ */ /** + * @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); + +/** + * @} + */ + +/** * @} */ Index: llvm/trunk/lib/IR/Core.cpp =================================================================== --- llvm/trunk/lib/IR/Core.cpp +++ llvm/trunk/lib/IR/Core.cpp @@ -2463,6 +2463,71 @@ 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) { Index: llvm/trunk/test/Bindings/llvm-c/echo.ll =================================================================== --- llvm/trunk/test/Bindings/llvm-c/echo.ll +++ llvm/trunk/test/Bindings/llvm-c/echo.ll @@ -28,6 +28,13 @@ @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 Index: llvm/trunk/tools/llvm-c-test/echo.cpp =================================================================== --- llvm/trunk/tools/llvm-c-test/echo.cpp +++ llvm/trunk/tools/llvm-c-test/echo.cpp @@ -939,7 +939,7 @@ 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 @@ 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 @@ 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 @@ 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);