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/ADT/StringTable.h"
12#include "llvm/IR/Module.h"
13#include "llvm/IR/SystemLibraries.h"
14#include "llvm/Support/Debug.h"
15#include "llvm/Support/xxhash.h"
16#include "llvm/TargetParser/ARMTargetParser.h"
17
18#define DEBUG_TYPE "runtime-libcalls-info"
19
20using namespace llvm;
21using namespace RTLIB;
22
23#define GET_RUNTIME_LIBCALLS_INFO
24#define GET_INIT_RUNTIME_LIBCALL_NAMES
25#define GET_SET_TARGET_RUNTIME_LIBCALL_SETS
26#define DEFINE_GET_LOOKUP_LIBCALL_IMPL_NAME
27#include "llvm/IR/RuntimeLibcalls.inc"
28
29RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Triple &TT,
30 ExceptionHandling ExceptionModel,
31 FloatABI::ABIType FloatABI,
32 EABI EABIVersion, StringRef ABIName,
33 VectorLibrary VecLib) {
34 // FIXME: The ExceptionModel parameter is to handle the field in
35 // TargetOptions. This interface fails to distinguish the forced disable
36 // case for targets which support exceptions by default. This should
37 // probably be a module flag and removed from TargetOptions.
38 if (ExceptionModel == ExceptionHandling::None)
39 ExceptionModel = TT.getDefaultExceptionHandling();
40
41 initLibcalls(TT, ExceptionModel, FloatABI, ABIType: EABIVersion, ABIName);
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 default:
93 break;
94 }
95}
96
97RuntimeLibcallsInfo::RuntimeLibcallsInfo(const Module &M)
98 : RuntimeLibcallsInfo(M.getTargetTriple()) {
99 // TODO: Consider module flags
100}
101
102/// Set default libcall names. If a target wants to opt-out of a libcall it
103/// should be placed here.
104void RuntimeLibcallsInfo::initLibcalls(const Triple &TT,
105 ExceptionHandling ExceptionModel,
106 FloatABI::ABIType FloatABI,
107 EABI EABIVersion, StringRef ABIName) {
108 setTargetRuntimeLibcallSets(TT, ExceptionModel, FloatABI, EABIVersion,
109 ABIName);
110}
111
112LLVM_ATTRIBUTE_ALWAYS_INLINE
113iota_range<RTLIB::LibcallImpl>
114RuntimeLibcallsInfo::libcallImplNameHit(uint16_t NameOffsetEntry,
115 uint16_t StrOffset) {
116 int NumAliases = 1;
117 for (uint16_t Entry : ArrayRef(RuntimeLibcallNameOffsetTable)
118 .drop_front(N: NameOffsetEntry + 1)) {
119 if (Entry != StrOffset)
120 break;
121 ++NumAliases;
122 }
123
124 RTLIB::LibcallImpl ImplStart = static_cast<RTLIB::LibcallImpl>(
125 &RuntimeLibcallNameOffsetTable[NameOffsetEntry] -
126 &RuntimeLibcallNameOffsetTable[0]);
127 return enum_seq(Begin: ImplStart,
128 End: static_cast<RTLIB::LibcallImpl>(ImplStart + NumAliases));
129}
130
131bool RuntimeLibcallsInfo::isAAPCS_ABI(const Triple &TT, StringRef ABIName) {
132 const ARM::ARMABI TargetABI = ARM::computeTargetABI(TT, ABIName);
133 return TargetABI == ARM::ARM_ABI_AAPCS || TargetABI == ARM::ARM_ABI_AAPCS16;
134}
135
136bool RuntimeLibcallsInfo::darwinHasExp10(const Triple &TT) {
137 switch (TT.getOS()) {
138 case Triple::MacOSX:
139 return !TT.isMacOSXVersionLT(Major: 10, Minor: 9);
140 case Triple::IOS:
141 return !TT.isOSVersionLT(Major: 7, Minor: 0);
142 case Triple::DriverKit:
143 case Triple::TvOS:
144 case Triple::WatchOS:
145 case Triple::XROS:
146 case Triple::BridgeOS:
147 return true;
148 default:
149 return false;
150 }
151}
152
153/// TODO: There is really no guarantee that sizeof(size_t) is equal to the index
154/// size of the default address space. This matches TargetLibraryInfo and should
155/// be kept in sync.
156static IntegerType *getSizeTType(LLVMContext &Ctx, const DataLayout &DL) {
157 return DL.getIndexType(C&: Ctx, /*AddressSpace=*/0);
158}
159
160std::pair<FunctionType *, AttributeList>
161RuntimeLibcallsInfo::getFunctionTy(LLVMContext &Ctx, const Triple &TT,
162 const DataLayout &DL,
163 RTLIB::LibcallImpl LibcallImpl) const {
164 // TODO: NoCallback probably unsafe in general
165 static constexpr Attribute::AttrKind CommonFnAttrs[] = {
166 Attribute::MustProgress, Attribute::NoCallback, Attribute::NoFree,
167 Attribute::NoSync, Attribute::NoUnwind, Attribute::WillReturn};
168 static constexpr Attribute::AttrKind MemoryFnAttrs[] = {
169 Attribute::MustProgress, Attribute::NoUnwind, Attribute::WillReturn};
170 static constexpr Attribute::AttrKind CommonPtrArgAttrs[] = {
171 Attribute::NoAlias, Attribute::WriteOnly, Attribute::NonNull};
172
173 switch (LibcallImpl) {
174 case RTLIB::impl___sincos_stret:
175 case RTLIB::impl___sincosf_stret: {
176 if (!darwinHasSinCosStret(TT)) // Non-darwin currently unexpected
177 return {};
178
179 Type *ScalarTy = LibcallImpl == RTLIB::impl___sincosf_stret
180 ? Type::getFloatTy(C&: Ctx)
181 : Type::getDoubleTy(C&: Ctx);
182
183 AttrBuilder FuncAttrBuilder(Ctx);
184 for (Attribute::AttrKind Attr : CommonFnAttrs)
185 FuncAttrBuilder.addAttribute(Val: Attr);
186
187 const bool UseSret =
188 TT.isX86_32() || ((TT.isARM() || TT.isThumb()) &&
189 ARM::computeTargetABI(TT) == ARM::ARM_ABI_APCS);
190
191 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argumentOrErrnoMemOnly(
192 ArgMR: UseSret ? ModRefInfo::Mod : ModRefInfo::NoModRef, ErrnoMR: ModRefInfo::Mod));
193
194 AttributeList Attrs;
195 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
196
197 if (UseSret) {
198 AttrBuilder AttrBuilder(Ctx);
199 StructType *StructTy = StructType::get(elt1: ScalarTy, elts: ScalarTy);
200 AttrBuilder.addStructRetAttr(Ty: StructTy);
201 AttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: StructTy));
202 FunctionType *FuncTy = FunctionType::get(
203 Result: Type::getVoidTy(C&: Ctx), Params: {DL.getAllocaPtrType(Ctx), ScalarTy}, isVarArg: false);
204
205 return {FuncTy, Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: AttrBuilder)};
206 }
207
208 Type *RetTy =
209 LibcallImpl == RTLIB::impl___sincosf_stret && TT.isX86_64()
210 ? static_cast<Type *>(FixedVectorType::get(ElementType: ScalarTy, NumElts: 2))
211 : static_cast<Type *>(StructType::get(elt1: ScalarTy, elts: ScalarTy));
212
213 return {FunctionType::get(Result: RetTy, Params: {ScalarTy}, isVarArg: false), Attrs};
214 }
215 case RTLIB::impl_malloc:
216 case RTLIB::impl_calloc: {
217 AttrBuilder FuncAttrBuilder(Ctx);
218 for (Attribute::AttrKind Attr : MemoryFnAttrs)
219 FuncAttrBuilder.addAttribute(Val: Attr);
220 FuncAttrBuilder.addAttribute(Val: Attribute::NoFree);
221
222 AllocFnKind AllocKind = AllocFnKind::Alloc;
223 if (LibcallImpl == RTLIB::impl_malloc)
224 AllocKind |= AllocFnKind::Uninitialized;
225
226 // TODO: Set memory attribute
227 FuncAttrBuilder.addAllocKindAttr(Kind: AllocKind);
228 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
229 FuncAttrBuilder.addAllocSizeAttr(ElemSizeArg: 0, NumElemsArg: LibcallImpl == RTLIB::impl_malloc
230 ? std::nullopt
231 : std::make_optional(t: 1));
232
233 AttributeList Attrs;
234 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
235
236 {
237 AttrBuilder ArgAttrBuilder(Ctx);
238 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
239 ArgAttrBuilder.addAttribute(Val: AK);
240
241 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoUndef);
242 Attrs = Attrs.addRetAttribute(C&: Ctx, Kind: Attribute::NoAlias);
243 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 0, Kind: Attribute::NoUndef);
244 if (LibcallImpl == RTLIB::impl_calloc)
245 Attrs = Attrs.addParamAttribute(C&: Ctx, ArgNo: 1, Kind: Attribute::NoUndef);
246 }
247
248 IntegerType *SizeT = getSizeTType(Ctx, DL);
249 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
250 SmallVector<Type *, 2> ArgTys = {SizeT};
251 if (LibcallImpl == RTLIB::impl_calloc)
252 ArgTys.push_back(Elt: SizeT);
253
254 return {FunctionType::get(Result: PtrTy, Params: ArgTys, isVarArg: false), Attrs};
255 }
256 case RTLIB::impl_free: {
257 // TODO: Set memory attribute
258 AttrBuilder FuncAttrBuilder(Ctx);
259 for (Attribute::AttrKind Attr : MemoryFnAttrs)
260 FuncAttrBuilder.addAttribute(Val: Attr);
261
262 FuncAttrBuilder.addAllocKindAttr(Kind: AllocFnKind::Free);
263 FuncAttrBuilder.addAttribute(A: "alloc-family", V: "malloc");
264
265 AttributeList Attrs;
266 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
267
268 {
269 AttrBuilder ArgAttrBuilder(Ctx);
270 ArgAttrBuilder.addAttribute(Val: Attribute::NoUndef);
271 ArgAttrBuilder.addAttribute(Val: Attribute::AllocatedPointer);
272 ArgAttrBuilder.addCapturesAttr(CI: CaptureInfo::none());
273 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 0, B: ArgAttrBuilder);
274 }
275
276 return {FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {PointerType::get(C&: Ctx, AddressSpace: 0)},
277 isVarArg: false),
278 Attrs};
279 }
280 case RTLIB::impl_sqrtf:
281 case RTLIB::impl_sqrt: {
282 AttrBuilder FuncAttrBuilder(Ctx);
283
284 for (Attribute::AttrKind Attr : CommonFnAttrs)
285 FuncAttrBuilder.addAttribute(Val: Attr);
286 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::errnoMemOnly(MR: ModRefInfo::Mod));
287
288 AttributeList Attrs;
289 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
290
291 Type *ScalarTy = LibcallImpl == RTLIB::impl_sqrtf ? Type::getFloatTy(C&: Ctx)
292 : Type::getDoubleTy(C&: Ctx);
293 FunctionType *FuncTy = FunctionType::get(Result: ScalarTy, Params: {ScalarTy}, isVarArg: false);
294
295 Attrs = Attrs.addRetAttribute(
296 C&: Ctx, Attr: Attribute::getWithNoFPClass(Context&: Ctx, Mask: fcNegInf | fcNegSubnormal |
297 fcNegNormal));
298 return {FuncTy, Attrs};
299 }
300 case RTLIB::impl__ZGVnN2vv_fmod:
301 case RTLIB::impl__ZGVnN4vv_fmodf:
302 case RTLIB::impl__ZGVsMxvv_fmod:
303 case RTLIB::impl__ZGVsMxvv_fmodf:
304 case RTLIB::impl_armpl_vfmodq_f32:
305 case RTLIB::impl_armpl_vfmodq_f64:
306 case RTLIB::impl_armpl_svfmod_f32_x:
307 case RTLIB::impl_armpl_svfmod_f64_x:
308 case RTLIB::impl_armpl_vpowq_f32:
309 case RTLIB::impl_armpl_vpowq_f64:
310 case RTLIB::impl_armpl_svpow_f32_x:
311 case RTLIB::impl_armpl_svpow_f64_x:
312 case RTLIB::impl_armpl_vcbrtq_f32:
313 case RTLIB::impl_armpl_vcbrtq_f64:
314 case RTLIB::impl_armpl_svcbrt_f32_x:
315 case RTLIB::impl_armpl_svcbrt_f64_x: {
316 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vv_fmodf ||
317 LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf ||
318 LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x ||
319 LibcallImpl == RTLIB::impl_armpl_vfmodq_f32 ||
320 LibcallImpl == RTLIB::impl_armpl_vpowq_f32 ||
321 LibcallImpl == RTLIB::impl_armpl_svpow_f32_x ||
322 LibcallImpl == RTLIB::impl_armpl_vcbrtq_f32 ||
323 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x;
324
325 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsMxvv_fmod ||
326 LibcallImpl == RTLIB::impl__ZGVsMxvv_fmodf ||
327 LibcallImpl == RTLIB::impl_armpl_svfmod_f32_x ||
328 LibcallImpl == RTLIB::impl_armpl_svfmod_f64_x ||
329 LibcallImpl == RTLIB::impl_armpl_svpow_f32_x ||
330 LibcallImpl == RTLIB::impl_armpl_svpow_f64_x ||
331 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x ||
332 LibcallImpl == RTLIB::impl_armpl_svcbrt_f64_x;
333
334 bool HasOneArg = LibcallImpl == RTLIB::impl_armpl_vcbrtq_f32 ||
335 LibcallImpl == RTLIB::impl_armpl_vcbrtq_f64 ||
336 LibcallImpl == RTLIB::impl_armpl_svcbrt_f32_x ||
337 LibcallImpl == RTLIB::impl_armpl_svcbrt_f64_x;
338
339 AttrBuilder FuncAttrBuilder(Ctx);
340
341 for (Attribute::AttrKind Attr : CommonFnAttrs)
342 FuncAttrBuilder.addAttribute(Val: Attr);
343
344 AttributeList Attrs;
345 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
346
347 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
348 unsigned EC = IsF32 ? 4 : 2;
349 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
350
351 SmallVector<Type *, 3> ArgTys(HasOneArg ? 1 : 2, VecTy);
352 if (hasVectorMaskArgument(Impl: LibcallImpl))
353 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
354
355 FunctionType *FuncTy = FunctionType::get(Result: VecTy, Params: ArgTys, isVarArg: false);
356 return {FuncTy, Attrs};
357 }
358 case RTLIB::impl__ZGVnN2vl8_modf:
359 case RTLIB::impl__ZGVnN4vl4_modff:
360 case RTLIB::impl__ZGVsNxvl8_modf:
361 case RTLIB::impl__ZGVsNxvl4_modff:
362 case RTLIB::impl_armpl_vmodfq_f64:
363 case RTLIB::impl_armpl_vmodfq_f32:
364 case RTLIB::impl_armpl_svmodf_f64_x:
365 case RTLIB::impl_armpl_svmodf_f32_x: {
366 AttrBuilder FuncAttrBuilder(Ctx);
367
368 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4_modff ||
369 LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff ||
370 LibcallImpl == RTLIB::impl_armpl_vmodfq_f32 ||
371 LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x;
372
373 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8_modf ||
374 LibcallImpl == RTLIB::impl__ZGVsNxvl4_modff ||
375 LibcallImpl == RTLIB::impl_armpl_svmodf_f64_x ||
376 LibcallImpl == RTLIB::impl_armpl_svmodf_f32_x;
377
378 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
379 unsigned EC = IsF32 ? 4 : 2;
380 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
381
382 for (Attribute::AttrKind Attr : CommonFnAttrs)
383 FuncAttrBuilder.addAttribute(Val: Attr);
384 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argMemOnly(MR: ModRefInfo::Mod));
385
386 AttributeList Attrs;
387 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
388
389 {
390 AttrBuilder ArgAttrBuilder(Ctx);
391 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
392 ArgAttrBuilder.addAttribute(Val: AK);
393 ArgAttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: VecTy));
394 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 1, B: ArgAttrBuilder);
395 }
396
397 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
398 SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy};
399 if (hasVectorMaskArgument(Impl: LibcallImpl))
400 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
401
402 return {FunctionType::get(Result: VecTy, Params: ArgTys, isVarArg: false), Attrs};
403 }
404 case RTLIB::impl__ZGVnN2vl8l8_sincos:
405 case RTLIB::impl__ZGVnN4vl4l4_sincosf:
406 case RTLIB::impl__ZGVsNxvl8l8_sincos:
407 case RTLIB::impl__ZGVsNxvl4l4_sincosf:
408 case RTLIB::impl_armpl_vsincosq_f64:
409 case RTLIB::impl_armpl_vsincosq_f32:
410 case RTLIB::impl_armpl_svsincos_f64_x:
411 case RTLIB::impl_armpl_svsincos_f32_x:
412 case RTLIB::impl__ZGVnN4vl4l4_sincospif:
413 case RTLIB::impl__ZGVnN2vl8l8_sincospi:
414 case RTLIB::impl__ZGVsNxvl4l4_sincospif:
415 case RTLIB::impl__ZGVsNxvl8l8_sincospi:
416 case RTLIB::impl_armpl_vsincospiq_f32:
417 case RTLIB::impl_armpl_vsincospiq_f64:
418 case RTLIB::impl_armpl_svsincospi_f32_x:
419 case RTLIB::impl_armpl_svsincospi_f64_x: {
420 AttrBuilder FuncAttrBuilder(Ctx);
421
422 bool IsF32 = LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincospif ||
423 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif ||
424 LibcallImpl == RTLIB::impl_armpl_vsincospiq_f32 ||
425 LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x ||
426 LibcallImpl == RTLIB::impl__ZGVnN4vl4l4_sincosf ||
427 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf ||
428 LibcallImpl == RTLIB::impl_armpl_vsincosq_f32 ||
429 LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x;
430
431 Type *ScalarTy = IsF32 ? Type::getFloatTy(C&: Ctx) : Type::getDoubleTy(C&: Ctx);
432 unsigned EC = IsF32 ? 4 : 2;
433
434 bool IsScalable = LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincos ||
435 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincosf ||
436 LibcallImpl == RTLIB::impl_armpl_svsincos_f32_x ||
437 LibcallImpl == RTLIB::impl_armpl_svsincos_f64_x ||
438 LibcallImpl == RTLIB::impl__ZGVsNxvl4l4_sincospif ||
439 LibcallImpl == RTLIB::impl__ZGVsNxvl8l8_sincospi ||
440 LibcallImpl == RTLIB::impl_armpl_svsincospi_f32_x ||
441 LibcallImpl == RTLIB::impl_armpl_svsincospi_f64_x;
442 VectorType *VecTy = VectorType::get(ElementType: ScalarTy, NumElements: EC, Scalable: IsScalable);
443
444 for (Attribute::AttrKind Attr : CommonFnAttrs)
445 FuncAttrBuilder.addAttribute(Val: Attr);
446 FuncAttrBuilder.addMemoryAttr(ME: MemoryEffects::argMemOnly(MR: ModRefInfo::Mod));
447
448 AttributeList Attrs;
449 Attrs = Attrs.addFnAttributes(C&: Ctx, B: FuncAttrBuilder);
450
451 {
452 AttrBuilder ArgAttrBuilder(Ctx);
453 for (Attribute::AttrKind AK : CommonPtrArgAttrs)
454 ArgAttrBuilder.addAttribute(Val: AK);
455 ArgAttrBuilder.addAlignmentAttr(Align: DL.getABITypeAlign(Ty: VecTy));
456 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 1, B: ArgAttrBuilder);
457 Attrs = Attrs.addParamAttributes(C&: Ctx, ArgNo: 2, B: ArgAttrBuilder);
458 }
459
460 PointerType *PtrTy = PointerType::get(C&: Ctx, AddressSpace: 0);
461 SmallVector<Type *, 4> ArgTys = {VecTy, PtrTy, PtrTy};
462 if (hasVectorMaskArgument(Impl: LibcallImpl))
463 ArgTys.push_back(Elt: VectorType::get(ElementType: Type::getInt1Ty(C&: Ctx), NumElements: EC, Scalable: IsScalable));
464
465 return {FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: ArgTys, isVarArg: false), Attrs};
466 }
467 default:
468 return {};
469 }
470
471 return {};
472}
473
474bool RuntimeLibcallsInfo::hasVectorMaskArgument(RTLIB::LibcallImpl Impl) {
475 /// FIXME: This should be generated by tablegen and support the argument at an
476 /// arbitrary position
477 switch (Impl) {
478 case RTLIB::impl_armpl_svfmod_f32_x:
479 case RTLIB::impl_armpl_svfmod_f64_x:
480 case RTLIB::impl_armpl_svmodf_f64_x:
481 case RTLIB::impl_armpl_svmodf_f32_x:
482 case RTLIB::impl_armpl_svsincos_f32_x:
483 case RTLIB::impl_armpl_svsincos_f64_x:
484 case RTLIB::impl_armpl_svsincospi_f32_x:
485 case RTLIB::impl_armpl_svsincospi_f64_x:
486 case RTLIB::impl__ZGVsMxvv_fmod:
487 case RTLIB::impl__ZGVsMxvv_fmodf:
488 case RTLIB::impl_armpl_svpow_f32_x:
489 case RTLIB::impl_armpl_svpow_f64_x:
490 case RTLIB::impl_armpl_svcbrt_f32_x:
491 case RTLIB::impl_armpl_svcbrt_f64_x:
492 return true;
493 default:
494 return false;
495 }
496}
497