[llvm] fb21f16 - RuntimeLibcalls: Add stub API for getting function signatures (#166290)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 4 10:06:33 PST 2025
Author: Matt Arsenault
Date: 2025-11-04T10:06:29-08:00
New Revision: fb21f16fe6fd1a1fa03662510bde042309ac8ae1
URL: https://github.com/llvm/llvm-project/commit/fb21f16fe6fd1a1fa03662510bde042309ac8ae1
DIFF: https://github.com/llvm/llvm-project/commit/fb21f16fe6fd1a1fa03662510bde042309ac8ae1.diff
LOG: RuntimeLibcalls: Add stub API for getting function signatures (#166290)
Eventually this should be generated by tablegen for all functions.
For now add a manually implementation for sincos_stret, which I
have an immediate use for. This will allow pulling repeated code
across targets into shared call sequence code.
Also add sqrt just to make sure we can handle adding return attributes
on the declaration.
Added:
llvm/test/Transforms/Util/DeclareRuntimeLibcalls/merge_attributes.ll
llvm/test/Transforms/Util/DeclareRuntimeLibcalls/sincos_stret.ll
llvm/test/Transforms/Util/DeclareRuntimeLibcalls/wrong_declaration.ll
Modified:
llvm/include/llvm/IR/RuntimeLibcalls.h
llvm/lib/IR/RuntimeLibcalls.cpp
llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp
llvm/test/Transforms/Util/DeclareRuntimeLibcalls/basic.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.h b/llvm/include/llvm/IR/RuntimeLibcalls.h
index 01359894b0421..ab14ed44fed52 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.h
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.h
@@ -186,6 +186,13 @@ struct RuntimeLibcallsInfo {
return RTLIB::Unsupported;
}
+ /// \returns the function type and attributes for the \p LibcallImpl,
+ /// depending on the target \p TT. If the function has incomplete type
+ /// information, return nullptr for the function type.
+ std::pair<FunctionType *, AttributeList>
+ getFunctionTy(LLVMContext &Ctx, const Triple &TT, const DataLayout &DL,
+ RTLIB::LibcallImpl LibcallImpl) const;
+
private:
LLVM_ABI static iota_range<RTLIB::LibcallImpl>
lookupLibcallImplNameImpl(StringRef Name);
diff --git a/llvm/lib/IR/RuntimeLibcalls.cpp b/llvm/lib/IR/RuntimeLibcalls.cpp
index 77af29b9d70f6..2ce5719228a0d 100644
--- a/llvm/lib/IR/RuntimeLibcalls.cpp
+++ b/llvm/lib/IR/RuntimeLibcalls.cpp
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/RuntimeLibcalls.h"
+#include "llvm/ADT/FloatingPointMode.h"
#include "llvm/ADT/StringTable.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/xxhash.h"
#include "llvm/TargetParser/ARMTargetParser.h"
@@ -72,3 +74,80 @@ bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) {
return false;
}
}
+
+std::pair<FunctionType *, AttributeList>
+RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT,
+ const DataLayout &DL,
+ RTLIB::LibcallImpl LibcallImpl) const {
+ static constexpr Attribute::AttrKind CommonFnAttrs[] = {
+ Attribute::NoCallback, Attribute::NoFree, Attribute::NoSync,
+ Attribute::NoUnwind, Attribute::WillReturn};
+
+ switch (LibcallImpl) {
+ case RTLIB::impl___sincos_stret:
+ case RTLIB::impl___sincosf_stret: {
+ if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected
+ return {};
+
+ Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret
+ ? Type::getFloatTy(Ctx)
+ : Type::getDoubleTy(Ctx);
+
+ AttrBuilder FuncAttrBuilder(Ctx);
+ for (Attribute::AttrKind Attr : CommonFnAttrs)
+ FuncAttrBuilder.addAttribute(Attr);
+
+ const bool UseSret =
+ TT.isX86_32() || ((TT.isARM() || TT.isThumb()) &&
+ ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS);
+
+ FuncAttrBuilder.addMemoryAttr(MemoryEffects::argumentOrErrnoMemOnly(
+ UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ModRefInfo::Mod));
+
+ AttributeList Attrs;
+ Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder);
+
+ if (UseSret) {
+ AttrBuilder AttrBuilder(Ctx);
+ StructType *StructTy = StructType::get(ScalarTy, ScalarTy);
+ AttrBuilder.addStructRetAttr(StructTy);
+ AttrBuilder.addAlignmentAttr(DL.getABITypeAlign(StructTy));
+ FunctionType *FuncTy = FunctionType::get(
+ Type::getVoidTy(Ctx), {DL.getAllocaPtrType(Ctx), ScalarTy}, false);
+
+ return {FuncTy, Attrs.addParamAttributes(Ctx, 0, AttrBuilder)};
+ }
+
+ Type *RetTy =
+ LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64()
+ ? static_cast<Type *>(FixedVectorType::get(ScalarTy, 2))
+ : static_cast<Type *>(StructType::get(ScalarTy, ScalarTy));
+
+ return {FunctionType::get(RetTy, {ScalarTy}, false), Attrs};
+ }
+ case RTLIB::impl_sqrtf:
+ case RTLIB::impl_sqrt: {
+ AttrBuilder FuncAttrBuilder(Ctx);
+
+ for (Attribute::AttrKind Attr : CommonFnAttrs)
+ FuncAttrBuilder.addAttribute(Attr);
+ FuncAttrBuilder.addMemoryAttr(MemoryEffects::errnoMemOnly(ModRefInfo::Mod));
+
+ AttributeList Attrs;
+ Attrs = Attrs.addFnAttributes(Ctx, FuncAttrBuilder);
+
+ Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(Ctx)
+ : Type::getDoubleTy(Ctx);
+ FunctionType *FuncTy = FunctionType::get(ScalarTy, {ScalarTy}, false);
+
+ Attrs = Attrs.addRetAttribute(
+ Ctx, Attribute::getWithNoFPClass(Ctx, fcNegInf | fcNegSubnormal |
+ fcNegNormal));
+ return {FuncTy, Attrs};
+ }
+ default:
+ return {};
+ }
+
+ return {};
+}
diff --git a/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp b/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp
index 0642d51cd2c21..6d4436b92c119 100644
--- a/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp
+++ b/llvm/lib/Transforms/Utils/DeclareRuntimeLibcalls.cpp
@@ -16,22 +16,62 @@
using namespace llvm;
+static void mergeAttributes(LLVMContext &Ctx, const Module &M,
+ const DataLayout &DL, const Triple &TT,
+ Function *Func, FunctionType *FuncTy,
+ AttributeList FuncAttrs) {
+ AttributeList OldAttrs = Func->getAttributes();
+ AttributeList NewAttrs = OldAttrs;
+
+ {
+ AttrBuilder OldBuilder(Ctx, OldAttrs.getFnAttrs());
+ AttrBuilder NewBuilder(Ctx, FuncAttrs.getFnAttrs());
+ OldBuilder.merge(NewBuilder);
+ NewAttrs = NewAttrs.addFnAttributes(Ctx, OldBuilder);
+ }
+
+ {
+ AttrBuilder OldBuilder(Ctx, OldAttrs.getRetAttrs());
+ AttrBuilder NewBuilder(Ctx, FuncAttrs.getRetAttrs());
+ OldBuilder.merge(NewBuilder);
+ NewAttrs = NewAttrs.addRetAttributes(Ctx, OldBuilder);
+ }
+
+ for (unsigned I = 0, E = FuncTy->getNumParams(); I != E; ++I) {
+ AttrBuilder OldBuilder(Ctx, OldAttrs.getParamAttrs(I));
+ AttrBuilder NewBuilder(Ctx, FuncAttrs.getParamAttrs(I));
+ OldBuilder.merge(NewBuilder);
+ NewAttrs = NewAttrs.addParamAttributes(Ctx, I, OldBuilder);
+ }
+
+ Func->setAttributes(NewAttrs);
+}
+
PreservedAnalyses DeclareRuntimeLibcallsPass::run(Module &M,
ModuleAnalysisManager &MAM) {
RTLIB::RuntimeLibcallsInfo RTLCI(M.getTargetTriple());
LLVMContext &Ctx = M.getContext();
+ const DataLayout &DL = M.getDataLayout();
+ const Triple &TT = M.getTargetTriple();
for (RTLIB::LibcallImpl Impl : RTLCI.getLibcallImpls()) {
if (Impl == RTLIB::Unsupported)
continue;
- // TODO: Declare with correct type, calling convention, and attributes.
+ auto [FuncTy, FuncAttrs] = RTLCI.getFunctionTy(Ctx, TT, DL, Impl);
- FunctionType *FuncTy =
- FunctionType::get(Type::getVoidTy(Ctx), {}, /*IsVarArgs=*/true);
+ // TODO: Declare with correct type, calling convention, and attributes.
+ if (!FuncTy)
+ FuncTy = FunctionType::get(Type::getVoidTy(Ctx), {}, /*IsVarArgs=*/true);
StringRef FuncName = RTLCI.getLibcallImplName(Impl);
- M.getOrInsertFunction(FuncName, FuncTy);
+
+ Function *Func =
+ cast<Function>(M.getOrInsertFunction(FuncName, FuncTy).getCallee());
+ if (Func->getFunctionType() == FuncTy) {
+ mergeAttributes(Ctx, M, DL, TT, Func, FuncTy, FuncAttrs);
+ Func->setCallingConv(RTLCI.getLibcallImplCallingConv(Impl));
+ }
}
return PreservedAnalyses::none();
diff --git a/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/basic.ll b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/basic.ll
index ee3a0539bf300..c005316f07f06 100644
--- a/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/basic.ll
+++ b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/basic.ll
@@ -11,5 +11,9 @@ define float @sinf(float %x) {
}
; CHECK: declare void @acosf(...)
+
+; CHECK: declare nofpclass(ninf nsub nnorm) float @sqrtf(float) [[SQRT_ATTRS:#[0-9]+]]
+; CHECK: declare nofpclass(ninf nsub nnorm) double @sqrt(double) [[SQRT_ATTRS:#[0-9]+]]
+
; CHECK: declare void @__umodti3(...)
diff --git a/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/merge_attributes.ll b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/merge_attributes.ll
new file mode 100644
index 0000000000000..ffbf11d4106dc
--- /dev/null
+++ b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/merge_attributes.ll
@@ -0,0 +1,11 @@
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define noundef nofpclass(nan) float @sqrtf(float %x) "foo" {
+ %ret = call float asm "; $0 = sqrt($1)", "=r,r"(float %x)
+ ret float %ret
+}
+
+; FIXME: Individual fields of nofpclass not merged
+; CHECK: define noundef nofpclass(ninf nsub nnorm) float @sqrtf(float %x) [[SQRT_ATTR:#[0-9]+]] {
+
+; CHECK: attributes [[SQRT_ATTR]] = { nocallback nofree nosync nounwind willreturn memory(errnomem: write) "foo" }
diff --git a/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/sincos_stret.ll b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/sincos_stret.ll
new file mode 100644
index 0000000000000..0d0e3da25eea7
--- /dev/null
+++ b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/sincos_stret.ll
@@ -0,0 +1,23 @@
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=x86_64-apple-macos10.9 < %s | FileCheck -check-prefixes=CHECK,X64 %s
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=arm64-apple-macos10.9 < %s | FileCheck -check-prefixes=CHECK,STRUCT %s
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=thumbv7k-apple-watchos2.0 < %s | FileCheck -check-prefixes=CHECK,STRUCT %s
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=armv7-apple-ios7 < %s | FileCheck -check-prefix=SRET %s
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=thumbv7-apple-ios7 < %s | FileCheck -check-prefix=SRET %s
+
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=armv7-apple-ios6 < %s | FileCheck -check-prefix=NONE %s
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=x86_64-apple-macos10.8 < %s | FileCheck -check-prefix=NONE %s
+
+; X64: declare <2 x float> @__sincosf_stret(float) [[SINCOS_ATTRS:#[0-9]+]]
+; X64: declare { double, double } @__sincos_stret(double) [[SINCOS_ATTRS:#[0-9]+]]
+
+; STRUCT: declare { float, float } @__sincosf_stret(float) [[SINCOS_ATTRS:#[0-9]+]]
+; STRUCT: declare { double, double } @__sincos_stret(double) [[SINCOS_ATTRS:#[0-9]+]]
+
+; SRET: declare void @__sincosf_stret(ptr sret({ float, float }) align 4, float) [[SINCOS_ATTRS:#[0-9]+]]
+; SRET: declare void @__sincos_stret(ptr sret({ double, double }) align 4, double) [[SINCOS_ATTRS:#[0-9]+]]
+
+; CHECK: attributes [[SINCOS_ATTRS]] = { nocallback nofree nosync nounwind willreturn memory(errnomem: write) }
+; SRET: attributes [[SINCOS_ATTRS]] = { nocallback nofree nosync nounwind willreturn memory(argmem: write, errnomem: write) }
+
+; NONE-NOT: __sincos_stret
+; NONE-NOT: __sincosf_stret
diff --git a/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/wrong_declaration.ll b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/wrong_declaration.ll
new file mode 100644
index 0000000000000..2451010df5b75
--- /dev/null
+++ b/llvm/test/Transforms/Util/DeclareRuntimeLibcalls/wrong_declaration.ll
@@ -0,0 +1,21 @@
+; RUN: opt -S -passes=declare-runtime-libcalls -mtriple=x86_64-apple-macos10.9 < %s | FileCheck %s
+
+; Make sure there is no crash if there are definitions or declarations
+; with the wrong type signature.
+
+; CHECK: define void @sqrtf() {
+define void @sqrtf() {
+ ret void
+}
+
+; CHECK: define float @sqrt(float %0) {
+define float @sqrt(float) {
+ ret float 0.0
+}
+
+; CHECK: declare double @__sincos_stret(double)
+declare double @__sincos_stret(double)
+
+; CHECK: declare { float, float } @__sincosf_stret(float)
+declare { float, float } @__sincosf_stret(float)
+
More information about the llvm-commits
mailing list