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_SET_TARGET_RUNTIME_LIBCALL_SETS
26#define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME
27#define GET_RUNTIME_LIBCALL_INTRINSIC_TO_LIBCALL
28#include "llvm/IR/RuntimeLibcalls.inc"
29
30RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Triple &TT,
31 ExceptionHandling ExceptionModel,
32 FloatABI::ABIType FloatABI,
33 StringRef ABIName,
34 VectorLibrary VecLib) {
35 // Only an unspecified model resolves to the triple default; None is left as
36 // an explicit disable.
37 if (ExceptionModel == ExceptionHandling::Default)
38 ExceptionModel = TT.getDefaultExceptionHandling();
39
40 initLibcalls(TT, ExceptionModel, FloatABI, ABIName,
41 LongDoubleFormat: TT.getDefaultLongDoubleFormat());
42
43 // TODO: Tablegen should generate these sets
44 switch (VecLib) {
45 case VectorLibrary::SLEEFGNUABI:
46 for (RTLIB::LibcallImpl Impl :
47 {RTLIB::impl__ZGVnN2vv_fmod, RTLIB::impl__ZGVnN4vv_fmodf,
48 RTLIB::impl__ZGVsMxvv_fmod, RTLIB::impl__ZGVsMxvv_fmodf,
49 RTLIB::impl__ZGVnN2vl8_modf, RTLIB::impl__ZGVnN4vl4_modff,
50 RTLIB::impl__ZGVsNxvl8_modf, RTLIB::impl__ZGVsNxvl4_modff,
51 RTLIB::impl__ZGVnN2vl8l8_sincos, RTLIB::impl__ZGVnN4vl4l4_sincosf,
52 RTLIB::impl__ZGVsNxvl8l8_sincos, RTLIB::impl__ZGVsNxvl4l4_sincosf,
53 RTLIB::impl__ZGVnN4vl4l4_sincospif, RTLIB::impl__ZGVnN2vl8l8_sincospi,
54 RTLIB::impl__ZGVsNxvl4l4_sincospif,
55 RTLIB::impl__ZGVsNxvl8l8_sincospi})
56 setAvailable(Impl);
57 break;
58 case VectorLibrary::ArmPL:
59 for (RTLIB::LibcallImpl Impl : {RTLIB::impl_armpl_svfmod_f32_x,
60 RTLIB::impl_armpl_svfmod_f64_x,
61 RTLIB::impl_armpl_vfmodq_f32,
62 RTLIB::impl_armpl_vfmodq_f64,
63 RTLIB::impl_armpl_vmodfq_f64,
64 RTLIB::impl_armpl_vmodfq_f32,
65 RTLIB::impl_armpl_svmodf_f64_x,
66 RTLIB::impl_armpl_svmodf_f32_x,
67 RTLIB::impl_armpl_vsincosq_f64,
68 RTLIB::impl_armpl_vsincosq_f32,
69 RTLIB::impl_armpl_svsincos_f64_x,
70 RTLIB::impl_armpl_svsincos_f32_x,
71 RTLIB::impl_armpl_vsincospiq_f32,
72 RTLIB::impl_armpl_vsincospiq_f64,
73 RTLIB::impl_armpl_svsincospi_f32_x,
74 RTLIB::impl_armpl_svsincospi_f64_x,
75 RTLIB::impl_armpl_svpow_f32_x,
76 RTLIB::impl_armpl_svpow_f64_x,
77 RTLIB::impl_armpl_vpowq_f32,
78 RTLIB::impl_armpl_vpowq_f64,
79 RTLIB::impl_armpl_svcbrt_f32_x,
80 RTLIB::impl_armpl_svcbrt_f64_x,
81 RTLIB::impl_armpl_vcbrtq_f32,
82 RTLIB::impl_armpl_vcbrtq_f64})
83 setAvailable(Impl);
84
85 for (RTLIB::LibcallImpl Impl :
86 {RTLIB::impl_armpl_vfmodq_f32, RTLIB::impl_armpl_vfmodq_f64,
87 RTLIB::impl_armpl_vsincosq_f64, RTLIB::impl_armpl_vsincosq_f32,
88 RTLIB::impl_armpl_vpowq_f32, RTLIB::impl_armpl_vpowq_f64,
89 RTLIB::impl_armpl_vcbrtq_f32, RTLIB::impl_armpl_vcbrtq_f64})
90 setLibcallImplCallingConv(Call: Impl, CC: CallingConv::AArch64_VectorCall);
91 break;
92 case VectorLibrary::AMDLIBM:
93 for (RTLIB::LibcallImpl Impl :
94 {RTLIB::impl_amd_vrd2_sincos, RTLIB::impl_amd_vrd4_sincos,
95 RTLIB::impl_amd_vrd8_sincos, RTLIB::impl_amd_vrs4_sincosf,
96 RTLIB::impl_amd_vrs8_sincosf, RTLIB::impl_amd_vrs16_sincosf})
97 setAvailable(Impl);
98 break;
99 default:
100 break;
101 }
102}
103
104// TODO: Consider the remaining module flags.
105RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M, StringRef ABIName,
106 VectorLibrary VecLib)
107 : RuntimeLibcallsInfo(M.getTargetTriple(), M.getExceptionModel(),
108 M.getFloatABI(), ABIName, VecLib) {}
109
110bool RuntimeLibcallsInfo::isLibraryAvailable(StringRef LibraryName) const {
111 // TODO: Drive this from module-level state (e.g. the linked runtime). For now
112 // every named library is reported as available.
113 return true;
114}
115
116/// Set default libcall names. If a target wants to opt-out of a libcall it
117/// should be placed here.
118void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
119 ExceptionHandling ExceptionModel,
120 FloatABI::ABIType FloatABI,
121 StringRef ABIName,
122 LongDoubleFormat LongDoubleFormat) {
123 setTargetRuntimeLibcallSets(TT, ExceptionModel, FloatABI, ABIName,
124 LongDoubleFormat);
125}
126
127LLVM_ATTRIBUTE_ALWAYS_INLINE
128iota_range<RTLIB::LibcallImpl>
129RuntimeLibcallsInfo::libcallImplNameHit(uint16_t NameOffsetEntry,
130 uint16_t StrOffset) {
131 int NumAliases = 1;
132 for (uint16_t Entry : ArrayRef(RuntimeLibcallNameOffsetTable)
133 .drop_front(N: NameOffsetEntry + 1)) {
134 if (Entry != StrOffset)
135 break;
136 ++NumAliases;
137 }
138
139 RTLIB::LibcallImpl ImplStart = static_cast<RTLIB::LibcallImpl>(
140 &RuntimeLibcallNameOffsetTable[NameOffsetEntry] -
141 &RuntimeLibcallNameOffsetTable[0]);
142 return enum_seq(Begin: ImplStart,
143 End: static_cast<RTLIB::LibcallImpl>(ImplStart + NumAliases));
144}
145
146bool RuntimeLibcallsInfo::isAAPCS_ABI(const Triple &TT, StringRef ABIName) {
147 const ARM::ARMABI TargetABI = ARM::computeTargetABI(TT, ABIName);
148 return TargetABI == ARM::ARM_ABI_AAPCS || TargetABI == ARM::ARM_ABI_AAPCS16;
149}
150
151/// TODO: There is really no guarantee that sizeof(size_t) is equal to the index
152/// size of the default address space. This matches TargetLibraryInfo and should
153/// be kept in sync.
154static IntegerType *getSizeTType(LLVMContext &Ctx, const DataLayout &DL) {
155 return DL.getIndexType(C&: Ctx, /*AddressSpace=*/0);
156}
157
158static std::pair<Type *, Attribute> convertToIRTypeAndAttr(FuncArgTypeID ID,
159 LLVMContext &Ctx,
160 const DataLayout &DL,
161 unsigned IntBits) {
162
163 // FIXME: Use the llvm/ABI library to get accurate IR types and attributes.
164 switch (ID) {
165 case Void:
166 return {Type::getVoidTy(C&: Ctx), Attribute()};
167 case Bool:
168 return {IntegerType::get(C&: Ctx, NumBits: 1), Attribute::get(Context&: Ctx, Kind: Attribute::ZExt)};
169 case Int16:
170 case UInt16:
171 return {IntegerType::get(C&: Ctx, NumBits: 16), Attribute()};
172 case Int32:
173 case UInt32:
174 return {IntegerType::get(C&: Ctx, NumBits: 32), Attribute()};
175 case Int:
176 case UInt:
177 case IntPlus:
178 case UIntPlus:
179 case Long:
180 case ULong:
181 case IntX:
182 case UIntX:
183 return {IntegerType::get(C&: Ctx, NumBits: IntBits), Attribute()};
184 case Int64:
185 case UInt64:
186 case LLong:
187 case ULLong:
188 return {IntegerType::get(C&: Ctx, NumBits: 64), Attribute()};
189 case SizeT:
190 case SSizeT:
191 return {getSizeTType(Ctx, DL), Attribute()};
192 case Flt:
193 case Floating:
194 return {Type::getFloatTy(C&: Ctx), Attribute()};
195 case Dbl:
196 case LDbl:
197 return {Type::getDoubleTy(C&: Ctx), Attribute()};
198 case Ptr:
199 return {PointerType::get(C&: Ctx, AddressSpace: 0), Attribute()};
200 default:
201 return {};
202 }
203}
204
205std::pair<FunctionType *, AttributeList>
206RuntimeLibcallsInfo::getDefaultFunctionTy(
207 LLVMContext &Ctx, const Triple &TT, const DataLayout &DL,
208 RTLIB::LibcallImpl LibcallImpl) const {
209 Libcall LC = getLibcallFromImpl(Impl: LibcallImpl);
210 const FuncArgTypeID *ProtoTypes = &SignatureTable[SignatureOffset[LC]];
211
212 if (ProtoTypes[0] == NoFuncArgType)
213 return {};
214
215 unsigned IntBits = getIntSize(TT);
216 AttributeList Attrs;
217
218 auto [RetTy, RetAttr] =
219 convertToIRTypeAndAttr(ID: ProtoTypes[0], Ctx, DL, IntBits);
220 if (RetAttr.isValid())
221 Attrs = Attrs.addRetAttribute(C&: Ctx, Attr: RetAttr);
222
223 Type *LastTy = RetTy, *ArgTy;
224 Attribute LastAttr = RetAttr, ArgAttr;
225 SmallVector<Type *, 4> ArgTys;
226 bool IsVarArg = false;
227 unsigned Idx = 1;
228 for (FuncArgTypeID TyID = ProtoTypes[Idx]; TyID != NoFuncArgType;
229 TyID = ProtoTypes[++Idx]) {
230 if (TyID == Ellip) {
231 // The ellipsis ends the protoype list so it must be followed by
232 // NoFuncArgType.
233 assert(ProtoTypes[Idx + 1] == NoFuncArgType);
234 IsVarArg = true;
235 break;
236 }
237
238 if (TyID == Same) {
239 ArgTy = LastTy;
240 ArgAttr = LastAttr;
241 } else {
242 std::tie(args&: ArgTy, args&: ArgAttr) =
243 convertToIRTypeAndAttr(ID: ProtoTypes[Idx], Ctx, DL, IntBits);
244 LastTy = ArgTy;
245 LastAttr = ArgAttr;
246 }
247
248 ArgTys.push_back(Elt: ArgTy);
249 if (ArgAttr.isValid())
250 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNos: Idx - 1, A: ArgAttr);
251 }
252
253 return {FunctionType::get(Result: RetTy, Params: ArgTys, isVarArg: IsVarArg), Attrs};
254}
255
256std::pair<FunctionType *, AttributeList>
257RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT,
258 const DataLayout &DL,
259 RTLIB::LibcallImpl LibcallImpl) const {
260 // TODO: NoCallback probably unsafe in general
261 static constexpr Attribute::AttrKind CommonFnAttrs[] = {
262 Attribute::NoCallback, Attribute::NoFree, Attribute::NoSync,
263 Attribute::NoUnwind, Attribute::WillReturn};
264 static constexpr Attribute::AttrKind MemoryFnAttrs[] = {
265 Attribute::NoUnwind, Attribute::WillReturn};
266 static constexpr Attribute::AttrKind CommonPtrArgAttrs[] = {
267 Attribute::NoAlias, Attribute::WriteOnly, Attribute::NonNull};
268
269 switch (LibcallImpl) {
270 case RTLIB::impl___sincos_stret:
271 case RTLIB::impl___sincosf_stret: {
272 if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected
273 return {};
274
275 Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret
276 ? Type::getFloatTy(C&: Ctx)
277 : Type::getDoubleTy(C&: Ctx);
278
279 AttrBuilder FuncAttrBuilder(Ctx);
280 for (Attribute::AttrKind Attr : CommonFnAttrs)
281 FuncAttrBuilder.addAttribute(Val: Attr);
282
283 const bool UseSret =
284 TT.isX86_32() || ((TT.isARM() || TT.isThumb()) &&
285 ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS);
286
287 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argumentOrErrnoMemOnly(
288 ArgMR: UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ErrnoMR: ModRefInfo::Mod));
289
290 AttributeList Attrs;
291 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
292
293 if (UseSret) {
294 AttrBuilder AttrBuilder(Ctx);
295 StructType *StructTy = StructType::get(elt1: ScalarTy, elts: ScalarTy);
296 AttrBuilder.addStructRetAttr(Ty: StructTy);
297 AttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: StructTy));
298 FunctionType *FuncTy = FunctionType::get(
299 Result: Type::getVoidTy(C&: Ctx), Params: {DL.getAllocaPtrType(Ctx), ScalarTy}, isVarArg: false);
300
301 return {FuncTy, Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: AttrBuilder)};
302 }
303
304 Type *RetTy =
305 LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64()
306 ? static_cast<Type *>(FixedVectorType::get(ElementType: ScalarTy, NumElts: 2))
307 : static_cast<Type *>(StructType::get(elt1: ScalarTy, elts: ScalarTy));
308
309 return {FunctionType::get(Result: RetTy, Params: {ScalarTy}, isVarArg: false), Attrs};
310 }
311 case RTLIB::impl_malloc:
312 case RTLIB::impl_calloc: {
313 AttrBuilder FuncAttrBuilder(Ctx);
314 for (Attribute::AttrKind Attr : MemoryFnAttrs)
315 FuncAttrBuilder.addAttribute(Val: Attr);
316 FuncAttrBuilder.addAttribute(Val: Attribute::NoFree);
317
318 AllocFnKind AllocKind = AllocFnKind::Alloc;
319 if (LibcallImpl == RTLIB::impl_malloc)
320 AllocKind |= AllocFnKind::Uninitialized;
321
322 // TODO: Set memory attribute
323 FuncAttrBuilder.addAllocKindAttr(Kind: AllocKind);
324 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
325 FuncAttrBuilder.addAllocSizeAttr(ElemSizeArg: 0, NumElemsArg: LibcallImpl == RTLIB::impl_malloc
326 ? std::nullopt
327 : std::make_optional(t: 1));
328
329 AttributeList Attrs;
330 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
331
332 {
333 AttrBuilder ArgAttrBuilder(Ctx);
334 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
335 ArgAttrBuilder.addAttribute(Val: AK);
336
337 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoUndef);
338 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoAlias);
339 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 0, Kind: Attribute::NoUndef);
340 if (LibcallImpl == RTLIB::impl_calloc)
341 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 1, Kind: Attribute::NoUndef);
342 }
343
344 IntegerType *SizeT = getSizeTType(Ctx, DL);
345 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
346 SmallVector<Type *, 2> ArgTys = {SizeT};
347 if (LibcallImpl == RTLIB::impl_calloc)
348 ArgTys.push_back(Elt: SizeT);
349
350 return {FunctionType::get(Result: PtrTy, Params: ArgTys, isVarArg: false), Attrs};
351 }
352 case RTLIB::impl_free: {
353 // TODO: Set memory attribute
354 AttrBuilder FuncAttrBuilder(Ctx);
355 for (Attribute::AttrKind Attr : MemoryFnAttrs)
356 FuncAttrBuilder.addAttribute(Val: Attr);
357
358 FuncAttrBuilder.addAllocKindAttr(Kind: AllocFnKind::Free);
359 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
360
361 AttributeList Attrs;
362 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
363
364 {
365 AttrBuilder ArgAttrBuilder(Ctx);
366 ArgAttrBuilder.addAttribute(Val: Attribute::NoUndef);
367 ArgAttrBuilder.addAttribute(Val: Attribute::AllocatedPointer);
368 ArgAttrBuilder.addCapturesAttr(CI: CaptureInfo::none());
369 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: ArgAttrBuilder);
370 }
371
372 return {FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {PointerType::get(C&: Ctx, AddressSpace: 0)},
373 isVarArg: false),
374 Attrs};
375 }
376 case RTLIB::impl___aeabi_idivmod:
377 case RTLIB::impl___aeabi_uidivmod:
378 case RTLIB::impl___aeabi_ldivmod:
379 case RTLIB::impl___aeabi_uldivmod:
380 case RTLIB::impl___rt_sdiv:
381 case RTLIB::impl___rt_udiv:
382 case RTLIB::impl___rt_sdiv64:
383 case RTLIB::impl___rt_udiv64: {
384 // The ARM AEABI (__aeabi_*divmod) and Windows (__rt_*div*) divmod functions
385 // return both values modeled as an inreg { iN, iN } struct (quotient,
386 // remainder). The __rt_*div* cases pass the arguments in opposite order,
387 // though this doesn't affect the declaration.
388 bool IsSigned;
389 unsigned Bits;
390 switch (LibcallImpl) {
391 case RTLIB::impl___aeabi_idivmod:
392 case RTLIB::impl___rt_sdiv:
393 IsSigned = true;
394 Bits = 32;
395 break;
396 case RTLIB::impl___aeabi_uidivmod:
397 case RTLIB::impl___rt_udiv:
398 IsSigned = false;
399 Bits = 32;
400 break;
401 case RTLIB::impl___aeabi_ldivmod:
402 case RTLIB::impl___rt_sdiv64:
403 IsSigned = true;
404 Bits = 64;
405 break;
406 case RTLIB::impl___aeabi_uldivmod:
407 case RTLIB::impl___rt_udiv64:
408 IsSigned = false;
409 Bits = 64;
410 break;
411 default:
412 llvm_unreachable("unexpected divmod libcall");
413 }
414
415 Type *IntTy = IntegerType::get(C&: Ctx, NumBits: Bits);
416 StructType *RetTy = StructType::get(elt1: IntTy, elts: IntTy);
417 FunctionType *FuncTy = FunctionType::get(Result: RetTy, Params: {IntTy, IntTy}, isVarArg: false);
418
419 AttrBuilder FuncAttrBuilder(Ctx);
420 for (Attribute::AttrKind Attr : CommonFnAttrs)
421 FuncAttrBuilder.addAttribute(Val: Attr);
422 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::none());
423
424 AttributeList Attrs;
425 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
426
427 Attribute::AttrKind ExtKind = IsSigned ? Attribute::SExt : Attribute::ZExt;
428 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::InReg);
429 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 0, Kind: ExtKind);
430 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 1, Kind: ExtKind);
431
432 return {FuncTy, Attrs};
433 }
434 case RTLIB::impl_sqrtf:
435 case RTLIB::impl_sqrt: {
436 AttrBuilder FuncAttrBuilder(Ctx);
437
438 for (Attribute::AttrKind Attr : CommonFnAttrs)
439 FuncAttrBuilder.addAttribute(Val: Attr);
440 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::errnoMemOnly(MR: ModRefInfo::Mod));
441
442 AttributeList Attrs;
443 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
444
445 Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(C&: Ctx)
446 : Type::getDoubleTy(C&: Ctx);
447 FunctionType *FuncTy = FunctionType::get(Result: ScalarTy, Params: {ScalarTy}, isVarArg: false);
448
449 Attrs = Attrs.addRetAttribute(
450 C&: Ctx, Attr: Attribute::getWithNoFPClass(Context&: Ctx, Mask: fcNegInf | fcNegSubnormal |
451 fcNegNormal));
452 return {FuncTy, Attrs};
453 }
454 case RTLIB::impl__ZGVnN2vv_fmod:
455 case RTLIB::impl__ZGVnN4vv_fmodf:
456 case RTLIB::impl__ZGVsMxvv_fmod:
457 case RTLIB::impl__ZGVsMxvv_fmodf:
458 case RTLIB::impl_armpl_vfmodq_f32:
459 case RTLIB::impl_armpl_vfmodq_f64:
460 case RTLIB::impl_armpl_svfmod_f32_x:
461 case RTLIB::impl_armpl_svfmod_f64_x:
462 case RTLIB::impl_armpl_vpowq_f32:
463 case RTLIB::impl_armpl_vpowq_f64:
464 case RTLIB::impl_armpl_svpow_f32_x:
465 case RTLIB::impl_armpl_svpow_f64_x:
466 case RTLIB::impl_armpl_vcbrtq_f32:
467 case RTLIB::impl_armpl_vcbrtq_f64:
468 case RTLIB::impl_armpl_svcbrt_f32_x:
469 case RTLIB::impl_armpl_svcbrt_f64_x: {
470 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vv_fmodf ||
471 LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf ||
472 LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x ||
473 LibcallImpl == RTLIB::impl_armpl_vfmodq_f32 ||
474 LibcallImpl == RTLIB::impl_armpl_vpowq_f32 ||
475 LibcallImpl == RTLIB::impl_armpl_svpow_f32_x ||
476 LibcallImpl == RTLIB::impl_armpl_vcbrtq_f32 ||
477 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x;
478
479 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsMxvv_fmod ||
480 LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf ||
481 LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x ||
482 LibcallImpl == RTLIB::impl_armpl_svfmod_f64_x ||
483 LibcallImpl == RTLIB::impl_armpl_svpow_f32_x ||
484 LibcallImpl == RTLIB::impl_armpl_svpow_f64_x ||
485 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x ||
486 LibcallImpl == RTLIB::impl_armpl_svcbrt_f64_x;
487
488 bool HasOneArg = LibcallImpl == RTLIB::impl_armpl_vcbrtq_f32 ||
489 LibcallImpl == RTLIB::impl_armpl_vcbrtq_f64 ||
490 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x ||
491 LibcallImpl == RTLIB::impl_armpl_svcbrt_f64_x;
492
493 AttrBuilder FuncAttrBuilder(Ctx);
494
495 for (Attribute::AttrKind Attr : CommonFnAttrs)
496 FuncAttrBuilder.addAttribute(Val: Attr);
497
498 AttributeList Attrs;
499 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
500
501 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
502 unsigned EC = IsF32 ? 4 : 2;
503 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
504
505 SmallVector<Type *, 3> ArgTys(HasOneArg ? 1 : 2, VecTy);
506 if (hasVectorMaskArgument(Impl: LibcallImpl))
507 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
508
509 FunctionType *FuncTy = FunctionType::get(Result: VecTy, Params: ArgTys, isVarArg: false);
510 return {FuncTy, Attrs};
511 }
512 case RTLIB::impl__ZGVnN2vl8_modf:
513 case RTLIB::impl__ZGVnN4vl4_modff:
514 case RTLIB::impl__ZGVsNxvl8_modf:
515 case RTLIB::impl__ZGVsNxvl4_modff:
516 case RTLIB::impl_armpl_vmodfq_f64:
517 case RTLIB::impl_armpl_vmodfq_f32:
518 case RTLIB::impl_armpl_svmodf_f64_x:
519 case RTLIB::impl_armpl_svmodf_f32_x: {
520 AttrBuilder FuncAttrBuilder(Ctx);
521
522 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4_modff ||
523 LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff ||
524 LibcallImpl == RTLIB::impl_armpl_vmodfq_f32 ||
525 LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x;
526
527 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8_modf ||
528 LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff ||
529 LibcallImpl == RTLIB::impl_armpl_svmodf_f64_x ||
530 LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x;
531
532 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
533 unsigned EC = IsF32 ? 4 : 2;
534 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
535
536 for (Attribute::AttrKind Attr : CommonFnAttrs)
537 FuncAttrBuilder.addAttribute(Val: Attr);
538 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argMemOnly(MR: ModRefInfo::Mod));
539
540 AttributeList Attrs;
541 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
542
543 {
544 AttrBuilder ArgAttrBuilder(Ctx);
545 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
546 ArgAttrBuilder.addAttribute(Val: AK);
547 ArgAttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: VecTy));
548 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 1, B: ArgAttrBuilder);
549 }
550
551 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
552 SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy};
553 if (hasVectorMaskArgument(Impl: LibcallImpl))
554 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
555
556 return {FunctionType::get(Result: VecTy, Params: ArgTys, isVarArg: false), Attrs};
557 }
558 case RTLIB::impl__ZGVnN2vl8l8_sincos:
559 case RTLIB::impl__ZGVnN4vl4l4_sincosf:
560 case RTLIB::impl__ZGVsNxvl8l8_sincos:
561 case RTLIB::impl__ZGVsNxvl4l4_sincosf:
562 case RTLIB::impl_armpl_vsincosq_f64:
563 case RTLIB::impl_armpl_vsincosq_f32:
564 case RTLIB::impl_armpl_svsincos_f64_x:
565 case RTLIB::impl_armpl_svsincos_f32_x:
566 case RTLIB::impl__ZGVnN4vl4l4_sincospif:
567 case RTLIB::impl__ZGVnN2vl8l8_sincospi:
568 case RTLIB::impl__ZGVsNxvl4l4_sincospif:
569 case RTLIB::impl__ZGVsNxvl8l8_sincospi:
570 case RTLIB::impl_armpl_vsincospiq_f32:
571 case RTLIB::impl_armpl_vsincospiq_f64:
572 case RTLIB::impl_armpl_svsincospi_f32_x:
573 case RTLIB::impl_armpl_svsincospi_f64_x: {
574 AttrBuilder FuncAttrBuilder(Ctx);
575
576 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincospif ||
577 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif ||
578 LibcallImpl == RTLIB::impl_armpl_vsincospiq_f32 ||
579 LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x ||
580 LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincosf ||
581 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf ||
582 LibcallImpl == RTLIB::impl_armpl_vsincosq_f32 ||
583 LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x;
584
585 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
586 unsigned EC = IsF32 ? 4 : 2;
587
588 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincos ||
589 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf ||
590 LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x ||
591 LibcallImpl == RTLIB::impl_armpl_svsincos_f64_x ||
592 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif ||
593 LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincospi ||
594 LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x ||
595 LibcallImpl == RTLIB::impl_armpl_svsincospi_f64_x;
596 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
597
598 for (Attribute::AttrKind Attr : CommonFnAttrs)
599 FuncAttrBuilder.addAttribute(Val: Attr);
600 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argMemOnly(MR: ModRefInfo::Mod));
601
602 AttributeList Attrs;
603 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
604
605 {
606 AttrBuilder ArgAttrBuilder(Ctx);
607 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
608 ArgAttrBuilder.addAttribute(Val: AK);
609 ArgAttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: VecTy));
610 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 1, B: ArgAttrBuilder);
611 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 2, B: ArgAttrBuilder);
612 }
613
614 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
615 SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy, PtrTy};
616 if (hasVectorMaskArgument(Impl: LibcallImpl))
617 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
618
619 return {FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: ArgTys, isVarArg: false), Attrs};
620 }
621 default:
622 return getDefaultFunctionTy(Ctx, TT, DL, LibcallImpl);
623 }
624
625 return {};
626}
627
628bool RuntimeLibcallsInfo::hasVectorMaskArgument(RTLIB::LibcallImpl Impl) {
629 /// FIXME: This should be generated by tablegen and support the argument at an
630 /// arbitrary position
631 switch (Impl) {
632 case RTLIB::impl_armpl_svfmod_f32_x:
633 case RTLIB::impl_armpl_svfmod_f64_x:
634 case RTLIB::impl_armpl_svmodf_f64_x:
635 case RTLIB::impl_armpl_svmodf_f32_x:
636 case RTLIB::impl_armpl_svsincos_f32_x:
637 case RTLIB::impl_armpl_svsincos_f64_x:
638 case RTLIB::impl_armpl_svsincospi_f32_x:
639 case RTLIB::impl_armpl_svsincospi_f64_x:
640 case RTLIB::impl__ZGVsMxvv_fmod:
641 case RTLIB::impl__ZGVsMxvv_fmodf:
642 case RTLIB::impl_armpl_svpow_f32_x:
643 case RTLIB::impl_armpl_svpow_f64_x:
644 case RTLIB::impl_armpl_svcbrt_f32_x:
645 case RTLIB::impl_armpl_svcbrt_f64_x:
646 return true;
647 default:
648 return false;
649 }
650}
651