1//===- RuntimeLibcalls.cpp - Interface for runtime libcalls -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/IR/RuntimeLibcalls.h"
10#include "llvm/ADT/FloatingPointMode.h"
11#include "llvm/IR/Intrinsics.h"
12#include "llvm/IR/Module.h"
13#include "llvm/IR/SystemLibraries.h"
14#include "llvm/IR/Type.h"
15#include "llvm/TargetParser/ARMTargetParser.h"
16
17#define DEBUG_TYPE "runtime-libcalls-info"
18
19using namespace llvm;
20using namespace RTLIB;
21
22#define GET_RUNTIME_LIBCALLS_INFO
23#define GET_INIT_RUNTIME_LIBCALL_NAMES
24#define GET_INIT_RUNTIME_LIBCALL_SIGNATURES
25#define GET_RUNTIME_LIBCALL_MASKED_VECTOR_LIBCALL_MAPPING
26#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
27#define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME
28#define GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL
29#include "llvm/IR/RuntimeLibcalls.inc"
30
31static RuntimeLibrary getVectorRuntimeLibrary(VectorLibrary VecLib) {
32 switch (VecLib) {
33 case VectorLibrary::NoLibrary:
34 break;
35 case VectorLibrary::Accelerate:
36 return RuntimeLibrary::accelerate;
37 case VectorLibrary::DarwinLibSystemM:
38 return RuntimeLibrary::darwin_libsystem_m;
39 case VectorLibrary::LIBMVEC:
40 return RuntimeLibrary::libmvec;
41 case VectorLibrary::MASSV:
42 return RuntimeLibrary::massv;
43 case VectorLibrary::SVML:
44 return RuntimeLibrary::svml;
45 case VectorLibrary::SLEEFGNUABI:
46 return RuntimeLibrary::sleefgnuabi;
47 case VectorLibrary::ArmPL:
48 return RuntimeLibrary::armpl;
49 case VectorLibrary::AMDLIBM:
50 return RuntimeLibrary::amdlibm;
51 }
52
53 llvm_unreachable("no RuntimeLibrary for VectorLibrary");
54}
55
56RuntimeLibcallsInfo::RuntimeLibcallsInfo(
57 const Triple &TT, ExceptionHandling ExceptionModel,
58 FloatABI::ABIType FloatABI, std::optional<LongDoubleFormat> LDblFormat,
59 StringRef ABIName, VectorLibrary VecLib)
60 : LongDoubleFmt(LDblFormat.value_or(u: TT.getDefaultLongDoubleFormat())) {
61 // Only an unspecified model resolves to the triple default; None is left as
62 // an explicit disable.
63 if (ExceptionModel == ExceptionHandling::Default)
64 ExceptionModel = TT.getDefaultExceptionHandling();
65
66 initLibcalls(TT, ExceptionModel, FloatABI, ABIName, LongDoubleFormat: LongDoubleFmt);
67
68 if (VecLib != VectorLibrary::NoLibrary) {
69 setAvailableLibraryLibcalls(Library: getVectorRuntimeLibrary(VecLib), TT,
70 ExceptionModel, FloatABI, ABIName,
71 LongDoubleFormat: LongDoubleFmt);
72 }
73}
74
75// TODO: Consider the remaining module flags.
76RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M, StringRef ABIName,
77 VectorLibrary VecLib)
78 : RuntimeLibcallsInfo(M.getTargetTriple(), M.getExceptionModel(),
79 M.getFloatABI(), M.getLongDoubleFormat(), ABIName,
80 VecLib) {}
81
82bool RuntimeLibcallsInfo::isLibraryAvailable(RuntimeLibrary Library) const {
83 // TODO: Drive this from module-level state (e.g. the linked runtime). For now
84 // every named library is reported as available.
85 return true;
86}
87
88/// Set default libcall names. If a target wants to opt-out of a libcall it
89/// should be placed here.
90void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
91 ExceptionHandling ExceptionModel,
92 FloatABI::ABIType FloatABI,
93 StringRef ABIName,
94 LongDoubleFormat LongDoubleFormat) {
95 setTargetRuntimeLibcallSets(TT, ExceptionModel, FloatABI, ABIName,
96 LongDoubleFormat);
97}
98
99LLVM_ATTRIBUTE_ALWAYS_INLINE
100iota_range<RTLIB::LibcallImpl>
101RuntimeLibcallsInfo::libcallImplNameHit(uint16_t NameOffsetEntry,
102 uint16_t StrOffset) {
103 int NumAliases = 1;
104 for (uint16_t Entry : ArrayRef(RuntimeLibcallNameOffsetTable)
105 .drop_front(N: NameOffsetEntry + 1)) {
106 if (Entry != StrOffset)
107 break;
108 ++NumAliases;
109 }
110
111 RTLIB::LibcallImpl ImplStart = static_cast<RTLIB::LibcallImpl>(
112 &RuntimeLibcallNameOffsetTable[NameOffsetEntry] -
113 &RuntimeLibcallNameOffsetTable[0]);
114 return enum_seq(Begin: ImplStart,
115 End: static_cast<RTLIB::LibcallImpl>(ImplStart + NumAliases));
116}
117
118bool RuntimeLibcallsInfo::isAAPCS_ABI(const Triple &TT, StringRef ABIName) {
119 const ARM::ARMABI TargetABI = ARM::computeTargetABI(TT, ABIName);
120 return TargetABI == ARM::ARM_ABI_AAPCS || TargetABI == ARM::ARM_ABI_AAPCS16;
121}
122
123/// TODO: There is really no guarantee that sizeof(size_t) is equal to the index
124/// size of the default address space. This matches TargetLibraryInfo and should
125/// be kept in sync.
126static IntegerType *getSizeTType(LLVMContext &Ctx, const DataLayout &DL) {
127 return DL.getIndexType(C&: Ctx, /*AddressSpace=*/0);
128}
129
130// TODO: NoCallback probably unsafe in general
131static constexpr Attribute::AttrKind CommonFnAttrs[] = {
132 Attribute::NoCallback, Attribute::NoFree, Attribute::NoSync,
133 Attribute::NoUnwind, Attribute::WillReturn};
134
135static Type *getLongDoubleType(LLVMContext &Ctx, LongDoubleFormat Format) {
136 switch (Format) {
137 case LongDoubleFormat::IEEEsingle:
138 return Type::getFloatTy(C&: Ctx);
139 case LongDoubleFormat::IEEEdouble:
140 return Type::getDoubleTy(C&: Ctx);
141 case LongDoubleFormat::X87DoubleExtended:
142 return Type::getX86_FP80Ty(C&: Ctx);
143 case LongDoubleFormat::IEEEquad:
144 return Type::getFP128Ty(C&: Ctx);
145 case LongDoubleFormat::PPCDoubleDouble:
146 return Type::getPPC_FP128Ty(C&: Ctx);
147 }
148
149 llvm_unreachable("unhandled long double format");
150}
151
152static std::pair<Type *, Attribute>
153convertToIRTypeAndAttr(FuncArgTypeID ID, LLVMContext &Ctx, const DataLayout &DL,
154 unsigned IntBits, Type *LongDoubleTy) {
155
156 // FIXME: Use the llvm/ABI library to get accurate IR types and attributes.
157 switch (ID) {
158 case Void:
159 return {Type::getVoidTy(C&: Ctx), Attribute()};
160 case Bool:
161 return {IntegerType::get(C&: Ctx, NumBits: 1), Attribute::get(Context&: Ctx, Kind: Attribute::ZExt)};
162 case Int16:
163 case UInt16:
164 return {IntegerType::get(C&: Ctx, NumBits: 16), Attribute()};
165 case Int32:
166 case UInt32:
167 return {IntegerType::get(C&: Ctx, NumBits: 32), Attribute()};
168 case Int:
169 case UInt:
170 case IntPlus:
171 case UIntPlus:
172 case Long:
173 case ULong:
174 case IntX:
175 case UIntX:
176 return {IntegerType::get(C&: Ctx, NumBits: IntBits), Attribute()};
177 case Int64:
178 case UInt64:
179 case LLong:
180 case ULLong:
181 return {IntegerType::get(C&: Ctx, NumBits: 64), Attribute()};
182 case SizeT:
183 case SSizeT:
184 return {getSizeTType(Ctx, DL), Attribute()};
185 case Flt:
186 case Floating:
187 return {Type::getFloatTy(C&: Ctx), Attribute()};
188 case Dbl:
189 return {Type::getDoubleTy(C&: Ctx), Attribute()};
190 case LDbl:
191 return {LongDoubleTy, Attribute()};
192 case Ptr:
193 return {PointerType::get(C&: Ctx, AddressSpace: 0), Attribute()};
194 case V2F32:
195 return {FixedVectorType::get(ElementType: Type::getFloatTy(C&: Ctx), NumElts: 2), Attribute()};
196 case V4F32:
197 return {FixedVectorType::get(ElementType: Type::getFloatTy(C&: Ctx), NumElts: 4), Attribute()};
198 case V8F32:
199 return {FixedVectorType::get(ElementType: Type::getFloatTy(C&: Ctx), NumElts: 8), Attribute()};
200 case V16F32:
201 return {FixedVectorType::get(ElementType: Type::getFloatTy(C&: Ctx), NumElts: 16), Attribute()};
202 case NXV4F32:
203 return {ScalableVectorType::get(ElementType: Type::getFloatTy(C&: Ctx), MinNumElts: 4), Attribute()};
204 case V2F64:
205 return {FixedVectorType::get(ElementType: Type::getDoubleTy(C&: Ctx), NumElts: 2), Attribute()};
206 case V4F64:
207 return {FixedVectorType::get(ElementType: Type::getDoubleTy(C&: Ctx), NumElts: 4), Attribute()};
208 case V8F64:
209 return {FixedVectorType::get(ElementType: Type::getDoubleTy(C&: Ctx), NumElts: 8), Attribute()};
210 case NXV2F64:
211 return {ScalableVectorType::get(ElementType: Type::getDoubleTy(C&: Ctx), MinNumElts: 2), Attribute()};
212 case NXV2I1:
213 return {ScalableVectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), MinNumElts: 2), Attribute()};
214 case NXV4I1:
215 return {ScalableVectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), MinNumElts: 4), Attribute()};
216 case V2I32:
217 return {FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), NumElts: 2), Attribute()};
218 case V4I32:
219 return {FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), NumElts: 4), Attribute()};
220 case V8I32:
221 return {FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), NumElts: 8), Attribute()};
222 case V16I32:
223 return {FixedVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), NumElts: 16), Attribute()};
224 case NXV2I32:
225 return {ScalableVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), MinNumElts: 2), Attribute()};
226 case NXV4I32:
227 return {ScalableVectorType::get(ElementType: Type::getInt32Ty(C&: Ctx), MinNumElts: 4), Attribute()};
228 default:
229 return {};
230 }
231}
232
233std::pair<FunctionType *, AttributeList>
234RuntimeLibcallsInfo::getDefaultFunctionTy(
235 LLVMContext &Ctx, const Triple &TT, const DataLayout &DL,
236 RTLIB::LibcallImpl LibcallImpl) const {
237 Libcall LC = getLibcallFromImpl(Impl: LibcallImpl);
238 const FuncArgTypeID *ProtoTypes = &SignatureTable[SignatureOffset[LC]];
239
240 if (ProtoTypes[0] == NoFuncArgType)
241 return {};
242
243 unsigned IntBits = getIntSize(TT);
244 Type *LongDoubleTy = getLongDoubleType(Ctx, Format: LongDoubleFmt);
245 AttributeList Attrs;
246
247 auto [RetTy, RetAttr] =
248 convertToIRTypeAndAttr(ID: ProtoTypes[0], Ctx, DL, IntBits, LongDoubleTy);
249 if (RetAttr.isValid())
250 Attrs = Attrs.addRetAttribute(C&: Ctx, Attr: RetAttr);
251
252 Type *LastTy = RetTy, *ArgTy;
253 Attribute LastAttr = RetAttr, ArgAttr;
254 SmallVector<Type *, 4> ArgTys;
255 bool IsVarArg = false;
256 unsigned Idx = 1;
257 for (FuncArgTypeID TyID = ProtoTypes[Idx]; TyID != NoFuncArgType;
258 TyID = ProtoTypes[++Idx]) {
259 if (TyID == Ellip) {
260 // The ellipsis ends the protoype list so it must be followed by
261 // NoFuncArgType.
262 assert(ProtoTypes[Idx + 1] == NoFuncArgType);
263 IsVarArg = true;
264 break;
265 }
266
267 if (TyID == Same) {
268 ArgTy = LastTy;
269 ArgAttr = LastAttr;
270 } else {
271 std::tie(args&: ArgTy, args&: ArgAttr) = convertToIRTypeAndAttr(
272 ID: ProtoTypes[Idx], Ctx, DL, IntBits, LongDoubleTy);
273 LastTy = ArgTy;
274 LastAttr = ArgAttr;
275 }
276
277 ArgTys.push_back(Elt: ArgTy);
278 if (ArgAttr.isValid())
279 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNos: Idx - 1, A: ArgAttr);
280 }
281
282 if (RetTy->isVectorTy()) {
283 AttrBuilder FuncAttrBuilder(Ctx);
284 for (Attribute::AttrKind Attr : CommonFnAttrs)
285 FuncAttrBuilder.addAttribute(Val: Attr);
286 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
287 }
288
289 return {FunctionType::get(Result: RetTy, Params: ArgTys, isVarArg: IsVarArg), Attrs};
290}
291
292std::pair<FunctionType *, AttributeList>
293RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT,
294 const DataLayout &DL,
295 RTLIB::LibcallImpl LibcallImpl) const {
296 static constexpr Attribute::AttrKind MemoryFnAttrs[] = {
297 Attribute::NoUnwind, Attribute::WillReturn};
298 static constexpr Attribute::AttrKind CommonPtrArgAttrs[] = {
299 Attribute::NoAlias, Attribute::WriteOnly, Attribute::NonNull};
300
301 switch (LibcallImpl) {
302 case RTLIB::impl___sincos_stret:
303 case RTLIB::impl___sincosf_stret: {
304 if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected
305 return {};
306
307 Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret
308 ? Type::getFloatTy(C&: Ctx)
309 : Type::getDoubleTy(C&: Ctx);
310
311 AttrBuilder FuncAttrBuilder(Ctx);
312 for (Attribute::AttrKind Attr : CommonFnAttrs)
313 FuncAttrBuilder.addAttribute(Val: Attr);
314
315 const bool UseSret =
316 TT.isX86_32() || ((TT.isARM() || TT.isThumb()) &&
317 ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS);
318
319 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argumentOrErrnoMemOnly(
320 ArgMR: UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ErrnoMR: ModRefInfo::Mod));
321
322 AttributeList Attrs;
323 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
324
325 if (UseSret) {
326 AttrBuilder AttrBuilder(Ctx);
327 StructType *StructTy = StructType::get(elt1: ScalarTy, elts: ScalarTy);
328 AttrBuilder.addStructRetAttr(Ty: StructTy);
329 AttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: StructTy));
330 FunctionType *FuncTy = FunctionType::get(
331 Result: Type::getVoidTy(C&: Ctx), Params: {DL.getAllocaPtrType(Ctx), ScalarTy}, isVarArg: false);
332
333 return {FuncTy, Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: AttrBuilder)};
334 }
335
336 Type *RetTy =
337 LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64()
338 ? static_cast<Type *>(FixedVectorType::get(ElementType: ScalarTy, NumElts: 2))
339 : static_cast<Type *>(StructType::get(elt1: ScalarTy, elts: ScalarTy));
340
341 return {FunctionType::get(Result: RetTy, Params: {ScalarTy}, isVarArg: false), Attrs};
342 }
343 case RTLIB::impl_malloc:
344 case RTLIB::impl_calloc: {
345 AttrBuilder FuncAttrBuilder(Ctx);
346 for (Attribute::AttrKind Attr : MemoryFnAttrs)
347 FuncAttrBuilder.addAttribute(Val: Attr);
348 FuncAttrBuilder.addAttribute(Val: Attribute::NoFree);
349
350 AllocFnKind AllocKind = AllocFnKind::Alloc;
351 if (LibcallImpl == RTLIB::impl_malloc)
352 AllocKind |= AllocFnKind::Uninitialized;
353
354 // TODO: Set memory attribute
355 FuncAttrBuilder.addAllocKindAttr(Kind: AllocKind);
356 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
357 FuncAttrBuilder.addAllocSizeAttr(ElemSizeArg: 0, NumElemsArg: LibcallImpl == RTLIB::impl_malloc
358 ? std::nullopt
359 : std::make_optional(t: 1));
360
361 AttributeList Attrs;
362 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
363
364 {
365 AttrBuilder ArgAttrBuilder(Ctx);
366 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
367 ArgAttrBuilder.addAttribute(Val: AK);
368
369 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoUndef);
370 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoAlias);
371 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 0, Kind: Attribute::NoUndef);
372 if (LibcallImpl == RTLIB::impl_calloc)
373 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 1, Kind: Attribute::NoUndef);
374 }
375
376 IntegerType *SizeT = getSizeTType(Ctx, DL);
377 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
378 SmallVector<Type *, 2> ArgTys = {SizeT};
379 if (LibcallImpl == RTLIB::impl_calloc)
380 ArgTys.push_back(Elt: SizeT);
381
382 return {FunctionType::get(Result: PtrTy, Params: ArgTys, isVarArg: false), Attrs};
383 }
384 case RTLIB::impl_free: {
385 // TODO: Set memory attribute
386 AttrBuilder FuncAttrBuilder(Ctx);
387 for (Attribute::AttrKind Attr : MemoryFnAttrs)
388 FuncAttrBuilder.addAttribute(Val: Attr);
389
390 FuncAttrBuilder.addAllocKindAttr(Kind: AllocFnKind::Free);
391 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
392
393 AttributeList Attrs;
394 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
395
396 {
397 AttrBuilder ArgAttrBuilder(Ctx);
398 ArgAttrBuilder.addAttribute(Val: Attribute::NoUndef);
399 ArgAttrBuilder.addAttribute(Val: Attribute::AllocatedPointer);
400 ArgAttrBuilder.addCapturesAttr(CI: CaptureInfo::none());
401 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: ArgAttrBuilder);
402 }
403
404 return {FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {PointerType::get(C&: Ctx, AddressSpace: 0)},
405 isVarArg: false),
406 Attrs};
407 }
408 case RTLIB::impl___aeabi_idivmod:
409 case RTLIB::impl___aeabi_uidivmod:
410 case RTLIB::impl___aeabi_ldivmod:
411 case RTLIB::impl___aeabi_uldivmod:
412 case RTLIB::impl___rt_sdiv:
413 case RTLIB::impl___rt_udiv:
414 case RTLIB::impl___rt_sdiv64:
415 case RTLIB::impl___rt_udiv64: {
416 // The ARM AEABI (__aeabi_*divmod) and Windows (__rt_*div*) divmod functions
417 // return both values modeled as an inreg { iN, iN } struct (quotient,
418 // remainder). The __rt_*div* cases pass the arguments in opposite order,
419 // though this doesn't affect the declaration.
420 bool IsSigned;
421 unsigned Bits;
422 switch (LibcallImpl) {
423 case RTLIB::impl___aeabi_idivmod:
424 case RTLIB::impl___rt_sdiv:
425 IsSigned = true;
426 Bits = 32;
427 break;
428 case RTLIB::impl___aeabi_uidivmod:
429 case RTLIB::impl___rt_udiv:
430 IsSigned = false;
431 Bits = 32;
432 break;
433 case RTLIB::impl___aeabi_ldivmod:
434 case RTLIB::impl___rt_sdiv64:
435 IsSigned = true;
436 Bits = 64;
437 break;
438 case RTLIB::impl___aeabi_uldivmod:
439 case RTLIB::impl___rt_udiv64:
440 IsSigned = false;
441 Bits = 64;
442 break;
443 default:
444 llvm_unreachable("unexpected divmod libcall");
445 }
446
447 Type *IntTy = IntegerType::get(C&: Ctx, NumBits: Bits);
448 StructType *RetTy = StructType::get(elt1: IntTy, elts: IntTy);
449 FunctionType *FuncTy = FunctionType::get(Result: RetTy, Params: {IntTy, IntTy}, isVarArg: false);
450
451 AttrBuilder FuncAttrBuilder(Ctx);
452 for (Attribute::AttrKind Attr : CommonFnAttrs)
453 FuncAttrBuilder.addAttribute(Val: Attr);
454 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::none());
455
456 AttributeList Attrs;
457 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
458
459 Attribute::AttrKind ExtKind = IsSigned ? Attribute::SExt : Attribute::ZExt;
460 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::InReg);
461 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 0, Kind: ExtKind);
462 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 1, Kind: ExtKind);
463
464 return {FuncTy, Attrs};
465 }
466 case RTLIB::impl_sqrtf:
467 case RTLIB::impl_sqrt: {
468 AttrBuilder FuncAttrBuilder(Ctx);
469
470 for (Attribute::AttrKind Attr : CommonFnAttrs)
471 FuncAttrBuilder.addAttribute(Val: Attr);
472 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::errnoMemOnly(MR: ModRefInfo::Mod));
473
474 AttributeList Attrs;
475 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
476
477 Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(C&: Ctx)
478 : Type::getDoubleTy(C&: Ctx);
479 FunctionType *FuncTy = FunctionType::get(Result: ScalarTy, Params: {ScalarTy}, isVarArg: false);
480
481 Attrs = Attrs.addRetAttribute(
482 C&: Ctx, Attr: Attribute::getWithNoFPClass(Context&: Ctx, Mask: fcNegInf | fcNegSubnormal |
483 fcNegNormal));
484 return {FuncTy, Attrs};
485 }
486 default:
487 break;
488 }
489
490 auto [FuncTy, Attrs] = getDefaultFunctionTy(Ctx, TT, DL, LibcallImpl);
491 if (!FuncTy || FuncTy->getNumParams() == 0 ||
492 !FuncTy->getParamType(i: 0)->isVectorTy())
493 return {FuncTy, Attrs};
494
495 Type *VecTy = FuncTy->getParamType(i: 0);
496 AttrBuilder ArgAttrBuilder(Ctx);
497 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
498 ArgAttrBuilder.addAttribute(Val: AK);
499 ArgAttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: VecTy));
500
501 bool HasPtrArg = false;
502 for (auto [Idx, ParamTy] : enumerate(First: FuncTy->params())) {
503 if (ParamTy->isPointerTy()) {
504 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: Idx, B: ArgAttrBuilder);
505 HasPtrArg = true;
506 }
507 }
508
509 if (HasPtrArg) {
510 AttrBuilder FuncAttrBuilder(Ctx);
511 for (Attribute::AttrKind Attr : CommonFnAttrs)
512 FuncAttrBuilder.addAttribute(Val: Attr);
513 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argMemOnly(MR: ModRefInfo::Mod));
514 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
515 }
516
517 return {FuncTy, Attrs};
518}
519